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.

6788 lines
255 KiB

  1. /****************************************************************************/
  2. // noeint.c
  3. //
  4. // RDP Order Encoder Display Driver internal functions
  5. //
  6. // Copyright (C) 1996-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <precmpdd.h>
  9. #pragma hdrstop
  10. #include <limits.h>
  11. #define TRC_FILE "noeint"
  12. #include <adcg.h>
  13. #include <atrcapi.h>
  14. #include <noedisp.h>
  15. #include <noadisp.h>
  16. #include <nsbcdisp.h>
  17. #include <nschdisp.h>
  18. #include <nprcount.h>
  19. #include <oe2.h>
  20. #define DC_INCLUDE_DATA
  21. #include <ndddata.c>
  22. #include <nsbcddat.c>
  23. #include <oe2data.c>
  24. #undef DC_INCLUDE_DATA
  25. #include <noedata.c>
  26. #include <nchdisp.h>
  27. #include <nbadisp.h>
  28. #include <nbainl.h>
  29. #include <noeinl.h>
  30. #include <nsbcdisp.h>
  31. #include <nsbcinl.h>
  32. #include <at128.h>
  33. #include <tsgdiplusenums.h>
  34. #define BAD_FRAG_INDEX 0xffff
  35. #ifdef NotUsed
  36. /****************************************************************************/
  37. // OEConvertMask
  38. //
  39. // Convert a colour mask to bit depth and shift values.
  40. /****************************************************************************/
  41. void RDPCALL OEConvertMask(
  42. ULONG mask,
  43. PUSHORT pBitDepth,
  44. PUSHORT pShift)
  45. {
  46. UINT16 count;
  47. DC_BEGIN_FN("OEConvertMask");
  48. /************************************************************************/
  49. /* A color mask is a bitwise field containing a 1 where the color uses */
  50. /* the bit entry for the color and a 0 to indicate that it is not used */
  51. /* for the color index. */
  52. /* */
  53. /* The bit sequences for each color must be one set of continuous data, */
  54. /* so for example 00011100 is valid but 00110100 is not. An example */
  55. /* bitmask for a 16 bit palette is as follows. */
  56. /* */
  57. /* Red ----> 11111000 00000000 - 0xF800 - 5 bits - 11 shift */
  58. /* Green --> 00000111 11100000 - 0x07E0 - 6 bits - 5 shift */
  59. /* Blue ---> 00000000 00011111 - 0x001F - 5 bits - 0 shift */
  60. /* */
  61. /* This function converts the mask to a bit and shift value. */
  62. /************************************************************************/
  63. // Set up default values.
  64. *pShift = 0;
  65. *pBitDepth = 0;
  66. // Make sure we have a valid mask.
  67. if (mask == 0) {
  68. TRC_NRM((TB, "Ignoring mask"));
  69. DC_QUIT;
  70. }
  71. // Keep shifting the mask right until we hit a non-zero value in bit 0.
  72. // Store the resulting count as the color shift.
  73. count = 0;
  74. while ((mask & 1) == 0) {
  75. mask >>= 1;
  76. count++;
  77. }
  78. *pShift = count;
  79. // Keep shifting the mask right until we hit a zero value in bit 0.
  80. // Store the resulting count as the color bit depth.
  81. count = 0;
  82. while ((mask & 1) != 0) {
  83. mask >>= 1;
  84. count++;
  85. }
  86. *pBitDepth = count;
  87. TRC_DBG((TB, "Shift %hd bits %hd", *pShift, *pBitDepth));
  88. DC_END_FN();
  89. }
  90. #endif // NotUsed
  91. /****************************************************************************/
  92. // OEConvertColor
  93. //
  94. // Converts a color from the NT Display Driver to a DCCOLOR.
  95. /****************************************************************************/
  96. void RDPCALL OEConvertColor(
  97. PDD_PDEV ppdev,
  98. DCCOLOR *pDCColor,
  99. ULONG osColor,
  100. XLATEOBJ *pxlo)
  101. {
  102. ULONG realIndex;
  103. DC_BEGIN_FN("OEConvertColor");
  104. // Check if color translation is required.
  105. if (pxlo == NULL || pxlo->flXlate == XO_TRIVIAL) {
  106. // Use the OS color without translation.
  107. realIndex = osColor;
  108. }
  109. else {
  110. // Convert from BMP to device color.
  111. realIndex = XLATEOBJ_iXlate(pxlo, osColor);
  112. if (realIndex == -1) {
  113. TRC_ERR((TB, "Failed to convert color 0x%lx", osColor));
  114. memset(pDCColor, 0, sizeof(DCCOLOR));
  115. DC_QUIT;
  116. }
  117. }
  118. TRC_DBG((TB, "Device color 0x%lX", realIndex));
  119. #ifdef DC_HICOLOR
  120. if (ppdev->cClientBitsPerPel == 24) {
  121. TRC_DBG((TB, "using real RGB value %06lx", realIndex));
  122. pDCColor->u.rgb.red = ((RGBQUAD *)&realIndex)->rgbRed;
  123. pDCColor->u.rgb.green = ((RGBQUAD *)&realIndex)->rgbGreen;
  124. pDCColor->u.rgb.blue = ((RGBQUAD *)&realIndex)->rgbBlue;
  125. }
  126. else if ((ppdev->cClientBitsPerPel == 16) ||
  127. (ppdev->cClientBitsPerPel == 15)) {
  128. TRC_DBG((TB, "using 16bpp color %04lx", realIndex));
  129. ((BYTE *)pDCColor)[0] = (BYTE)realIndex;
  130. ((BYTE *)pDCColor)[1] = (BYTE)(realIndex >> 8);
  131. ((BYTE *)pDCColor)[2] = 0;
  132. }
  133. else
  134. #endif
  135. if (oeColorIndexSupported) {
  136. TRC_DBG((TB, "using index %d", realIndex));
  137. pDCColor->u.index = (BYTE)realIndex;
  138. // Zero out the rest of the color.
  139. pDCColor->u.rgb.green = 0;
  140. pDCColor->u.rgb.blue = 0;
  141. }
  142. else {
  143. pDCColor->u.rgb.red = (BYTE)ppdev->Palette[realIndex].peRed;
  144. pDCColor->u.rgb.green= (BYTE)ppdev->Palette[realIndex].peGreen;
  145. pDCColor->u.rgb.blue = (BYTE)ppdev->Palette[realIndex].peBlue;
  146. TRC_DBG((TB, "Red %x green %x blue %x", pDCColor->u.rgb.red,
  147. pDCColor->u.rgb.green, pDCColor->u.rgb.blue));
  148. }
  149. DC_EXIT_POINT:
  150. DC_END_FN();
  151. }
  152. /****************************************************************************/
  153. // OESendBrushOrder
  154. //
  155. // Allocates and sends brush orders. Returns FALSE on failure.
  156. /****************************************************************************/
  157. BOOL RDPCALL OESendBrushOrder(
  158. PDD_PDEV ppdev,
  159. POE_BRUSH_DATA pBrush,
  160. PBYTE pBits,
  161. UINT32 oeBrushId)
  162. {
  163. PINT_ORDER pOrder;
  164. PTS_CACHE_BRUSH_ORDER pBrushOrder;
  165. unsigned cbOrderSize;
  166. BOOL rc;
  167. DC_BEGIN_FN("OESendBrushOrder");
  168. // Calculate and allocate brush order buffer.
  169. cbOrderSize = sizeof(TS_CACHE_BRUSH_ORDER) -
  170. FIELDSIZE(TS_CACHE_BRUSH_ORDER, brushData) + pBrush->iBytes;
  171. pOrder = OA_AllocOrderMem(ppdev, cbOrderSize);
  172. if (pOrder != NULL) {
  173. // We've successfully allocated the order, so fill in the details.
  174. pBrushOrder = (PTS_CACHE_BRUSH_ORDER)pOrder->OrderData;
  175. pBrushOrder->header.extraFlags = 0;
  176. pBrushOrder->header.orderType = TS_CACHE_BRUSH;
  177. pBrushOrder->header.orderHdr.controlFlags = TS_STANDARD | TS_SECONDARY;
  178. pBrushOrder->cacheEntry = (char)pBrush->cacheEntry;
  179. pBrushOrder->iBitmapFormat = (char)pBrush->iBitmapFormat;
  180. pBrushOrder->cx = (char)pBrush->sizlBitmap.cx;
  181. pBrushOrder->cy = (char)pBrush->sizlBitmap.cy;
  182. pBrushOrder->style = pBrush->style;
  183. // Copy over the brush bits.
  184. pBrushOrder->iBytes = (char)pBrush->iBytes;
  185. memcpy(pBrushOrder->brushData, pBits, pBrush->iBytes);
  186. pBrushOrder->header.orderLength = (UINT16)
  187. TS_CALCULATE_SECONDARY_ORDER_ORDERLENGTH(cbOrderSize);
  188. INC_OUTCOUNTER(OUT_CACHEBRUSH);
  189. ADD_OUTCOUNTER(OUT_CACHEBRUSH_BYTES, cbOrderSize);
  190. OA_AppendToOrderList(pOrder);
  191. TRC_NRM((TB, "Brush Data PDU (%08lx, %08lx):%02ld entry(%02ld:%02ld), "
  192. "format:%ld, cx/cy:%02ld/%02ld",
  193. pBrush->key1, pBrush->key2, pBrushOrder->iBytes, oeBrushId,
  194. pBrushOrder->cacheEntry, pBrushOrder->iBitmapFormat,
  195. pBrushOrder->cx, pBrushOrder->cy));
  196. rc = TRUE;
  197. }
  198. else {
  199. TRC_ERR((TB, "Failed to allocate brush order"));
  200. pBrush->style = BS_NULL;
  201. rc = FALSE;
  202. }
  203. DC_END_FN();
  204. return rc;
  205. }
  206. /****************************************************************************/
  207. /* Function: OEStoreBrush */
  208. /* */
  209. /* Description: Store the brush data required for pattern realted orders. */
  210. /* This function is called by DrvRealiseBrush when it has data */
  211. /* to be stored about a brush. */
  212. /* */
  213. /* Parameters: pbo - BRUSHOBJ of the brush to be stored */
  214. /* style - Style of the brush (as defined in the DC-Share */
  215. /* protocol) */
  216. /* iBitmapFormat - color depth of brush */
  217. /* sizlBitmap - dimensions of brush */
  218. /* iBytes - number of brush bytes */
  219. /* pBits - Pointer to the bits which are used to define */
  220. /* a BS_PATTERN brush. */
  221. /* pxlo - XLATEOBJ for the brush. */
  222. /* hatch - Standard Windows hatch pattern index for a */
  223. /* BS_HATCHED brush. */
  224. /* pEncode - brush color encoding table */
  225. /* pColors - table of unique colors */
  226. /* numColors - number of unique colors */
  227. /****************************************************************************/
  228. BOOL RDPCALL OEStoreBrush(
  229. PDD_PDEV ppdev,
  230. BRUSHOBJ *pbo,
  231. BYTE style,
  232. ULONG iBitmapFormat,
  233. SIZEL *sizlBitmap,
  234. ULONG iBytes,
  235. PBYTE pBits,
  236. XLATEOBJ *pxlo,
  237. BYTE hatch,
  238. PBYTE pEncode,
  239. PUINT32 pColors,
  240. UINT32 numColors)
  241. {
  242. BOOL rc = FALSE;
  243. ULONG i, j;
  244. PBYTE pData = pBits;
  245. PULONG pColorTable;
  246. POE_BRUSH_DATA pBrush;
  247. BOOL bFoundIt;
  248. DCCOLOR devColor;
  249. UINT32 brushSupportLevel, brushSize;
  250. PVOID pUserDefined = NULL;
  251. DC_BEGIN_FN("OEStoreBrush");
  252. #ifdef DC_HICOLOR
  253. // Determine which realized brush size we will need
  254. if (numColors <= 2) {
  255. brushSize = 8;
  256. }
  257. else if (numColors <= MAX_BRUSH_ENCODE_COLORS) {
  258. if (ppdev->cClientBitsPerPel == 24)
  259. brushSize = 28;
  260. else if (ppdev->cClientBitsPerPel > 8) // 15 and 16 bpp
  261. brushSize = 24;
  262. else
  263. brushSize = 20;
  264. }
  265. else {
  266. brushSize = iBytes;
  267. }
  268. #else
  269. // Determine which realized brush size we will need
  270. if (numColors <= 2)
  271. brushSize = 8;
  272. else if (numColors <= MAX_BRUSH_ENCODE_COLORS)
  273. brushSize = 20;
  274. else
  275. brushSize = 64;
  276. #endif
  277. // Allocate the space for the brush data.
  278. pBrush = (POE_BRUSH_DATA)BRUSHOBJ_pvAllocRbrush(pbo,
  279. sizeof(OE_BRUSH_DATA) - FIELDSIZE(OE_BRUSH_DATA, brushData) +
  280. brushSize);
  281. if (pBrush != NULL) {
  282. // Reset the brush definition (init the minimum size).
  283. memset(pBrush, 0, sizeof(OE_BRUSH_DATA));
  284. // Set the new brush data. Brush fore and back colors are set below
  285. // depending on the brush style.
  286. pBrush->style = style;
  287. pBrush->hatch = hatch;
  288. pBrush->iBitmapFormat = iBitmapFormat;
  289. pBrush->sizlBitmap = *sizlBitmap;
  290. pBrush->iBytes = brushSize;
  291. pBrush->cacheEntry = -1;
  292. }
  293. else {
  294. TRC_ERR((TB, "No memory"));
  295. DC_QUIT;
  296. }
  297. // For pattern brushes, copy the brush specific data.
  298. if (style == BS_PATTERN) {
  299. brushSupportLevel = pddShm->sbc.caps.brushSupportLevel;
  300. // Encode all monochrome brushes as 1 bpp - hence the name!
  301. if (numColors <= 2) {
  302. switch (iBitmapFormat) {
  303. // already in the right format
  304. case BMF_1BPP:
  305. // Store the foreground and background colours for the brush
  306. OEConvertColor(ppdev, &pBrush->fore, 0, pxlo);
  307. OEConvertColor(ppdev, &pBrush->back, 1, pxlo);
  308. TRC_ASSERT((pxlo != NULL), (TB, "pxlo is NULL"));
  309. break;
  310. // convert to 1bpp
  311. case BMF_4BPP:
  312. case BMF_8BPP:
  313. case BMF_16BPP:
  314. case BMF_24BPP:
  315. // Store the foreground and background colours for the brush
  316. #ifdef DC_HICOLOR
  317. // The convert color fn takes care of the color depth
  318. OEConvertColor(ppdev, &pBrush->fore, pColors[0], NULL);
  319. OEConvertColor(ppdev, &pBrush->back, pColors[1], NULL);
  320. #else
  321. pBrush->fore.u.rgb.red = 0;
  322. pBrush->fore.u.rgb.green = 0;
  323. pBrush->fore.u.rgb.blue = 0;
  324. pBrush->back.u.rgb.red = 0;
  325. pBrush->back.u.rgb.green = 0;
  326. pBrush->back.u.rgb.blue = 0;
  327. pBrush->fore.u.index = (BYTE)pColors[0];
  328. pBrush->back.u.index = (BYTE)pColors[1];
  329. #endif
  330. // Each pixel is represented by 1 bit
  331. #ifdef DC_HICOLOR
  332. if (ppdev->cClientBitsPerPel > 8) {
  333. // Don't use endcoding table for hicolor sessions
  334. for (i = 0; i < 8; i++) {
  335. pBits[i] = (BYTE)((pBits[i * 8] << 7) & 0x80);
  336. for (j = 1; j < 8; j++)
  337. pBits[i] |= (BYTE)(pBits[i * 8 + j] <<
  338. (7 - j));
  339. }
  340. }
  341. else {
  342. #endif
  343. for (i = 0; i < 8; i++) {
  344. pBits[i] = (BYTE)
  345. (((pEncode[pBits[i * 8]]) << 7) & 0x80);
  346. for (j = 1; j < 8; j++)
  347. pBits[i] |= (BYTE)
  348. ((pEncode[pBits[i * 8 + j]]) <<
  349. (7 - j));
  350. }
  351. #ifdef DC_HICOLOR
  352. }
  353. #endif
  354. TRC_DBG((TB, "Encoded Bytes:"));
  355. TRC_DBG((TB, "%02lx %02lx %02lx %02lx",
  356. pBits[0], pBits[1], pBits[2], pBits[3]));
  357. TRC_DBG((TB, "%02lx %02lx %02lx %02lx",
  358. pBits[4], pBits[5], pBits[6], pBits[7]));
  359. iBitmapFormat = pBrush->iBitmapFormat = BMF_1BPP;
  360. iBytes = pBrush->iBytes = 8;
  361. break;
  362. default:
  363. TRC_ASSERT((FALSE), (TB, "Unknown brush depth: %ld",
  364. iBitmapFormat));
  365. }
  366. // if brush caching is enabled, check the cache
  367. if ((brushSupportLevel > TS_BRUSH_DEFAULT) &&
  368. (sbcEnabled & SBC_BRUSH_CACHE_ENABLED)) {
  369. UINT32 key1, key2;
  370. key1 = pBits[0] +
  371. ((ULONG) pBits[1] << 8) +
  372. ((ULONG) pBits[2] << 16) +
  373. ((ULONG) pBits[3] << 24);
  374. key2 = pBits[4] +
  375. ((ULONG) pBits[5] << 8) +
  376. ((ULONG) pBits[6] << 16) +
  377. ((ULONG) pBits[7] << 24);
  378. pBrush->key1 = key1;
  379. pBrush->key2 = key2;
  380. bFoundIt = CH_SearchCache(sbcSmallBrushCacheHandle, key1, key2,
  381. &pUserDefined, &pBrush->cacheEntry);
  382. pBrush->style = (BYTE) (TS_CACHED_BRUSH | iBitmapFormat);
  383. // this brush was already cached
  384. if (bFoundIt) {
  385. pBrush->hatch = (BYTE) pBrush->cacheEntry;
  386. pBrush->brushId = (INT32) (UINT_PTR) pUserDefined;
  387. pddCacheStats[BRUSH].CacheHits++;
  388. }
  389. // cache and send the brush
  390. else {
  391. pBrush->hatch = pBrush->cacheEntry = (BYTE)CH_CacheKey(
  392. sbcSmallBrushCacheHandle, key1, key2,
  393. (PVOID)ULongToPtr(pddShm->shareId));
  394. pBrush->brushId = pddShm->shareId;
  395. OESendBrushOrder(ppdev, pBrush, pBits, pBrush->brushId);
  396. TRC_NRM((TB, "Small Brush(%08lx,%08lx):%02ld, "
  397. "F/S/H(%ld/%d/%d), ID %02ld:%02ld",
  398. key1, key2, iBytes, iBitmapFormat, style, hatch,
  399. pBrush->brushId, pBrush->hatch));
  400. }
  401. // Note: this branch intentionally does NOT copy the brush
  402. // bits into the brush realization, but leaves that data zero.
  403. // This causes OE2 to think this field never changes. If the
  404. // brush becomes stale across reconnects, then the cache is
  405. // restored using key1/key2 since in this case the keys == data
  406. }
  407. else {
  408. // Copy the brush bits. Since this is an 8x8 mono bitmap, we can
  409. // copy the first byte of the brush data for each scan line.
  410. // NOTE however that the brush structures sent over the wire
  411. // re-use the hatching variable as the first byte of the brush
  412. // data.
  413. pData = pBits;
  414. pBrush->hatch = *pData;
  415. TRC_DBG((TB, " Hatch: %d", *pData));
  416. pData++;
  417. for (i = 0; i < 7; i++)
  418. pBrush->brushData[i] = pData[i];
  419. }
  420. }
  421. // Else we have to use the large brush cache. Note that DrvRealize
  422. // will not ask us to cache a brush if the client does not support
  423. // color brushes.
  424. else {
  425. CHDataKeyContext CHContext;
  426. CH_CreateKeyFromFirstData(&CHContext, pData, iBytes);
  427. #ifdef DC_HICOLOR
  428. /****************************************************************/
  429. /* If we're running in high color mode, the way we encode the */
  430. /* colors means that brushes with the same pattern but */
  431. /* different colors will appear the same. E.g. a brush that */
  432. /* starts lt blue, dk blue, pink will be encoded as 0,1,2 with */
  433. /* the color table set to */
  434. /* */
  435. /* 0 = lt blue */
  436. /* 1 = dk blue */
  437. /* 2 = pink */
  438. /* */
  439. /* Now consider a brush that goes green, blue, purple. It too */
  440. /* will be encoded as 0,1,2, with the color table set to */
  441. /* */
  442. /* 0 = green */
  443. /* 1 = blue */
  444. /* 2 = purple */
  445. /* */
  446. /* Thus a check simply on the pel values will find a false */
  447. /* match with the first brush. To avoid this, we need to build */
  448. /* the cache key from the pels AND the color table. */
  449. /****************************************************************/
  450. if ((ppdev->cClientBitsPerPel > 8) &&
  451. (numColors <= MAX_BRUSH_ENCODE_COLORS))
  452. CH_CreateKeyFromNextData(&CHContext, pColors,
  453. 4 * sizeof(UINT32));
  454. #endif
  455. pBrush->key1 = CHContext.Key1;
  456. pBrush->key2 = CHContext.Key2;
  457. // see if it is already cached
  458. bFoundIt = CH_SearchCache(sbcLargeBrushCacheHandle,
  459. CHContext.Key1, CHContext.Key2,
  460. &pUserDefined, &pBrush->cacheEntry);
  461. #ifdef DC_HICOLOR
  462. pBrush->iBitmapFormat = iBitmapFormat;
  463. #else
  464. // Only send 8 bpp brushes for simplicity
  465. iBitmapFormat = pBrush->iBitmapFormat = BMF_8BPP;
  466. #endif
  467. pBrush->style = (BYTE) (TS_CACHED_BRUSH | iBitmapFormat);
  468. pBrush->fore.u.rgb.red = 0;
  469. pBrush->fore.u.rgb.green = 0;
  470. pBrush->fore.u.rgb.blue = 0;
  471. pBrush->back.u.rgb.red = 0;
  472. pBrush->back.u.rgb.green = 0;
  473. pBrush->back.u.rgb.blue = 0;
  474. // this brush was already cached
  475. if (bFoundIt) {
  476. pBrush->hatch = (BYTE) pBrush->cacheEntry;
  477. pBrush->brushId = (INT32) (UINT_PTR) pUserDefined;
  478. pddCacheStats[BRUSH].CacheHits++;
  479. }
  480. // else cache and send the brush
  481. else {
  482. pBrush->hatch = pBrush->cacheEntry = (BYTE)CH_CacheKey(
  483. sbcLargeBrushCacheHandle, CHContext.Key1,
  484. CHContext.Key2, (PVOID) ULongToPtr(pddShm->shareId));
  485. #ifdef DC_HICOLOR
  486. // The vast majority of brushes are less than 4 unique colors
  487. // Note that to have got here, it has however got more than
  488. // 2 colors or we'd have sent it as mono!
  489. if (numColors <= MAX_BRUSH_ENCODE_COLORS) {
  490. UINT32 currIndex;
  491. // This code assumse that MAX_BRUSH_ENCODE_COLORS is 4!
  492. // If not, the sizes will be wrong
  493. TRC_ASSERT((MAX_BRUSH_ENCODE_COLORS == 4),
  494. (TB, "Max Brush Encode colors must be 4"));
  495. // Encode as 2 bits per pixel. We have to use the
  496. // pEncode table for lo color; for hi color we don't
  497. // need it because the pColors array contains the actual
  498. // colors rather than indices into a color table
  499. currIndex = 0;
  500. if (ppdev->cClientBitsPerPel > 8) {
  501. for (i = 0; i < (iBytes / 4); i++) {
  502. pBrush->brushData[i] =
  503. (((BYTE) pBits[currIndex ]) << 6) |
  504. (((BYTE) pBits[currIndex + 1]) << 4) |
  505. (((BYTE) pBits[currIndex + 2]) << 2) |
  506. (((BYTE) pBits[currIndex + 3]));
  507. currIndex += 4;
  508. }
  509. // Tag on the encoding table - remembering that the
  510. // size differs by color depth
  511. if (ppdev->cClientBitsPerPel == 24) {
  512. RGBTRIPLE *pIntoData =
  513. (RGBTRIPLE *)&(pBrush->brushData[16]);
  514. TRC_DBG((TB, "Encoding table:"));
  515. for (i = 0; i < 4; i++) {
  516. TRC_DBG((TB, "%d %08lx", i,
  517. (UINT32)pColors[i]));
  518. pIntoData[i] = *((RGBTRIPLE * )&pColors[i]);
  519. }
  520. pBrush->iBytes = iBytes = 28;
  521. }
  522. else {
  523. BYTE *pIntoData =
  524. (BYTE *)&(pBrush->brushData[16]);
  525. TRC_DBG((TB, "Encoding table:"));
  526. for (i = 0; i < 4; i++) {
  527. TRC_DBG((TB, "%d %08lx", i,
  528. (UINT32)pColors[i]));
  529. pIntoData[i * 2] = (BYTE)pColors[i];
  530. pIntoData[i * 2 + 1] = (BYTE)(pColors[i] >> 8);
  531. }
  532. pBrush->iBytes = iBytes = 24;
  533. }
  534. }
  535. else {
  536. for (i = 0; i < (iBytes / 4); i++) {
  537. pBrush->brushData[i] =
  538. (((BYTE)pEncode[pBits[currIndex ]]) << 6) |
  539. (((BYTE)pEncode[pBits[currIndex + 1]]) << 4) |
  540. (((BYTE)pEncode[pBits[currIndex + 2]]) << 2) |
  541. (((BYTE)pEncode[pBits[currIndex + 3]]));
  542. currIndex += 4;
  543. }
  544. // Tag on the encoding table
  545. TRC_DBG((TB, "Encoding table:"));
  546. for (i = 0; i < 4; i++) {
  547. TRC_DBG((TB, "%d %08lx", i, (UINT32)pColors[i]));
  548. pBrush->brushData[i + 16] = (BYTE) pColors[i];
  549. }
  550. pBrush->iBytes = iBytes = 20;
  551. }
  552. }
  553. // Else, leave it as N bytes per pixel
  554. else {
  555. memcpy(pBrush->brushData, pBits, iBytes);
  556. TRC_ALT((TB, "Non-compressed N-bpp brush (colors=%ld):",
  557. numColors));
  558. }
  559. #else
  560. // The vast majority of brushes are less than 4 unique colors
  561. if (numColors <= MAX_BRUSH_ENCODE_COLORS) {
  562. UINT32 currIndex;
  563. // Encode as 2 bits per pixel
  564. currIndex = 0;
  565. for (i = 0; i < (iBytes / MAX_BRUSH_ENCODE_COLORS); i++) {
  566. pBrush->brushData[i] =
  567. (((BYTE) pEncode[pBits[currIndex]]) << 6) |
  568. (((BYTE) pEncode[pBits[currIndex + 1]]) << 4) |
  569. (((BYTE) pEncode[pBits[currIndex + 2]]) << 2) |
  570. (((BYTE) pEncode[pBits[currIndex + 3]]));
  571. currIndex += MAX_BRUSH_ENCODE_COLORS;
  572. }
  573. // Tag on the encoding table
  574. for (i = 0; i < MAX_BRUSH_ENCODE_COLORS; i++) {
  575. pBrush->brushData[i + 16] = (BYTE) pColors[i];
  576. }
  577. pBrush->iBytes = iBytes = 20;
  578. }
  579. // Else, leave it as 1 byte per pixel
  580. else {
  581. for (i = 0; i < iBytes; i++)
  582. pBrush->brushData[i] = pBits[i];
  583. TRC_ALT((TB, "Non-compressed 8-bpp brush (colors=%ld):",
  584. numColors));
  585. }
  586. #endif
  587. pBrush->brushId = pddShm->shareId;
  588. OESendBrushOrder(ppdev, pBrush, pBrush->brushData,
  589. pBrush->brushId);
  590. TRC_NRM((TB, "Large Brush(%08lx,%08lx):%02ld, "
  591. "F/S/H(%ld/%d/%d), ID %02ld:%02ld",
  592. CHContext.Key1, CHContext.Key2, iBytes,
  593. iBitmapFormat, style, hatch,
  594. pBrush->brushId, pBrush->hatch));
  595. }
  596. }
  597. }
  598. else {
  599. if (pColors) {
  600. // Store the foreground and background colors for the brush
  601. OEConvertColor(ppdev, &pBrush->fore, pColors[0], pxlo);
  602. OEConvertColor(ppdev, &pBrush->back, pColors[1], pxlo);
  603. }
  604. }
  605. rc = TRUE;
  606. INC_OUTCOUNTER(OUT_BRUSH_STORED);
  607. DC_EXIT_POINT:
  608. DC_END_FN();
  609. return rc;
  610. }
  611. /****************************************************************************/
  612. /* Function: OEReCacheBrush */
  613. /* */
  614. /* Description: This routine is called when we discover a GRE cached brush */
  615. /* which was realized in a previous session. In this case we */
  616. /* must recache the brush and send it to the client. */
  617. /****************************************************************************/
  618. BOOL RDPCALL OEReCacheBrush(
  619. PDD_PDEV ppdev,
  620. POE_BRUSH_DATA pBrush)
  621. {
  622. BOOL rc = FALSE;
  623. PVOID pUserDefined = NULL;
  624. UINT32 key1, key2;
  625. CHCACHEHANDLE hBrushCache;
  626. BYTE brushData[8];
  627. PBYTE pBits;
  628. DC_BEGIN_FN("OEReCacheBrush");
  629. key1 = pBrush->key1;
  630. key2 = pBrush->key2;
  631. if (pBrush->iBitmapFormat == BMF_1BPP) {
  632. brushData[0] = key1 & 0x000000FF;
  633. brushData[1] = (key1 >> 8) & 0x000000FF;
  634. brushData[2] = (key1 >> 16) & 0x000000FF;
  635. brushData[3] = (key1 >> 24) & 0x000000FF;
  636. brushData[4] = key2 & 0x000000FF;
  637. brushData[5] = (key2 >> 8) & 0x000000FF;
  638. brushData[6] = (key2 >> 16) & 0x000000FF;
  639. brushData[7] = (key2 >> 24) & 0x000000FF;
  640. pBits = brushData;
  641. if ((pddShm->sbc.caps.brushSupportLevel > TS_BRUSH_DEFAULT) &&
  642. (sbcEnabled & SBC_BRUSH_CACHE_ENABLED)) {
  643. hBrushCache = sbcSmallBrushCacheHandle;
  644. }
  645. else {
  646. int i;
  647. // Copy the brush bits. Since this is an 8x8 mono bitmap, we can
  648. // copy the first byte of the brush data for each scan line.
  649. // NOTE however that the brush structures sent over the wire
  650. // re-use the hatching variable as the first byte of the brush
  651. // data.
  652. pBrush->style = BS_PATTERN;
  653. pBrush->brushId = pddShm->shareId;
  654. pBrush->cacheEntry = -1;
  655. pBrush->hatch = *pBits++;
  656. for (i = 0; i < 7; i++)
  657. pBrush->brushData[i] = pBits[i];
  658. rc = TRUE;
  659. DC_QUIT;
  660. }
  661. }
  662. else {
  663. if ((pddShm->sbc.caps.brushSupportLevel > TS_BRUSH_DEFAULT) &&
  664. (sbcEnabled & SBC_BRUSH_CACHE_ENABLED)) {
  665. hBrushCache = sbcLargeBrushCacheHandle;
  666. pBits = pBrush->brushData;
  667. }
  668. else {
  669. DC_QUIT;
  670. }
  671. }
  672. // cache and send the brush
  673. pBrush->hatch = pBrush->cacheEntry = (BYTE)CH_CacheKey(
  674. hBrushCache, key1, key2, (PVOID) ULongToPtr(pddShm->shareId));
  675. pBrush->brushId = pddShm->shareId;
  676. rc = OESendBrushOrder(ppdev, pBrush, pBits, pBrush->brushId);
  677. if (rc) {
  678. TRC_ERR((TB, "Re-cached brush(%08lx,%08lx):%02ld, ID %02ld:%02ld",
  679. key1, key2, pBrush->iBytes, pBrush->brushId, pBrush->hatch));
  680. INC_OUTCOUNTER(OUT_BRUSH_STORED);
  681. }
  682. DC_EXIT_POINT:
  683. DC_END_FN();
  684. return rc;
  685. }
  686. /****************************************************************************/
  687. // OECheckBrushIsSimple
  688. //
  689. // Check that the brush is a 'simple' object the protocol can send.
  690. /****************************************************************************/
  691. BOOL RDPCALL OECheckBrushIsSimple(
  692. PDD_PDEV ppdev,
  693. BRUSHOBJ *pbo,
  694. POE_BRUSH_DATA *ppBrush)
  695. {
  696. BOOL rc;
  697. POE_BRUSH_DATA pBrush = NULL;
  698. UINT32 style;
  699. DC_BEGIN_FN("OECheckBrushIsSimple");
  700. // A 'simple' brush satisfies any of the following.
  701. // 1) It is a solid color.
  702. // 2) It is a valid brush as stored by DrvRealizeBrush.
  703. // Check for a simple solid color.
  704. if (pbo->iSolidColor != -1) {
  705. // Use the reserved brush definition to set up the solid colour.
  706. TRC_DBG((TB, "Simple solid colour %08lx", pbo->iSolidColor));
  707. pBrush = &oeBrushData;
  708. // Set up the specific data for this brush.
  709. OEConvertColor(ppdev, &pBrush->fore, pbo->iSolidColor, NULL);
  710. pBrush->back.u.index = 0;
  711. pBrush->back.u.rgb.red = 0;
  712. pBrush->back.u.rgb.green = 0;
  713. pBrush->back.u.rgb.blue = 0;
  714. pBrush->style = BS_SOLID;
  715. pBrush->hatch = 0;
  716. RtlFillMemory(pBrush->brushData, sizeof(pBrush->brushData), 0);
  717. rc = TRUE;
  718. DC_QUIT;
  719. }
  720. rc = FALSE;
  721. // Check brush definition (which was stored when we realized the
  722. // brush). Here we find out if we've realised (cached) the brush already.
  723. // This is counted as a automatic cache read. Subsequent routines
  724. // increment the hit count if the brush was already cached.
  725. pddCacheStats[BRUSH].CacheReads++;
  726. pBrush = (POE_BRUSH_DATA)pbo->pvRbrush;
  727. if (pBrush == NULL) {
  728. pBrush = (POE_BRUSH_DATA)BRUSHOBJ_pvGetRbrush(pbo);
  729. if (pBrush == NULL) {
  730. // We can get NULL returned from BRUSHOBJ_pvGetRbrush when the
  731. // brush is NULL or in low-memory situations (when the brush
  732. // realization may fail).
  733. TRC_NRM((TB, "NULL returned from BRUSHOBJ_pvGetRbrush"));
  734. INC_OUTCOUNTER(OUT_CHECKBRUSH_NOREALIZATION);
  735. DC_QUIT;
  736. }
  737. }
  738. // If brush caching make sure this brush isn't from a previous session
  739. else if (pBrush->style & TS_CACHED_BRUSH) {
  740. if (pBrush->brushId == pddShm->shareId) {
  741. pddCacheStats[BRUSH].CacheHits++;
  742. }
  743. else {
  744. TRC_ERR((TB, "Stale brush [%ld] detected! (%ld != %ld)",
  745. pBrush->cacheEntry, pBrush->brushId, pddShm->shareId));
  746. if (!OEReCacheBrush(ppdev, pBrush)) {
  747. TRC_NRM((TB, "Unencodable brush, failed to ReCacheBrush"));
  748. INC_OUTCOUNTER(OUT_CHECKBRUSH_COMPLEX);
  749. DC_QUIT;
  750. }
  751. }
  752. }
  753. // Check it is an encodable brush. We cannot encode
  754. // - BS_NULL
  755. // - anything other than BS_SOLID or BS_PATTERN if
  756. // oeSendSolidPatternBrushOnly is TRUE.
  757. style = pBrush->style;
  758. if ((style == BS_NULL) ||
  759. (oeSendSolidPatternBrushOnly &&
  760. (style != BS_SOLID) &&
  761. (style != BS_PATTERN) &&
  762. (!(style & TS_CACHED_BRUSH))))
  763. {
  764. TRC_NRM((TB, "Unencodable brush type %d", style));
  765. INC_OUTCOUNTER(OUT_CHECKBRUSH_COMPLEX);
  766. DC_QUIT;
  767. }
  768. // Everything passed - let's use this brush.
  769. rc = TRUE;
  770. DC_EXIT_POINT:
  771. // Return the brush definition
  772. *ppBrush = pBrush;
  773. TRC_DBG((TB, "Returning %d - 0x%p", rc, pBrush));
  774. DC_END_FN();
  775. return rc;
  776. }
  777. #ifdef PERF_SPOILING
  778. /****************************************************************************/
  779. // OEIsSDAIncluded
  780. //
  781. // Returns TRUE if the list of RECTs passed in all lie completely within
  782. // our current SDA bounds.
  783. /****************************************************************************/
  784. BOOL RDPCALL OEIsSDAIncluded(PRECTL prc, UINT count)
  785. {
  786. BOOL rc = FALSE;
  787. unsigned uCurrentSDARect;
  788. PRECTL pSDARect;
  789. UINT i;
  790. DC_BEGIN_FN("OEIsSDAIncluded");
  791. // first check if we have SDA rects.
  792. if (pddShm->ba.firstRect != BA_INVALID_RECT_INDEX) {
  793. for (i=0 ; i < count; i++) {
  794. for (uCurrentSDARect = pddShm->ba.firstRect;
  795. uCurrentSDARect != BA_INVALID_RECT_INDEX;
  796. uCurrentSDARect = pddShm->ba.bounds[uCurrentSDARect].iNext) {
  797. pSDARect = &pddShm->ba.bounds[uCurrentSDARect].coord;
  798. if (prc[i].top >= pSDARect->top &&
  799. prc[i].bottom <= pSDARect->bottom &&
  800. prc[i].left >= pSDARect->left &&
  801. prc[i].right <= pSDARect->right) {
  802. break;
  803. }
  804. }
  805. // We got to the end of the SDA array so that means
  806. // we didn't find a rect that includes the target rect
  807. if (uCurrentSDARect == BA_INVALID_RECT_INDEX) {
  808. DC_QUIT;
  809. }
  810. }
  811. // We looped through all the rects and all were clipped
  812. rc = TRUE;
  813. DC_QUIT;
  814. }
  815. DC_EXIT_POINT:
  816. DC_END_FN();
  817. return rc;
  818. }
  819. #endif
  820. /****************************************************************************/
  821. // OEGetClipRects
  822. //
  823. // Fills in *pEnumRects with up to COMPLEX_CLIP_RECT_COUNT clip rectangles,
  824. // in standard GDI exclusive coordinates. The number of rects returned
  825. // is zero if there is no clip object or the clipping is trivial.
  826. // Returns FALSE if there are more than COMPLEX_CLIP_RECT_COUNT rects,
  827. // indicating the clip object is too complex to encode.
  828. /****************************************************************************/
  829. BOOL RDPCALL OEGetClipRects(CLIPOBJ *pco, OE_ENUMRECTS *pEnumRects)
  830. {
  831. BOOL rc = TRUE;
  832. DC_BEGIN_FN("OEGetClipRects");
  833. // No clip obj or trivial are the most common.
  834. if (pco == NULL || pco->iDComplexity == DC_TRIVIAL) {
  835. TRC_DBG((TB,"No/trivial clipobj"));
  836. pEnumRects->rects.c = 0;
  837. }
  838. else if (pco->iDComplexity == DC_RECT) {
  839. // Single rect is easy, just grab it.
  840. pEnumRects->rects.c = 1;
  841. pEnumRects->rects.arcl[0] = pco->rclBounds;
  842. }
  843. else {
  844. BOOL fMoreRects;
  845. unsigned NumRects = 0;
  846. OE_ENUMRECTS clip;
  847. TRC_ASSERT((pco->iDComplexity == DC_COMPLEX),
  848. (TB,"Unknown clipping %u", pco->iDComplexity));
  849. // Enumerate all the rectangles involved in this drawing operation.
  850. // The documentation for this function incorrectly states that the
  851. // returned value is the total number of rectangles comprising the
  852. // clip region. In fact, -1 is always returned, even when the final
  853. // parameter is non-zero.
  854. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  855. // Get the clip rectangles. We fetch these into the clip buffer which
  856. // is big enough to get all the clip rectangles we expect + 1. The
  857. // clip rectangle fetching is contained within a loop because, while
  858. // we expect to call CLIPOBJ_bEnum once only, it is possible for this
  859. // function to return zero rects and report that there are more to
  860. // fetch (according to MSDN).
  861. do {
  862. fMoreRects = CLIPOBJ_bEnum(pco, sizeof(clip),
  863. (ULONG *)&clip.rects);
  864. // CLIPOBJ_bEnum can return a count of zero when there are still
  865. // more rects.
  866. if (clip.rects.c != 0) {
  867. // Check to see if we have too many rects.
  868. if ((NumRects + clip.rects.c) <= COMPLEX_CLIP_RECT_COUNT) {
  869. // Copy the rects into the final destination.
  870. memcpy(&pEnumRects->rects.arcl[NumRects],
  871. &clip.rects.arcl[0],
  872. sizeof(RECTL) * clip.rects.c);
  873. NumRects += clip.rects.c;
  874. }
  875. else {
  876. rc = FALSE;
  877. break;
  878. }
  879. }
  880. } while (fMoreRects);
  881. pEnumRects->rects.c = NumRects;
  882. }
  883. DC_END_FN();
  884. return rc;
  885. }
  886. /****************************************************************************/
  887. // OEGetIntersectingClipRects
  888. //
  889. // Fills in *pClipRects with up to COMPLEX_CLIP_RECT_COUNT clip rectangles,
  890. // in standard GDI exclusive coordinates. Each result rectangle is clipped
  891. // against the provided (exclusive) order rect. The number of rects
  892. // returned is zero if there is no clip object or the clipping is trivial.
  893. // Returns CLIPRECTS_TOO_COMPLEX if there are more than
  894. // COMPLEX_CLIP_RECT_COUNT rects, CLIPRECTS_NO_INTERSECTIONS if there is
  895. // no intersection between the order rect and the clip rects.
  896. /****************************************************************************/
  897. unsigned RDPCALL OEGetIntersectingClipRects(
  898. CLIPOBJ *pco,
  899. RECTL *pRect,
  900. unsigned EnumType,
  901. OE_ENUMRECTS *pClipRects)
  902. {
  903. unsigned rc = CLIPRECTS_OK;
  904. RECTL OrderRect;
  905. RECTL ClippedRect;
  906. unsigned i;
  907. unsigned NumIntersections;
  908. OE_ENUMRECTS clip;
  909. DC_BEGIN_FN("OEGetIntersectingClipRects");
  910. // No clip obj or trivial are the most common.
  911. if (pco == NULL || pco->iDComplexity == DC_TRIVIAL) {
  912. TRC_DBG((TB,"No/trivial clipobj"));
  913. pClipRects->rects.c = 0;
  914. DC_QUIT;
  915. }
  916. OrderRect = *pRect;
  917. if (pco->iDComplexity == DC_RECT) {
  918. // Check for an intersection.
  919. ClippedRect = pco->rclBounds;
  920. if (ClippedRect.left < OrderRect.right &&
  921. ClippedRect.bottom > OrderRect.top &&
  922. ClippedRect.right > OrderRect.left &&
  923. ClippedRect.top < OrderRect.bottom) {
  924. // Get the intersection rect.
  925. ClippedRect.left = max(ClippedRect.left, OrderRect.left);
  926. ClippedRect.top = max(ClippedRect.top, OrderRect.top);
  927. ClippedRect.bottom = min(ClippedRect.bottom, OrderRect.bottom);
  928. ClippedRect.right = min(ClippedRect.right, OrderRect.right);
  929. pClipRects->rects.c = 1;
  930. pClipRects->rects.arcl[0] = ClippedRect;
  931. }
  932. else {
  933. rc = CLIPRECTS_NO_INTERSECTIONS;
  934. }
  935. }
  936. else {
  937. BOOL fMoreRects;
  938. unsigned NumRects = 0;
  939. OE_ENUMRECTS clip;
  940. TRC_ASSERT((pco->iDComplexity == DC_COMPLEX),
  941. (TB,"Unknown clipping %u", pco->iDComplexity));
  942. // Enumerate all the rectangles involved in this drawing operation.
  943. // The documentation for this function incorrectly states that the
  944. // returned value is the total number of rectangles comprising the
  945. // clip region. In fact, -1 is always returned, even when the final
  946. // parameter is non-zero.
  947. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, EnumType, 0);
  948. // Get the clip rectangles. We fetch these into the clip buffer which
  949. // is big enough to get all the clip rectangles we expect + 1. The
  950. // clip rectangle fetching is contained within a loop because, while
  951. // we expect to call CLIPOBJ_bEnum once only, it is possible for this
  952. // function to return zero rects and report that there are more to
  953. // fetch (according to MSDN).
  954. NumIntersections = 0;
  955. do {
  956. fMoreRects = CLIPOBJ_bEnum(pco, sizeof(clip),
  957. (ULONG *)&clip.rects);
  958. // CLIPOBJ_bEnum can return a count of zero when there are still
  959. // more rects.
  960. if (clip.rects.c != 0) {
  961. // Check to see if we have too many rects.
  962. if ((NumIntersections + clip.rects.c) <=
  963. COMPLEX_CLIP_RECT_COUNT) {
  964. for (i = 0; i < clip.rects.c; i++) {
  965. // Check for an intersection.
  966. if (clip.rects.arcl[i].left < OrderRect.right &&
  967. clip.rects.arcl[i].bottom > OrderRect.top &&
  968. clip.rects.arcl[i].right > OrderRect.left &&
  969. clip.rects.arcl[i].top < OrderRect.bottom) {
  970. // Clip the intersection rect.
  971. ClippedRect.left = max(clip.rects.arcl[i].left,
  972. OrderRect.left);
  973. ClippedRect.top = max(clip.rects.arcl[i].top,
  974. OrderRect.top);
  975. ClippedRect.right = min(clip.rects.arcl[i].right,
  976. OrderRect.right);
  977. ClippedRect.bottom = min(clip.rects.arcl[i].bottom,
  978. OrderRect.bottom);
  979. pClipRects->rects.arcl[NumIntersections] =
  980. ClippedRect;
  981. NumIntersections++;
  982. }
  983. }
  984. }
  985. else {
  986. rc = CLIPRECTS_TOO_COMPLEX;
  987. DC_QUIT;
  988. }
  989. }
  990. } while (fMoreRects);
  991. if (NumIntersections > 0)
  992. pClipRects->rects.c = NumIntersections;
  993. else
  994. rc = CLIPRECTS_NO_INTERSECTIONS;
  995. }
  996. DC_EXIT_POINT:
  997. DC_END_FN();
  998. return rc;
  999. }
  1000. /****************************************************************************/
  1001. // OEGetFontCacheInfo
  1002. //
  1003. // Gets the FCI for a font, allocating it if need be. Returns NULL on failure.
  1004. /****************************************************************************/
  1005. PFONTCACHEINFO RDPCALL OEGetFontCacheInfo(FONTOBJ *pfo)
  1006. {
  1007. PFONTCACHEINFO pfci;
  1008. PVOID pvConsumer;
  1009. DC_BEGIN_FN("OEGetFontCacheInfo");
  1010. pvConsumer = pfo->pvConsumer;
  1011. if (pvConsumer == NULL) {
  1012. pvConsumer = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTCACHEINFO),
  1013. DD_ALLOC_TAG);
  1014. if (pvConsumer != NULL && sbcFontCacheInfoList != NULL) {
  1015. // Save the pvConsumer data pointer so that on disconnect/logoff
  1016. // we can cleanup the memory.
  1017. if (sbcFontCacheInfoListIndex < sbcFontCacheInfoListSize) {
  1018. sbcFontCacheInfoList[sbcFontCacheInfoListIndex] =
  1019. (PFONTCACHEINFO)pvConsumer;
  1020. ((PFONTCACHEINFO)pvConsumer)->listIndex = sbcFontCacheInfoListIndex;
  1021. sbcFontCacheInfoListIndex++;
  1022. }
  1023. else {
  1024. unsigned i, j;
  1025. PFONTCACHEINFO * tempList;
  1026. // We ran out of the preallocated memory, we have to
  1027. // reallocate the info list and recompact the list to the
  1028. // new one.
  1029. // Note: We need to update the list index now!
  1030. tempList = (PFONTCACHEINFO *) EngAllocMem(0,
  1031. sizeof(PFONTCACHEINFO) * sbcFontCacheInfoListSize * 2,
  1032. DD_ALLOC_TAG);
  1033. if (tempList != NULL) {
  1034. j = 0;
  1035. for (i = 0; i < sbcFontCacheInfoListIndex; i++) {
  1036. if (sbcFontCacheInfoList[i] != NULL) {
  1037. tempList[j] = sbcFontCacheInfoList[i];
  1038. ((PFONTCACHEINFO)tempList[j])->listIndex = j;
  1039. j++;
  1040. }
  1041. }
  1042. EngFreeMem(sbcFontCacheInfoList);
  1043. sbcFontCacheInfoListSize = sbcFontCacheInfoListSize * 2;
  1044. sbcFontCacheInfoList = tempList;
  1045. sbcFontCacheInfoList[j] = (PFONTCACHEINFO)pvConsumer;
  1046. ((PFONTCACHEINFO)pvConsumer)->listIndex = j;
  1047. sbcFontCacheInfoListIndex = ++j;
  1048. }
  1049. else {
  1050. EngFreeMem(pvConsumer);
  1051. pvConsumer = NULL;
  1052. }
  1053. }
  1054. }
  1055. }
  1056. if (pvConsumer != NULL) {
  1057. pfci = (PFONTCACHEINFO)pvConsumer;
  1058. if (pfo->pvConsumer == NULL || pfci->shareId != pddShm->shareId ||
  1059. pfci->cacheHandle != pddShm->sbc.glyphCacheInfo[pfci->cacheId].cacheHandle) {
  1060. pfci->shareId = pddShm->shareId;
  1061. pfci->fontId = oeFontId++;
  1062. pfci->cacheId = -1;
  1063. }
  1064. pfo->pvConsumer = pvConsumer;
  1065. }
  1066. DC_END_FN();
  1067. return pvConsumer;
  1068. }
  1069. /****************************************************************************/
  1070. /* Worker function - encodes a delta from one rect to another in a minimal */
  1071. /* form in the MultiRectangle coded delta list. The encoding follows the */
  1072. /* following rules: */
  1073. /* 1. If a coordinate delta is zero, a flag is set saying so. This */
  1074. /* closely follows the data distribution which tends to have vertical */
  1075. /* and horizontal lines and so have a lot of zero deltas. */
  1076. /* 2. If we can pack the delta into 7 bits, do so, with the high bit */
  1077. /* cleared. This is similar to ASN.1 PER encoding; the high bit is a */
  1078. /* flag telling us whether the encoding is long. */
  1079. /* 3. Otherwise, we must be able to pack into 15 bits (assert if not), */
  1080. /* do so and set the high-order bit to indicate this is a long */
  1081. /* encoding. This differs from ASN.1 PER encoding in that we don't */
  1082. /* allow more than 15 bits of data. */
  1083. /* */
  1084. /* We usually see several small rectangles starting from about the same */
  1085. /* place but of wildly different shapes, so the delta between subsequent */
  1086. /* top-left's is small, and should normally fit in one byte, but the delta */
  1087. /* between bottom-rights may be large */
  1088. /* */
  1089. /* Thus we calculate the delta differently for the two corners: */
  1090. /* - the top left delta is the change from the last rectangle */
  1091. /* - the bottom right is the change from the top left of this rectangle */
  1092. /****************************************************************************/
  1093. void OEEncodeMultiRectangles(
  1094. BYTE **ppCurEncode,
  1095. unsigned *pNumDeltas,
  1096. unsigned *pDeltaSize,
  1097. BYTE *ZeroFlags,
  1098. RECTL *pFromRect,
  1099. RECTL *pToRect)
  1100. {
  1101. int Delta;
  1102. BYTE Zeros = 0;
  1103. BYTE *pBuffer;
  1104. unsigned EncodeLen = 0;
  1105. DC_BEGIN_FN("OEEncodeMultiRectangles");
  1106. pBuffer = *ppCurEncode;
  1107. // calculate the top-left x delta
  1108. Delta = pToRect->left - pFromRect->left;
  1109. TRC_DBG((TB, "Delta x-left %d", Delta));
  1110. if (Delta == 0) {
  1111. EncodeLen += 0;
  1112. Zeros |= ORD_CLIP_RECTS_XLDELTA_ZERO;
  1113. }
  1114. else if (Delta >= -64 && Delta <= 63) {
  1115. *pBuffer++ = (BYTE)(Delta & 0x7F);
  1116. EncodeLen += 1;
  1117. }
  1118. else {
  1119. // We can't encode deltas outside the range -16384 to +16383
  1120. if (Delta < -16384) {
  1121. TRC_ERR((TB,"X delta %d is too large to encode, clipping",Delta));
  1122. Delta = -16384;
  1123. }
  1124. else if (Delta > 16383) {
  1125. TRC_ERR((TB,"X delta %d is too large to encode, clipping",Delta));
  1126. Delta = 16383;
  1127. }
  1128. *pBuffer++ = (BYTE)((Delta >> 8) | ORD_CLIP_RECTS_LONG_DELTA);
  1129. *pBuffer++ = (BYTE)(Delta & 0xFF);
  1130. EncodeLen += 2;
  1131. }
  1132. // and the top-left y delta
  1133. Delta = pToRect->top - pFromRect->top;
  1134. TRC_DBG((TB, "Delta y-top %d", Delta));
  1135. if (Delta == 0) {
  1136. Zeros |= ORD_CLIP_RECTS_YTDELTA_ZERO;
  1137. }
  1138. else if (Delta >= -64 && Delta <= 63) {
  1139. *pBuffer++ = (BYTE)(Delta & 0x7F);
  1140. EncodeLen += 1;
  1141. }
  1142. else {
  1143. // See comments for the similar code above.
  1144. if (Delta < -16384) {
  1145. TRC_ERR((TB,"Y delta %d is too large to encode, clipping",Delta));
  1146. Delta = -16384;
  1147. }
  1148. else if (Delta > 16383) {
  1149. TRC_ERR((TB,"Y delta %d is too large to encode, clipping",Delta));
  1150. Delta = 16383;
  1151. }
  1152. *pBuffer++ = (BYTE)((Delta >> 8) | ORD_CLIP_RECTS_LONG_DELTA);
  1153. *pBuffer++ = (BYTE)(Delta & 0xFF);
  1154. EncodeLen += 2;
  1155. }
  1156. // Now the bottom-right x delta. Note this is relative to the current
  1157. // top left rather than the previous bottom right.
  1158. Delta = pToRect->right - pToRect->left;
  1159. TRC_DBG((TB, "Delta x-right %d", Delta));
  1160. if (Delta == 0) {
  1161. EncodeLen += 0;
  1162. Zeros |= ORD_CLIP_RECTS_XRDELTA_ZERO;
  1163. }
  1164. else if (Delta >= -64 && Delta <= 63) {
  1165. *pBuffer++ = (BYTE)(Delta & 0x7F);
  1166. EncodeLen += 1;
  1167. }
  1168. else {
  1169. // We can't encode deltas outside the range -16384 to +16383.
  1170. if (Delta < -16384) {
  1171. TRC_ERR((TB,"X delta %d is too large to encode, clipping",Delta));
  1172. Delta = -16384;
  1173. }
  1174. else if (Delta > 16383) {
  1175. TRC_ERR((TB,"X delta %d is too large to encode, clipping",Delta));
  1176. Delta = 16383;
  1177. }
  1178. *pBuffer++ = (BYTE)((Delta >> 8) | ORD_CLIP_RECTS_LONG_DELTA);
  1179. *pBuffer++ = (BYTE)(Delta & 0xFF);
  1180. EncodeLen += 2;
  1181. }
  1182. // and the bottom-right y delta.
  1183. Delta = pToRect->bottom - pToRect->top;
  1184. TRC_DBG((TB, "Delta y-bottom %d", Delta));
  1185. if (Delta == 0) {
  1186. Zeros |= ORD_CLIP_RECTS_YBDELTA_ZERO;
  1187. }
  1188. else if (Delta >= -64 && Delta <= 63) {
  1189. *pBuffer++ = (BYTE)(Delta & 0x7F);
  1190. EncodeLen += 1;
  1191. }
  1192. else {
  1193. // See comments for the similar code above.
  1194. if (Delta < -16384) {
  1195. TRC_ERR((TB,"Y delta %d is too large to encode, clipping",Delta));
  1196. Delta = -16384;
  1197. }
  1198. else if (Delta > 16383) {
  1199. TRC_ERR((TB,"Y delta %d is too large to encode, clipping",Delta));
  1200. Delta = 16383;
  1201. }
  1202. *pBuffer++ = (BYTE)((Delta >> 8) | ORD_CLIP_RECTS_LONG_DELTA);
  1203. *pBuffer++ = (BYTE)(Delta & 0xFF);
  1204. EncodeLen += 2;
  1205. }
  1206. // Set the zero flags by shifting the two bits we've accumulated.
  1207. ZeroFlags[(*pNumDeltas / 2)] |= (Zeros >> (4 * (*pNumDeltas & 0x01)));
  1208. *pNumDeltas += 1;
  1209. *pDeltaSize += EncodeLen;
  1210. *ppCurEncode = pBuffer;
  1211. DC_END_FN();
  1212. }
  1213. /****************************************************************************/
  1214. // OEBuildMultiClipOrder
  1215. //
  1216. // Creates a multi-clip-rect blob in intermediate format for multi-clip
  1217. // orders. Returns the number of clip rects in the blob.
  1218. /****************************************************************************/
  1219. unsigned OEBuildMultiClipOrder(
  1220. PDD_PDEV ppdev,
  1221. CLIP_RECT_VARIABLE_CODEDDELTALIST *pCodedDeltaList,
  1222. OE_ENUMRECTS *pClipRects)
  1223. {
  1224. unsigned NumRects;
  1225. unsigned i;
  1226. unsigned NumZeroFlagBytes;
  1227. BYTE Deltas[ORD_MAX_CLIP_RECTS_CODEDDELTAS_LEN] = { 0 };
  1228. BYTE ZeroFlags[ORD_MAX_CLIP_RECTS_ZERO_FLAGS_BYTES] = { 0 };
  1229. BYTE *pCurEncode;
  1230. unsigned NumDeltas = 0;
  1231. unsigned DeltaSize = 0;
  1232. RECTL nextRect = { 0 };
  1233. DC_BEGIN_FN("OEBuildMultiClipOrder");
  1234. #ifdef DRAW_NINEGRID
  1235. // Check that we actually have at least one clip rect.
  1236. TRC_ASSERT((pClipRects->rects.c > 0), (TB, "Got non-complex pClipObj"));
  1237. #else
  1238. // Check that we actually have more than one clip rect.
  1239. TRC_ASSERT((pClipRects->rects.c > 1), (TB, "Got non-complex pClipObj"));
  1240. #endif
  1241. // We expect no more than COMPLEX_CLIP_RECT_COUNT since
  1242. // somewhere up the encoding path we would have determined
  1243. // the number of clip rects already.
  1244. TRC_ASSERT((pClipRects->rects.c <= COMPLEX_CLIP_RECT_COUNT),
  1245. (TB, "Got %u rects but more exist", pClipRects->rects.c));
  1246. NumRects = pClipRects->rects.c;
  1247. pCurEncode = Deltas;
  1248. for (i = 0; i < NumRects; i++) {
  1249. // Add it to the delta array.
  1250. OEEncodeMultiRectangles(&pCurEncode, &NumDeltas, &DeltaSize,
  1251. ZeroFlags, &nextRect, &pClipRects->rects.arcl[i]);
  1252. nextRect = pClipRects->rects.arcl[i];
  1253. }
  1254. // Put the deltas into the supplied array.
  1255. NumZeroFlagBytes = (NumDeltas + 1) / 2;
  1256. TRC_NRM((TB, "Num zero flags %d", NumZeroFlagBytes));
  1257. pCodedDeltaList->len = DeltaSize + NumZeroFlagBytes;
  1258. // Copy the zero flags first.
  1259. memcpy(pCodedDeltaList->Deltas, ZeroFlags, NumZeroFlagBytes);
  1260. // Next copy the encoded deltas.
  1261. memcpy(pCodedDeltaList->Deltas + NumZeroFlagBytes, Deltas, DeltaSize);
  1262. TRC_NRM((TB, "num deltas %d in list len %d",
  1263. NumDeltas,
  1264. pCodedDeltaList->len));
  1265. TRC_DATA_NRM("zero flags", ZeroFlags, NumZeroFlagBytes);
  1266. TRC_DATA_NRM("deltas", Deltas, DeltaSize);
  1267. DC_END_FN();
  1268. return NumDeltas;
  1269. }
  1270. /****************************************************************************/
  1271. // OEBuildPrecodeMultiClipFields
  1272. //
  1273. // Given a CLIPOBJ, encodes the clip rects directly into the wire format for
  1274. // the nDeltaEntries and CLIP_RECT_VARIABLE_CODEDDELTALIST fields.
  1275. // Returns field flags for the nDeltaEntries and deltas fields:
  1276. // 0x01 for nDeltaEntries
  1277. // 0x02 for deltas
  1278. /****************************************************************************/
  1279. unsigned RDPCALL OEBuildPrecodeMultiClipFields(
  1280. OE_ENUMRECTS *pClipRects,
  1281. BYTE **ppBuffer,
  1282. UINT32 *pPrevNumDeltaEntries,
  1283. BYTE *pPrevCodedDeltas)
  1284. {
  1285. BYTE *pBuffer;
  1286. unsigned rc;
  1287. unsigned i;
  1288. unsigned NumRects;
  1289. unsigned NumZeroFlagBytes;
  1290. BYTE *pCurEncode;
  1291. unsigned NumDeltas = 0;
  1292. unsigned DeltaSize = 0;
  1293. unsigned TotalSize;
  1294. RECTL nextRect = { 0 };
  1295. BYTE Deltas[ORD_MAX_CLIP_RECTS_CODEDDELTAS_LEN] = { 0 };
  1296. BYTE ZeroFlags[ORD_MAX_CLIP_RECTS_ZERO_FLAGS_BYTES] = { 0 };
  1297. DC_BEGIN_FN("OEBuildPrecodeMultiClipFields");
  1298. // Check that we actually have more than one clip rect.
  1299. TRC_ASSERT((pClipRects->rects.c > 1), (TB, "Got non-complex clip"));
  1300. // We expect no more than COMPLEX_CLIP_RECT_COUNT since
  1301. // somewhere up the encoding path we would have determined
  1302. // the number of clip rects already.
  1303. TRC_ASSERT((pClipRects->rects.c <= COMPLEX_CLIP_RECT_COUNT),
  1304. (TB, "Got %u rects but more exist", pClipRects->rects.c));
  1305. NumRects = pClipRects->rects.c;
  1306. TRC_NRM((TB,"Encoding %u rects", NumRects));
  1307. pCurEncode = Deltas;
  1308. for (i = 0; i < NumRects; i++) {
  1309. // Add it to the delta array.
  1310. OEEncodeMultiRectangles(&pCurEncode, &NumDeltas, &DeltaSize,
  1311. ZeroFlags, &nextRect, &pClipRects->rects.arcl[i]);
  1312. TRC_DBG((TB," Added rect (%d,%d,%d,%d)",
  1313. pClipRects->rects.arcl[i].left,
  1314. pClipRects->rects.arcl[i].top,
  1315. pClipRects->rects.arcl[i].right,
  1316. pClipRects->rects.arcl[i].bottom));
  1317. nextRect = pClipRects->rects.arcl[i];
  1318. }
  1319. // Now use the accumulated information to encode the wire format.
  1320. pBuffer = *ppBuffer;
  1321. // nDeltaEntries - one-byte encoding if not same as previous.
  1322. if (NumDeltas == *pPrevNumDeltaEntries) {
  1323. rc = 0;
  1324. }
  1325. else {
  1326. rc = 0x01;
  1327. *pBuffer++ = (BYTE)NumDeltas;
  1328. *pPrevNumDeltaEntries = NumDeltas;
  1329. }
  1330. // The size is placed on the wire as 2 bytes, followed by the flag bytes
  1331. // and the deltas, as long as they are different from the previous.
  1332. NumZeroFlagBytes = (NumDeltas + 1) / 2;
  1333. TRC_DBG((TB, "Num flag bytes %d", NumZeroFlagBytes));
  1334. // Assemble the encoded rect deltas for comparison to the previous
  1335. // deltas in the last OE2 order encoding.
  1336. *((PUINT16_UA)pBuffer) = (UINT16)(DeltaSize + NumZeroFlagBytes);
  1337. memcpy(pBuffer + 2, ZeroFlags, NumZeroFlagBytes);
  1338. memcpy(pBuffer + 2 + NumZeroFlagBytes, Deltas, DeltaSize);
  1339. TotalSize = 2 + NumZeroFlagBytes + DeltaSize;
  1340. if (memcmp(pBuffer, pPrevCodedDeltas, TotalSize)) {
  1341. // Only send the deltas if the block is different from
  1342. // the previous block.
  1343. memcpy(pPrevCodedDeltas, pBuffer, TotalSize);
  1344. pBuffer += TotalSize;
  1345. rc |= 0x02;
  1346. }
  1347. *ppBuffer = pBuffer;
  1348. DC_END_FN();
  1349. return rc;
  1350. }
  1351. /****************************************************************************/
  1352. // OEGetIntersectionsWithClipRects
  1353. //
  1354. // Determines the rects that intersect between a set of (exclusive) clip
  1355. // rects and a single (exclusive) order rect. Clips the rects to the order
  1356. // rect while returning them; result rects are in exclusive coords.
  1357. // Returns the number of intersecting rects. Should only be called when
  1358. // there are more than zero clip rects.
  1359. /****************************************************************************/
  1360. unsigned OEGetIntersectionsWithClipRects(
  1361. RECTL *pRect,
  1362. OE_ENUMRECTS *pClipRects,
  1363. OE_ENUMRECTS *pResultRects)
  1364. {
  1365. RECTL OrderRect;
  1366. RECTL ClippedRect;
  1367. RECTL ClipRect;
  1368. unsigned i;
  1369. unsigned NumRects;
  1370. unsigned NumIntersections;
  1371. DC_BEGIN_FN("OEGetIntersectionsWithClipRects");
  1372. TRC_ASSERT((pClipRects->rects.c != 0),(TB,"Zero cliprects not allowed"));
  1373. OrderRect = *pRect;
  1374. NumRects = pClipRects->rects.c;
  1375. NumIntersections = 0;
  1376. for (i = 0; i < NumRects; i++) {
  1377. ClipRect = pClipRects->rects.arcl[i];
  1378. // Check for an intersection.
  1379. if (ClipRect.left < OrderRect.right &&
  1380. ClipRect.bottom > OrderRect.top &&
  1381. ClipRect.right > OrderRect.left &&
  1382. ClipRect.top < OrderRect.bottom) {
  1383. // Clip the intersection rect.
  1384. ClippedRect.left = max(ClipRect.left, OrderRect.left);
  1385. ClippedRect.bottom = min(ClipRect.bottom, OrderRect.bottom);
  1386. ClippedRect.right = min(ClipRect.right, OrderRect.right);
  1387. ClippedRect.top = max(ClipRect.top, OrderRect.top);
  1388. pResultRects->rects.arcl[NumIntersections] = ClippedRect;
  1389. NumIntersections++;
  1390. }
  1391. }
  1392. pResultRects->rects.c = NumIntersections;
  1393. DC_END_FN();
  1394. return NumIntersections;
  1395. }
  1396. /****************************************************************************/
  1397. // OEClipAndAddScreenDataAreaByIntersectRects
  1398. //
  1399. // Adds areas specified in intersect rect list to the SDA. If there are
  1400. // no intersect rects, adds the entire *pRect to the SDA.
  1401. /****************************************************************************/
  1402. void RDPCALL OEClipAndAddScreenDataAreaByIntersectRects(
  1403. PRECTL pRect,
  1404. OE_ENUMRECTS *pClipRects)
  1405. {
  1406. RECTL ClippedRect;
  1407. unsigned i;
  1408. unsigned NumRects;
  1409. DC_BEGIN_FN("OEClipAndAddScreenDataAreaByIntersectRects");
  1410. NumRects = pClipRects->rects.c;
  1411. if (NumRects == 0) {
  1412. // No clip rects; add the entire bounds.
  1413. // Use the inclusive rect. We make a copy because BA_AddScreenData
  1414. // can modify the rectangle.
  1415. ClippedRect = *pRect;
  1416. TRC_NRM((TB, "Adding SDA (%d,%d)(%d,%d)", ClippedRect.left,
  1417. ClippedRect.top, ClippedRect.right, ClippedRect.bottom));
  1418. BA_AddScreenData(&ClippedRect);
  1419. }
  1420. else {
  1421. for (i = 0; i < NumRects; i++) {
  1422. // Convert each rect to inclusive.
  1423. ClippedRect.left = pClipRects->rects.arcl[i].left;
  1424. ClippedRect.top = pClipRects->rects.arcl[i].top;
  1425. ClippedRect.right = pClipRects->rects.arcl[i].right;
  1426. ClippedRect.bottom = pClipRects->rects.arcl[i].bottom;
  1427. // Add the clipped rect into the SDA.
  1428. TRC_NRM((TB, "Adding SDA (%d,%d)(%d,%d)",
  1429. ClippedRect.left, ClippedRect.top,
  1430. ClippedRect.right, ClippedRect.bottom));
  1431. BA_AddScreenData(&ClippedRect);
  1432. }
  1433. }
  1434. DC_END_FN();
  1435. }
  1436. /****************************************************************************/
  1437. // OEClipAndAddScreenDataArea
  1438. //
  1439. // ClipObj version of OEClipAndAddScreenDataAreaByIntersectRects(), uses pco
  1440. // for enumeration since it may contain more than COMPLEX_CLIP_RECT_COUNT
  1441. // rects.
  1442. /****************************************************************************/
  1443. void RDPCALL OEClipAndAddScreenDataArea(PRECTL pRect, CLIPOBJ *pco)
  1444. {
  1445. BOOL fMoreRects;
  1446. RECTL clippedRect;
  1447. unsigned i;
  1448. OE_ENUMRECTS clip;
  1449. DC_BEGIN_FN("OEClipAndAddScreenDataArea");
  1450. if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL)) {
  1451. // No clipping -- add the (exclusive) *pRect directly, making a copy
  1452. // since BA_AddScreenData() can modify the rect.
  1453. clippedRect = *pRect;
  1454. TRC_NRM((TB, "Adding SDA (%d,%d)(%d,%d)", clippedRect.left,
  1455. clippedRect.top, clippedRect.right, clippedRect.bottom));
  1456. BA_AddScreenData(&clippedRect);
  1457. }
  1458. else if (pco->iDComplexity == DC_RECT) {
  1459. // One clipping rectangle - use it directly. Make sure the rectangle
  1460. // is valid before adding to the SDA.
  1461. clippedRect.left = max(pco->rclBounds.left, pRect->left);
  1462. clippedRect.right = min(pco->rclBounds.right, pRect->right);
  1463. if (clippedRect.left < clippedRect.right) {
  1464. clippedRect.bottom = min(pco->rclBounds.bottom,
  1465. pRect->bottom);
  1466. clippedRect.top = max(pco->rclBounds.top, pRect->top);
  1467. if (clippedRect.bottom > clippedRect.top) {
  1468. // Add the clipped rect into the SDA.
  1469. TRC_NRM((TB, "Adding SDA RECT (%d,%d)(%d,%d)",
  1470. clippedRect.left, clippedRect.top,
  1471. clippedRect.right, clippedRect.bottom));
  1472. BA_AddScreenData(&clippedRect);
  1473. }
  1474. }
  1475. }
  1476. else {
  1477. // Enumerate all the rectangles involved in this drawing operation.
  1478. // The documentation for this function incorrectly states that
  1479. // the returned value is the total number of rectangles
  1480. // comprising the clip region. In fact, -1 is always returned,
  1481. // even when the final parameter is non-zero.
  1482. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  1483. do {
  1484. // Get the next batch of clipping rectangles.
  1485. fMoreRects = CLIPOBJ_bEnum(pco, sizeof(clip),
  1486. (ULONG *)&clip.rects);
  1487. for (i = 0; i < clip.rects.c; i++) {
  1488. TRC_DBG((TB, " (%d,%d)(%d,%d)",
  1489. clip.rects.arcl[i].left, clip.rects.arcl[i].top,
  1490. clip.rects.arcl[i].right, clip.rects.arcl[i].bottom));
  1491. // Intersect the SDA rect with the clip rect, checking for
  1492. // no intersection. Convert clip.rects.arcl[i] to inclusive
  1493. // coords during comparisons.
  1494. clippedRect.left = max(clip.rects.arcl[i].left,
  1495. pRect->left);
  1496. clippedRect.right = min(clip.rects.arcl[i].right,
  1497. pRect->right);
  1498. // No horizontal intersection if the left boundary is to the
  1499. // right of the right boundary.
  1500. if (clippedRect.left < clippedRect.right) {
  1501. clippedRect.bottom = min(clip.rects.arcl[i].bottom,
  1502. pRect->bottom);
  1503. clippedRect.top = max(clip.rects.arcl[i].top, pRect->top);
  1504. // No vertical intersection if the top boundary is below
  1505. // the bottom boundary.
  1506. if (clippedRect.top < clippedRect.bottom) {
  1507. TRC_NRM((TB, "Adding SDA (%d,%d)(%d,%d)",
  1508. clippedRect.left, clippedRect.top,
  1509. clippedRect.right, clippedRect.bottom));
  1510. BA_AddScreenData(&clippedRect);
  1511. }
  1512. }
  1513. }
  1514. } while (fMoreRects);
  1515. }
  1516. DC_END_FN();
  1517. }
  1518. /****************************************************************************/
  1519. // OEEncodeLineToOrder
  1520. //
  1521. // Encodes a LineTo order to wire format.
  1522. /****************************************************************************/
  1523. BOOL RDPCALL OEEncodeLineToOrder(
  1524. PDD_PDEV ppdev,
  1525. PPOINTL startPoint,
  1526. PPOINTL endPoint,
  1527. UINT32 rop2,
  1528. UINT32 color,
  1529. OE_ENUMRECTS *pClipRects)
  1530. {
  1531. BOOL rc;
  1532. PINT_ORDER pOrder;
  1533. DC_BEGIN_FN("OEEncodeLineToOrder");
  1534. // 2 field flag bytes.
  1535. pOrder = OA_AllocOrderMem(ppdev, MAX_ORDER_SIZE(pClipRects->rects.c,
  1536. 2, MAX_LINETO_FIELD_SIZE));
  1537. if (pOrder != NULL) {
  1538. BYTE *pControlFlags = pOrder->OrderData;
  1539. BYTE *pBuffer = pControlFlags + 1;
  1540. PUINT32_UA pFieldFlags;
  1541. short Delta, NormalCoordEncoding[4];
  1542. BOOLEAN bUseDeltaCoords;
  1543. unsigned NumFields;
  1544. DCCOLOR Color;
  1545. POINTL ClippedPoint;
  1546. memset(NormalCoordEncoding, 0, sizeof(NormalCoordEncoding));
  1547. // Direct-encode the primary order fields. 2 field flag bytes.
  1548. *pControlFlags = TS_STANDARD;
  1549. OE2_EncodeOrderType(pControlFlags, &pBuffer, TS_ENC_LINETO_ORDER);
  1550. pFieldFlags = (PUINT32_UA)pBuffer;
  1551. *pFieldFlags = 0;
  1552. *(pFieldFlags + 1) = 0;
  1553. pBuffer += 2;
  1554. if (pClipRects->rects.c != 0)
  1555. OE2_EncodeBounds(pControlFlags, &pBuffer,
  1556. &pClipRects->rects.arcl[0]);
  1557. // Start with the BackMode field.
  1558. // We only draw solid lines with no option as to what we do to the
  1559. // background, so this is always transparent. We will end up sending
  1560. // the field once with the first LineTo we send.
  1561. if (PrevLineTo.BackMode != TRANSPARENT) {
  1562. PrevLineTo.BackMode = TRANSPARENT;
  1563. *((unsigned short UNALIGNED *)pBuffer) =
  1564. (unsigned short)TRANSPARENT;
  1565. pBuffer += sizeof(short);
  1566. *pFieldFlags |= 0x0001;
  1567. }
  1568. // Simultaneously determine if each of the coordinate fields has
  1569. // changed, whether we can use delta coordinates, and save changed
  1570. // fields.
  1571. NumFields = 0;
  1572. bUseDeltaCoords = TRUE;
  1573. // Clip the start point coords.
  1574. ClippedPoint = *startPoint;
  1575. OEClipPoint(&ClippedPoint);
  1576. // nXStart
  1577. Delta = (short)(ClippedPoint.x - PrevLineTo.nXStart);
  1578. if (Delta) {
  1579. PrevLineTo.nXStart = ClippedPoint.x;
  1580. if (Delta != (short)(char)Delta)
  1581. bUseDeltaCoords = FALSE;
  1582. pBuffer[NumFields] = (char)Delta;
  1583. NormalCoordEncoding[NumFields] = (short)ClippedPoint.x;
  1584. NumFields++;
  1585. *pFieldFlags |= 0x0002;
  1586. }
  1587. // nYStart
  1588. Delta = (short)(ClippedPoint.y - PrevLineTo.nYStart);
  1589. if (Delta) {
  1590. PrevLineTo.nYStart = ClippedPoint.y;
  1591. if (Delta != (short)(char)Delta)
  1592. bUseDeltaCoords = FALSE;
  1593. pBuffer[NumFields] = (char)Delta;
  1594. NormalCoordEncoding[NumFields] = (short)ClippedPoint.y;
  1595. NumFields++;
  1596. *pFieldFlags |= 0x0004;
  1597. }
  1598. // Clip the end point coords.
  1599. ClippedPoint = *endPoint;
  1600. OEClipPoint(&ClippedPoint);
  1601. // nXEnd
  1602. Delta = (short)(ClippedPoint.x - PrevLineTo.nXEnd);
  1603. if (Delta) {
  1604. PrevLineTo.nXEnd = ClippedPoint.x;
  1605. if (Delta != (short)(char)Delta)
  1606. bUseDeltaCoords = FALSE;
  1607. pBuffer[NumFields] = (char)Delta;
  1608. NormalCoordEncoding[NumFields] = (short)ClippedPoint.x;
  1609. NumFields++;
  1610. *pFieldFlags |= 0x0008;
  1611. }
  1612. // nYEnd
  1613. Delta = (short)(ClippedPoint.y - PrevLineTo.nYEnd);
  1614. if (Delta) {
  1615. PrevLineTo.nYEnd = ClippedPoint.y;
  1616. if (Delta != (short)(char)Delta)
  1617. bUseDeltaCoords = FALSE;
  1618. pBuffer[NumFields] = (char)Delta;
  1619. NormalCoordEncoding[NumFields] = (short)ClippedPoint.y;
  1620. NumFields++;
  1621. *pFieldFlags |= 0x0010;
  1622. }
  1623. // Copy the final coordinates to the order.
  1624. if (bUseDeltaCoords) {
  1625. *pControlFlags |= TS_DELTA_COORDINATES;
  1626. pBuffer += NumFields;
  1627. }
  1628. else {
  1629. *((DWORD UNALIGNED *)pBuffer) = *((DWORD *)NormalCoordEncoding);
  1630. *((DWORD UNALIGNED *)(pBuffer + 4)) =
  1631. *((DWORD *)&NormalCoordEncoding[2]);
  1632. pBuffer += NumFields * sizeof(short);
  1633. }
  1634. // BackColor is a 3-byte color field.
  1635. // As it happens, we always draw solid lines, so we can choose any
  1636. // color. For convenience we choose black (0,0,0) so we never have to
  1637. // send this field at all. We skip encoding flag 0x0020.
  1638. // ROP2
  1639. if (rop2 != PrevLineTo.ROP2) {
  1640. PrevLineTo.ROP2 = rop2;
  1641. *pBuffer++ = (BYTE)rop2;
  1642. *pFieldFlags |= 0x0040;
  1643. }
  1644. // PenStyle
  1645. // The NT Display Driver is only called to accelerate simple solid
  1646. // lines. So we only support pen styles of PS_SOLID. Since PS_SOLID is
  1647. // zero, we never have to send this field. Skip encoding flag 0x0080.
  1648. // PenWidth
  1649. // We only accelerate width 1 fields. Which means we will send the
  1650. // 1 value only once in the first LineTo in the session.
  1651. if (PrevLineTo.PenWidth != 1) {
  1652. PrevLineTo.PenWidth = 1;
  1653. *pBuffer++ = 1;
  1654. *pFieldFlags |= 0x0100;
  1655. }
  1656. // PenColor is a 3-byte color field.
  1657. OEConvertColor(ppdev, &Color, color, NULL);
  1658. if (memcmp(&Color, &PrevLineTo.PenColor, sizeof(Color))) {
  1659. PrevLineTo.PenColor = Color;
  1660. *pBuffer++ = Color.u.rgb.red;
  1661. *pBuffer++ = Color.u.rgb.green;
  1662. *pBuffer++ = Color.u.rgb.blue;
  1663. *pFieldFlags |= 0x0200;
  1664. }
  1665. // Set final size.
  1666. pOrder->OrderLength = (unsigned)(pBuffer - pOrder->OrderData);
  1667. // See if we can save sending some of the order field bytes.
  1668. pOrder->OrderLength -= OE2_CheckTwoZeroFlagBytes(pControlFlags,
  1669. (BYTE *)pFieldFlags,
  1670. (unsigned)(pBuffer - (BYTE *)pFieldFlags - 2));
  1671. INC_OUTCOUNTER(OUT_LINETO_ORDR);
  1672. ADD_INCOUNTER(IN_LINETO_BYTES, pOrder->OrderLength);
  1673. OA_AppendToOrderList(pOrder);
  1674. // Flush the order.
  1675. if (pClipRects->rects.c < 2)
  1676. rc = TRUE;
  1677. else
  1678. rc = OEEmitReplayOrders(ppdev, 2, pClipRects);
  1679. TRC_NRM((TB, "LineTo: rop2=%02X, PenColor=%04X, start=(%d,%d), "
  1680. "end=(%d,%d)", rop2, Color.u.index,
  1681. startPoint->x, startPoint->y,
  1682. endPoint->x, endPoint->y));
  1683. }
  1684. else {
  1685. TRC_ERR((TB, "Failed to alloc order"));
  1686. rc = FALSE;
  1687. }
  1688. DC_END_FN();
  1689. return rc;
  1690. }
  1691. /****************************************************************************/
  1692. // OESendSwitchSurfacePDU
  1693. //
  1694. // If the last drawing surface changed since, we need to send a switch
  1695. // surface PDU to the client to switch to the new surface
  1696. // This PDU is added to support multisurface rendering.
  1697. /****************************************************************************/
  1698. BOOL RDPCALL OESendSwitchSurfacePDU(PDD_PDEV ppdev, PDD_DSURF pdsurf)
  1699. {
  1700. unsigned bitmapSurfaceId;
  1701. void *UserDefined;
  1702. PINT_ORDER pOrder;
  1703. PTS_SWITCH_SURFACE_ORDER pSurfSwitchOrder;
  1704. BOOL rc;
  1705. DC_BEGIN_FN("OESendSwitchSurfacePDU");
  1706. // Check if the surface has changed since the last drawing order.
  1707. // If not, then we don't need to send the switch surface order.
  1708. if (pdsurf != oeLastDstSurface) {
  1709. // set last surface to the new surface
  1710. oeLastDstSurface = pdsurf;
  1711. if (pdsurf == NULL) {
  1712. // Destination surface is the client screen
  1713. bitmapSurfaceId = SCREEN_BITMAP_SURFACE;
  1714. }
  1715. else {
  1716. if (pdsurf->shareId == pddShm->shareId) {
  1717. // Get the offscreen bitmap Id.
  1718. bitmapSurfaceId = pdsurf->bitmapId;
  1719. // Udate the mru list of the offscreen cache
  1720. CH_TouchCacheEntry(sbcOffscreenBitmapCacheHandle,
  1721. pdsurf->bitmapId);
  1722. }
  1723. else {
  1724. // This is the stale offscreen bitmap from last disconnected
  1725. // session. We need to turn off the offscreen flag on this
  1726. TRC_ALT((TB, "Need to turn off this offscreen bitmap"));
  1727. pdsurf->flags |= DD_NO_OFFSCREEN;
  1728. rc = FALSE;
  1729. DC_QUIT;
  1730. }
  1731. }
  1732. }
  1733. else {
  1734. // Return TRUE here since we didn't fail the send the order,
  1735. // there's just no need to send it.
  1736. rc = TRUE;
  1737. DC_QUIT;
  1738. }
  1739. pOrder = OA_AllocOrderMem(ppdev, sizeof(TS_SWITCH_SURFACE_ORDER));
  1740. if (pOrder != NULL) {
  1741. pSurfSwitchOrder = (PTS_SWITCH_SURFACE_ORDER)pOrder->OrderData;
  1742. pSurfSwitchOrder->ControlFlags = (TS_ALTSEC_SWITCH_SURFACE <<
  1743. TS_ALTSEC_ORDER_TYPE_SHIFT) | TS_SECONDARY;
  1744. pSurfSwitchOrder->BitmapID = (UINT16)bitmapSurfaceId;
  1745. INC_OUTCOUNTER(OUT_SWITCHSURFACE);
  1746. ADD_OUTCOUNTER(OUT_SWITCHSURFACE_BYTES,
  1747. sizeof(TS_SWITCH_SURFACE_ORDER));
  1748. OA_AppendToOrderList(pOrder);
  1749. rc = TRUE;
  1750. }
  1751. else {
  1752. TRC_ERR((TB, "Failed to add a switch surface PDU to the order heap"));
  1753. rc = FALSE;
  1754. }
  1755. DC_EXIT_POINT:
  1756. DC_END_FN();
  1757. return rc;
  1758. }
  1759. #ifdef DRAW_NINEGRID
  1760. /****************************************************************************/
  1761. // OESendStreamBitmapOrder
  1762. //
  1763. // This is to stream the bitmap bits (either compressed or not compressed
  1764. // to the client in 4K block
  1765. /****************************************************************************/
  1766. BOOL RDPCALL OESendStreamBitmapOrder(PDD_PDEV ppdev, unsigned bitmapId,
  1767. SIZEL *sizl, unsigned bitmapBpp, PBYTE BitmapBuffer, unsigned BitmapSize,
  1768. BOOL compressed)
  1769. {
  1770. PINT_ORDER pIntOrder;
  1771. PTS_STREAM_BITMAP_FIRST_PDU pStreamBitmapFirstPDU;
  1772. PTS_STREAM_BITMAP_FIRST_PDU_REV2 pStreamBitmapFirstPDURev2;
  1773. PTS_STREAM_BITMAP_NEXT_PDU pStreamBitmapNextPDU;
  1774. BOOL rc = FALSE;
  1775. BOOL fEndOfStream = FALSE;
  1776. unsigned StreamBlockSize;
  1777. unsigned BitmapRemainingSize;
  1778. PBYTE BitmapRemainingBuffer;
  1779. DC_BEGIN_FN("OESendStreamBitmapOrder");
  1780. // Send the first stream block
  1781. BitmapRemainingBuffer = BitmapBuffer;
  1782. StreamBlockSize = min(BitmapSize, TS_STREAM_BITMAP_BLOCK);
  1783. BitmapRemainingSize = BitmapSize - StreamBlockSize;
  1784. if (pddShm->sbc.drawNineGridCacheInfo.supportLevel < TS_DRAW_NINEGRID_SUPPORTED_REV2) {
  1785. pIntOrder = OA_AllocOrderMem(ppdev, sizeof(TS_STREAM_BITMAP_FIRST_PDU) +
  1786. StreamBlockSize);
  1787. }
  1788. else {
  1789. // TS_STREAM_BITMAP REV2
  1790. pIntOrder = OA_AllocOrderMem(ppdev, sizeof(TS_STREAM_BITMAP_FIRST_PDU_REV2) +
  1791. StreamBlockSize);
  1792. }
  1793. if (BitmapRemainingSize == 0) {
  1794. fEndOfStream = TRUE;
  1795. }
  1796. if (pIntOrder != NULL) {
  1797. if (pddShm->sbc.drawNineGridCacheInfo.supportLevel < TS_DRAW_NINEGRID_SUPPORTED_REV2) {
  1798. pStreamBitmapFirstPDU = (PTS_STREAM_BITMAP_FIRST_PDU)pIntOrder->OrderData;
  1799. pStreamBitmapFirstPDU->ControlFlags = (TS_ALTSEC_STREAM_BITMAP_FIRST <<
  1800. TS_ALTSEC_ORDER_TYPE_SHIFT) | TS_SECONDARY;
  1801. pStreamBitmapFirstPDU->BitmapFlags = fEndOfStream ? TS_STREAM_BITMAP_END : 0;
  1802. pStreamBitmapFirstPDU->BitmapFlags |= compressed ? TS_STREAM_BITMAP_COMPRESSED : 0;
  1803. pStreamBitmapFirstPDU->BitmapId = (unsigned short)bitmapId;
  1804. pStreamBitmapFirstPDU->BitmapBpp = (TSUINT8)bitmapBpp;
  1805. pStreamBitmapFirstPDU->BitmapWidth = (TSUINT16)(sizl->cx);
  1806. pStreamBitmapFirstPDU->BitmapHeight = (TSUINT16)(sizl->cy);
  1807. pStreamBitmapFirstPDU->BitmapLength = (TSUINT16)BitmapSize;
  1808. pStreamBitmapFirstPDU->BitmapBlockLength = (TSUINT16)(StreamBlockSize);
  1809. memcpy(pStreamBitmapFirstPDU + 1, BitmapRemainingBuffer, StreamBlockSize);
  1810. }
  1811. else {
  1812. // TS_STREAM_BITMAP REV2
  1813. pStreamBitmapFirstPDURev2 = (PTS_STREAM_BITMAP_FIRST_PDU_REV2)pIntOrder->OrderData;
  1814. pStreamBitmapFirstPDURev2->ControlFlags = (TS_ALTSEC_STREAM_BITMAP_FIRST <<
  1815. TS_ALTSEC_ORDER_TYPE_SHIFT) | TS_SECONDARY;
  1816. pStreamBitmapFirstPDURev2->BitmapFlags = fEndOfStream ? TS_STREAM_BITMAP_END : 0;
  1817. pStreamBitmapFirstPDURev2->BitmapFlags |= compressed ? TS_STREAM_BITMAP_COMPRESSED : 0;
  1818. pStreamBitmapFirstPDURev2->BitmapFlags |= TS_STREAM_BITMAP_REV2;
  1819. pStreamBitmapFirstPDURev2->BitmapId = (unsigned short)bitmapId;
  1820. pStreamBitmapFirstPDURev2->BitmapBpp = (TSUINT8)bitmapBpp;
  1821. pStreamBitmapFirstPDURev2->BitmapWidth = (TSUINT16)(sizl->cx);
  1822. pStreamBitmapFirstPDURev2->BitmapHeight = (TSUINT16)(sizl->cy);
  1823. pStreamBitmapFirstPDURev2->BitmapLength = (TSUINT32)BitmapSize;
  1824. pStreamBitmapFirstPDURev2->BitmapBlockLength = (TSUINT16)(StreamBlockSize);
  1825. memcpy(pStreamBitmapFirstPDURev2 + 1, BitmapRemainingBuffer, StreamBlockSize);
  1826. }
  1827. BitmapRemainingBuffer += StreamBlockSize;
  1828. OA_AppendToOrderList(pIntOrder);
  1829. }
  1830. else {
  1831. TRC_ERR((TB, "Failed to allocated order for stream bitmap"));
  1832. DC_QUIT;
  1833. }
  1834. // Send the subsequent streamblock
  1835. while (BitmapRemainingSize) {
  1836. StreamBlockSize = min(BitmapRemainingSize, TS_STREAM_BITMAP_BLOCK);
  1837. BitmapRemainingSize = BitmapRemainingSize - StreamBlockSize;
  1838. pIntOrder = OA_AllocOrderMem(ppdev, sizeof(TS_STREAM_BITMAP_NEXT_PDU) +
  1839. StreamBlockSize);
  1840. if (BitmapRemainingSize == 0) {
  1841. fEndOfStream = TRUE;
  1842. }
  1843. if (pIntOrder != NULL) {
  1844. pStreamBitmapNextPDU = (PTS_STREAM_BITMAP_NEXT_PDU)pIntOrder->OrderData;
  1845. pStreamBitmapNextPDU->ControlFlags = (TS_ALTSEC_STREAM_BITMAP_NEXT <<
  1846. TS_ALTSEC_ORDER_TYPE_SHIFT) | TS_SECONDARY;
  1847. pStreamBitmapNextPDU->BitmapFlags = fEndOfStream ? TS_STREAM_BITMAP_END : 0;
  1848. pStreamBitmapNextPDU->BitmapFlags |= compressed ? TS_STREAM_BITMAP_COMPRESSED : 0;
  1849. pStreamBitmapNextPDU->BitmapId = (unsigned short)bitmapId;
  1850. pStreamBitmapNextPDU->BitmapBlockLength = (TSUINT16)StreamBlockSize;
  1851. memcpy(pStreamBitmapNextPDU + 1, BitmapRemainingBuffer, StreamBlockSize);
  1852. BitmapRemainingBuffer += StreamBlockSize;
  1853. OA_AppendToOrderList(pIntOrder);
  1854. }
  1855. else {
  1856. TRC_ERR((TB, "Failed to allocated order for stream bitmap"));
  1857. DC_QUIT;
  1858. }
  1859. }
  1860. rc = TRUE;
  1861. DC_EXIT_POINT:
  1862. DC_END_FN();
  1863. return rc;
  1864. }
  1865. /****************************************************************************/
  1866. // OESendCreateNineGridBitmapOrder
  1867. //
  1868. // Send the alternative secondary order to client to create the ninegrid bitmap
  1869. /****************************************************************************/
  1870. BOOL RDPCALL OESendCreateNineGridBitmapOrder(PDD_PDEV ppdev, unsigned nineGridBitmapId,
  1871. SIZEL *sizl, unsigned bitmapBpp, PNINEGRID png)
  1872. {
  1873. PINT_ORDER pOrder;
  1874. PTS_CREATE_NINEGRID_BITMAP_ORDER pCreateNineGridBitmapOrder;
  1875. BOOL rc = FALSE;
  1876. DC_BEGIN_FN("OESendCreateNineGridBitmapOrder");
  1877. pOrder = OA_AllocOrderMem(ppdev, sizeof(TS_CREATE_NINEGRID_BITMAP_ORDER));
  1878. if (pOrder != NULL) {
  1879. pCreateNineGridBitmapOrder = (PTS_CREATE_NINEGRID_BITMAP_ORDER)pOrder->OrderData;
  1880. pCreateNineGridBitmapOrder->ControlFlags = (TS_ALTSEC_CREATE_NINEGRID_BITMAP <<
  1881. TS_ALTSEC_ORDER_TYPE_SHIFT) | TS_SECONDARY;
  1882. pCreateNineGridBitmapOrder->BitmapID = (UINT16)nineGridBitmapId;
  1883. pCreateNineGridBitmapOrder->BitmapBpp = (BYTE)bitmapBpp;
  1884. pCreateNineGridBitmapOrder->cx = (TSUINT16)sizl->cx;
  1885. pCreateNineGridBitmapOrder->cy = (TSUINT16)sizl->cy;
  1886. pCreateNineGridBitmapOrder->nineGridInfo.crTransparent = png->crTransparent;
  1887. pCreateNineGridBitmapOrder->nineGridInfo.flFlags = png->flFlags;
  1888. pCreateNineGridBitmapOrder->nineGridInfo.ulLeftWidth = (TSUINT16)png->ulLeftWidth;
  1889. pCreateNineGridBitmapOrder->nineGridInfo.ulRightWidth = (TSUINT16)png->ulRightWidth;
  1890. pCreateNineGridBitmapOrder->nineGridInfo.ulTopHeight = (TSUINT16)png->ulTopHeight;
  1891. pCreateNineGridBitmapOrder->nineGridInfo.ulBottomHeight = (TSUINT16)png->ulBottomHeight;
  1892. //INC_OUTCOUNTER(OUT_SWITCHSURFACE);
  1893. //ADD_OUTCOUNTER(OUT_SWITCHSURFACE_BYTES,
  1894. // sizeof(TS_SWITCH_SURFACE_ORDER));
  1895. OA_AppendToOrderList(pOrder);
  1896. rc = TRUE;
  1897. }
  1898. else {
  1899. TRC_ERR((TB, "Failed to add a create drawninegrid order to the order heap"));
  1900. rc = FALSE;
  1901. }
  1902. DC_END_FN();
  1903. return rc;
  1904. }
  1905. /****************************************************************************/
  1906. // OECacheDrawNineGridBitmap
  1907. //
  1908. // Cache the draw ninegrid bitmap
  1909. /****************************************************************************/
  1910. BOOL RDPCALL OECacheDrawNineGridBitmap(PDD_PDEV ppdev, SURFOBJ *psoSrc,
  1911. PNINEGRID png, unsigned *bitmapId)
  1912. {
  1913. CHDataKeyContext CHContext;
  1914. void *UserDefined;
  1915. HSURF hWorkBitmap = NULL;
  1916. SURFOBJ *pWorkSurf = NULL;
  1917. SIZEL bitmapSize;
  1918. BOOL rc = FALSE;
  1919. PBYTE pWorkingBuffer = NULL;
  1920. PBYTE BitmapBuffer = NULL;
  1921. unsigned BitmapBufferSize = 0;
  1922. DC_BEGIN_FN("OECacheDrawNineGridBitmap");
  1923. CH_CreateKeyFromFirstData(&CHContext, psoSrc->pvBits, psoSrc->cjBits);
  1924. CH_CreateKeyFromNextData(&CHContext, png, sizeof(NINEGRID));
  1925. if (!CH_SearchCache(sbcDrawNineGridBitmapCacheHandle, CHContext.Key1, CHContext.Key2,
  1926. &UserDefined, bitmapId)) {
  1927. *bitmapId = CH_CacheKey(sbcDrawNineGridBitmapCacheHandle, CHContext.Key1,
  1928. CHContext.Key2, NULL);
  1929. if (*bitmapId != CH_KEY_UNCACHABLE) {
  1930. unsigned BitmapRawSize;
  1931. unsigned BitmapCompSize = 0;
  1932. unsigned BitmapBpp;
  1933. PBYTE BitmapRawBuffer;
  1934. unsigned paddedBitmapWidth;
  1935. BOOL ret;
  1936. // Get the protocol bitmap bpp
  1937. switch (psoSrc->iBitmapFormat)
  1938. {
  1939. case BMF_16BPP:
  1940. BitmapBpp = 16;
  1941. break;
  1942. case BMF_24BPP:
  1943. BitmapBpp = 24;
  1944. break;
  1945. case BMF_32BPP:
  1946. BitmapBpp = 32;
  1947. break;
  1948. default:
  1949. TRC_ASSERT((FALSE), (TB, "Invalid bitmap bpp: %d", psoSrc->iBitmapFormat));
  1950. BitmapBpp = 8;
  1951. }
  1952. paddedBitmapWidth = (psoSrc->sizlBitmap.cx + 3) & ~3;
  1953. bitmapSize.cx = paddedBitmapWidth;
  1954. bitmapSize.cy = psoSrc->sizlBitmap.cy;
  1955. // The bitmap width needs to be dword aligned
  1956. if (paddedBitmapWidth != psoSrc->sizlBitmap.cx) {
  1957. RECTL rect = { 0 };
  1958. POINTL origin = { 0 };
  1959. rect.right = psoSrc->sizlBitmap.cx;
  1960. rect.bottom = psoSrc->sizlBitmap.cy;
  1961. hWorkBitmap = (HSURF)EngCreateBitmap(bitmapSize,
  1962. TS_BYTES_IN_SCANLINE(bitmapSize.cx, BitmapBpp),
  1963. psoSrc->iBitmapFormat, 0, NULL);
  1964. if (hWorkBitmap) {
  1965. pWorkSurf = EngLockSurface(hWorkBitmap);
  1966. if (pWorkSurf) {
  1967. // Copy to a worker bitmap
  1968. if (EngCopyBits(pWorkSurf, psoSrc, NULL, NULL, &rect, &origin)) {
  1969. BitmapRawSize = pWorkSurf->cjBits;
  1970. BitmapRawBuffer = pWorkSurf->pvBits;
  1971. BitmapBuffer = EngAllocMem(0, BitmapRawSize, WD_ALLOC_TAG);
  1972. BitmapBufferSize = BitmapRawSize;
  1973. if (BitmapBuffer == NULL) {
  1974. ret = FALSE;
  1975. goto Post_Compression;
  1976. }
  1977. if (BitmapRawSize > MAX_UNCOMPRESSED_DATA_SIZE) {
  1978. pWorkingBuffer = EngAllocMem(0, BitmapRawSize, WD_ALLOC_TAG);
  1979. if (pWorkingBuffer == NULL) {
  1980. ret = FALSE;
  1981. goto Post_Compression;
  1982. }
  1983. }
  1984. ret = BC_CompressBitmap(pWorkSurf->pvBits, BitmapBuffer, pWorkingBuffer,
  1985. BitmapBufferSize, &BitmapCompSize, paddedBitmapWidth,
  1986. psoSrc->sizlBitmap.cy, BitmapBpp);
  1987. }
  1988. else {
  1989. TRC_ERR((TB, "Failed EngCopyBits"));
  1990. DC_QUIT;
  1991. }
  1992. }
  1993. else {
  1994. TRC_ERR((TB, "Failed to lock the bitmap"));
  1995. DC_QUIT;
  1996. }
  1997. }
  1998. else {
  1999. TRC_ERR((TB, "Failed to create the bitmap"));
  2000. DC_QUIT;
  2001. }
  2002. }
  2003. else {
  2004. BitmapRawSize = psoSrc->cjBits;
  2005. BitmapRawBuffer = psoSrc->pvBits;
  2006. BitmapBuffer = EngAllocMem(0, BitmapRawSize, WD_ALLOC_TAG);
  2007. BitmapBufferSize = BitmapRawSize;
  2008. if (BitmapBuffer == NULL) {
  2009. ret = FALSE;
  2010. goto Post_Compression;
  2011. }
  2012. if (BitmapRawSize > MAX_UNCOMPRESSED_DATA_SIZE) {
  2013. pWorkingBuffer = EngAllocMem(0, BitmapRawSize, WD_ALLOC_TAG);
  2014. if (pWorkingBuffer == NULL) {
  2015. ret = FALSE;
  2016. goto Post_Compression;
  2017. }
  2018. }
  2019. ret = BC_CompressBitmap(psoSrc->pvBits, BitmapBuffer, pWorkingBuffer, BitmapBufferSize,
  2020. &BitmapCompSize, paddedBitmapWidth, psoSrc->sizlBitmap.cy,
  2021. BitmapBpp);
  2022. }
  2023. Post_Compression:
  2024. if (ret) {
  2025. // Send compressed bitmap
  2026. if (!OESendStreamBitmapOrder(ppdev, TS_DRAW_NINEGRID_BITMAP_CACHE, &bitmapSize, BitmapBpp,
  2027. BitmapBuffer, BitmapCompSize, TRUE)) {
  2028. TRC_ERR((TB, "Failed to send stream bitmap order"));
  2029. DC_QUIT;
  2030. }
  2031. }
  2032. else {
  2033. // Send uncompressed bitmap
  2034. if (!OESendStreamBitmapOrder(ppdev, TS_DRAW_NINEGRID_BITMAP_CACHE, &bitmapSize, BitmapBpp,
  2035. BitmapRawBuffer, BitmapRawSize, FALSE))
  2036. {
  2037. TRC_ERR((TB, "Failed to send stream bitmap order"));
  2038. DC_QUIT;
  2039. }
  2040. }
  2041. // send a create drawninegrid bitmap pdu
  2042. if (OESendCreateNineGridBitmapOrder(ppdev, *bitmapId,
  2043. &(psoSrc->sizlBitmap), BitmapBpp, png)) {
  2044. // Update the current offscreen cache size
  2045. //oeCurrentOffscreenCacheSize += bitmapSize;
  2046. //pdsurf->bitmapId = offscrBitmapId;
  2047. TRC_NRM((TB, "Created a drawninegrid bitmap"));
  2048. }
  2049. else {
  2050. TRC_ERR((TB, "Failed to send the create bitmap pdu"));
  2051. DC_QUIT;
  2052. }
  2053. }
  2054. else {
  2055. TRC_ERR((TB, "Failed to cache the bitmap"));
  2056. DC_QUIT;
  2057. }
  2058. }
  2059. else {
  2060. // bitmap already cached
  2061. }
  2062. rc = TRUE;
  2063. DC_EXIT_POINT:
  2064. if (pWorkSurf)
  2065. EngUnlockSurface(pWorkSurf);
  2066. if (hWorkBitmap)
  2067. EngDeleteSurface(hWorkBitmap);
  2068. if (pWorkingBuffer) {
  2069. EngFreeMem(pWorkingBuffer);
  2070. }
  2071. if (BitmapBuffer) {
  2072. EngFreeMem(BitmapBuffer);
  2073. }
  2074. if (rc != TRUE && *bitmapId != CH_KEY_UNCACHABLE)
  2075. CH_RemoveCacheEntry(sbcDrawNineGridBitmapCacheHandle, *bitmapId);
  2076. DC_END_FN();
  2077. return rc;
  2078. }
  2079. /****************************************************************************/
  2080. // OEEncodeDrawNineGrid
  2081. //
  2082. // Encodes the DrawNineGrid order. Returns FALSE on failure.
  2083. /****************************************************************************/
  2084. BOOL RDPCALL OEEncodeDrawNineGrid(
  2085. RECTL *pBounds,
  2086. RECTL *psrcRect,
  2087. unsigned bitmapId,
  2088. PDD_PDEV ppdev,
  2089. OE_ENUMRECTS *pClipRects)
  2090. {
  2091. BOOL rc = FALSE;
  2092. unsigned OrderSize;
  2093. unsigned NumFieldFlagBytes = 0;
  2094. BYTE OrderType = 0;
  2095. PINT_ORDER pOrder;
  2096. MULTI_DRAWNINEGRID_ORDER *pPrevDNG;
  2097. DC_BEGIN_FN("OEEncodeDrawNineGrid");
  2098. // Check whether we should use the multi-cliprect version.
  2099. if (pClipRects->rects.c == 0) {
  2100. // Non-multi version.
  2101. OrderType = TS_ENC_DRAWNINEGRID_ORDER;
  2102. OrderSize = MAX_DRAWNINEGRID_FIELD_SIZE;
  2103. pPrevDNG = (MULTI_DRAWNINEGRID_ORDER *)&PrevDrawNineGrid;
  2104. NumFieldFlagBytes = 1;
  2105. }
  2106. else {
  2107. // Multi version.
  2108. OrderType = TS_ENC_MULTI_DRAWNINEGRID_ORDER;
  2109. OrderSize = MAX_MULTI_DRAWNINEGRID_FIELD_SIZE_NCLIP(pClipRects->rects.c);
  2110. pPrevDNG = &PrevMultiDrawNineGrid;
  2111. NumFieldFlagBytes = 1;
  2112. }
  2113. // Encode and send the order
  2114. pOrder = OA_AllocOrderMem(ppdev, MAX_ORDER_SIZE(((NULL == pBounds) ? 0 : 1),
  2115. NumFieldFlagBytes, OrderSize));
  2116. if (pOrder != NULL) {
  2117. DRAWNINEGRID_ORDER *pDNG;
  2118. pDNG = (DRAWNINEGRID_ORDER *)oeTempOrderBuffer;
  2119. pDNG->srcLeft = psrcRect->left;
  2120. pDNG->srcTop = psrcRect->top;
  2121. pDNG->srcRight = psrcRect->right;
  2122. pDNG->srcBottom = psrcRect->bottom;
  2123. pDNG->bitmapId = (unsigned short)bitmapId;
  2124. // Need to increment this bound as we use it as cliprect and in the encode order
  2125. // code it'll make it includsive over the wire
  2126. pBounds->right += 1;
  2127. pBounds->bottom += 1;
  2128. if (OrderType == TS_ENC_DRAWNINEGRID_ORDER) {
  2129. // Slow-field-encode the order
  2130. pOrder->OrderLength = OE2_EncodeOrder(pOrder->OrderData,
  2131. TS_ENC_DRAWNINEGRID_ORDER, NUM_DRAWNINEGRID_FIELDS,
  2132. (BYTE *)pDNG, (BYTE *)pPrevDNG, etable_NG,
  2133. pBounds);
  2134. //INC_OUTCOUNTER(OUT_SCRBLT_ORDER);
  2135. //ADD_INCOUNTER(IN_SCRBLT_BYTES, pOrder->OrderLength);
  2136. OA_AppendToOrderList(pOrder);
  2137. rc = TRUE;
  2138. }
  2139. else {
  2140. MULTI_DRAWNINEGRID_ORDER *pMultiDNG = (MULTI_DRAWNINEGRID_ORDER *)
  2141. oeTempOrderBuffer;
  2142. // Encode the clip rects directly into the order.
  2143. pMultiDNG->nDeltaEntries = OEBuildMultiClipOrder(ppdev,
  2144. &pMultiDNG->codedDeltaList, pClipRects);
  2145. // Slow-field-encode the order with no clip rects.
  2146. pOrder->OrderLength = OE2_EncodeOrder(pOrder->OrderData,
  2147. TS_ENC_MULTI_DRAWNINEGRID_ORDER, NUM_MULTI_DRAWNINEGRID_FIELDS,
  2148. (BYTE *)pMultiDNG, (BYTE *)pPrevDNG, etable_MG,
  2149. pBounds);
  2150. //INC_OUTCOUNTER(OUT_MULTI_SCRBLT_ORDER);
  2151. //ADD_INCOUNTER(IN_MULTI_SCRBLT_BYTES, pOrder->OrderLength);
  2152. OA_AppendToOrderList(pOrder);
  2153. rc = TRUE;
  2154. }
  2155. }
  2156. else {
  2157. TRC_ERR((TB, "Failed to alloc order"));
  2158. INC_OUTCOUNTER(OUT_BITBLT_SDA_HEAPALLOCFAILED);
  2159. rc = FALSE;
  2160. }
  2161. DC_END_FN();
  2162. return rc;
  2163. }
  2164. #if 0
  2165. BOOL RDPCALL OESendCreateDrawStreamOrder(PDD_PDEV ppdev, unsigned bitmapId,
  2166. SIZEL *sizl, unsigned bitmapBpp)
  2167. {
  2168. PINT_ORDER pOrder;
  2169. PTS_CREATE_DRAW_STREAM_ORDER pCreateDrawStreamOrder;
  2170. BOOL rc = FALSE;
  2171. DC_BEGIN_FN("OESendCreateDrawStreamOrder");
  2172. pOrder = OA_AllocOrderMem(ppdev, sizeof(TS_CREATE_DRAW_STREAM_ORDER));
  2173. if (pOrder != NULL) {
  2174. pCreateDrawStreamOrder = (PTS_CREATE_DRAW_STREAM_ORDER)pOrder->OrderData;
  2175. pDrawStreamOrder->ControlFlags = (TS_ALTSEC_DRAW_STREAM <<
  2176. TS_ALTSEC_ORDER_TYPE_SHIFT) | TS_SECONDARY;
  2177. pCreateDrawStreamOrder->BitmapID = (UINT16)bitmapId;
  2178. pCreateDrawStreamOrder->bitmapBpp = (BYTE)bitmapBpp;
  2179. pCreateDrawStreamOrder->cx = (TSUINT16)sizl->cx;
  2180. pCreateDrawStreamOrder->cy = (TSUINT16)sizl->cy;
  2181. //INC_OUTCOUNTER(OUT_SWITCHSURFACE);
  2182. //ADD_OUTCOUNTER(OUT_SWITCHSURFACE_BYTES,
  2183. // sizeof(TS_SWITCH_SURFACE_ORDER));
  2184. OA_AppendToOrderList(pOrder);
  2185. rc = TRUE;
  2186. }
  2187. else {
  2188. TRC_ERR((TB, "Failed to add a create draw stream order to the order heap"));
  2189. rc = FALSE;
  2190. }
  2191. rc = TRUE;
  2192. DC_END_FN();
  2193. return rc;
  2194. }
  2195. VOID OEEncodeDrawStream(PVOID stream, ULONG streamSize, PPOINTL dstOffset,
  2196. PBYTE streamOut, unsigned* streamSizeOut)
  2197. {
  2198. ULONG * pul = (ULONG *) stream;
  2199. ULONG cjIn = streamSize;
  2200. DC_BEGIN_FN("OEEncodeDrawStream");
  2201. *streamSizeOut = 0;
  2202. while(cjIn >= sizeof(ULONG))
  2203. {
  2204. ULONG command = *pul;
  2205. ULONG commandSize;
  2206. switch(command)
  2207. {
  2208. case DS_COPYTILEID:
  2209. {
  2210. DS_COPYTILE * cmd = (DS_COPYTILE *) pul;
  2211. RDP_DS_COPYTILE * rdpcmd = (RDP_DS_COPYTILE *) streamOut;
  2212. commandSize = sizeof(*cmd);
  2213. if (cjIn < commandSize) {
  2214. DC_QUIT;
  2215. }
  2216. cmd->rclDst.left += dstOffset->x;
  2217. cmd->rclDst.right += dstOffset->x;
  2218. cmd->rclDst.top += dstOffset->y;
  2219. cmd->rclDst.bottom += dstOffset->y;
  2220. rdpcmd->ulCmdID = (BYTE)(DS_COPYTILEID);
  2221. OEClipRect(&(cmd->rclDst));
  2222. OEClipRect(&(cmd->rclSrc));
  2223. OEClipPoint(&(cmd->ptlOrigin));
  2224. RECTL_TO_TSRECT16(rdpcmd->rclDst, cmd->rclDst);
  2225. RECTL_TO_TSRECT16(rdpcmd->rclSrc, cmd->rclSrc);
  2226. POINTL_TO_TSPOINT16(rdpcmd->ptlOrigin, cmd->ptlOrigin);
  2227. *streamSizeOut += sizeof(RDP_DS_COPYTILE);
  2228. streamOut += sizeof(RDP_DS_COPYTILE);
  2229. }
  2230. break;
  2231. case DS_SOLIDFILLID:
  2232. {
  2233. DS_SOLIDFILL * cmd = (DS_SOLIDFILL *) pul;
  2234. RDP_DS_SOLIDFILL * rdpcmd = (RDP_DS_SOLIDFILL *) streamOut;
  2235. commandSize = sizeof(*cmd);
  2236. if (cjIn < commandSize) {
  2237. DC_QUIT;
  2238. }
  2239. cmd->rclDst.left += dstOffset->x;
  2240. cmd->rclDst.right += dstOffset->x;
  2241. cmd->rclDst.top += dstOffset->y;
  2242. cmd->rclDst.bottom += dstOffset->y;
  2243. rdpcmd->ulCmdID = (BYTE)(DS_SOLIDFILLID);
  2244. rdpcmd->crSolidColor = cmd->crSolidColor;
  2245. OEClipRect(&(cmd->rclDst));
  2246. RECTL_TO_TSRECT16(rdpcmd->rclDst, cmd->rclDst);
  2247. *streamSizeOut += sizeof(RDP_DS_SOLIDFILL);
  2248. streamOut += sizeof(RDP_DS_SOLIDFILL);
  2249. }
  2250. break;
  2251. case DS_TRANSPARENTTILEID:
  2252. {
  2253. DS_TRANSPARENTTILE * cmd = (DS_TRANSPARENTTILE *) pul;
  2254. RDP_DS_TRANSPARENTTILE * rdpcmd = (RDP_DS_TRANSPARENTTILE *) streamOut;
  2255. commandSize = sizeof(*cmd);
  2256. if (cjIn < commandSize) {
  2257. DC_QUIT;
  2258. }
  2259. cmd->rclDst.left += dstOffset->x;
  2260. cmd->rclDst.right += dstOffset->x;
  2261. cmd->rclDst.top += dstOffset->y;
  2262. cmd->rclDst.bottom += dstOffset->y;
  2263. rdpcmd->ulCmdID = (BYTE)(DS_TRANSPARENTTILEID);
  2264. rdpcmd->crTransparentColor = cmd->crTransparentColor;
  2265. OEClipRect(&(cmd->rclDst));
  2266. OEClipRect(&(cmd->rclSrc));
  2267. OEClipPoint(&(cmd->ptlOrigin));
  2268. RECTL_TO_TSRECT16(rdpcmd->rclDst, cmd->rclDst);
  2269. RECTL_TO_TSRECT16(rdpcmd->rclSrc, cmd->rclSrc);
  2270. POINTL_TO_TSPOINT16(rdpcmd->ptlOrigin, cmd->ptlOrigin);
  2271. *streamSizeOut += sizeof(RDP_DS_TRANSPARENTTILE);
  2272. streamOut += sizeof(RDP_DS_TRANSPARENTTILE);
  2273. }
  2274. break;
  2275. case DS_ALPHATILEID:
  2276. {
  2277. DS_ALPHATILE * cmd = (DS_ALPHATILE *) pul;
  2278. RDP_DS_ALPHATILE * rdpcmd = (RDP_DS_ALPHATILE *) streamOut;
  2279. commandSize = sizeof(*cmd);
  2280. if (cjIn < commandSize) {
  2281. DC_QUIT;
  2282. }
  2283. cmd->rclDst.left += dstOffset->x;
  2284. cmd->rclDst.right += dstOffset->x;
  2285. cmd->rclDst.top += dstOffset->y;
  2286. cmd->rclDst.bottom += dstOffset->y;
  2287. rdpcmd->ulCmdID = (BYTE)(DS_ALPHATILEID);
  2288. rdpcmd->blendFunction.AlphaFormat = cmd->blendFunction.AlphaFormat;
  2289. rdpcmd->blendFunction.BlendFlags = cmd->blendFunction.BlendFlags;
  2290. rdpcmd->blendFunction.BlendOp = cmd->blendFunction.BlendOp;
  2291. rdpcmd->blendFunction.SourceConstantAlpha = cmd->blendFunction.SourceConstantAlpha;
  2292. OEClipRect(&(cmd->rclDst));
  2293. OEClipRect(&(cmd->rclSrc));
  2294. OEClipPoint(&(cmd->ptlOrigin));
  2295. RECTL_TO_TSRECT16(rdpcmd->rclDst, cmd->rclDst);
  2296. RECTL_TO_TSRECT16(rdpcmd->rclSrc, cmd->rclSrc);
  2297. POINTL_TO_TSPOINT16(rdpcmd->ptlOrigin, cmd->ptlOrigin);
  2298. *streamSizeOut += sizeof(RDP_DS_ALPHATILE);
  2299. streamOut += sizeof(RDP_DS_ALPHATILE);
  2300. }
  2301. break;
  2302. case DS_STRETCHID:
  2303. {
  2304. DS_STRETCH * cmd = (DS_STRETCH *) pul;
  2305. RDP_DS_STRETCH * rdpcmd = (RDP_DS_STRETCH *) streamOut;
  2306. commandSize = sizeof(*cmd);
  2307. if (cjIn < commandSize) {
  2308. DC_QUIT;
  2309. }
  2310. cmd->rclDst.left += dstOffset->x;
  2311. cmd->rclDst.right += dstOffset->x;
  2312. cmd->rclDst.top += dstOffset->y;
  2313. cmd->rclDst.bottom += dstOffset->y;
  2314. rdpcmd->ulCmdID = (BYTE)(DS_STRETCHID);
  2315. OEClipRect(&(cmd->rclDst));
  2316. OEClipRect(&(cmd->rclSrc));
  2317. RECTL_TO_TSRECT16(rdpcmd->rclDst, cmd->rclDst);
  2318. RECTL_TO_TSRECT16(rdpcmd->rclSrc, cmd->rclSrc);
  2319. *streamSizeOut += sizeof(RDP_DS_STRETCH);
  2320. streamOut += sizeof(RDP_DS_STRETCH);
  2321. }
  2322. break;
  2323. case DS_TRANSPARENTSTRETCHID:
  2324. {
  2325. DS_TRANSPARENTSTRETCH * cmd = (DS_TRANSPARENTSTRETCH *) pul;
  2326. RDP_DS_TRANSPARENTSTRETCH * rdpcmd = (RDP_DS_TRANSPARENTSTRETCH *) streamOut;
  2327. commandSize = sizeof(*cmd);
  2328. if (cjIn < commandSize) {
  2329. DC_QUIT;
  2330. }
  2331. cmd->rclDst.left += dstOffset->x;
  2332. cmd->rclDst.right += dstOffset->x;
  2333. cmd->rclDst.top += dstOffset->y;
  2334. cmd->rclDst.bottom += dstOffset->y;
  2335. rdpcmd->ulCmdID = (BYTE)(DS_TRANSPARENTSTRETCHID);
  2336. rdpcmd->crTransparentColor = cmd->crTransparentColor;
  2337. OEClipRect(&(cmd->rclDst));
  2338. OEClipRect(&(cmd->rclSrc));
  2339. RECTL_TO_TSRECT16(rdpcmd->rclDst, cmd->rclDst);
  2340. RECTL_TO_TSRECT16(rdpcmd->rclSrc, cmd->rclSrc);
  2341. *streamSizeOut += sizeof(RDP_DS_TRANSPARENTSTRETCH);
  2342. streamOut += sizeof(RDP_DS_TRANSPARENTSTRETCH);
  2343. }
  2344. break;
  2345. case DS_ALPHASTRETCHID:
  2346. {
  2347. DS_ALPHASTRETCH * cmd = (DS_ALPHASTRETCH *) pul;
  2348. RDP_DS_ALPHASTRETCH * rdpcmd = (RDP_DS_ALPHASTRETCH *) streamOut;
  2349. commandSize = sizeof(*cmd);
  2350. if (cjIn < commandSize) {
  2351. DC_QUIT;
  2352. }
  2353. cmd->rclDst.left += dstOffset->x;
  2354. cmd->rclDst.right += dstOffset->x;
  2355. cmd->rclDst.top += dstOffset->y;
  2356. cmd->rclDst.bottom += dstOffset->y;
  2357. rdpcmd->ulCmdID = (BYTE)(DS_ALPHASTRETCHID);
  2358. rdpcmd->blendFunction.AlphaFormat = cmd->blendFunction.AlphaFormat;
  2359. rdpcmd->blendFunction.BlendFlags = cmd->blendFunction.BlendFlags;
  2360. rdpcmd->blendFunction.BlendOp = cmd->blendFunction.BlendOp;
  2361. rdpcmd->blendFunction.SourceConstantAlpha = cmd->blendFunction.SourceConstantAlpha;
  2362. OEClipRect(&(cmd->rclDst));
  2363. OEClipRect(&(cmd->rclSrc));
  2364. RECTL_TO_TSRECT16(rdpcmd->rclDst, cmd->rclDst);
  2365. RECTL_TO_TSRECT16(rdpcmd->rclSrc, cmd->rclSrc);
  2366. *streamSizeOut += sizeof(RDP_DS_ALPHASTRETCH);
  2367. streamOut += sizeof(RDP_DS_ALPHASTRETCH);
  2368. }
  2369. break;
  2370. default:
  2371. {
  2372. DC_QUIT;
  2373. }
  2374. }
  2375. cjIn -= commandSize;
  2376. pul += commandSize / 4;
  2377. }
  2378. DC_EXIT_POINT:
  2379. DC_END_FN();
  2380. }
  2381. BOOL RDPCALL OESendDrawStreamOrder(PDD_PDEV ppdev, unsigned bitmapId, unsigned ulIn, PVOID pvIn,
  2382. PPOINTL dstOffset, RECTL *bounds, OE_ENUMRECTS *pclipRects)
  2383. {
  2384. PINT_ORDER pOrder;
  2385. PTS_DRAW_STREAM_ORDER pDrawStreamOrder;
  2386. unsigned cbOrderSize;
  2387. BOOL rc = FALSE;
  2388. DC_BEGIN_FN("OESendDrawStreamOrder");
  2389. cbOrderSize = sizeof(TS_DRAW_STREAM_ORDER) + ulIn +
  2390. sizeof(TS_RECTANGLE16) * pclipRects->rects.c;
  2391. pOrder = OA_AllocOrderMem(ppdev, cbOrderSize);
  2392. if (pOrder != NULL) {
  2393. unsigned i, streamSize;
  2394. TS_RECTANGLE16 *clipRects;
  2395. PBYTE stream;
  2396. pDrawStreamOrder = (PTS_DRAW_STREAM_ORDER)pOrder->OrderData;
  2397. pDrawStreamOrder->ControlFlags = (TS_ALTSEC_DRAW_STREAM <<
  2398. TS_ALTSEC_ORDER_TYPE_SHIFT) | TS_SECONDARY;
  2399. pDrawStreamOrder->Bounds.left = (TSINT16)(bounds->left);
  2400. pDrawStreamOrder->Bounds.top = (TSINT16)(bounds->top);
  2401. pDrawStreamOrder->Bounds.right = (TSINT16)(bounds->right);
  2402. pDrawStreamOrder->Bounds.bottom = (TSINT16)(bounds->bottom);
  2403. pDrawStreamOrder->nClipRects = (TSUINT8)(pclipRects->rects.c);
  2404. pDrawStreamOrder->BitmapID = (UINT16)bitmapId;
  2405. clipRects = (TS_RECTANGLE16 *)(pDrawStreamOrder + 1);
  2406. // add the cliprects here.
  2407. for (i = 0; i < pclipRects->rects.c; i++) {
  2408. clipRects[i].left = (TSINT16)pclipRects->rects.arcl[i].left;
  2409. clipRects[i].right = (TSINT16)pclipRects->rects.arcl[i].right;
  2410. clipRects[i].top = (TSINT16)pclipRects->rects.arcl[i].top;
  2411. clipRects[i].bottom = (TSINT16)pclipRects->rects.arcl[i].bottom;
  2412. }
  2413. // add the stream data
  2414. stream = (PBYTE)clipRects + sizeof(TS_RECTANGLE16) * pclipRects->rects.c;
  2415. OEEncodeDrawStream(pvIn, ulIn, dstOffset, stream, &streamSize);
  2416. pDrawStreamOrder->StreamLen = (TSUINT16)streamSize;
  2417. cbOrderSize = sizeof(TS_DRAW_STREAM_ORDER) + streamSize +
  2418. sizeof(TS_RECTANGLE16) * pclipRects->rects.c;
  2419. //INC_OUTCOUNTER(OUT_SWITCHSURFACE);
  2420. //ADD_OUTCOUNTER(OUT_SWITCHSURFACE_BYTES,
  2421. // sizeof(TS_SWITCH_SURFACE_ORDER));
  2422. OA_TruncateAllocatedOrder(pOrder, cbOrderSize);
  2423. OA_AppendToOrderList(pOrder);
  2424. rc = TRUE;
  2425. }
  2426. else {
  2427. TRC_ERR((TB, "Failed to add a draw stream order to the order heap"));
  2428. rc = FALSE;
  2429. }
  2430. rc = TRUE;
  2431. DC_END_FN();
  2432. return rc;
  2433. }
  2434. BOOL RDPCALL OESendDrawNineGridOrder(PDD_PDEV ppdev, unsigned bitmapId,
  2435. PRECTL prclSrc, RECTL *bounds, OE_ENUMRECTS *pclipRects)
  2436. {
  2437. PINT_ORDER pOrder;
  2438. PTS_DRAW_NINEGRID_ORDER pDrawNineGridOrder;
  2439. BOOL rc;
  2440. unsigned cbOrderSize;
  2441. unsigned srcRectIndex;
  2442. DC_BEGIN_FN("OESendDrawNineGridOrder");
  2443. cbOrderSize = sizeof(TS_DRAW_NINEGRID_ORDER) +
  2444. sizeof(TS_RECTANGLE16) * pclipRects->rects.c;
  2445. pOrder = OA_AllocOrderMem(ppdev, cbOrderSize);
  2446. if (pOrder != NULL) {
  2447. unsigned i;
  2448. TS_RECTANGLE16 *clipRects;
  2449. pDrawNineGridOrder = (PTS_DRAW_NINEGRID_ORDER)pOrder->OrderData;
  2450. pDrawNineGridOrder->ControlFlags = (TS_ALTSEC_DRAW_NINEGRID <<
  2451. TS_ALTSEC_ORDER_TYPE_SHIFT) | TS_SECONDARY;
  2452. pDrawNineGridOrder->Bounds.left = (TSINT16)(bounds->left);
  2453. pDrawNineGridOrder->Bounds.top = (TSINT16)(bounds->top);
  2454. pDrawNineGridOrder->Bounds.right = (TSINT16)(bounds->right);
  2455. pDrawNineGridOrder->Bounds.bottom = (TSINT16)(bounds->bottom);
  2456. pDrawNineGridOrder->nClipRects = (TSUINT8)(pclipRects->rects.c);
  2457. pDrawNineGridOrder->BitmapID = (TSUINT8)bitmapId;
  2458. pDrawNineGridOrder->srcBounds.left = (TSINT16)(prclSrc->left);
  2459. pDrawNineGridOrder->srcBounds.top = (TSINT16)(prclSrc->top);
  2460. pDrawNineGridOrder->srcBounds.right = (TSINT16)(prclSrc->right);
  2461. pDrawNineGridOrder->srcBounds.bottom = (TSINT16)(prclSrc->bottom);
  2462. clipRects = (TS_RECTANGLE16 *)(pDrawNineGridOrder + 1);
  2463. // add the cliprects here.
  2464. for (i = 0; i < pclipRects->rects.c; i++) {
  2465. clipRects[i].left = (TSINT16)pclipRects->rects.arcl[i].left;
  2466. clipRects[i].right = (TSINT16)pclipRects->rects.arcl[i].right;
  2467. clipRects[i].top = (TSINT16)pclipRects->rects.arcl[i].top;
  2468. clipRects[i].bottom = (TSINT16)pclipRects->rects.arcl[i].bottom;
  2469. }
  2470. OA_AppendToOrderList(pOrder);
  2471. rc = TRUE;
  2472. }
  2473. else {
  2474. TRC_ERR((TB, "Failed to add a draw stream order to the order heap"));
  2475. rc = FALSE;
  2476. }
  2477. rc = TRUE;
  2478. DC_END_FN();
  2479. return rc;
  2480. }
  2481. #endif
  2482. #endif //DRAW_NINEGRID
  2483. #ifdef DRAW_GDIPLUS
  2484. /****************************************************************************/
  2485. // OECreateDrawGdiplusOrder
  2486. //
  2487. // Create and Send DrawGdiplus order.
  2488. /****************************************************************************/
  2489. BOOL RDPCALL OECreateDrawGdiplusOrder(PDD_PDEV ppdev, RECTL *prcl, ULONG cjIn, PVOID pvIn)
  2490. {
  2491. BOOL rc = FALSE;
  2492. unsigned int sizeLeft;
  2493. unsigned int CopyDataSize, MoveDataSize;
  2494. PTSEmfPlusRecord pEmfRecord;
  2495. unsigned int NewRecordSize = 0;
  2496. unsigned int CacheID;
  2497. BYTE *pData;
  2498. BOOL bReturn;
  2499. BYTE *pGdipOrderBuffer = NULL;
  2500. unsigned int GdipOrderBufferOffset, GdipOrderBufferLeft;
  2501. unsigned int GdipOrderSize, NewEmfSize;
  2502. DC_BEGIN_FN("OECreateDrawGdiplusOrder");
  2503. sizeLeft = (int)cjIn;
  2504. pData = (BYTE*) pvIn;
  2505. // Allocate the draw order buffer
  2506. pGdipOrderBuffer = EngAllocMem(FL_ZERO_MEMORY, TS_GDIPLUS_ORDER_SIZELIMIT, DD_ALLOC_TAG);
  2507. if (NULL == pGdipOrderBuffer) {
  2508. rc = FALSE;
  2509. DC_QUIT;
  2510. }
  2511. GdipOrderBufferOffset = 0;
  2512. GdipOrderBufferLeft = TS_GDIPLUS_ORDER_SIZELIMIT;
  2513. GdipOrderSize = 0;
  2514. NewEmfSize = 0;
  2515. while (sizeLeft >= sizeof(TSEmfPlusRecord)) {
  2516. bReturn = FALSE;
  2517. CacheID = CH_KEY_UNCACHABLE;
  2518. pEmfRecord = (PTSEmfPlusRecord)pData;
  2519. if ((pEmfRecord->Size > sizeLeft) ||
  2520. (pEmfRecord->Size == 0)) {
  2521. TRC_ERR((TB, "GDI+ EMF record size %d is not correct", pEmfRecord->Size));
  2522. rc = FALSE;
  2523. DC_QUIT;
  2524. }
  2525. if (pddShm->sbc.drawGdiplusInfo.GdipCacheLevel > TS_DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT) {
  2526. // Cache this record
  2527. bReturn = OECacheDrawGdiplus(ppdev, pEmfRecord, &CacheID);
  2528. }
  2529. if (bReturn && (CacheID != CH_KEY_UNCACHABLE)) {
  2530. //This record is cached
  2531. MoveDataSize = pEmfRecord->Size; // This is used data size in pData
  2532. CopyDataSize = sizeof(TSEmfPlusRecord) + sizeof(TSUINT16);
  2533. // If the order buffer can't hold more data, send this order first
  2534. if (CopyDataSize > GdipOrderBufferLeft) {
  2535. OESendDrawGdiplusOrder(ppdev, prcl, GdipOrderSize, pGdipOrderBuffer, NewEmfSize);
  2536. GdipOrderBufferOffset = 0;
  2537. GdipOrderBufferLeft = TS_GDIPLUS_ORDER_SIZELIMIT;
  2538. GdipOrderSize = 0;
  2539. NewEmfSize = 0;
  2540. }
  2541. // Copy the data to the order buffer
  2542. memcpy(pGdipOrderBuffer + GdipOrderBufferOffset, pData, CopyDataSize);
  2543. pEmfRecord = (PTSEmfPlusRecord)(pGdipOrderBuffer + GdipOrderBufferOffset);
  2544. GdipOrderBufferOffset += CopyDataSize;
  2545. GdipOrderBufferLeft -= CopyDataSize;
  2546. GdipOrderSize += CopyDataSize;
  2547. NewEmfSize += MoveDataSize;
  2548. pEmfRecord->Size = CopyDataSize;
  2549. // set the cache flag
  2550. pEmfRecord->Size |= 0x80000000;
  2551. // CacheID follows
  2552. *(TSUINT16 *)(pEmfRecord +1) = (TSUINT16)CacheID;
  2553. }
  2554. else {
  2555. // Not cachable, just copy the data
  2556. MoveDataSize = pEmfRecord->Size; // This is used data size in pData
  2557. // If the order buffer can't hold more data, send this order first
  2558. if ((MoveDataSize > GdipOrderBufferLeft) && (GdipOrderSize != 0)) {
  2559. OESendDrawGdiplusOrder(ppdev, prcl, GdipOrderSize, pGdipOrderBuffer, NewEmfSize);
  2560. GdipOrderBufferOffset = 0;
  2561. GdipOrderBufferLeft = TS_GDIPLUS_ORDER_SIZELIMIT;
  2562. GdipOrderSize = 0;
  2563. NewEmfSize = 0;
  2564. }
  2565. if (MoveDataSize > GdipOrderBufferLeft) {
  2566. // This single EMF record is larger than the order sizelimit, send it
  2567. OESendDrawGdiplusOrder(ppdev, prcl, MoveDataSize, pData, MoveDataSize);
  2568. }
  2569. else {
  2570. // Copy the data to the order buffer
  2571. memcpy(pGdipOrderBuffer + GdipOrderBufferOffset, pData, MoveDataSize);
  2572. GdipOrderBufferOffset += MoveDataSize;
  2573. GdipOrderBufferLeft -= MoveDataSize;
  2574. GdipOrderSize += MoveDataSize;
  2575. NewEmfSize += MoveDataSize;
  2576. }
  2577. }
  2578. sizeLeft -= (int)MoveDataSize;
  2579. pData += MoveDataSize;
  2580. }
  2581. // Temporarily remove this assert since GDI+ might send incorrect EMF record size
  2582. //TRC_ASSERT((sizeLeft == 0), (TB, "Gdiplus EMF+ record has invalid data size"));
  2583. // Send the remaining in the order buffer
  2584. if (GdipOrderSize != 0) {
  2585. OESendDrawGdiplusOrder(ppdev, prcl, GdipOrderSize, pGdipOrderBuffer, NewEmfSize);
  2586. }
  2587. rc = TRUE;
  2588. DC_END_FN();
  2589. DC_EXIT_POINT:
  2590. if (pGdipOrderBuffer) {
  2591. EngFreeMem(pGdipOrderBuffer);
  2592. }
  2593. return rc;
  2594. }
  2595. /****************************************************************************/
  2596. // OECacheDrawGdiplus
  2597. //
  2598. // Cache the Gdiplus EMF+ record
  2599. /****************************************************************************/
  2600. BOOL RDPCALL OECacheDrawGdiplus(PDD_PDEV ppdev, PVOID pvIn, unsigned int *CacheID)
  2601. {
  2602. BOOL rc = FALSE;
  2603. CHDataKeyContext CHContext;
  2604. PTSEmfPlusRecord pEmfRecord = (PTSEmfPlusRecord)pvIn;
  2605. CHCACHEHANDLE CacheHandle;
  2606. TSUINT16 CacheType;
  2607. void *UserDefined;
  2608. BYTE *CacheBuffer;
  2609. unsigned CacheBufferSize;
  2610. unsigned Temp, RemoveCacheID;
  2611. TSUINT16 RemoveCacheNum = 0, *RemoveCacheIDList = NULL;
  2612. TSUINT16 CacheSize; // used for image cache, in number of chunks
  2613. unsigned MaxCacheSize; // used for other caches, in bytes
  2614. DC_BEGIN_FN("OECacheDrawGdiplus");
  2615. TRC_NRM((TB, "EmfPlusRecord type is %d", pEmfRecord->Type));
  2616. if (pEmfRecord->Type == EmfPlusRecordTypeSetTSGraphics) {
  2617. CacheHandle = sbcGdipGraphicsCacheHandle;
  2618. CacheType = GDIP_CACHE_GRAPHICS_DATA;
  2619. MaxCacheSize = sbcGdipGraphicsCacheChunkSize;
  2620. }
  2621. else if (pEmfRecord->Type == EmfPlusRecordTypeObject) {
  2622. switch ((enum ObjectType)(pEmfRecord->Flags >> 8) ) {
  2623. case ObjectTypeBrush:
  2624. CacheHandle = sbcGdipObjectBrushCacheHandle;
  2625. CacheType = GDIP_CACHE_OBJECT_BRUSH;
  2626. MaxCacheSize = sbcGdipObjectBrushCacheChunkSize;
  2627. break;
  2628. case ObjectTypePen:
  2629. CacheHandle = sbcGdipObjectPenCacheHandle;
  2630. CacheType = GDIP_CACHE_OBJECT_PEN;
  2631. MaxCacheSize = sbcGdipObjectPenCacheChunkSize;
  2632. break;
  2633. case ObjectTypeImage:
  2634. CacheHandle = sbcGdipObjectImageCacheHandle;
  2635. CacheType = GDIP_CACHE_OBJECT_IMAGE;
  2636. break;
  2637. case ObjectTypeImageAttributes:
  2638. CacheHandle = sbcGdipObjectImageAttributesCacheHandle;
  2639. CacheType = GDIP_CACHE_OBJECT_IMAGEATTRIBUTES;
  2640. MaxCacheSize = sbcGdipObjectImageAttributesCacheChunkSize;
  2641. break;
  2642. default:
  2643. *CacheID = CH_KEY_UNCACHABLE;
  2644. goto NO_CACHE;
  2645. }
  2646. }
  2647. else {
  2648. *CacheID = CH_KEY_UNCACHABLE;
  2649. goto NO_CACHE;
  2650. }
  2651. // Data size needs to be multiple of DWORD to calculate cache key
  2652. Temp = (pEmfRecord->Size - sizeof(TSEmfPlusRecord)) % sizeof(UINT32);
  2653. if (Temp != 0) {
  2654. // Not multiple of DWORD, need to craete a new buffer to hold the data
  2655. CacheBufferSize = (((pEmfRecord->Size - sizeof(TSEmfPlusRecord)) / sizeof(UINT32) + 1) * sizeof(UINT32));
  2656. CacheBuffer = (BYTE *)EngAllocMem(FL_ZERO_MEMORY, CacheBufferSize, DD_ALLOC_TAG);
  2657. if (CacheBuffer == NULL) {
  2658. *CacheID = CH_KEY_UNCACHABLE;
  2659. goto NO_CACHE;
  2660. }
  2661. memcpy(CacheBuffer, (BYTE *)(pEmfRecord + 1), (pEmfRecord->Size - sizeof(TSEmfPlusRecord)));
  2662. CH_CreateKeyFromFirstData(&CHContext, CacheBuffer, CacheBufferSize);
  2663. EngFreeMem(CacheBuffer);
  2664. }
  2665. else {
  2666. CH_CreateKeyFromFirstData(&CHContext, (pEmfRecord + 1), (pEmfRecord->Size - sizeof(TSEmfPlusRecord)));
  2667. }
  2668. if (!CH_SearchCache(CacheHandle, CHContext.Key1, CHContext.Key2, &UserDefined, CacheID)) {
  2669. // This record is not cached, need to create a new one
  2670. if (CacheType == GDIP_CACHE_OBJECT_IMAGE) {
  2671. // Convert the size in bytes to the number of cache chunks
  2672. CacheSize = (TSUINT16)ActualSizeToChunkSize(pEmfRecord->Size, sbcGdipObjectImageCacheChunkSize);
  2673. if (CacheSize > sbcGdipObjectImageCacheMaxSize) {
  2674. TRC_NRM((TB, ("Image Cache Size %d too big, will not cache it"), CacheSize));
  2675. *CacheID = CH_KEY_UNCACHABLE;
  2676. goto NO_CACHE;
  2677. }
  2678. // The total cache cap is sbcGdipObjectImageCacheTotalSize
  2679. // if sbcGdipObjectImageCacheSizeUsed plus the new cache size exceeds the cap
  2680. // we remove the cache entry in LRU list until cache cap won't be exceeded
  2681. RemoveCacheID = CH_GetLRUCacheEntry(CacheHandle);
  2682. //TRC_ERR((TB, ("Shoud discard cache type: %d, ID: %d"), CacheType, CH_GetLRUCacheEntry(CacheHandle)));
  2683. *CacheID = CH_CacheKey(CacheHandle, CHContext.Key1, CHContext.Key2, NULL);
  2684. if ((RemoveCacheID == *CacheID) &&
  2685. (RemoveCacheID != CH_KEY_UNCACHABLE)) {
  2686. // New cache entry will replace an old one, need to update sbcGdipObjectImageCacheSizeUsed
  2687. sbcGdipObjectImageCacheSizeUsed -= sbcGdipObjectImageCacheSizeList[RemoveCacheID];
  2688. }
  2689. TRC_NRM((TB, ("Size used is %d, will add %d"), sbcGdipObjectImageCacheSizeUsed, CacheSize));
  2690. if ((sbcGdipObjectImageCacheSizeUsed + CacheSize) > sbcGdipObjectImageCacheTotalSize) {
  2691. RemoveCacheNum = 0;
  2692. RemoveCacheIDList = EngAllocMem(FL_ZERO_MEMORY,
  2693. sizeof(TSUINT16) * pddShm->sbc.drawGdiplusInfo.GdipCacheEntries.GdipObjectImageCacheEntries, DD_ALLOC_TAG);
  2694. if (RemoveCacheIDList == NULL) {
  2695. TRC_ERR((TB, "Can't allocate the memory for RemoveCacheIDList"));
  2696. goto NO_CACHE;
  2697. }
  2698. while ((sbcGdipObjectImageCacheSizeUsed + CacheSize) > sbcGdipObjectImageCacheTotalSize) {
  2699. RemoveCacheID = CH_GetLRUCacheEntry(CacheHandle);
  2700. sbcGdipObjectImageCacheSizeUsed -= sbcGdipObjectImageCacheSizeList[RemoveCacheID];
  2701. TRC_NRM((TB, ("Remove cacheId %d, minus size %d, Used size is %d"), RemoveCacheID,
  2702. sbcGdipObjectImageCacheSizeList[RemoveCacheID], sbcGdipObjectImageCacheSizeUsed));
  2703. CH_RemoveCacheEntry(CacheHandle, RemoveCacheID);
  2704. // Add the RemoveCacheID to the list, will send it with the cache order
  2705. RemoveCacheIDList[RemoveCacheNum] = (TSUINT16)RemoveCacheID;
  2706. RemoveCacheNum++;
  2707. sbcGdipObjectImageCacheSizeList[RemoveCacheID] = 0;
  2708. }
  2709. }
  2710. }
  2711. else {
  2712. if (pEmfRecord->Size > MaxCacheSize) {
  2713. TRC_NRM((TB, ("Cache Size %d with type %d too big, will not cache it"), pEmfRecord->Size, CacheType));
  2714. *CacheID = CH_KEY_UNCACHABLE;
  2715. goto NO_CACHE;
  2716. }
  2717. *CacheID = CH_CacheKey(CacheHandle, CHContext.Key1, CHContext.Key2, NULL);
  2718. }
  2719. if (CacheType == GDIP_CACHE_OBJECT_IMAGE)
  2720. TRC_NRM((TB, ("new cache: type %d, ID: %d, size: %d"), CacheType, *CacheID, CacheSize));
  2721. if (*CacheID != CH_KEY_UNCACHABLE) {
  2722. if (!OESendDrawGdiplusCacheOrder(ppdev, pEmfRecord, CacheID, CacheType, RemoveCacheNum, RemoveCacheIDList))
  2723. {
  2724. TRC_ERR((TB, ("OESendDrawGdiplusCacheOrder failed to send cache order")));
  2725. DC_QUIT;
  2726. }
  2727. if (CacheType == GDIP_CACHE_OBJECT_IMAGE) {
  2728. // Update the used image cache size
  2729. sbcGdipObjectImageCacheSizeList[*CacheID] = CacheSize;
  2730. sbcGdipObjectImageCacheSizeUsed += CacheSize;
  2731. TRC_NRM((TB, ("add size %d, new used size is %d"), CacheSize, sbcGdipObjectImageCacheSizeUsed));
  2732. }
  2733. }
  2734. else {
  2735. TRC_ERR((TB, "Failed to cache the Gdiplus object"));
  2736. goto NO_CACHE;
  2737. }
  2738. }
  2739. else {
  2740. TRC_NRM((TB, ("Already cached: type %d, ID: %d"), CacheType, *CacheID));
  2741. }
  2742. NO_CACHE:
  2743. rc = TRUE;
  2744. DC_EXIT_POINT:
  2745. if (rc != TRUE && *CacheID != CH_KEY_UNCACHABLE)
  2746. CH_RemoveCacheEntry(CacheHandle, *CacheID);
  2747. if (NULL != RemoveCacheIDList) {
  2748. EngFreeMem(RemoveCacheIDList);
  2749. }
  2750. DC_END_FN();
  2751. return rc;
  2752. }
  2753. /****************************************************************************/
  2754. // OESendDrawGdiplusCacheOrder
  2755. //
  2756. // Send the Gdiplus EMF+ record cache order
  2757. /****************************************************************************/
  2758. BOOL RDPCALL OESendDrawGdiplusCacheOrder(PDD_PDEV ppdev, PVOID pvIn, unsigned int *CacheID, TSUINT16 CacheType,
  2759. TSUINT16 RemoveCacheNum, TSUINT16 * RemoveCacheIDList)
  2760. {
  2761. BOOL rc = FALSE;
  2762. PINT_ORDER pIntOrder;
  2763. PTSEmfPlusRecord pEmfRecord = (PTSEmfPlusRecord)pvIn;
  2764. PTS_DRAW_GDIPLUS_CACHE_ORDER_FIRST pDrawGdiplusCachePDUFirst;
  2765. PTS_DRAW_GDIPLUS_CACHE_ORDER_NEXT pDrawGdiplusCachePDUNext;
  2766. PTS_DRAW_GDIPLUS_CACHE_ORDER_END pDrawGdiplusCachePDUEnd;
  2767. unsigned sizeLeft, sizeOrder, sizeTotal, sizeUsed;
  2768. BOOL bFirst = TRUE;
  2769. BOOL bAddRemoveCacheList = FALSE;
  2770. BYTE *pDataOffset;
  2771. TSUINT16 *pImageCacheData, i;
  2772. DC_BEGIN_FN("OESendDrawGdiplusCacheOrder");
  2773. sizeTotal = pEmfRecord->Size - sizeof(TSEmfPlusRecord);
  2774. sizeLeft = sizeTotal;
  2775. pDataOffset = (BYTE *)(pEmfRecord +1);
  2776. while (sizeLeft > 0) {
  2777. sizeUsed = (sizeLeft <= TS_GDIPLUS_ORDER_SIZELIMIT) ? sizeLeft : TS_GDIPLUS_ORDER_SIZELIMIT;
  2778. sizeLeft -= sizeUsed;
  2779. if (bFirst && (RemoveCacheNum != 0) &&
  2780. (CacheType == GDIP_CACHE_OBJECT_IMAGE)) {
  2781. // Need to add the RemoveCacheList to this order
  2782. sizeOrder = sizeUsed + sizeof(TSUINT16) * (RemoveCacheNum + 1);
  2783. bAddRemoveCacheList = TRUE;
  2784. }
  2785. else {
  2786. sizeOrder = sizeUsed;
  2787. }
  2788. if (bFirst) {
  2789. pIntOrder = OA_AllocOrderMem(ppdev, sizeof(TS_DRAW_GDIPLUS_CACHE_ORDER_FIRST) + sizeOrder);
  2790. if (pIntOrder != NULL) {
  2791. // First block of the order data
  2792. pDrawGdiplusCachePDUFirst = (PTS_DRAW_GDIPLUS_CACHE_ORDER_FIRST)pIntOrder->OrderData;
  2793. pDrawGdiplusCachePDUFirst->ControlFlags = (TS_ALTSEC_GDIP_CACHE_FIRST <<
  2794. TS_ALTSEC_ORDER_TYPE_SHIFT) | TS_SECONDARY;
  2795. bFirst = FALSE;
  2796. if (bAddRemoveCacheList) {
  2797. // Need to add the RemoveCacheList to this order
  2798. pImageCacheData = (TSUINT16 *)(pDrawGdiplusCachePDUFirst + 1);
  2799. *pImageCacheData = RemoveCacheNum;
  2800. pImageCacheData ++;
  2801. for (i=0; i<RemoveCacheNum; i++) {
  2802. TRC_NRM((TB, "Remove Cache ID: %d", *(RemoveCacheIDList + i)));
  2803. *pImageCacheData = *(RemoveCacheIDList + i);
  2804. pImageCacheData++;
  2805. }
  2806. }
  2807. pDrawGdiplusCachePDUFirst->Flags = 0;
  2808. pDrawGdiplusCachePDUFirst->CacheID = (TSUINT16)*CacheID;
  2809. pDrawGdiplusCachePDUFirst->CacheType = CacheType;
  2810. pDrawGdiplusCachePDUFirst->cbTotalSize = sizeTotal;
  2811. pDrawGdiplusCachePDUFirst->cbSize = (TSUINT16)sizeOrder;
  2812. if (!bAddRemoveCacheList) {
  2813. memcpy(pDrawGdiplusCachePDUFirst + 1, pDataOffset, sizeUsed);
  2814. }
  2815. else {
  2816. // Set the flag to indicate there's RemoveCacheIDList in this order
  2817. pDrawGdiplusCachePDUFirst->Flags |= TS_GDIPLUS_CACHE_ORDER_REMOVE_CACHEENTRY;
  2818. memcpy((BYTE *)pImageCacheData, pDataOffset, sizeUsed);
  2819. bAddRemoveCacheList = FALSE;
  2820. }
  2821. }
  2822. else {
  2823. TRC_ERR((TB, "Failed to allocated order for drawgdiplus cache"));
  2824. DC_QUIT;
  2825. }
  2826. }
  2827. else {
  2828. if (sizeLeft == 0) {
  2829. // Last block of the order data
  2830. pIntOrder = OA_AllocOrderMem(ppdev, sizeof(TS_DRAW_GDIPLUS_CACHE_ORDER_END) + sizeOrder);
  2831. if (pIntOrder != NULL) {
  2832. pDrawGdiplusCachePDUEnd = (PTS_DRAW_GDIPLUS_CACHE_ORDER_END)pIntOrder->OrderData;
  2833. pDrawGdiplusCachePDUEnd->ControlFlags = (TS_ALTSEC_GDIP_CACHE_END <<
  2834. TS_ALTSEC_ORDER_TYPE_SHIFT) | TS_SECONDARY;
  2835. pDrawGdiplusCachePDUEnd->Flags = 0;
  2836. pDrawGdiplusCachePDUEnd->CacheID = (TSUINT16)*CacheID;
  2837. pDrawGdiplusCachePDUEnd->CacheType = CacheType;
  2838. pDrawGdiplusCachePDUEnd->cbSize = (TSUINT16)sizeOrder;
  2839. pDrawGdiplusCachePDUEnd->cbTotalSize = sizeTotal;
  2840. memcpy(pDrawGdiplusCachePDUEnd + 1, pDataOffset, sizeUsed);
  2841. }
  2842. else {
  2843. TRC_ERR((TB, "Failed to allocated order for drawgdiplus cache"));
  2844. DC_QUIT;
  2845. }
  2846. }
  2847. else {
  2848. // subsequent block of the order data
  2849. pIntOrder = OA_AllocOrderMem(ppdev, sizeof(TS_DRAW_GDIPLUS_CACHE_ORDER_NEXT) + sizeOrder);
  2850. if (pIntOrder != NULL) {
  2851. pDrawGdiplusCachePDUNext = (PTS_DRAW_GDIPLUS_CACHE_ORDER_NEXT)pIntOrder->OrderData;
  2852. pDrawGdiplusCachePDUNext->ControlFlags = (TS_ALTSEC_GDIP_CACHE_NEXT <<
  2853. TS_ALTSEC_ORDER_TYPE_SHIFT) | TS_SECONDARY;
  2854. pDrawGdiplusCachePDUNext->Flags = 0;
  2855. pDrawGdiplusCachePDUNext->CacheID = (TSUINT16)*CacheID;
  2856. pDrawGdiplusCachePDUNext->CacheType = CacheType;
  2857. pDrawGdiplusCachePDUNext->cbSize = (TSUINT16)sizeOrder;
  2858. memcpy(pDrawGdiplusCachePDUNext + 1, pDataOffset, sizeUsed);
  2859. }
  2860. else {
  2861. TRC_ERR((TB, "Failed to allocated order for drawgdiplus cache"));
  2862. DC_QUIT;
  2863. }
  2864. }
  2865. }
  2866. pDataOffset += sizeUsed;
  2867. OA_AppendToOrderList(pIntOrder);
  2868. }
  2869. rc = TRUE;
  2870. DC_EXIT_POINT:
  2871. DC_END_FN();
  2872. return rc;
  2873. }
  2874. /****************************************************************************/
  2875. // OESendDrawGdiplusOrder
  2876. //
  2877. // Send the Gdiplus EMF+ record order
  2878. /****************************************************************************/
  2879. BOOL RDPCALL OESendDrawGdiplusOrder(PDD_PDEV ppdev, RECTL *prcl, ULONG cjIn, PVOID pvIn, ULONG TotalEmfSize)
  2880. {
  2881. BOOL rc = FALSE;
  2882. PINT_ORDER pIntOrder;
  2883. PTS_DRAW_GDIPLUS_ORDER_FIRST pDrawGdiplusPDUFirst;
  2884. PTS_DRAW_GDIPLUS_ORDER_NEXT pDrawGdiplusPDUNext;
  2885. PTS_DRAW_GDIPLUS_ORDER_END pDrawGdiplusPDUEnd;
  2886. unsigned sizeLeft, sizeOrder, sizeTotal;
  2887. BOOL bFirst = TRUE;
  2888. BYTE *pDataOffset;
  2889. DC_BEGIN_FN("OESendDrawGdiplusOrder");
  2890. sizeTotal = cjIn;
  2891. sizeLeft = sizeTotal;
  2892. pDataOffset = pvIn;
  2893. while (sizeLeft > 0) {
  2894. sizeOrder = (sizeLeft <= TS_GDIPLUS_ORDER_SIZELIMIT) ? sizeLeft : TS_GDIPLUS_ORDER_SIZELIMIT;
  2895. sizeLeft -= sizeOrder;
  2896. if (bFirst) {
  2897. // First block of the order data
  2898. pIntOrder = OA_AllocOrderMem(ppdev, sizeof(TS_DRAW_GDIPLUS_ORDER_FIRST) + sizeOrder);
  2899. if (pIntOrder != NULL) {
  2900. pDrawGdiplusPDUFirst = (PTS_DRAW_GDIPLUS_ORDER_FIRST)pIntOrder->OrderData;
  2901. pDrawGdiplusPDUFirst->ControlFlags = (TS_ALTSEC_GDIP_FIRST <<
  2902. TS_ALTSEC_ORDER_TYPE_SHIFT) | TS_SECONDARY;
  2903. pDrawGdiplusPDUFirst->cbTotalSize = sizeTotal;
  2904. pDrawGdiplusPDUFirst->cbSize = (TSUINT16)sizeOrder;
  2905. pDrawGdiplusPDUFirst->cbTotalEmfSize = TotalEmfSize;
  2906. memcpy(pDrawGdiplusPDUFirst + 1, pDataOffset, sizeOrder);
  2907. bFirst = FALSE;
  2908. }
  2909. else {
  2910. TRC_ERR((TB, "Failed to allocated order for drawgdiplus"));
  2911. DC_QUIT;
  2912. }
  2913. }
  2914. else {
  2915. if (sizeLeft == 0) {
  2916. // Last block of the order data
  2917. pIntOrder = OA_AllocOrderMem(ppdev, sizeof(TS_DRAW_GDIPLUS_ORDER_END) + sizeOrder);
  2918. if (pIntOrder != NULL) {
  2919. pDrawGdiplusPDUEnd = (PTS_DRAW_GDIPLUS_ORDER_END)pIntOrder->OrderData;
  2920. pDrawGdiplusPDUEnd->ControlFlags = (TS_ALTSEC_GDIP_END <<
  2921. TS_ALTSEC_ORDER_TYPE_SHIFT) | TS_SECONDARY;
  2922. pDrawGdiplusPDUEnd->cbTotalSize = sizeTotal;
  2923. pDrawGdiplusPDUEnd->cbSize = (TSUINT16)sizeOrder;
  2924. pDrawGdiplusPDUEnd->cbTotalEmfSize = TotalEmfSize;
  2925. memcpy(pDrawGdiplusPDUEnd + 1, pDataOffset, sizeOrder);
  2926. }
  2927. else {
  2928. TRC_ERR((TB, "Failed to allocated order for drawgdiplus"));
  2929. DC_QUIT;
  2930. }
  2931. }
  2932. else {
  2933. // subsequent block of the order data
  2934. pIntOrder = OA_AllocOrderMem(ppdev, sizeof(TS_DRAW_GDIPLUS_ORDER_NEXT) + sizeOrder);
  2935. if (pIntOrder != NULL) {
  2936. pDrawGdiplusPDUNext = (PTS_DRAW_GDIPLUS_ORDER_NEXT)pIntOrder->OrderData;
  2937. pDrawGdiplusPDUNext->ControlFlags = (TS_ALTSEC_GDIP_NEXT <<
  2938. TS_ALTSEC_ORDER_TYPE_SHIFT) | TS_SECONDARY;
  2939. pDrawGdiplusPDUNext->cbSize = (TSUINT16)sizeOrder;
  2940. memcpy(pDrawGdiplusPDUNext + 1, pDataOffset, sizeOrder);
  2941. }
  2942. else {
  2943. TRC_ERR((TB, "Failed to allocated order for drawgdiplus"));
  2944. DC_QUIT;
  2945. }
  2946. }
  2947. }
  2948. OA_AppendToOrderList(pIntOrder);
  2949. pDataOffset += sizeOrder;
  2950. }
  2951. DC_EXIT_POINT:
  2952. DC_END_FN();
  2953. return rc;
  2954. }
  2955. #endif // DRAW_GDIPLUS
  2956. /****************************************************************************/
  2957. // OEEncodeDstBlt
  2958. //
  2959. // Performs all encoding steps required to encode a DstBlt order, then adds
  2960. // to order list. Returns FALSE if the order needs to be added to the screen
  2961. // data area.
  2962. /****************************************************************************/
  2963. BOOL RDPCALL OEEncodeDstBlt(
  2964. RECTL *pBounds,
  2965. BYTE Rop3,
  2966. PDD_PDEV ppdev,
  2967. OE_ENUMRECTS *pClipRects)
  2968. {
  2969. BOOL rc;
  2970. unsigned OrderSize;
  2971. BYTE OrderType;
  2972. PINT_ORDER pOrder;
  2973. MULTI_DSTBLT_ORDER *pPrevDB;
  2974. DC_BEGIN_FN("OEEncodeDstBlt");
  2975. // Check whether we should use the multi-cliprect version. Must be a
  2976. // complex clip region and the client must support the order.
  2977. if (pClipRects->rects.c < 2 ||
  2978. !OE_SendAsOrder(TS_ENC_MULTIDSTBLT_ORDER)) {
  2979. // Non-multi version.
  2980. OrderType = TS_ENC_DSTBLT_ORDER;
  2981. OrderSize = MAX_DSTBLT_FIELD_SIZE;
  2982. pPrevDB = (MULTI_DSTBLT_ORDER *)&PrevDstBlt;
  2983. }
  2984. else {
  2985. // Multi version.
  2986. OrderType = TS_ENC_MULTIDSTBLT_ORDER;
  2987. OrderSize = MAX_MULTI_DSTBLT_FIELD_SIZE_NCLIP(pClipRects->rects.c);
  2988. pPrevDB = &PrevMultiDstBlt;
  2989. }
  2990. if (OE_SendAsOrder(OrderType)) {
  2991. // Alloc the order memory.
  2992. // 1 field flag byte for both regular and Multi.
  2993. pOrder = OA_AllocOrderMem(ppdev, MAX_ORDER_SIZE(pClipRects->rects.c,
  2994. 1, OrderSize));
  2995. if (pOrder != NULL) {
  2996. BYTE *pControlFlags = pOrder->OrderData;
  2997. BYTE *pBuffer = pControlFlags + 1;
  2998. BYTE *pFieldFlags;
  2999. // Direct-encode the primary order fields. 1 field flag byte.
  3000. *pControlFlags = TS_STANDARD;
  3001. OE2_EncodeOrderType(pControlFlags, &pBuffer, OrderType);
  3002. pFieldFlags = pBuffer;
  3003. *pFieldFlags = 0;
  3004. pBuffer++;
  3005. // Only set boundrect for non-multi order.
  3006. if (pClipRects->rects.c != 0 && OrderType == TS_ENC_DSTBLT_ORDER)
  3007. OE2_EncodeBounds(pControlFlags, &pBuffer,
  3008. &pClipRects->rects.arcl[0]);
  3009. // Simultaneously determine if each of the coordinate fields has
  3010. // changed, whether we can use delta coordinates, and save changed
  3011. // fields.
  3012. *pFieldFlags |= (BYTE)OEDirectEncodeRect(pBounds,
  3013. (RECT *)&pPrevDB->nLeftRect, &pBuffer,
  3014. pControlFlags);
  3015. // bRop
  3016. if (Rop3 != pPrevDB->bRop) {
  3017. pPrevDB->bRop = Rop3;
  3018. *pBuffer++ = Rop3;
  3019. *pFieldFlags |= 0x10;
  3020. }
  3021. // Add the order to the list.
  3022. if (OrderType == TS_ENC_DSTBLT_ORDER) {
  3023. pOrder->OrderLength = (unsigned)(pBuffer - pOrder->OrderData);
  3024. // See if we can save sending the order field bytes.
  3025. pOrder->OrderLength -= OE2_CheckOneZeroFlagByte(pControlFlags,
  3026. pFieldFlags, (unsigned)(pBuffer - pFieldFlags - 1));
  3027. INC_OUTCOUNTER(OUT_DSTBLT_ORDER);
  3028. ADD_INCOUNTER(IN_DSTBLT_BYTES, pOrder->OrderLength);
  3029. OA_AppendToOrderList(pOrder);
  3030. // Flush the order.
  3031. if (pClipRects->rects.c < 2)
  3032. rc = TRUE;
  3033. else
  3034. rc = OEEmitReplayOrders(ppdev, 1, pClipRects);
  3035. }
  3036. else {
  3037. // Append the cliprect info.
  3038. *pFieldFlags |= (BYTE)(OEBuildPrecodeMultiClipFields(
  3039. pClipRects, &pBuffer, &pPrevDB->nDeltaEntries,
  3040. (BYTE *)&pPrevDB->codedDeltaList) << 5);
  3041. pOrder->OrderLength = (unsigned)(pBuffer - pOrder->OrderData);
  3042. // See if we can save sending the order field bytes.
  3043. pOrder->OrderLength -= OE2_CheckOneZeroFlagByte(pControlFlags,
  3044. pFieldFlags, (unsigned)(pBuffer - pFieldFlags - 1));
  3045. INC_OUTCOUNTER(OUT_MULTI_DSTBLT_ORDER);
  3046. ADD_INCOUNTER(IN_MULTI_DSTBLT_BYTES, pOrder->OrderLength);
  3047. OA_AppendToOrderList(pOrder);
  3048. rc = TRUE;
  3049. }
  3050. TRC_NRM((TB, "%sDstBlt X %d Y %d w %d h %d rop %02X",
  3051. (OrderType == TS_ENC_DSTBLT_ORDER ? "" : "Multi"),
  3052. pBounds->left, pBounds->top, pBounds->right,
  3053. pBounds->bottom, Rop3));
  3054. }
  3055. else {
  3056. TRC_ERR((TB, "Failed to alloc order"));
  3057. INC_OUTCOUNTER(OUT_BITBLT_SDA_HEAPALLOCFAILED);
  3058. rc = FALSE;
  3059. }
  3060. }
  3061. else {
  3062. TRC_NRM((TB,"(Multi)DstBlt order not supported"));
  3063. INC_OUTCOUNTER(OUT_BITBLT_SDA_UNSUPPORTED);
  3064. rc = FALSE;
  3065. }
  3066. DC_END_FN();
  3067. return rc;
  3068. }
  3069. /****************************************************************************/
  3070. // OEEncodeOpaqueRect
  3071. //
  3072. // Encodes the OpaqueRect order. Returns FALSE on failure.
  3073. /****************************************************************************/
  3074. BOOL RDPCALL OEEncodeOpaqueRect(
  3075. RECTL *pBounds,
  3076. BRUSHOBJ *pbo,
  3077. PDD_PDEV ppdev,
  3078. OE_ENUMRECTS *pClipRects)
  3079. {
  3080. BOOL rc;
  3081. unsigned OrderSize = 0;
  3082. unsigned NumFieldFlagBytes = 0;
  3083. BYTE OrderType = 0;
  3084. PINT_ORDER pOrder;
  3085. MULTI_OPAQUERECT_ORDER *pPrevOR = NULL;
  3086. DC_BEGIN_FN("OEEncodeOpaqueRect");
  3087. // Check whether we should use the multi-cliprect version. Must be a
  3088. // complex clip region and the client must support the order.
  3089. if (pClipRects->rects.c < 2 ||
  3090. !OE_SendAsOrder(TS_ENC_MULTIOPAQUERECT_ORDER)) {
  3091. // The single version is implied by PatBlt, so we check for that
  3092. // order support instead.
  3093. if (OE_SendAsOrder(TS_ENC_PATBLT_ORDER)) {
  3094. // Non-multi version.
  3095. OrderType = TS_ENC_OPAQUERECT_ORDER;
  3096. OrderSize = MAX_OPAQUERECT_FIELD_SIZE;
  3097. pPrevOR = (MULTI_OPAQUERECT_ORDER *)&PrevOpaqueRect;
  3098. NumFieldFlagBytes = 1;
  3099. }
  3100. else {
  3101. TRC_NRM((TB,"OpaqueRect/PatBlt order not supported"));
  3102. INC_OUTCOUNTER(OUT_BITBLT_SDA_UNSUPPORTED);
  3103. rc = FALSE;
  3104. DC_QUIT;
  3105. }
  3106. }
  3107. else {
  3108. // Multi version.
  3109. OrderType = TS_ENC_MULTIOPAQUERECT_ORDER;
  3110. OrderSize = MAX_MULTI_OPAQUERECT_FIELD_SIZE_NCLIP(pClipRects->rects.c);
  3111. pPrevOR = &PrevMultiOpaqueRect;
  3112. NumFieldFlagBytes = 2;
  3113. }
  3114. pOrder = OA_AllocOrderMem(ppdev, MAX_ORDER_SIZE(pClipRects->rects.c,
  3115. NumFieldFlagBytes, OrderSize));
  3116. if (pOrder != NULL) {
  3117. BYTE *pControlFlags = pOrder->OrderData;
  3118. BYTE *pBuffer = pControlFlags + 1;
  3119. PUINT32_UA pFieldFlags;
  3120. DCCOLOR Color;
  3121. // Direct-encode the primary order fields.
  3122. *pControlFlags = TS_STANDARD;
  3123. OE2_EncodeOrderType(pControlFlags, &pBuffer, OrderType);
  3124. pFieldFlags = (PUINT32_UA)pBuffer;
  3125. *pFieldFlags = 0;
  3126. pBuffer += NumFieldFlagBytes;
  3127. // Only set boundrect for non-multi order.
  3128. if (pClipRects->rects.c != 0 && OrderType == TS_ENC_OPAQUERECT_ORDER)
  3129. OE2_EncodeBounds(pControlFlags, &pBuffer,
  3130. &pClipRects->rects.arcl[0]);
  3131. *pFieldFlags |= OEDirectEncodeRect(pBounds,
  3132. (RECT *)&pPrevOR->nLeftRect, &pBuffer, pControlFlags);
  3133. // Copy non-coordinate fields, saving copies as needed.
  3134. OEConvertColor(ppdev, &Color, pbo->iSolidColor, NULL);
  3135. if (Color.u.rgb.red != pPrevOR->Color.u.rgb.red) {
  3136. pPrevOR->Color.u.rgb.red = Color.u.rgb.red;
  3137. *pBuffer++ = Color.u.rgb.red;
  3138. *pFieldFlags |= 0x10;
  3139. }
  3140. if (Color.u.rgb.green != pPrevOR->Color.u.rgb.green) {
  3141. pPrevOR->Color.u.rgb.green = Color.u.rgb.green;
  3142. *pBuffer++ = Color.u.rgb.green;
  3143. *pFieldFlags |= 0x20;
  3144. }
  3145. if (Color.u.rgb.blue != pPrevOR->Color.u.rgb.blue) {
  3146. pPrevOR->Color.u.rgb.blue = Color.u.rgb.blue;
  3147. *pBuffer++ = Color.u.rgb.blue;
  3148. *pFieldFlags |= 0x40;
  3149. }
  3150. // Different handling based on the type.
  3151. if (OrderType == TS_ENC_OPAQUERECT_ORDER) {
  3152. pOrder->OrderLength = (unsigned)(pBuffer - pOrder->OrderData);
  3153. // See if we can save sending the order field bytes.
  3154. pOrder->OrderLength -= OE2_CheckOneZeroFlagByte(pControlFlags,
  3155. (BYTE *)pFieldFlags,
  3156. (unsigned)(pBuffer - (BYTE *)pFieldFlags - 1));
  3157. // Flush the order.
  3158. INC_OUTCOUNTER(OUT_OPAQUERECT_ORDER);
  3159. ADD_INCOUNTER(IN_OPAQUERECT_BYTES, pOrder->OrderLength);
  3160. OA_AppendToOrderList(pOrder);
  3161. if (pClipRects->rects.c < 2)
  3162. rc = TRUE;
  3163. else
  3164. rc = OEEmitReplayOrders(ppdev, 1, pClipRects);
  3165. }
  3166. else {
  3167. // Append the cliprect info.
  3168. *pFieldFlags |= (OEBuildPrecodeMultiClipFields(pClipRects,
  3169. &pBuffer, &pPrevOR->nDeltaEntries,
  3170. (BYTE *)&pPrevOR->codedDeltaList) << 7);
  3171. pOrder->OrderLength = (unsigned)(pBuffer - pOrder->OrderData);
  3172. // See if we can save sending the order field bytes.
  3173. pOrder->OrderLength -= OE2_CheckTwoZeroFlagBytes(pControlFlags,
  3174. (BYTE *)pFieldFlags,
  3175. (unsigned)(pBuffer - (BYTE *)pFieldFlags - 2));
  3176. // Flush the order.
  3177. INC_OUTCOUNTER(OUT_MULTI_OPAQUERECT_ORDER);
  3178. ADD_INCOUNTER(IN_MULTI_OPAQUERECT_BYTES, pOrder->OrderLength);
  3179. OA_AppendToOrderList(pOrder);
  3180. rc = TRUE;
  3181. }
  3182. TRC_NRM((TB, "%sOpaqueRect x(%d) y(%d) w(%d) h(%d) c(%#02x)",
  3183. (OrderType == TS_ENC_OPAQUERECT_ORDER ? "" : "Multi"),
  3184. pBounds->left, pBounds->top,
  3185. pBounds->right - pBounds->left,
  3186. pBounds->bottom - pBounds->top,
  3187. Color.u.index));
  3188. }
  3189. else {
  3190. TRC_ERR((TB, "Failed to alloc order"));
  3191. INC_OUTCOUNTER(OUT_BITBLT_SDA_HEAPALLOCFAILED);
  3192. rc = FALSE;
  3193. }
  3194. DC_EXIT_POINT:
  3195. DC_END_FN();
  3196. return rc;
  3197. }
  3198. /****************************************************************************/
  3199. // OEDirectEncodeRect
  3200. //
  3201. // Common code for handling the various XxxBlt and MultiXxxBlt direct
  3202. // encoding to wire format. Encodes the left, top, width, and height
  3203. // of the exclusive bound rect. Assumes that the bound rect values are
  3204. // encoded as 2-byte coords on the wire and that they are the only coords
  3205. // in the target order. Returns the field encoding flags.
  3206. /****************************************************************************/
  3207. unsigned OEDirectEncodeRect(
  3208. RECTL *pBounds,
  3209. RECT *pPrevBounds,
  3210. BYTE **ppBuf,
  3211. BYTE *pControlFlags)
  3212. {
  3213. BYTE *pBuf = *ppBuf;
  3214. long Temp;
  3215. BOOL bUseDeltaCoords;
  3216. short Delta, NormalCoordEncoding[4];
  3217. unsigned NumFields;
  3218. unsigned FieldFlags;
  3219. DC_BEGIN_FN("OEDirectEncodeRect");
  3220. memset(NormalCoordEncoding, 0, sizeof(NormalCoordEncoding));
  3221. // Simultaneously determine if each of the coordinate fields
  3222. // has changed, whether we can use delta coordinates, and
  3223. // save changed fields. Note bounds are in exclusive coords.
  3224. FieldFlags = 0;
  3225. NumFields = 0;
  3226. bUseDeltaCoords = TRUE;
  3227. // Left
  3228. Delta = (short)(pBounds->left - pPrevBounds->left);
  3229. if (Delta) {
  3230. pPrevBounds->left = pBounds->left;
  3231. if (Delta != (short)(char)Delta)
  3232. bUseDeltaCoords = FALSE;
  3233. pBuf[NumFields] = (char)Delta;
  3234. NormalCoordEncoding[NumFields] = (short)pBounds->left;
  3235. NumFields++;
  3236. FieldFlags |= 0x01;
  3237. }
  3238. // Top
  3239. Delta = (short)(pBounds->top - pPrevBounds->top);
  3240. if (Delta) {
  3241. pPrevBounds->top = pBounds->top;
  3242. if (Delta != (short)(char)Delta)
  3243. bUseDeltaCoords = FALSE;
  3244. pBuf[NumFields] = (char)Delta;
  3245. NormalCoordEncoding[NumFields] = (short)pBounds->top;
  3246. NumFields++;
  3247. FieldFlags |= 0x02;
  3248. }
  3249. // Width -- we use pPrevBounds->right as prev value.
  3250. Temp = pBounds->right - pBounds->left;
  3251. Delta = (short)(Temp - pPrevBounds->right);
  3252. if (Delta) {
  3253. pPrevBounds->right = Temp;
  3254. if (Delta != (short)(char)Delta)
  3255. bUseDeltaCoords = FALSE;
  3256. pBuf[NumFields] = (char)Delta;
  3257. NormalCoordEncoding[NumFields] = (short)Temp;
  3258. NumFields++;
  3259. FieldFlags |= 0x04;
  3260. }
  3261. // Height -- we use pPrevBounds->bottom as prev value.
  3262. Temp = pBounds->bottom - pBounds->top;
  3263. Delta = (short)(Temp - pPrevBounds->bottom);
  3264. if (Delta) {
  3265. pPrevBounds->bottom = Temp;
  3266. if (Delta != (short)(char)Delta)
  3267. bUseDeltaCoords = FALSE;
  3268. pBuf[NumFields] = (char)Delta;
  3269. NormalCoordEncoding[NumFields] = (short)Temp;
  3270. NumFields++;
  3271. FieldFlags |= 0x08;
  3272. }
  3273. // Copy the final coordinates to the order.
  3274. if (bUseDeltaCoords) {
  3275. *pControlFlags |= TS_DELTA_COORDINATES;
  3276. pBuf += NumFields;
  3277. }
  3278. else {
  3279. *((DWORD UNALIGNED *)pBuf) = *((DWORD *)NormalCoordEncoding);
  3280. *((DWORD UNALIGNED *)(pBuf + 4)) = *((DWORD *)&NormalCoordEncoding[2]);
  3281. pBuf += NumFields * sizeof(short);
  3282. }
  3283. *ppBuf = pBuf;
  3284. DC_END_FN();
  3285. return FieldFlags;
  3286. }
  3287. /****************************************************************************/
  3288. // OEEncodePatBlt
  3289. //
  3290. // Encodes a PatBlt order. Retruns FALSE on failure.
  3291. /****************************************************************************/
  3292. BOOL RDPCALL OEEncodePatBlt(
  3293. PDD_PDEV ppdev,
  3294. BRUSHOBJ *pbo,
  3295. RECTL *pBounds,
  3296. POINTL *pptlBrush,
  3297. BYTE Rop3,
  3298. OE_ENUMRECTS *pClipRects)
  3299. {
  3300. BOOL rc;
  3301. unsigned OrderSize;
  3302. BYTE OrderType;
  3303. PINT_ORDER pOrder;
  3304. MULTI_PATBLT_ORDER *pPrevPB;
  3305. POE_BRUSH_DATA pCurrentBrush;
  3306. DC_BEGIN_FN("OEEncodePatBlt");
  3307. // Check for a simple brush pattern.
  3308. if (OECheckBrushIsSimple(ppdev, pbo, &pCurrentBrush)) {
  3309. // Check whether we should use the multi-cliprect version. Must be a
  3310. // complex clip region and the client must support the order.
  3311. if (pClipRects->rects.c < 2 ||
  3312. !OE_SendAsOrder(TS_ENC_MULTIPATBLT_ORDER)) {
  3313. // Non-multi version.
  3314. OrderType = TS_ENC_PATBLT_ORDER;
  3315. OrderSize = MAX_PATBLT_FIELD_SIZE;
  3316. pPrevPB = (MULTI_PATBLT_ORDER *)&PrevPatBlt;
  3317. }
  3318. else {
  3319. // Multi version.
  3320. OrderType = TS_ENC_MULTIPATBLT_ORDER;
  3321. OrderSize = MAX_MULTI_PATBLT_FIELD_SIZE_NCLIP(pClipRects->rects.c);
  3322. pPrevPB = &PrevMultiPatBlt;
  3323. }
  3324. // Make sure we don't have orders turned off.
  3325. if (OE_SendAsOrder(OrderType)) {
  3326. // 2 field flag bytes for regular and multi.
  3327. pOrder = OA_AllocOrderMem(ppdev, MAX_ORDER_SIZE(
  3328. pClipRects->rects.c, 2, OrderSize));
  3329. if (pOrder != NULL) {
  3330. BYTE *pControlFlags = pOrder->OrderData;
  3331. BYTE *pBuffer = pControlFlags + 1;
  3332. PUINT32_UA pFieldFlags;
  3333. DCCOLOR Color;
  3334. POINTL ClippedBrushOrg;
  3335. // Direct-encode the primary order fields.
  3336. *pControlFlags = TS_STANDARD;
  3337. OE2_EncodeOrderType(pControlFlags, &pBuffer, OrderType);
  3338. pFieldFlags = (PUINT32_UA)pBuffer;
  3339. *pFieldFlags = 0;
  3340. pBuffer += 2;
  3341. // Only set boundrect for non-multi order.
  3342. if (pClipRects->rects.c != 0 &&
  3343. OrderType == TS_ENC_PATBLT_ORDER)
  3344. OE2_EncodeBounds(pControlFlags, &pBuffer,
  3345. &pClipRects->rects.arcl[0]);
  3346. // Inline field encoding to wire format.
  3347. *pFieldFlags |= OEDirectEncodeRect(pBounds,
  3348. (RECT *)&pPrevPB->nLeftRect, &pBuffer, pControlFlags);
  3349. // bRop
  3350. if (Rop3 != pPrevPB->bRop) {
  3351. pPrevPB->bRop = Rop3;
  3352. *pBuffer++ = (BYTE)Rop3;
  3353. *pFieldFlags |= 0x0010;
  3354. }
  3355. // BackColor is a 3-byte color field.
  3356. if (memcmp(&pCurrentBrush->back, &pPrevPB->BackColor,
  3357. sizeof(pCurrentBrush->back))) {
  3358. pPrevPB->BackColor = pCurrentBrush->back;
  3359. *pBuffer++ = pCurrentBrush->back.u.rgb.red;
  3360. *pBuffer++ = pCurrentBrush->back.u.rgb.green;
  3361. *pBuffer++ = pCurrentBrush->back.u.rgb.blue;
  3362. *pFieldFlags |= 0x0020;
  3363. }
  3364. // ForeColor is a 3-byte color field.
  3365. if (memcmp(&pCurrentBrush->fore, &pPrevPB->ForeColor,
  3366. sizeof(pCurrentBrush->fore))) {
  3367. pPrevPB->ForeColor = pCurrentBrush->fore;
  3368. *pBuffer++ = pCurrentBrush->fore.u.rgb.red;
  3369. *pBuffer++ = pCurrentBrush->fore.u.rgb.green;
  3370. *pBuffer++ = pCurrentBrush->fore.u.rgb.blue;
  3371. *pFieldFlags |= 0x0040;
  3372. }
  3373. // The protocol brush origin is the point on the screen where
  3374. // we want the brush to start being drawn from (tiling where
  3375. // necessary).
  3376. ClippedBrushOrg = *pptlBrush;
  3377. OEClipPoint(&ClippedBrushOrg);
  3378. // BrushOrgX
  3379. if (ClippedBrushOrg.x != pPrevPB->BrushOrgX) {
  3380. pPrevPB->BrushOrgX = ClippedBrushOrg.x;
  3381. *pBuffer++ = (BYTE)ClippedBrushOrg.x;
  3382. *pFieldFlags |= 0x0080;
  3383. }
  3384. // BrushOrgY
  3385. if (ClippedBrushOrg.y != pPrevPB->BrushOrgY) {
  3386. pPrevPB->BrushOrgY = ClippedBrushOrg.y;
  3387. *pBuffer++ = (BYTE)ClippedBrushOrg.y;
  3388. *pFieldFlags |= 0x0100;
  3389. }
  3390. // BrushStyle
  3391. if (pCurrentBrush->style != pPrevPB->BrushStyle) {
  3392. pPrevPB->BrushStyle = pCurrentBrush->style;
  3393. *pBuffer++ = (BYTE)pCurrentBrush->style;
  3394. *pFieldFlags |= 0x0200;
  3395. }
  3396. // BrushHatch
  3397. if (pCurrentBrush->hatch != pPrevPB->BrushHatch) {
  3398. pPrevPB->BrushHatch = pCurrentBrush->hatch;
  3399. *pBuffer++ = (BYTE)pCurrentBrush->hatch;
  3400. *pFieldFlags |= 0x0400;
  3401. }
  3402. // BrushExtra, a 7-byte field.
  3403. if (memcmp(pCurrentBrush->brushData, pPrevPB->BrushExtra, 7)) {
  3404. memcpy(pPrevPB->BrushExtra, pCurrentBrush->brushData, 7);
  3405. memcpy(pBuffer, pCurrentBrush->brushData, 7);
  3406. pBuffer += 7;
  3407. *pFieldFlags |= 0x0800;
  3408. }
  3409. // Different handling based on the order type.
  3410. if (OrderType == TS_ENC_PATBLT_ORDER) {
  3411. pOrder->OrderLength = (unsigned)(pBuffer -
  3412. pOrder->OrderData);
  3413. // See if we can save sending the order field bytes.
  3414. pOrder->OrderLength -= OE2_CheckTwoZeroFlagBytes(
  3415. pControlFlags, (BYTE *)pFieldFlags,
  3416. (unsigned)(pBuffer - (BYTE *)pFieldFlags - 2));
  3417. INC_OUTCOUNTER(OUT_PATBLT_ORDER);
  3418. ADD_INCOUNTER(IN_PATBLT_BYTES, pOrder->OrderLength);
  3419. OA_AppendToOrderList(pOrder);
  3420. // Flush the order.
  3421. if (pClipRects->rects.c < 2)
  3422. rc = TRUE;
  3423. else
  3424. rc = OEEmitReplayOrders(ppdev, 2, pClipRects);
  3425. }
  3426. else {
  3427. // Append the cliprect info.
  3428. *pFieldFlags |= (OEBuildPrecodeMultiClipFields(pClipRects,
  3429. &pBuffer, &pPrevPB->nDeltaEntries,
  3430. (BYTE *)&pPrevPB->codedDeltaList) << 12);
  3431. pOrder->OrderLength = (unsigned)(pBuffer -
  3432. pOrder->OrderData);
  3433. // See if we can save sending the order field bytes.
  3434. pOrder->OrderLength -= OE2_CheckTwoZeroFlagBytes(
  3435. pControlFlags, (BYTE *)pFieldFlags,
  3436. (unsigned)(pBuffer - (BYTE *)pFieldFlags - 2));
  3437. INC_OUTCOUNTER(OUT_MULTI_PATBLT_ORDER);
  3438. ADD_INCOUNTER(IN_MULTI_PATBLT_BYTES, pOrder->OrderLength);
  3439. OA_AppendToOrderList(pOrder);
  3440. rc = TRUE;
  3441. }
  3442. TRC_NRM((TB, "%sPatBlt BC %02x FC %02x "
  3443. "Brush %02X %02X X %d Y %d w %d h %d rop %02X",
  3444. (OrderType == TS_ENC_PATBLT_ORDER ? "" : "Multi"),
  3445. pCurrentBrush->back.u.index,
  3446. pCurrentBrush->fore.u.index,
  3447. pCurrentBrush->style,
  3448. pCurrentBrush->hatch,
  3449. pBounds->left,
  3450. pBounds->top,
  3451. pBounds->right - pBounds->left,
  3452. pBounds->bottom = pBounds->top,
  3453. Rop3));
  3454. }
  3455. else {
  3456. TRC_ERR((TB, "Failed to alloc order"));
  3457. INC_OUTCOUNTER(OUT_BITBLT_SDA_HEAPALLOCFAILED);
  3458. rc = FALSE;
  3459. }
  3460. }
  3461. else {
  3462. TRC_NRM((TB,"(Multi)PatBlt order not supported"));
  3463. INC_OUTCOUNTER(OUT_BITBLT_SDA_UNSUPPORTED);
  3464. rc = FALSE;
  3465. }
  3466. }
  3467. else {
  3468. TRC_NRM((TB, "Brush is not simple"));
  3469. rc = FALSE;
  3470. }
  3471. DC_END_FN();
  3472. return rc;
  3473. }
  3474. /****************************************************************************/
  3475. // OEDirectEncodeMemBlt
  3476. //
  3477. // Handles all steps required to encode MemBlt. Assumes the order data
  3478. // has been placed in oeTempMemBlt.
  3479. /****************************************************************************/
  3480. BOOL OEDirectEncodeMemBlt(PDD_PDEV ppdev, OE_ENUMRECTS *pClipRects)
  3481. {
  3482. BOOL rc;
  3483. BYTE DeltaEncoding2[2];
  3484. short Delta, NormalEncoding1[4], NormalEncoding2[2];
  3485. BOOLEAN bUseDeltaCoords;
  3486. unsigned NumFields1, NumFields2;
  3487. PINT_ORDER pOrder;
  3488. DC_BEGIN_FN("OEDirectEncodeMemBlt");
  3489. TRC_NRM((TB,"MemBlt: Dst=(%d,%d),w=%d,h=%d, Src=(%d,%d), "
  3490. "clip=%s (%d,%d,%d,%d)",
  3491. oeTempMemBlt.Common.nLeftRect,
  3492. oeTempMemBlt.Common.nTopRect,
  3493. oeTempMemBlt.Common.nWidth,
  3494. oeTempMemBlt.Common.nHeight,
  3495. oeTempMemBlt.Common.nXSrc,
  3496. oeTempMemBlt.Common.nYSrc,
  3497. pClipRects->rects.c == 0 ? "n/a" : "present",
  3498. pClipRects->rects.arcl[0].left,
  3499. pClipRects->rects.arcl[0].top,
  3500. pClipRects->rects.arcl[0].right,
  3501. pClipRects->rects.arcl[0].bottom));
  3502. // 2 field flag bytes.
  3503. pOrder = OA_AllocOrderMem(ppdev, MAX_ORDER_SIZE(pClipRects->rects.c, 2,
  3504. MAX_MEMBLT_FIELD_SIZE));
  3505. if (pOrder != NULL) {
  3506. BYTE *pControlFlags = pOrder->OrderData;
  3507. BYTE *pBuffer = pControlFlags + 1;
  3508. PUINT32_UA pFieldFlags;
  3509. // Direct-encode the primary order fields. 2 field flag bytes.
  3510. *pControlFlags = TS_STANDARD;
  3511. OE2_EncodeOrderType(pControlFlags, &pBuffer, TS_ENC_MEMBLT_R2_ORDER);
  3512. pFieldFlags = (PUINT32_UA)pBuffer;
  3513. *pFieldFlags = 0;
  3514. pBuffer += 2;
  3515. if (pClipRects->rects.c != 0)
  3516. OE2_EncodeBounds(pControlFlags, &pBuffer,
  3517. &pClipRects->rects.arcl[0]);
  3518. if (oeTempMemBlt.Common.cacheId != PrevMemBlt.Common.cacheId) {
  3519. PrevMemBlt.Common.cacheId = oeTempMemBlt.Common.cacheId;
  3520. *((UNALIGNED unsigned short *)pBuffer) =
  3521. oeTempMemBlt.Common.cacheId;
  3522. pBuffer += sizeof(unsigned short);
  3523. *pFieldFlags |= 0x0001;
  3524. }
  3525. // Simultaneously determine if each of the coordinate fields has changed,
  3526. // whether we can use delta coordinates, and save changed fields.
  3527. NumFields1 = NumFields2 = 0;
  3528. bUseDeltaCoords = TRUE;
  3529. Delta = (short)(oeTempMemBlt.Common.nLeftRect -
  3530. PrevMemBlt.Common.nLeftRect);
  3531. if (Delta) {
  3532. PrevMemBlt.Common.nLeftRect = oeTempMemBlt.Common.nLeftRect;
  3533. if (Delta != (short)(char)Delta)
  3534. bUseDeltaCoords = FALSE;
  3535. pBuffer[NumFields1] = (char)Delta;
  3536. NormalEncoding1[NumFields1] = (short)oeTempMemBlt.Common.nLeftRect;
  3537. NumFields1++;
  3538. *pFieldFlags |= 0x0002;
  3539. }
  3540. Delta = (short)(oeTempMemBlt.Common.nTopRect -
  3541. PrevMemBlt.Common.nTopRect);
  3542. if (Delta) {
  3543. PrevMemBlt.Common.nTopRect = oeTempMemBlt.Common.nTopRect;
  3544. if (Delta != (short)(char)Delta)
  3545. bUseDeltaCoords = FALSE;
  3546. pBuffer[NumFields1] = (char)Delta;
  3547. NormalEncoding1[NumFields1] = (short)oeTempMemBlt.Common.nTopRect;
  3548. NumFields1++;
  3549. *pFieldFlags |= 0x0004;
  3550. }
  3551. Delta = (short)(oeTempMemBlt.Common.nWidth - PrevMemBlt.Common.nWidth);
  3552. if (Delta) {
  3553. PrevMemBlt.Common.nWidth = oeTempMemBlt.Common.nWidth;
  3554. if (Delta != (short)(char)Delta)
  3555. bUseDeltaCoords = FALSE;
  3556. pBuffer[NumFields1] = (char)Delta;
  3557. NormalEncoding1[NumFields1] = (short)oeTempMemBlt.Common.nWidth;
  3558. NumFields1++;
  3559. *pFieldFlags |= 0x0008;
  3560. }
  3561. Delta = (short)(oeTempMemBlt.Common.nHeight -
  3562. PrevMemBlt.Common.nHeight);
  3563. if (Delta) {
  3564. PrevMemBlt.Common.nHeight = oeTempMemBlt.Common.nHeight;
  3565. if (Delta != (short)(char)Delta)
  3566. bUseDeltaCoords = FALSE;
  3567. pBuffer[NumFields1] = (char)Delta;
  3568. NormalEncoding1[NumFields1] = (short)oeTempMemBlt.Common.nHeight;
  3569. NumFields1++;
  3570. *pFieldFlags |= 0x0010;
  3571. }
  3572. Delta = (short)(oeTempMemBlt.Common.nXSrc - PrevMemBlt.Common.nXSrc);
  3573. if (Delta) {
  3574. PrevMemBlt.Common.nXSrc = oeTempMemBlt.Common.nXSrc;
  3575. if (Delta != (short)(char)Delta)
  3576. bUseDeltaCoords = FALSE;
  3577. DeltaEncoding2[NumFields2] = (char)Delta;
  3578. NormalEncoding2[NumFields2] = (short)oeTempMemBlt.Common.nXSrc;
  3579. NumFields2++;
  3580. *pFieldFlags |= 0x0040;
  3581. }
  3582. Delta = (short)(oeTempMemBlt.Common.nYSrc - PrevMemBlt.Common.nYSrc);
  3583. if (Delta) {
  3584. PrevMemBlt.Common.nYSrc = oeTempMemBlt.Common.nYSrc;
  3585. if (Delta != (short)(char)Delta)
  3586. bUseDeltaCoords = FALSE;
  3587. DeltaEncoding2[NumFields2] = (char)Delta;
  3588. NormalEncoding2[NumFields2] = (short)oeTempMemBlt.Common.nYSrc;
  3589. NumFields2++;
  3590. *pFieldFlags |= 0x0080;
  3591. }
  3592. // Begin copying the final coordinates to the order.
  3593. if (bUseDeltaCoords) {
  3594. *pControlFlags |= TS_DELTA_COORDINATES;
  3595. pBuffer += NumFields1;
  3596. }
  3597. else {
  3598. memcpy(pBuffer, NormalEncoding1, NumFields1 * sizeof(short));
  3599. pBuffer += NumFields1 * sizeof(short);
  3600. }
  3601. // Copy the intervening bRop field.
  3602. if (oeTempMemBlt.Common.bRop != PrevMemBlt.Common.bRop) {
  3603. PrevMemBlt.Common.bRop = oeTempMemBlt.Common.bRop;
  3604. *pBuffer++ = (BYTE)oeTempMemBlt.Common.bRop;
  3605. *pFieldFlags |= 0x0020;
  3606. }
  3607. // Copy the src coords.
  3608. if (bUseDeltaCoords) {
  3609. memcpy(pBuffer, DeltaEncoding2, NumFields2);
  3610. pBuffer += NumFields2;
  3611. }
  3612. else {
  3613. memcpy(pBuffer, NormalEncoding2, NumFields2 * sizeof(short));
  3614. pBuffer += NumFields2 * sizeof(short);
  3615. }
  3616. // Finish with the cache index.
  3617. if (oeTempMemBlt.Common.cacheIndex != PrevMemBlt.Common.cacheIndex) {
  3618. PrevMemBlt.Common.cacheIndex = oeTempMemBlt.Common.cacheIndex;
  3619. *((UNALIGNED unsigned short *)pBuffer) =
  3620. oeTempMemBlt.Common.cacheIndex;
  3621. pBuffer += sizeof(unsigned short);
  3622. *pFieldFlags |= 0x0100;
  3623. }
  3624. pOrder->OrderLength = (unsigned)(pBuffer - pOrder->OrderData);
  3625. // See if we can save sending the order field bytes.
  3626. pOrder->OrderLength -= OE2_CheckTwoZeroFlagBytes(pControlFlags,
  3627. (BYTE *)pFieldFlags,
  3628. (unsigned)(pBuffer - (BYTE *)pFieldFlags - 2));
  3629. INC_OUTCOUNTER(OUT_MEMBLT_ORDER);
  3630. ADD_INCOUNTER(IN_MEMBLT_BYTES, pOrder->OrderLength);
  3631. OA_AppendToOrderList(pOrder);
  3632. // Flush the order.
  3633. if (pClipRects->rects.c < 2)
  3634. rc = TRUE;
  3635. else
  3636. rc = OEEmitReplayOrders(ppdev, 2, pClipRects);
  3637. }
  3638. else {
  3639. TRC_ERR((TB,"Failed alloc MemBlt order on heap"));
  3640. INC_OUTCOUNTER(OUT_BITBLT_SDA_HEAPALLOCFAILED);
  3641. rc = FALSE;
  3642. }
  3643. DC_END_FN();
  3644. return rc;
  3645. }
  3646. /****************************************************************************/
  3647. // OEAllocAndSendMem3BltOrder
  3648. //
  3649. // Performs steps needed to launch a Mem3Blt order. Assumes the order data
  3650. // has been placed in oeTempMemBlt.
  3651. /****************************************************************************/
  3652. BOOL OEAllocAndSendMem3BltOrder(PDD_PDEV ppdev, OE_ENUMRECTS *pClipRects)
  3653. {
  3654. BOOL rc;
  3655. PINT_ORDER pOrder;
  3656. DC_BEGIN_FN("OEAllocAndSendMem3BltOrder");
  3657. TRC_NRM((TB,"Mem3Blt: Dst=(%d,%d),w=%d,h=%d, Src=(%d,%d), "
  3658. "clip=%s (%d,%d,%d,%d)",
  3659. oeTempMemBlt.Common.nLeftRect,
  3660. oeTempMemBlt.Common.nTopRect,
  3661. oeTempMemBlt.Common.nWidth,
  3662. oeTempMemBlt.Common.nHeight,
  3663. oeTempMemBlt.Common.nXSrc,
  3664. oeTempMemBlt.Common.nYSrc,
  3665. pClipRects->rects.c == 0 ? "n/a" : "present",
  3666. pClipRects->rects.arcl[0].left,
  3667. pClipRects->rects.arcl[0].top,
  3668. pClipRects->rects.arcl[0].right,
  3669. pClipRects->rects.arcl[0].bottom));
  3670. // 3 field flag bytes.
  3671. pOrder = OA_AllocOrderMem(ppdev, MAX_ORDER_SIZE(pClipRects->rects.c,
  3672. 3, MAX_MEM3BLT_FIELD_SIZE));
  3673. if (pOrder != NULL) {
  3674. // Slow-field-encode the order with the first clip rect
  3675. // (if present).
  3676. pOrder->OrderLength = OE2_EncodeOrder(pOrder->OrderData,
  3677. TS_ENC_MEM3BLT_R2_ORDER, NUM_MEM3BLT_FIELDS,
  3678. (BYTE *)&oeTempMemBlt, (BYTE *)&PrevMem3Blt, etable_3C,
  3679. (pClipRects->rects.c == 0 ? NULL :
  3680. &pClipRects->rects.arcl[0]));
  3681. INC_OUTCOUNTER(OUT_MEM3BLT_ORDER);
  3682. ADD_INCOUNTER(IN_MEM3BLT_BYTES, pOrder->OrderLength);
  3683. OA_AppendToOrderList(pOrder);
  3684. // Flush the order.
  3685. if (pClipRects->rects.c < 2)
  3686. rc = TRUE;
  3687. else
  3688. rc = OEEmitReplayOrders(ppdev, 3, pClipRects);
  3689. }
  3690. else {
  3691. TRC_ERR((TB,"Failed alloc Mem3Blt order on heap"));
  3692. INC_OUTCOUNTER(OUT_BITBLT_SDA_HEAPALLOCFAILED);
  3693. rc = FALSE;
  3694. }
  3695. DC_END_FN();
  3696. return rc;
  3697. }
  3698. /****************************************************************************/
  3699. // OETileBitBltOrder
  3700. //
  3701. // Divides a single large BitBlt order into a series of small, "tiled"
  3702. // BitBlt orders, each of which is added to the order queue. Returns FALSE
  3703. // on failure (alloc failure on offscr target).
  3704. /****************************************************************************/
  3705. BOOL OETileBitBltOrder(
  3706. PDD_PDEV ppdev,
  3707. PPOINTL pptlSrc,
  3708. RECTL *pBounds,
  3709. unsigned OrderType,
  3710. unsigned ColorTableIndex,
  3711. PMEMBLT_ORDER_EXTRA_INFO pExInfo,
  3712. OE_ENUMRECTS *pClipRects)
  3713. {
  3714. int srcRight, srcBottom;
  3715. int xTile, yTile;
  3716. unsigned xFirstTile, yFirstTile;
  3717. unsigned Width, Height;
  3718. BOOL rc = TRUE;
  3719. RECTL SrcRect, DestRect;
  3720. OE_ENUMRECTS TileClipRects;
  3721. POINTL SrcPt;
  3722. SIZEL SrcSize;
  3723. #ifdef PERF_SPOILING
  3724. BOOL bDiscardTile;
  3725. #endif
  3726. DC_BEGIN_FN("OETileBitBltOrder");
  3727. Width = pBounds->right - pBounds->left;
  3728. Height = pBounds->bottom - pBounds->top;
  3729. SrcSize = pExInfo->pSource->sizlBitmap;
  3730. // Find out what the tile size and ID will be.
  3731. pExInfo->TileID = SBC_DDQueryBitmapTileSize(SrcSize.cx, SrcSize.cy,
  3732. pptlSrc, Width, Height);
  3733. pExInfo->TileSize = (unsigned)(SBC_CACHE_0_DIMENSION << pExInfo->TileID);
  3734. // Tile the order. If an individual tile fails to go as an order,
  3735. // it's up to OEAddTiledBitBltOrder to add the tile's destination as
  3736. // screen data.
  3737. SrcPt = *pptlSrc;
  3738. TRC_NRM((TB, "Tiling order"));
  3739. TRC_DBG((TB, "l=%u, t=%u, w=%u, h=%u, tile=%u",
  3740. SrcPt.x, SrcPt.y, Width, Height, pExInfo->TileSize));
  3741. xFirstTile = SrcPt.x - (SrcPt.x & (pExInfo->TileSize - 1));
  3742. yFirstTile = SrcPt.y - (SrcPt.y & (pExInfo->TileSize - 1));
  3743. TRC_DBG((TB, "xStart=%hd, yStart=%hd", xFirstTile, yFirstTile));
  3744. // Note we are creating exclusive bounds now.
  3745. srcRight = (int)(SrcPt.x + Width);
  3746. srcBottom = (int)(SrcPt.y + Height);
  3747. // Enumerate all tiles, left-to-right, top-to-bottom, and send
  3748. // Cache Bitmap and Mem(3)Blt orders for each tile.
  3749. for (yTile = yFirstTile; (yTile < srcBottom && yTile < SrcSize.cy);
  3750. yTile += pExInfo->TileSize) {
  3751. for (xTile = xFirstTile; (xTile < srcRight && xTile < SrcSize.cx);
  3752. xTile += pExInfo->TileSize) {
  3753. // SrcRect and DestRect are exclusive rects.
  3754. SrcRect.left = SrcPt.x;
  3755. SrcRect.top = SrcPt.y;
  3756. SrcRect.right = SrcRect.left + Width;
  3757. SrcRect.bottom = SrcRect.top + Height;
  3758. DestRect.left = pBounds->left;
  3759. DestRect.top = pBounds->top;
  3760. // Intersect source and tile rects, and set up destination rect
  3761. // accordingly.
  3762. TRC_DBG((TB, "pre: xTile(%d) yTile(%d) src.left(%d) src.top(%d)",
  3763. xTile, yTile, SrcRect.left, SrcRect.top));
  3764. // Modify srcRect to contain the tile's left and top if they are
  3765. // within the full blt rect. Also move the destRect left and top
  3766. // out the same amount to match.
  3767. if (xTile > SrcRect.left) {
  3768. DestRect.left += (xTile - SrcRect.left);
  3769. SrcRect.left = xTile;
  3770. }
  3771. if (yTile > SrcRect.top) {
  3772. DestRect.top += (yTile - SrcRect.top);
  3773. SrcRect.top = yTile;
  3774. }
  3775. TRC_DBG((TB, "post: xTile(%d) yTile(%d) src.left(%d) src.top(%d)",
  3776. xTile, yTile, SrcRect.left, SrcRect.top));
  3777. // Find the right and bottom of the tile, making sure not to
  3778. // overrun the actual blt boundaries and the screen boundaries,
  3779. // and remaining in exclusive coords.
  3780. SrcRect.right = min((unsigned)SrcRect.right, (unsigned)xTile +
  3781. pExInfo->TileSize);
  3782. SrcRect.bottom = min((unsigned)SrcRect.bottom, (unsigned)yTile +
  3783. pExInfo->TileSize);
  3784. DestRect.right = DestRect.left + (SrcRect.right - SrcRect.left);
  3785. DestRect.bottom = DestRect.top + (SrcRect.bottom - SrcRect.top);
  3786. // Now that we have the exclusive dest rect, find out if the
  3787. // overall DrvBitBlt() clip rects intersect with the tile. If not,
  3788. // no need to either cache the tile or send the order.
  3789. TileClipRects.rects.c = 0;
  3790. #ifndef PERF_SPOILING
  3791. if (pClipRects->rects.c == 0 ||
  3792. OEGetIntersectionsWithClipRects(&DestRect, pClipRects,
  3793. &TileClipRects)) {
  3794. #else
  3795. // Normally, we send the tile to the client to be rendered and
  3796. // added to the bitmap cache. However, there are two cases where
  3797. // this can be avoided:
  3798. // 1) The tile doesn't intersect with the current clipping-region.
  3799. // In this case, the bitmap won't paint anyway.
  3800. // 2) The tile lies completely within our SDA bounds, meaning that
  3801. // it is already being sent as SDA. In this case, sending it
  3802. // as a cached-item would just be sending it twice over the wire!
  3803. if (pClipRects->rects.c == 0) {
  3804. bDiscardTile = pExInfo->bIsPrimarySurface &&
  3805. OEIsSDAIncluded(&DestRect,1);
  3806. } else {
  3807. if (OEGetIntersectionsWithClipRects(&DestRect,
  3808. pClipRects,
  3809. &TileClipRects)) {
  3810. bDiscardTile = pExInfo->bIsPrimarySurface &&
  3811. OEIsSDAIncluded(&(TileClipRects.rects.arcl[0]), TileClipRects.rects.c);
  3812. } else {
  3813. bDiscardTile = TRUE;
  3814. }
  3815. }
  3816. if (!bDiscardTile) {
  3817. #endif //PERF_SPOILING
  3818. // First step is to make sure the source data tile is in the
  3819. // bitmap cache. If we fail this, we simply add the
  3820. // intersected clip rects to the SDA.
  3821. if (SBC_CacheBitmapTile(ppdev, pExInfo, &SrcRect, &DestRect)) {
  3822. // nXSrc and nYSrc are the source within the tile.
  3823. // Since we've cached tiles sitting at TileSize
  3824. // boundaries, we simply use the offset into the tile by
  3825. // taking the modulo.
  3826. oeTempMemBlt.Common.nXSrc = SrcRect.left &
  3827. (pExInfo->TileSize - 1);
  3828. oeTempMemBlt.Common.nYSrc = SrcRect.top &
  3829. (pExInfo->TileSize - 1);
  3830. oeTempMemBlt.Common.nLeftRect = DestRect.left;
  3831. oeTempMemBlt.Common.nTopRect = DestRect.top;
  3832. oeTempMemBlt.Common.nWidth = SrcRect.right - SrcRect.left;
  3833. oeTempMemBlt.Common.nHeight = SrcRect.bottom - SrcRect.top;
  3834. oeTempMemBlt.Common.cacheId = (UINT16)
  3835. ((ColorTableIndex << 8) | pExInfo->CacheID);
  3836. oeTempMemBlt.Common.cacheIndex =
  3837. (UINT16)pExInfo->CacheIndex;
  3838. if (OrderType == TS_ENC_MEMBLT_R2_ORDER)
  3839. rc = OEDirectEncodeMemBlt(ppdev, &TileClipRects);
  3840. else
  3841. rc = OEAllocAndSendMem3BltOrder(ppdev, &TileClipRects);
  3842. if (!rc) {
  3843. if (oeLastDstSurface == NULL) {
  3844. // If this is a screen target, send screen data and
  3845. // continue trying to create tiles. Reset the
  3846. // return value to TRUE to indicate the tile
  3847. // was handled.
  3848. OEClipAndAddScreenDataAreaByIntersectRects(
  3849. &DestRect, &TileClipRects);
  3850. rc = TRUE;
  3851. }
  3852. else {
  3853. // On failure for offscreen rendering, we forget
  3854. // the rest of the tiles and return FALSE.
  3855. DC_QUIT;
  3856. }
  3857. }
  3858. }
  3859. else {
  3860. TRC_ERR((TB, "Failed cache bitmap order"));
  3861. INC_OUTCOUNTER(OUT_BITBLT_SDA_HEAPALLOCFAILED);
  3862. // If this is a screen target, send screen data, but still
  3863. // return TRUE to indicate we handled the tile. If an
  3864. // offscreen target, return FALSE to force the target
  3865. // surface to become uncacheable.
  3866. if (oeLastDstSurface == NULL) {
  3867. OEClipAndAddScreenDataAreaByIntersectRects(&DestRect,
  3868. &TileClipRects);
  3869. }
  3870. else {
  3871. // On failure for offscreen rendering, we forget
  3872. // the rest of the tiles and return FALSE.
  3873. rc = FALSE;
  3874. DC_QUIT;
  3875. }
  3876. }
  3877. }
  3878. else {
  3879. // We still succeed here -- the tile was handled OK.
  3880. TRC_NRM((TB,"Dropping tile - no intersections w/clip rects"));
  3881. }
  3882. }
  3883. }
  3884. DC_EXIT_POINT:
  3885. DC_END_FN();
  3886. return rc;
  3887. }
  3888. /****************************************************************************/
  3889. // OEEncodeMemBlt
  3890. //
  3891. // Performs all encoding steps required to encode a Mem(3)Blt order, then adds
  3892. // to order list. Returns FALSE if the order needs to be added to the screen
  3893. // data area.
  3894. /****************************************************************************/
  3895. BOOL RDPCALL OEEncodeMemBlt(
  3896. RECTL *pBounds,
  3897. MEMBLT_ORDER_EXTRA_INFO *pMemBltExtraInfo,
  3898. unsigned OrderType,
  3899. unsigned SrcSurfaceId,
  3900. BYTE Rop3,
  3901. POINTL *pptlSrc,
  3902. POINTL *pptlBrush,
  3903. BRUSHOBJ *pbo,
  3904. PDD_PDEV ppdev,
  3905. OE_ENUMRECTS *pClipRects)
  3906. {
  3907. BOOL rc;
  3908. unsigned ColorTableIndex;
  3909. PINT_ORDER pOrder;
  3910. MEMBLT_COMMON *pCommon;
  3911. MEM3BLT_R2_ORDER *pMem3Blt;
  3912. DC_BEGIN_FN("OEEncodeMemBlt");
  3913. // Make sure we can cache the blt -- caching must be enabled too.
  3914. if (SrcSurfaceId == CH_KEY_UNCACHABLE) {
  3915. rc = SBC_DDIsMemScreenBltCachable(pMemBltExtraInfo);
  3916. }
  3917. else {
  3918. // The surface bitmap bits already cached at the client.
  3919. // There is no need to send the bits
  3920. rc = (sbcEnabled & SBC_BITMAP_CACHE_ENABLED);
  3921. }
  3922. if (rc) {
  3923. // We have to cache the color table first.
  3924. if (SBC_SendCacheColorTableOrder(ppdev, &ColorTableIndex)) {
  3925. TRC_ASSERT((ColorTableIndex < SBC_NUM_COLOR_TABLE_CACHE_ENTRIES),
  3926. (TB, "Invalid ColorTableIndex(%u)", ColorTableIndex));
  3927. // Set up only the ROP common MemBlt field here; the rest need
  3928. // to wait until we have tile information (if retrived).
  3929. oeTempMemBlt.Common.bRop = Rop3;
  3930. if (OrderType == TS_ENC_MEMBLT_R2_ORDER) {
  3931. TRC_NRM((TB, "MemBlt dx %d dy %d w %d h %d sx %d sy %d "
  3932. "rop %04X", pBounds->left, pBounds->top,
  3933. pBounds->right - pBounds->left,
  3934. pBounds->bottom - pBounds->top,
  3935. pptlSrc->x, pptlSrc->y, Rop3));
  3936. }
  3937. else {
  3938. POE_BRUSH_DATA pCurrentBrush;
  3939. // For Mem3Blt, create the extra brush-related fields
  3940. // in oeTempMemBlt so it will be set up properly
  3941. // when we encode the order later.
  3942. // Check that the brush pattern is simple.
  3943. if (OECheckBrushIsSimple(ppdev, pbo, &pCurrentBrush)) {
  3944. // The protocol brush origin is the point on the screen
  3945. // where we want the brush to start being drawn from
  3946. // (tiling where necessary).
  3947. oeTempMemBlt.BrushOrgX = pptlBrush->x;
  3948. oeTempMemBlt.BrushOrgY = pptlBrush->y;
  3949. OEClipPoint((PPOINTL)&oeTempMemBlt.BrushOrgX);
  3950. // Pattern data.
  3951. oeTempMemBlt.BackColor = pCurrentBrush->back;
  3952. oeTempMemBlt.ForeColor = pCurrentBrush->fore;
  3953. // Realized brush data.
  3954. oeTempMemBlt.BrushStyle = pCurrentBrush->style;
  3955. oeTempMemBlt.BrushHatch = pCurrentBrush->hatch;
  3956. memcpy(oeTempMemBlt.BrushExtra, pCurrentBrush->brushData,
  3957. sizeof(oeTempMemBlt.BrushExtra));
  3958. TRC_NRM((TB, "Mem3Blt brush %02X %02X dx %d dy %d "
  3959. "w %d h %d sx %d sy %d rop %04X",
  3960. oeTempMemBlt.BrushStyle,
  3961. oeTempMemBlt.BrushHatch,
  3962. oeTempMemBlt.Common.nLeftRect,
  3963. oeTempMemBlt.Common.nTopRect,
  3964. oeTempMemBlt.Common.nWidth,
  3965. oeTempMemBlt.Common.nHeight,
  3966. oeTempMemBlt.Common.nXSrc,
  3967. oeTempMemBlt.Common.nYSrc,
  3968. oeTempMemBlt.Common.bRop));
  3969. }
  3970. else {
  3971. TRC_NRM((TB, "Mem3Blt brush is not simple"));
  3972. INC_OUTCOUNTER(OUT_BITBLT_SDA_M3BCOMPLEXBRUSH);
  3973. rc = FALSE;
  3974. DC_QUIT;
  3975. }
  3976. }
  3977. // Send the order to be cached.
  3978. if (SrcSurfaceId == CH_KEY_UNCACHABLE) {
  3979. rc = OETileBitBltOrder(ppdev, pptlSrc, pBounds, OrderType,
  3980. ColorTableIndex, pMemBltExtraInfo, pClipRects);
  3981. }
  3982. else {
  3983. // Set up the order fields not set up above. We rely on the
  3984. // Common field in MEMBLT_ORDER and MEM3BLT_ORDER orders
  3985. // being in the same position.
  3986. oeTempMemBlt.Common.nLeftRect = pBounds->left;
  3987. oeTempMemBlt.Common.nTopRect = pBounds->top;
  3988. oeTempMemBlt.Common.nWidth = pBounds->right - pBounds->left;
  3989. oeTempMemBlt.Common.nHeight = pBounds->bottom - pBounds->top;
  3990. // Store the source bitmap origin.
  3991. oeTempMemBlt.Common.nXSrc = pptlSrc->x;
  3992. oeTempMemBlt.Common.nYSrc = pptlSrc->y;
  3993. // Store the color table cache index and cache ID.
  3994. // The source bitmap is at client offscreen bitmap, we
  3995. // use 0xff as bitmap ID to indicate that. The cache index
  3996. // is used to indicate the client offscreen bitmap Id.
  3997. oeTempMemBlt.Common.cacheId = (UINT16)((ColorTableIndex << 8) |
  3998. TS_BITMAPCACHE_SCREEN_ID);
  3999. oeTempMemBlt.Common.cacheIndex = (UINT16)SrcSurfaceId;
  4000. if (OrderType == TS_ENC_MEMBLT_R2_ORDER)
  4001. rc = OEDirectEncodeMemBlt(ppdev, pClipRects);
  4002. else
  4003. rc = OEAllocAndSendMem3BltOrder(ppdev, pClipRects);
  4004. }
  4005. }
  4006. else {
  4007. TRC_ALT((TB, "Unable to send color table for MemBlt"));
  4008. INC_OUTCOUNTER(OUT_BITBLT_SDA_NOCOLORTABLE);
  4009. rc = FALSE;
  4010. }
  4011. }
  4012. else {
  4013. TRC_NRM((TB, "MemBlt is not cachable"));
  4014. INC_OUTCOUNTER(OUT_BITBLT_SDA_MBUNCACHEABLE);
  4015. }
  4016. DC_EXIT_POINT:
  4017. DC_END_FN();
  4018. return rc;
  4019. }
  4020. /****************************************************************************/
  4021. // OEIntersectScrBltWithSDA
  4022. //
  4023. // Intersects a ScrBlt order (given the source point and exclusive dest rect)
  4024. // with the current SDA. Returns FALSE if the entire ScrBlt order should be
  4025. // spoiled because its source rect is entirely within the current SDA.
  4026. //
  4027. // Algorithm notes:
  4028. //
  4029. // OLD (ORIGINAL) SCRBLT SCHEME
  4030. // ----------------------------
  4031. // If the source rectangle intersects the current SDA then the src rectangle
  4032. // is modified so that no there is no intersection with the SDA, and the dst
  4033. // rectangle adjusted accordingly (this is the theory - in practice the
  4034. // operation remains the same and we just adjust the dst clip rectangle).
  4035. // The destination area that is removed is added into the SDA. The code
  4036. // works, but can result in more screen data being sent than is required.
  4037. // E.g. for the following operation:
  4038. //
  4039. // SSSSSS DDDDDD | S = src rect
  4040. // SSSSSS -> DDDDDD | D = dst rect
  4041. // SSSSSS DDDDDD | x = SDA overlap
  4042. // SxSSSS DDDDDD |
  4043. //
  4044. // The bottom edge of the blt is trimmed off, and the corresponding
  4045. // destination area added into the SDA.
  4046. //
  4047. // SSSSSS DDDDDD
  4048. // SSSSSS -> DDDDDD
  4049. // SSSSSS DDDDDD
  4050. // xxxxxx
  4051. //
  4052. // NEW SCRBLT SCHEME
  4053. // -----------------
  4054. // The new scheme does not modify the blt rectangles, and just maps the SDA
  4055. // overlap to the destination rect and adds that area back into the SDA.
  4056. // E.g. (as above):
  4057. //
  4058. // SSSSSS DDDDDD
  4059. // SSSSSS -> DDDDDD
  4060. // SSSSSS DDDDDD
  4061. // SxSSSS DDDDDD
  4062. //
  4063. // The blt operation remains the same, but the overlap area is mapped to the
  4064. // destination rectangle and added into the SDA.
  4065. //
  4066. // SSSSSS DDDDDD
  4067. // SSSSSS -> DDDDDD
  4068. // SSSSSS DDDDDD
  4069. // SxSSSS DxDDDD
  4070. //
  4071. // This scheme results in a smaller SDA area. However, this scheme does blt
  4072. // potentially invalid data to the destination - which may briefly be visible
  4073. // at the remote machine (because orders are replayed before Screen Data).
  4074. // This has not (yet) proved to be a problem. The main benefit of the new
  4075. // scheme vs. the old is when scrolling an area that includes a small SDA:
  4076. //
  4077. // new old
  4078. // AAAAAAAA AAAAAAAA AAAAAAAA
  4079. // AAAAAAAA AAAxAAAA xxxxxxxx
  4080. // AAAAAAAA scroll up 3 times -> AAAxAAAA xxxxxxxx
  4081. // AAAAAAAA AAAxAAAA xxxxxxxx
  4082. // AAAxAAAA AAAxAAAA xxxxxxxx
  4083. /****************************************************************************/
  4084. BOOL OEIntersectScrBltWithSDA(
  4085. PPOINTL pSrcPt,
  4086. RECTL *pDestRect,
  4087. OE_ENUMRECTS *pClipRects)
  4088. {
  4089. BOOL rc = TRUE;
  4090. unsigned NumSDA;
  4091. unsigned totalBounds;
  4092. unsigned i, j;
  4093. unsigned NumClipRects;
  4094. int dx;
  4095. int dy;
  4096. RECTL SrcRect;
  4097. RECTL TempRect;
  4098. RECTL InvalidDestRect;
  4099. RECTL SDARects[BA_MAX_ACCUMULATED_RECTS];
  4100. DC_BEGIN_FN("OEIntersectScrBltWithSDA");
  4101. // Calculate the full source rect (exclusive coords).
  4102. SrcRect.left = pSrcPt->x;
  4103. SrcRect.top = pSrcPt->y;
  4104. SrcRect.right = SrcRect.left + pDestRect->right - pDestRect->left;
  4105. SrcRect.bottom = SrcRect.top + pDestRect->bottom - pDestRect->top;
  4106. // Calculate the offset from the src to the dest.
  4107. dx = pDestRect->left - SrcRect.left;
  4108. dy = pDestRect->top - SrcRect.top;
  4109. NumClipRects = pClipRects->rects.c;
  4110. // Get the current SDA rects.
  4111. BA_QueryBounds(SDARects, &NumSDA);
  4112. for (i = 0; i < NumSDA; i++) {
  4113. if (SrcRect.left < SDARects[i].left ||
  4114. SrcRect.right > SDARects[i].right ||
  4115. SrcRect.top < SDARects[i].top ||
  4116. SrcRect.bottom > SDARects[i].bottom) {
  4117. // Intersect the src rect with the SDA rect and offset to
  4118. // get the invalid dest rect.
  4119. InvalidDestRect.left = max(SrcRect.left, SDARects[i].left) + dx;
  4120. InvalidDestRect.right = min(SrcRect.right, SDARects[i].right) + dx;
  4121. InvalidDestRect.top = max(SrcRect.top, SDARects[i].top) + dy;
  4122. InvalidDestRect.bottom = min(SrcRect.bottom,
  4123. SDARects[i].bottom) + dy;
  4124. // Walk through each of the dest clip rects (or the entire
  4125. // dest rect if there are no clip rects), intersecting with the
  4126. // invalid dest rect, and adding the intersections into the SDA.
  4127. if (NumClipRects == 0) {
  4128. // DestRect is already in inclusive coords.
  4129. TempRect.left = max(InvalidDestRect.left,
  4130. pDestRect->left);
  4131. TempRect.top = max(InvalidDestRect.top,
  4132. pDestRect->top);
  4133. TempRect.right = min(InvalidDestRect.right,
  4134. pDestRect->right);
  4135. TempRect.bottom = min(InvalidDestRect.bottom,
  4136. pDestRect->bottom);
  4137. // If there is a 3-way intersection, add the rect to the SDA.
  4138. if (TempRect.left < TempRect.right &&
  4139. TempRect.top < TempRect.bottom)
  4140. BA_AddScreenData(&TempRect);
  4141. }
  4142. else {
  4143. // Clip rects are in exclusive coords, we have to take
  4144. // this into account when getting the intersection.
  4145. for (j = 0; j < NumClipRects; j++) {
  4146. TempRect.left = max(InvalidDestRect.left,
  4147. pClipRects->rects.arcl[j].left);
  4148. TempRect.top = max(InvalidDestRect.top,
  4149. pClipRects->rects.arcl[j].top);
  4150. TempRect.right = min(InvalidDestRect.right,
  4151. pClipRects->rects.arcl[j].right);
  4152. TempRect.bottom = min(InvalidDestRect.bottom,
  4153. pClipRects->rects.arcl[j].bottom);
  4154. // If there is a 3-way intersection, add the rect to the
  4155. // SDA.
  4156. if (TempRect.left < TempRect.right &&
  4157. TempRect.top < TempRect.bottom)
  4158. BA_AddScreenData(&TempRect);
  4159. }
  4160. }
  4161. }
  4162. else {
  4163. // The src of the ScrBlt is completely within the SDA. We
  4164. // must add each of the dest clip rects (or the entire
  4165. // dest rect if there are no clip rects) into the SDA and
  4166. // spoil the ScrBlt.
  4167. TRC_NRM((TB, "ScrBlt src within SDA - spoil it"));
  4168. if (NumClipRects == 0) {
  4169. // We can just add DestRect to SDA.
  4170. InvalidDestRect = *pDestRect;
  4171. BA_AddScreenData(&InvalidDestRect);
  4172. }
  4173. else {
  4174. for (j = 0; j < NumClipRects; j++) {
  4175. InvalidDestRect = pClipRects->rects.arcl[j];
  4176. BA_AddScreenData(&InvalidDestRect);
  4177. }
  4178. }
  4179. rc = FALSE;
  4180. DC_QUIT;
  4181. }
  4182. }
  4183. DC_EXIT_POINT:
  4184. DC_END_FN();
  4185. return rc;
  4186. }
  4187. /****************************************************************************/
  4188. // OEDeviceBitmapCachable
  4189. //
  4190. // Check if we can cache this device bitmap in the client side offscreen
  4191. // bitmap memory
  4192. /****************************************************************************/
  4193. BOOL RDPCALL OEDeviceBitmapCachable(PDD_PDEV ppdev,SIZEL sizl, ULONG iFormat)
  4194. {
  4195. BOOL rc = FALSE;
  4196. unsigned bitmapSize, minBitmapSize;
  4197. DC_BEGIN_FN("OEDeviceBitmapCachable");
  4198. // Return 0 if client doesn't support offscreen rendering
  4199. if (pddShm != NULL && sbcOffscreenBitmapCacheHandle != NULL &&
  4200. pddShm->sbc.offscreenCacheInfo.supportLevel > TS_OFFSCREEN_DEFAULT) {
  4201. // We only support device bitmaps that are the same color depth
  4202. // as our display.
  4203. // Actually, those are the only kind GDI will ever call us with,
  4204. // but we may as well check. Note that this implies you'll never
  4205. // get a crack at 1bpp bitmaps.
  4206. if (iFormat == ppdev->iBitmapFormat) {
  4207. // Get the bitmap size
  4208. // The assumption here is that iFormat is > 1BPP, i << iFormat
  4209. // gives the actual bits per pel. bitmapSize is in bytes.
  4210. if (iFormat < 5) {
  4211. bitmapSize = sizl.cx * sizl.cy * (1 << iFormat) / 8;
  4212. minBitmapSize = MIN_OFFSCREEN_BITMAP_PIXELS * (1 << iFormat) / 8;
  4213. }
  4214. else if (iFormat == 5) {
  4215. bitmapSize = sizl.cx * sizl.cy * 24 / 8;
  4216. minBitmapSize = MIN_OFFSCREEN_BITMAP_PIXELS * 24 / 8;
  4217. }
  4218. else if (iFormat == 6) {
  4219. bitmapSize = sizl.cx * sizl.cy * 32 / 8;
  4220. minBitmapSize = MIN_OFFSCREEN_BITMAP_PIXELS * 32 / 8;
  4221. }
  4222. else {
  4223. minBitmapSize = 0;
  4224. TRC_NRM((TB, "Bitmap format not supported"));
  4225. DC_QUIT;
  4226. }
  4227. // From Winbench99 Business Graphics benchmark, we found
  4228. // creating offscreen bitmaps of 2K or smaller does not
  4229. // improve our bandwidth. This parameter needs to be highly
  4230. // tuned.
  4231. // We also don't want to cache any cursor bitmaps for offscreen
  4232. // the maximum cursor size is 32x32, which is less than the
  4233. // minBitmapSize.
  4234. if (bitmapSize > minBitmapSize) {
  4235. SURFOBJ *psoDevice;
  4236. SIZEL screenSize;
  4237. // Get the bitmap size for the primary device.
  4238. psoDevice = EngLockSurface(ppdev->hsurfDevice);
  4239. TRC_ERR((TB,"Null device surfac"));
  4240. if (NULL == psoDevice) {
  4241. TRC_ERR((TB, "Failed to lock ppdev surface"));
  4242. DC_QUIT;
  4243. }
  4244. screenSize = psoDevice->sizlBitmap;
  4245. EngUnlockSurface(psoDevice);
  4246. // We only support bitmap of size less than the primary device
  4247. if ((sizl.cx <= screenSize.cx) && (sizl.cy <= screenSize.cy)) {
  4248. // If adding this offscreen bitmap exceeds the client total
  4249. // offscreen bitmap memory, we have to let GDI to manage
  4250. // this bitmap
  4251. if (oeCurrentOffscreenCacheSize + bitmapSize <=
  4252. (pddShm->sbc.offscreenCacheInfo.cacheSize * 1024)) {
  4253. rc = TRUE;
  4254. }
  4255. else {
  4256. TRC_NRM((TB, "run out of offscreen memory"));
  4257. DC_QUIT;
  4258. }
  4259. } else {
  4260. TRC_NRM((TB, "offscreen bitmap size too big"));
  4261. DC_QUIT;
  4262. }
  4263. } else {
  4264. TRC_NRM((TB, "Offscreen bitmap size is 2K or less"));
  4265. DC_QUIT;
  4266. }
  4267. }
  4268. else {
  4269. TRC_NRM((TB, "offscreen bitmap iFormat different from ppdev"));
  4270. DC_QUIT;
  4271. }
  4272. }
  4273. else {
  4274. TRC_NRM((TB, "Offscreen bitmap rendering not supported"));
  4275. DC_QUIT;
  4276. }
  4277. DC_EXIT_POINT:
  4278. return rc;
  4279. }
  4280. /****************************************************************************/
  4281. // OETransformClipRectsForScrBlt
  4282. //
  4283. // Transforms the CD_ANY cliprect ordering to a particular order depending
  4284. // on the direction of the scrblt.
  4285. /****************************************************************************/
  4286. void OETransformClipRectsForScrBlt(
  4287. OE_ENUMRECTS *pClipRects,
  4288. PPOINTL pSrcPt,
  4289. RECTL *pDestRect,
  4290. CLIPOBJ *pco)
  4291. {
  4292. unsigned EnumType;
  4293. unsigned RetVal;
  4294. DC_BEGIN_FN("OESendScrBltAsOrder");
  4295. // If there are zero or one clip rectangles then we can send it OK.
  4296. TRC_ASSERT((pClipRects->rects.c > 1),(TB,"Called with too few cliprects"));
  4297. // Check common cases and re-enumerate the rectangles as needed to
  4298. // get an ordering compatible with the direction of scroll.
  4299. if (pDestRect->top <= pSrcPt->y) {
  4300. // Upward/horizontal cases.
  4301. if (pDestRect->left <= pSrcPt->x) {
  4302. // Vertical up (most common case), horizontal to the left,
  4303. // or up and to the left. Enumerate rects left-to-right,
  4304. // top-to-bottom.
  4305. EnumType = CD_RIGHTDOWN;
  4306. }
  4307. else {
  4308. // Up and to the right or horizontal right. Enumerate
  4309. // right-to-left, top-to-bottom.
  4310. EnumType = CD_LEFTDOWN;
  4311. }
  4312. }
  4313. else {
  4314. // Downward cases.
  4315. if (pDestRect->left <= pSrcPt->x) {
  4316. // Vertical down or down and to the left. Enumerate left-to-right,
  4317. // bottom-to-top.
  4318. EnumType = CD_RIGHTUP;
  4319. }
  4320. else {
  4321. // Down and to the right. Enumerate right-to-left, bottom-to-top.
  4322. EnumType = CD_LEFTUP;
  4323. }
  4324. }
  4325. RetVal = OEGetIntersectingClipRects(pco, pDestRect, EnumType, pClipRects);
  4326. TRC_ASSERT((RetVal == CLIPRECTS_OK),
  4327. (TB,"Re-enumeration of clip rects produced err %u", RetVal));
  4328. DC_END_FN();
  4329. }
  4330. /****************************************************************************/
  4331. // OEEncodeScrBlt
  4332. //
  4333. // Performs all encoding steps required to encode a ScrBlt order, then adds
  4334. // to order list. Returns FALSE if the order needs to be added to the screen
  4335. // data area.
  4336. /****************************************************************************/
  4337. BOOL RDPCALL OEEncodeScrBlt(
  4338. RECTL *pBounds,
  4339. BYTE Rop3,
  4340. POINTL *pptlSrc,
  4341. PDD_PDEV ppdev,
  4342. OE_ENUMRECTS *pClipRects,
  4343. CLIPOBJ *pco)
  4344. {
  4345. unsigned i;
  4346. unsigned OrderSize;
  4347. unsigned NumFieldFlagBytes;
  4348. POINTL Origin;
  4349. BYTE OrderType;
  4350. BOOL rc = TRUE;
  4351. RECTL SrcRect;
  4352. PINT_ORDER pOrder;
  4353. SCRBLT_ORDER *pScrBlt;
  4354. DC_BEGIN_FN("OEEncodeScrBlt");
  4355. // Check whether we should use the multi-cliprect version. Must be a
  4356. // complex clip region and the client must support the order.
  4357. if (pClipRects->rects.c < 2 ||
  4358. !OE_SendAsOrder(TS_ENC_MULTISCRBLT_ORDER)) {
  4359. // Non-multi version.
  4360. OrderType = TS_ENC_SCRBLT_ORDER;
  4361. OrderSize = MAX_SCRBLT_FIELD_SIZE;
  4362. NumFieldFlagBytes = 1;
  4363. }
  4364. else {
  4365. // Multi version.
  4366. OrderType = TS_ENC_MULTISCRBLT_ORDER;
  4367. OrderSize = MAX_MULTI_SCRBLT_FIELD_SIZE_NCLIP(pClipRects->rects.c);
  4368. NumFieldFlagBytes = 2;
  4369. }
  4370. // Make sure we don't have orders turned off.
  4371. if (OE_SendAsOrder(OrderType)) {
  4372. // Clip source point.
  4373. Origin = *pptlSrc;
  4374. OEClipPoint(&Origin);
  4375. // Where there are multiple clipping rectangles, it is
  4376. // difficult to calculate the correct order to move the various
  4377. // bits of target surface around - we might move the bottom left
  4378. // to the middle before we moved the middle up to the top right.
  4379. //
  4380. // We make an exception where:
  4381. // - there is only horizontal or vertical movement
  4382. // - there is no overlap between the different clipping
  4383. // rectangles (source or destination)
  4384. // - there are 3 or fewer clipping rectangles.
  4385. //
  4386. // This takes care of several important cases - particularly
  4387. // scrolling in Excel.
  4388. if (pClipRects->rects.c > 1)
  4389. OETransformClipRectsForScrBlt(pClipRects, &Origin, pBounds, pco);
  4390. // For screen targets, we have to take into account the existing
  4391. // screen data areas. The problem here arises from the fact that
  4392. // SDA is bltted to the screen *after* all orders in a packet
  4393. // are drawn. If we do not take this into account, we can end
  4394. // up ScrBltting pieces of the screen around that are wrong
  4395. // because the SDA should have been written first, but won't
  4396. // have been.
  4397. if (oeLastDstSurface == NULL) {
  4398. if (!OEIntersectScrBltWithSDA(&Origin, pBounds, pClipRects)) {
  4399. TRC_NRM((TB,"ScrBlt entirely contained within SDA, "
  4400. "not sending"));
  4401. DC_QUIT;
  4402. }
  4403. }
  4404. // By this point either we've got no clip rects, so we simply send
  4405. // the order straight, or some clip rects that might have been
  4406. // intersected with the SDA if the target is the screen, so we
  4407. // send one or more copies of the order, one for each clip rect.
  4408. // 1 or 2 field flag bytes.
  4409. pOrder = OA_AllocOrderMem(ppdev, MAX_ORDER_SIZE(
  4410. pClipRects->rects.c, NumFieldFlagBytes, OrderSize));
  4411. if (pOrder != NULL) {
  4412. pScrBlt = (SCRBLT_ORDER *)oeTempOrderBuffer;
  4413. pScrBlt->nLeftRect = pBounds->left;
  4414. pScrBlt->nTopRect = pBounds->top;
  4415. pScrBlt->nWidth = pBounds->right - pBounds->left;
  4416. pScrBlt->nHeight = pBounds->bottom - pBounds->top;
  4417. pScrBlt->bRop = Rop3;
  4418. pScrBlt->nXSrc = Origin.x;
  4419. pScrBlt->nYSrc = Origin.y;
  4420. if (OrderType == TS_ENC_SCRBLT_ORDER) {
  4421. // Slow-field-encode the order with the first clip rect
  4422. // (if present).
  4423. pOrder->OrderLength = OE2_EncodeOrder(pOrder->OrderData,
  4424. TS_ENC_SCRBLT_ORDER, NUM_SCRBLT_FIELDS,
  4425. (BYTE *)pScrBlt, (BYTE *)&PrevScrBlt, etable_SB,
  4426. (pClipRects->rects.c == 0 ? NULL :
  4427. &pClipRects->rects.arcl[0]));
  4428. INC_OUTCOUNTER(OUT_SCRBLT_ORDER);
  4429. ADD_INCOUNTER(IN_SCRBLT_BYTES, pOrder->OrderLength);
  4430. OA_AppendToOrderList(pOrder);
  4431. // Flush the order.
  4432. if (pClipRects->rects.c < 2)
  4433. rc = TRUE;
  4434. else
  4435. rc = OEEmitReplayOrders(ppdev, 1, pClipRects);
  4436. }
  4437. else {
  4438. MULTI_SCRBLT_ORDER *pMultiSB = (MULTI_SCRBLT_ORDER *)
  4439. oeTempOrderBuffer;
  4440. // Encode the clip rects directly into the order.
  4441. pMultiSB->nDeltaEntries = OEBuildMultiClipOrder(ppdev,
  4442. &pMultiSB->codedDeltaList, pClipRects);
  4443. // Slow-field-encode the order with no clip rects.
  4444. pOrder->OrderLength = OE2_EncodeOrder(pOrder->OrderData,
  4445. TS_ENC_MULTISCRBLT_ORDER, NUM_MULTI_SCRBLT_FIELDS,
  4446. (BYTE *)pMultiSB, (BYTE *)&PrevMultiScrBlt, etable_MS,
  4447. NULL);
  4448. INC_OUTCOUNTER(OUT_MULTI_SCRBLT_ORDER);
  4449. ADD_INCOUNTER(IN_MULTI_SCRBLT_BYTES, pOrder->OrderLength);
  4450. OA_AppendToOrderList(pOrder);
  4451. }
  4452. TRC_NRM((TB, "%sScrBlt x %d y %d w %d h %d sx %d sy %d rop %02X",
  4453. (OrderType == TS_ENC_SCRBLT_ORDER ? "" : "Multi"),
  4454. pScrBlt->nLeftRect, pScrBlt->nTopRect,
  4455. pScrBlt->nWidth, pScrBlt->nHeight,
  4456. pScrBlt->nXSrc, pScrBlt->nYSrc, pScrBlt->bRop));
  4457. }
  4458. else {
  4459. TRC_ERR((TB, "Failed to alloc order"));
  4460. INC_OUTCOUNTER(OUT_BITBLT_SDA_HEAPALLOCFAILED);
  4461. // On failure with a screen target, add all of the clip
  4462. // destination rects to SDA. Clip rects are in exclusive
  4463. // coords so convert before adding.
  4464. if (oeLastDstSurface == NULL)
  4465. OEClipAndAddScreenDataAreaByIntersectRects(pBounds,
  4466. pClipRects);
  4467. rc = FALSE;
  4468. }
  4469. }
  4470. else {
  4471. TRC_NRM((TB, "(Multi)ScrBlt order not allowed"));
  4472. INC_OUTCOUNTER(OUT_BITBLT_SDA_UNSUPPORTED);
  4473. rc = FALSE;
  4474. }
  4475. DC_EXIT_POINT:
  4476. DC_END_FN();
  4477. return rc;
  4478. }
  4479. /****************************************************************************/
  4480. // OECacheGlyphs
  4481. //
  4482. // Caches glyphs as presented in the given font and string objects. Returns
  4483. // FALSE on failure to cache.
  4484. /****************************************************************************/
  4485. BOOL RDPCALL OECacheGlyphs(
  4486. STROBJ *pstro,
  4487. FONTOBJ *pfo,
  4488. PFONTCACHEINFO pfci,
  4489. PGLYPHCONTEXT pglc)
  4490. {
  4491. unsigned i;
  4492. unsigned j;
  4493. BOOL fMore;
  4494. UINT32 cGlyphs;
  4495. unsigned cbDataSize;
  4496. GLYPHPOS *pGlyphPos;
  4497. UINT32 Key1, Key2;
  4498. void *UserDefined;
  4499. unsigned cx;
  4500. unsigned cy;
  4501. unsigned dx;
  4502. unsigned dy;
  4503. unsigned x;
  4504. unsigned y;
  4505. FONTINFO fi;
  4506. DC_BEGIN_FN("OECacheGlyphs");
  4507. // Determine appropriate glyph cache if we haven't already done so.
  4508. if (pfci->cacheId < 0) {
  4509. FONTOBJ_vGetInfo(pfo, sizeof(fi), &fi);
  4510. cbDataSize = (fi.cjMaxGlyph1 + 3) & ~3;
  4511. if (SBCSelectGlyphCache(cbDataSize, &pfci->cacheId)) {
  4512. pfci->cacheHandle =
  4513. pddShm->sbc.glyphCacheInfo[pfci->cacheId].cacheHandle;
  4514. pddShm->sbc.glyphCacheInfo[pfci->cacheId].cbUseCount++;
  4515. }
  4516. else {
  4517. TRC_NRM((TB, "Failed to determine glyph cache"));
  4518. goto FailCache;
  4519. }
  4520. }
  4521. // Establish our cache context.
  4522. CH_SetCacheContext(pfci->cacheHandle, pglc);
  4523. // Loop through each glyph, caching it appropriately.
  4524. if (pstro->pgp == NULL)
  4525. STROBJ_vEnumStart(pstro);
  4526. dx = 0;
  4527. dy = 0;
  4528. j = 0;
  4529. fMore = TRUE;
  4530. while (fMore) {
  4531. if (pstro->pgp != NULL) {
  4532. fMore = FALSE;
  4533. cGlyphs = pstro->cGlyphs;
  4534. pGlyphPos = pstro->pgp;
  4535. }
  4536. else {
  4537. fMore = STROBJ_bEnum(pstro, &cGlyphs, &pGlyphPos);
  4538. if (cGlyphs == 0) {
  4539. TRC_NRM((TB, "STROBJ_bEnum - 0 glyphs"));
  4540. goto FailCache;
  4541. }
  4542. }
  4543. if (j == 0) {
  4544. x = pGlyphPos->ptl.x;
  4545. y = pGlyphPos->ptl.y;
  4546. }
  4547. for (i = 0; i < cGlyphs; i++) {
  4548. // GDI never sets the SO_VERTICAL bit, and there are cases where
  4549. // it does not properly set the SO_HORIZONTAL bit either. As a
  4550. // result, when GDI is silent we need to look for ourselves if
  4551. // we plan on catching these cases.
  4552. if ((pstro->flAccel & SO_HORIZONTAL) == 0) {
  4553. dx += (x - pGlyphPos->ptl.x);
  4554. dy += (y - pGlyphPos->ptl.y);
  4555. if (dx && dy) {
  4556. TRC_NRM((TB, "Can't process horizertical text"));
  4557. goto FailCache;
  4558. }
  4559. }
  4560. // Search for cache entry.
  4561. Key1 = pGlyphPos->hg; // Key1 has to be the most variable for the hash.
  4562. Key2 = pfci->fontId;
  4563. if (CH_SearchCache(pfci->cacheHandle, Key1, Key2, &UserDefined,
  4564. &pglc->rgCacheIndex[j])) {
  4565. // If the cache entry already existed, then flag our index
  4566. // item as such so we know later on not to send the glyph
  4567. // Set the entry tag for this DrvTextOut.
  4568. CH_SetUserDefined(pfci->cacheHandle, pglc->rgCacheIndex[j],
  4569. (void *)pglc->cacheTag);
  4570. pddCacheStats[GLYPH].CacheHits++;
  4571. pglc->rgCacheIndex[j] = ~pglc->rgCacheIndex[j];
  4572. pglc->nCacheHit++;
  4573. }
  4574. else {
  4575. // Cache the key.
  4576. pglc->rgCacheIndex[j] = CH_CacheKey(pfci->cacheHandle, Key1,
  4577. Key2, (void *)pglc->cacheTag);
  4578. if (pglc->rgCacheIndex[j] != CH_KEY_UNCACHABLE) {
  4579. // Keep a running total of the glyph data size for
  4580. // later use.
  4581. cx = pGlyphPos->pgdf->pgb->sizlBitmap.cx;
  4582. cy = pGlyphPos->pgdf->pgb->sizlBitmap.cy;
  4583. cbDataSize = ((cx + 7) / 8) * cy;
  4584. cbDataSize = (cbDataSize + 3) & ~3;
  4585. pglc->cbTotalDataSize += cbDataSize;
  4586. pglc->cbTotalDataSize += sizeof(TS_CACHE_GLYPH_DATA) -
  4587. FIELDSIZE(TS_CACHE_GLYPH_DATA, aj);
  4588. }
  4589. else {
  4590. TRC_NRM((TB, "Glyph could not be added to cache"));
  4591. goto FailCache;
  4592. }
  4593. }
  4594. pglc->nCacheIndex = ++j;
  4595. pGlyphPos++;
  4596. }
  4597. }
  4598. // Establish text orientation when GDI is silent (see above comment).
  4599. if ((pstro->flAccel & SO_HORIZONTAL) == 0) {
  4600. if (dx != 0)
  4601. pstro->flAccel |= SO_HORIZONTAL;
  4602. else if (dy != 0)
  4603. pstro->flAccel |= SO_VERTICAL;
  4604. }
  4605. // De-establish our context to be used for the cache callback.
  4606. if (pfci->cacheId >= 0)
  4607. CH_SetCacheContext(pfci->cacheHandle, NULL);
  4608. DC_END_FN();
  4609. return TRUE;
  4610. FailCache:
  4611. // De-establish our context to be used for the cache callback.
  4612. if (pfci->cacheId >= 0)
  4613. CH_SetCacheContext(pfci->cacheHandle, NULL);
  4614. // Remove any entries we did cache.
  4615. for (i = 0; i < pglc->nCacheIndex; i++)
  4616. if (pglc->rgCacheIndex[i] < SBC_NUM_GLYPH_CACHE_ENTRIES)
  4617. CH_RemoveCacheEntry(pfci->cacheHandle, pglc->rgCacheIndex[i]);
  4618. DC_END_FN();
  4619. return FALSE;
  4620. }
  4621. /****************************************************************************/
  4622. // OEFlushCacheGlyphOrder
  4623. //
  4624. // Flushes a buffered Cache Glyph order.
  4625. /****************************************************************************/
  4626. void OEFlushCacheGlyphOrder(
  4627. STROBJ *pstro,
  4628. PINT_ORDER pOrder,
  4629. PGLYPHCONTEXT pglc)
  4630. {
  4631. unsigned cbOrderSize;
  4632. PTS_CACHE_GLYPH_ORDER pGlyphOrder;
  4633. unsigned i, cGlyphs;
  4634. UINT16 UNALIGNED *pUnicode;
  4635. UINT16 UNALIGNED *pUnicodeEnd;
  4636. DC_BEGIN_FN("OEFlushCacheGlyphOrder");
  4637. if (pOrder != NULL) {
  4638. TRC_ASSERT((pglc->cbDataSize > 0),
  4639. (TB, "Bad pglc->cbDataSize"));
  4640. pGlyphOrder = (PTS_CACHE_GLYPH_ORDER)pOrder->OrderData;
  4641. if (pddShm->sbc.caps.GlyphSupportLevel >= CAPS_GLYPH_SUPPORT_ENCODE) {
  4642. cGlyphs = (pGlyphOrder->header.extraFlags &
  4643. TS_CacheGlyphRev2_cGlyphs_Mask) >> 8;
  4644. cbOrderSize = sizeof(TS_CACHE_GLYPH_ORDER_REV2) -
  4645. FIELDSIZE(TS_CACHE_GLYPH_ORDER_REV2, glyphData) +
  4646. pglc->cbDataSize;
  4647. }
  4648. else {
  4649. cGlyphs = pGlyphOrder->cGlyphs;
  4650. cbOrderSize = sizeof(TS_CACHE_GLYPH_ORDER) -
  4651. FIELDSIZE(TS_CACHE_GLYPH_ORDER, glyphData) +
  4652. pglc->cbDataSize;
  4653. }
  4654. pUnicode = (UINT16 UNALIGNED *)&pOrder->OrderData[cbOrderSize];
  4655. pUnicodeEnd = pUnicode + cGlyphs;
  4656. for (i = pglc->indexNextSend; pUnicode < pUnicodeEnd; i++)
  4657. if (pglc->rgCacheIndex[i] < SBC_NUM_GLYPH_CACHE_ENTRIES)
  4658. *pUnicode++ = pstro->pwszOrg[i];
  4659. cbOrderSize += cGlyphs * sizeof(UINT16);
  4660. pGlyphOrder->header.orderLength = (USHORT)
  4661. TS_CALCULATE_SECONDARY_ORDER_ORDERLENGTH(cbOrderSize);
  4662. OA_TruncateAllocatedOrder(pOrder, cbOrderSize);
  4663. INC_OUTCOUNTER(OUT_CACHEGLYPH);
  4664. ADD_OUTCOUNTER(OUT_CACHEGLYPH_BYTES, cbOrderSize);
  4665. OA_AppendToOrderList(pOrder);
  4666. pglc->cbDataSize = 0;
  4667. pglc->cbBufferSize = 0;
  4668. }
  4669. DC_END_FN();
  4670. }
  4671. __inline void Encode2ByteFields(
  4672. BYTE **pEncode,
  4673. unsigned Val,
  4674. unsigned *pOrderSize)
  4675. {
  4676. if (Val <= 127) {
  4677. **pEncode = (BYTE) Val;
  4678. (*pOrderSize)++;
  4679. (*pEncode)++;
  4680. }
  4681. else {
  4682. **pEncode = (BYTE)(((Val & 0x7F00) >> 8) | 0x80);
  4683. *(*pEncode + 1) = (BYTE)(Val & 0x00FF);
  4684. (*pOrderSize) += 2;
  4685. (*pEncode) += 2;
  4686. }
  4687. }
  4688. __inline void Encode2ByteSignedFields(
  4689. BYTE **pEncode,
  4690. int Val,
  4691. unsigned *pOrderSize)
  4692. {
  4693. if (Val < 0) {
  4694. **pEncode = 0x40;
  4695. Val = - Val;
  4696. }
  4697. else {
  4698. **pEncode = 0;
  4699. }
  4700. if (Val <= 63) {
  4701. **pEncode |= (BYTE)Val;
  4702. (*pOrderSize)++;
  4703. (*pEncode)++;
  4704. }
  4705. else {
  4706. **pEncode |= ((BYTE)(((Val & 0x3F00) >> 8) | 0x80));
  4707. *((*pEncode) + 1) = (BYTE)(Val & 0x00FF);
  4708. (*pOrderSize) += 2;
  4709. (*pEncode) += 2;
  4710. }
  4711. }
  4712. /****************************************************************************/
  4713. // OESendCacheGlyphRev2
  4714. //
  4715. // Allocates and sends a Cache Glyph Rev2 secondary order. REturns FALSE on
  4716. // failure.
  4717. /****************************************************************************/
  4718. BOOL OESendCacheGlyphRev2(
  4719. PDD_PDEV ppdev,
  4720. STROBJ *pstro,
  4721. FONTOBJ *pfo,
  4722. PFONTCACHEINFO pfci,
  4723. PGLYPHCONTEXT pglc,
  4724. unsigned index,
  4725. GLYPHPOS *pGlyphPos,
  4726. PINT_ORDER *ppOrder)
  4727. {
  4728. BOOL rc = TRUE;
  4729. unsigned cbDataSize, cbGlyphSize;
  4730. unsigned cx;
  4731. unsigned cy;
  4732. PTS_CACHE_GLYPH_ORDER_REV2 pGlyphOrder;
  4733. PBYTE pGlyphData;
  4734. PINT_ORDER pOrder = *ppOrder;
  4735. DC_BEGIN_FN("OESendCacheGlyphRev2");
  4736. // Calculate and allocate glyph order buffer.
  4737. cx = pGlyphPos->pgdf->pgb->sizlBitmap.cx;
  4738. cy = pGlyphPos->pgdf->pgb->sizlBitmap.cy;
  4739. cbGlyphSize = ((cx + 7) / 8) * cy;
  4740. cbGlyphSize = (cbGlyphSize + 3) & ~3;
  4741. cbDataSize = cbGlyphSize;
  4742. if (pglc->cbBufferSize < (TS_GLYPH_DATA_REV2_HDR_MAX_SIZE + cbDataSize +
  4743. sizeof(UINT16))) {
  4744. if (pOrder != NULL) {
  4745. pglc->cbTotalDataSize += pglc->cbBufferSize;
  4746. OEFlushCacheGlyphOrder(pstro, pOrder, pglc);
  4747. pglc->indexNextSend = index;
  4748. }
  4749. pglc->cbBufferSize = min(pglc->cbTotalDataSize, 4096);
  4750. pglc->cbTotalDataSize -= pglc->cbBufferSize;
  4751. pOrder = OA_AllocOrderMem(ppdev, sizeof(TS_CACHE_GLYPH_ORDER_REV2) -
  4752. FIELDSIZE(TS_CACHE_GLYPH_ORDER_REV2, glyphData) +
  4753. pglc->cbBufferSize);
  4754. if (pOrder != NULL) {
  4755. pGlyphOrder = (PTS_CACHE_GLYPH_ORDER_REV2)pOrder->OrderData;
  4756. pGlyphOrder->header.extraFlags = TS_EXTRA_GLYPH_UNICODE |
  4757. TS_CacheGlyphRev2_Mask;
  4758. pGlyphOrder->header.orderType = TS_CACHE_GLYPH;
  4759. pGlyphOrder->header.orderHdr.controlFlags = TS_STANDARD |
  4760. TS_SECONDARY;
  4761. pGlyphOrder->header.extraFlags |= (((char)pfci->cacheId) &
  4762. TS_CacheGlyphRev2_CacheID_Mask);
  4763. }
  4764. else {
  4765. TRC_ERR((TB, "Failed to allocate glyph order"));
  4766. rc = FALSE;
  4767. DC_QUIT;
  4768. }
  4769. }
  4770. pGlyphOrder = (PTS_CACHE_GLYPH_ORDER_REV2)pOrder->OrderData;
  4771. pGlyphData = (PBYTE)(pGlyphOrder->glyphData) + pglc->cbDataSize;
  4772. *pGlyphData++ = (BYTE)pglc->rgCacheIndex[index];
  4773. cbDataSize++;
  4774. Encode2ByteSignedFields(&pGlyphData, (INT16)pGlyphPos->pgdf->pgb->ptlOrigin.x,
  4775. &cbDataSize);
  4776. Encode2ByteSignedFields(&pGlyphData, (INT16)pGlyphPos->pgdf->pgb->ptlOrigin.y,
  4777. &cbDataSize);
  4778. Encode2ByteFields(&pGlyphData, (UINT16)cx, &cbDataSize);
  4779. Encode2ByteFields(&pGlyphData, (UINT16)cy, &cbDataSize);
  4780. RtlCopyMemory(pGlyphData, pGlyphPos->pgdf->pgb->aj, cbGlyphSize);
  4781. // number of glyphs. cGlyphs is the upper byte in extraflag
  4782. pGlyphOrder->header.extraFlags += 0x100;
  4783. TRC_ASSERT((pglc->cbBufferSize >= cbDataSize),
  4784. (TB, "Bad pglc->cbBufferSize"));
  4785. pglc->cbDataSize += cbDataSize;
  4786. pglc->cbBufferSize -= (cbDataSize + sizeof(UINT16));
  4787. DC_EXIT_POINT:
  4788. *ppOrder = pOrder;
  4789. DC_END_FN();
  4790. return rc;
  4791. }
  4792. /****************************************************************************/
  4793. // OESendCacheGlyph
  4794. //
  4795. // Allocates and sends glyph orders. Returns FALSE on failure.
  4796. /****************************************************************************/
  4797. BOOL OESendCacheGlyph(
  4798. PDD_PDEV ppdev,
  4799. STROBJ *pstro,
  4800. FONTOBJ *pfo,
  4801. PFONTCACHEINFO pfci,
  4802. PGLYPHCONTEXT pglc,
  4803. unsigned index,
  4804. GLYPHPOS *pGlyphPos,
  4805. PINT_ORDER *ppOrder)
  4806. {
  4807. BOOL rc = TRUE;
  4808. unsigned cbDataSize;
  4809. unsigned cbOrderSize;
  4810. unsigned cx;
  4811. unsigned cy;
  4812. PTS_CACHE_GLYPH_DATA pGlyphData;
  4813. PTS_CACHE_GLYPH_ORDER pGlyphOrder;
  4814. PINT_ORDER pOrder = *ppOrder;
  4815. DC_BEGIN_FN("OESendCacheGlyph");
  4816. // Calculate and allocate glyph order buffer.
  4817. cx = pGlyphPos->pgdf->pgb->sizlBitmap.cx;
  4818. cy = pGlyphPos->pgdf->pgb->sizlBitmap.cy;
  4819. cbDataSize = ((cx + 7) / 8) * cy;
  4820. cbDataSize = (cbDataSize + 3) & ~3;
  4821. cbOrderSize = (sizeof(TS_CACHE_GLYPH_DATA) -
  4822. FIELDSIZE(TS_CACHE_GLYPH_DATA, aj) + cbDataSize);
  4823. if (pglc->cbBufferSize < cbOrderSize + sizeof(UINT16)) {
  4824. if (*ppOrder != NULL) {
  4825. pglc->cbTotalDataSize += pglc->cbBufferSize;
  4826. OEFlushCacheGlyphOrder(pstro, pOrder, pglc);
  4827. pglc->indexNextSend = index;
  4828. }
  4829. pglc->cbBufferSize = min(pglc->cbTotalDataSize, 4096);
  4830. pglc->cbTotalDataSize -= pglc->cbBufferSize;
  4831. pOrder = OA_AllocOrderMem(ppdev, sizeof(TS_CACHE_GLYPH_ORDER) -
  4832. FIELDSIZE(TS_CACHE_GLYPH_ORDER, glyphData) +
  4833. pglc->cbBufferSize);
  4834. if (pOrder != NULL) {
  4835. pGlyphOrder = (PTS_CACHE_GLYPH_ORDER)pOrder->OrderData;
  4836. pGlyphOrder->header.extraFlags = TS_EXTRA_GLYPH_UNICODE;
  4837. pGlyphOrder->header.orderType = TS_CACHE_GLYPH;
  4838. pGlyphOrder->header.orderHdr.controlFlags = TS_STANDARD |
  4839. TS_SECONDARY;
  4840. pGlyphOrder->cacheId = (char)pfci->cacheId;
  4841. pGlyphOrder->cGlyphs = 0;
  4842. }
  4843. else {
  4844. TRC_ERR((TB, "Failed to allocate glyph order"));
  4845. rc = FALSE;
  4846. DC_QUIT;
  4847. }
  4848. }
  4849. pGlyphOrder = (PTS_CACHE_GLYPH_ORDER)pOrder->OrderData;
  4850. pGlyphData = (PTS_CACHE_GLYPH_DATA)
  4851. ((PBYTE)(pGlyphOrder->glyphData) + pglc->cbDataSize);
  4852. pGlyphData->cacheIndex = (UINT16)pglc->rgCacheIndex[index];
  4853. pGlyphData->x = (INT16)pGlyphPos->pgdf->pgb->ptlOrigin.x;
  4854. pGlyphData->y = (INT16)pGlyphPos->pgdf->pgb->ptlOrigin.y;
  4855. pGlyphData->cx = (INT16)cx;
  4856. pGlyphData->cy = (INT16)cy;
  4857. RtlCopyMemory(pGlyphData->aj, pGlyphPos->pgdf->pgb->aj, cbDataSize);
  4858. pGlyphOrder->cGlyphs++;
  4859. TRC_ASSERT((pglc->cbBufferSize >= cbOrderSize),
  4860. (TB, "Bad pglc->cbBufferSize"));
  4861. pglc->cbDataSize += cbOrderSize;
  4862. pglc->cbBufferSize -= (cbOrderSize + sizeof(UINT16));
  4863. DC_EXIT_POINT:
  4864. *ppOrder = pOrder;
  4865. DC_END_FN();
  4866. return rc;
  4867. }
  4868. /****************************************************************************/
  4869. // OESendGlyphs
  4870. //
  4871. // Sends glyphs. Returns FALSE on failure.
  4872. /****************************************************************************/
  4873. BOOL RDPCALL OESendGlyphs(
  4874. SURFOBJ *pso,
  4875. STROBJ *pstro,
  4876. FONTOBJ *pfo,
  4877. PFONTCACHEINFO pfci,
  4878. PGLYPHCONTEXT pglc)
  4879. {
  4880. BOOL rc = TRUE;
  4881. unsigned i;
  4882. unsigned j;
  4883. BOOL fMore;
  4884. UINT32 cGlyphs;
  4885. UINT32 dwSize;
  4886. GLYPHPOS *pGlyphPos;
  4887. PDD_PDEV ppdev;
  4888. PINT_ORDER pOrder;
  4889. DC_BEGIN_FN("OESendGlyphs");
  4890. j = 0;
  4891. pOrder = NULL;
  4892. // If we don't have to send ANY glyphs, then just exit.
  4893. if (pglc->nCacheHit < pstro->cGlyphs) {
  4894. ppdev = (PDD_PDEV)pso->dhpdev;
  4895. pglc->cbTotalDataSize += ((pstro->cGlyphs - pglc->nCacheHit) *
  4896. (sizeof(UINT16)));
  4897. // Loop through all glyphs, sending those that have not yet been sent.
  4898. if (pstro->pgp == NULL)
  4899. STROBJ_vEnumStart(pstro);
  4900. fMore = TRUE;
  4901. while (rc && fMore) {
  4902. if (pstro->pgp != NULL) {
  4903. fMore = FALSE;
  4904. cGlyphs = pstro->cGlyphs;
  4905. pGlyphPos = pstro->pgp;
  4906. }
  4907. else {
  4908. fMore = STROBJ_bEnum(pstro, &cGlyphs, &pGlyphPos);
  4909. if (cGlyphs == 0) {
  4910. TRC_NRM((TB, "STROBJ_bEnum - 0 glyphs"));
  4911. goto SucceedEncode;
  4912. }
  4913. }
  4914. // Send all current retrieved glyphs.
  4915. for (i = 0; i < cGlyphs; i++) {
  4916. if (pglc->rgCacheIndex[j] < SBC_NUM_GLYPH_CACHE_ENTRIES) {
  4917. if (pddShm->sbc.caps.GlyphSupportLevel >=
  4918. CAPS_GLYPH_SUPPORT_ENCODE) {
  4919. rc = OESendCacheGlyphRev2(ppdev, pstro, pfo, pfci,
  4920. pglc, j, pGlyphPos, &pOrder);
  4921. }
  4922. else {
  4923. rc = OESendCacheGlyph(ppdev, pstro, pfo, pfci, pglc,
  4924. j, pGlyphPos, &pOrder);
  4925. }
  4926. if (!rc)
  4927. goto FailEncode;
  4928. }
  4929. j++;
  4930. pGlyphPos++;
  4931. }
  4932. }
  4933. }
  4934. SucceedEncode:
  4935. // All is well, make sure we flush out any buffered glyphs.
  4936. if (pOrder != NULL)
  4937. OEFlushCacheGlyphOrder(pstro, pOrder, pglc);
  4938. DC_END_FN();
  4939. return TRUE;
  4940. FailEncode:
  4941. // If we could not send all the required glyphs, then remove them from
  4942. // the cache (as future hits on this entry will be invalid).
  4943. if (pOrder != NULL)
  4944. OA_FreeOrderMem(pOrder);
  4945. for (i = 0; i < pglc->nCacheIndex; i++) {
  4946. if (pglc->rgCacheIndex[i] < SBC_NUM_GLYPH_CACHE_ENTRIES)
  4947. CH_RemoveCacheEntry(pfci->cacheHandle, pglc->rgCacheIndex[i]);
  4948. }
  4949. DC_END_FN();
  4950. return FALSE;
  4951. }
  4952. /****************************************************************************/
  4953. // OESendGlyphAndIndexOrder
  4954. //
  4955. // Sends FastGlyph order. Returns FALSE on failure.
  4956. /****************************************************************************/
  4957. BOOL OESendGlyphAndIndexOrder(
  4958. PDD_PDEV ppdev,
  4959. STROBJ *pstro,
  4960. OE_ENUMRECTS *pClipRects,
  4961. PRECTL prclOpaque,
  4962. POE_BRUSH_DATA pCurrentBrush,
  4963. PFONTCACHEINFO pfci,
  4964. PGLYPHCONTEXT pglc)
  4965. {
  4966. BOOL rc = TRUE;
  4967. GLYPHPOS *pGlyphPos;
  4968. PINT_ORDER pOrder;
  4969. unsigned tempVar, OpEncodeFlags;
  4970. unsigned cx, cy, cbDataSize, cbGlyphSize;
  4971. PBYTE pGlyphData;
  4972. LPFAST_GLYPH_ORDER pFastGlyphOrder;
  4973. RECTL BoundRect;
  4974. OE_ENUMRECTS IntersectRects;
  4975. DC_BEGIN_FN("OESendGlyphIndexOrder");
  4976. pOrder = NULL;
  4977. // First determine if this order is clipped out by the clip rects.
  4978. // If so, no need to allocate and send it.
  4979. if (prclOpaque != NULL) {
  4980. // Bounded by the opaque rect. Clip it to our max first.
  4981. if (prclOpaque->right > OE_MAX_COORD)
  4982. prclOpaque->right = OE_MAX_COORD;
  4983. if (prclOpaque->bottom > OE_MAX_COORD)
  4984. prclOpaque->bottom = OE_MAX_COORD;
  4985. // If the rect is inverted or null, we use the target string rect
  4986. // instead.
  4987. if (prclOpaque->top < prclOpaque->bottom)
  4988. BoundRect = *prclOpaque;
  4989. else
  4990. BoundRect = pstro->rclBkGround;
  4991. }
  4992. else {
  4993. // Bounded by the string target rect.
  4994. BoundRect = pstro->rclBkGround;
  4995. }
  4996. IntersectRects.rects.c = 0;
  4997. if (pClipRects->rects.c == 0 ||
  4998. OEGetIntersectionsWithClipRects(&BoundRect, pClipRects,
  4999. &IntersectRects)) {
  5000. if (pstro->pgp != NULL) {
  5001. pGlyphPos = pstro->pgp;
  5002. }
  5003. else {
  5004. STROBJ_vEnumStart(pstro);
  5005. STROBJ_bEnum(pstro, &tempVar, &pGlyphPos);
  5006. if (tempVar == 0) {
  5007. TRC_NRM((TB, "STROBJ_bEnum - 0 glyphs"));
  5008. rc = FALSE;
  5009. DC_QUIT;
  5010. }
  5011. }
  5012. }
  5013. else {
  5014. TRC_NRM((TB,"Order bounds do not intersect with clip, not sending"));
  5015. rc = FALSE;
  5016. DC_QUIT;
  5017. }
  5018. pFastGlyphOrder = (LPFAST_GLYPH_ORDER)oeTempOrderBuffer;
  5019. if (pglc->nCacheHit == 0) {
  5020. // We don't have a cache hit, so need to send the glyph.
  5021. // First create the variable-size data in the temp order buf
  5022. // to determine its size.
  5023. pGlyphData = (PBYTE)(pFastGlyphOrder->variableBytes.glyphData);
  5024. *pGlyphData++ = (BYTE)pglc->rgCacheIndex[0];
  5025. cbDataSize = 1;
  5026. Encode2ByteSignedFields(&pGlyphData,
  5027. (INT16)pGlyphPos->pgdf->pgb->ptlOrigin.x, &cbDataSize);
  5028. Encode2ByteSignedFields(&pGlyphData,
  5029. (INT16)pGlyphPos->pgdf->pgb->ptlOrigin.y, &cbDataSize);
  5030. cx = pGlyphPos->pgdf->pgb->sizlBitmap.cx;
  5031. cy = pGlyphPos->pgdf->pgb->sizlBitmap.cy;
  5032. cbGlyphSize = ((cx + 7) / 8) * cy;
  5033. cbGlyphSize = (cbGlyphSize + 3) & ~3;
  5034. cbDataSize += cbGlyphSize;
  5035. *pGlyphData++ = (BYTE)cx;
  5036. *pGlyphData++ = (BYTE)cy;
  5037. cbDataSize += 2;
  5038. memcpy(pGlyphData, pGlyphPos->pgdf->pgb->aj, cbGlyphSize);
  5039. // append unicode to the end of glyph data
  5040. *((UINT16 UNALIGNED *)(pGlyphData + cbGlyphSize)) = pstro->pwszOrg[0];
  5041. cbDataSize += 2;
  5042. pFastGlyphOrder->variableBytes.len = cbDataSize;
  5043. }
  5044. else {
  5045. // We have a cache hit. We only need to send a 1-byte cache index
  5046. // in the variable size data.
  5047. cbDataSize = 1;
  5048. // Store the variable data in the order data
  5049. if (pglc->rgCacheIndex[0] > SBC_GL_MAX_CACHE_ENTRIES)
  5050. pFastGlyphOrder->variableBytes.glyphData[0] =
  5051. (BYTE)(~pglc->rgCacheIndex[0]);
  5052. else
  5053. pFastGlyphOrder->variableBytes.glyphData[0] =
  5054. (BYTE)pglc->rgCacheIndex[0];
  5055. pFastGlyphOrder->variableBytes.len = 1;
  5056. }
  5057. // 2 field flag bytes, plus the variable data size.
  5058. pOrder = OA_AllocOrderMem(ppdev, MAX_ORDER_SIZE(IntersectRects.rects.c,
  5059. 2, MAX_FAST_GLYPH_FIELD_SIZE_DATASIZE(cbDataSize)));
  5060. if (pOrder != NULL) {
  5061. // Establish per order settings.
  5062. pFastGlyphOrder->cacheId = (BYTE)pfci->cacheId;
  5063. pFastGlyphOrder->fDrawing = (((BYTE) pstro->flAccel) << 8) |
  5064. ((BYTE)pstro->ulCharInc);
  5065. pFastGlyphOrder->BackColor = pCurrentBrush->back;
  5066. pFastGlyphOrder->ForeColor = pCurrentBrush->fore;
  5067. // Establish bounding rect left and right values.
  5068. pFastGlyphOrder->BkTop = pstro->rclBkGround.top;
  5069. pFastGlyphOrder->BkBottom = pstro->rclBkGround.bottom;
  5070. pFastGlyphOrder->BkLeft = pstro->rclBkGround.left;
  5071. pFastGlyphOrder->BkRight = pstro->rclBkGround.right;
  5072. // Set up x, y coordinates
  5073. if (pGlyphPos->ptl.x == pFastGlyphOrder->BkLeft)
  5074. pFastGlyphOrder->x = INT16_MIN;
  5075. else
  5076. pFastGlyphOrder->x = pGlyphPos->ptl.x;
  5077. if (pGlyphPos->ptl.y == pFastGlyphOrder->BkTop)
  5078. pFastGlyphOrder->y = INT16_MIN;
  5079. else
  5080. pFastGlyphOrder->y = pGlyphPos->ptl.y;
  5081. // Setup Opaque rect coordinates. Note we clipped to OE_MAX_COORD
  5082. // above.
  5083. if (prclOpaque) {
  5084. pFastGlyphOrder->OpTop = prclOpaque->top;
  5085. pFastGlyphOrder->OpBottom = prclOpaque->bottom;
  5086. pFastGlyphOrder->OpLeft = prclOpaque->left;
  5087. pFastGlyphOrder->OpRight = prclOpaque->right;
  5088. }
  5089. else {
  5090. pFastGlyphOrder->OpTop = 0;
  5091. pFastGlyphOrder->OpBottom = 0;
  5092. pFastGlyphOrder->OpLeft = 0;
  5093. pFastGlyphOrder->OpRight = 0;
  5094. }
  5095. // Is the Opaque rect redundant?
  5096. OpEncodeFlags =
  5097. ((pFastGlyphOrder->OpLeft == pFastGlyphOrder->BkLeft) << 3) |
  5098. ((pFastGlyphOrder->OpTop == pFastGlyphOrder->BkTop) << 2) |
  5099. ((pFastGlyphOrder->OpRight == pFastGlyphOrder->BkRight) << 1) |
  5100. (pFastGlyphOrder->OpBottom == pFastGlyphOrder->BkBottom);
  5101. // For Fast Index order, we can encode even better for x, y and
  5102. // opaque rect.
  5103. if (OpEncodeFlags == 0xf) {
  5104. // All 4 bits present, Opaque rect is same as Bk rect.
  5105. pFastGlyphOrder->OpLeft = 0;
  5106. pFastGlyphOrder->OpTop = OpEncodeFlags;
  5107. pFastGlyphOrder->OpRight = 0;
  5108. pFastGlyphOrder->OpBottom = INT16_MIN;
  5109. }
  5110. else if (OpEncodeFlags == 0xd) {
  5111. // Bit 1 is 0, others are 1.
  5112. // Opaque rect matches Bk rect except OpRight
  5113. // we store OpRight at OpRight field
  5114. pFastGlyphOrder->OpLeft = 0;
  5115. pFastGlyphOrder->OpTop = OpEncodeFlags;
  5116. pFastGlyphOrder->OpRight = pFastGlyphOrder->OpRight;
  5117. pFastGlyphOrder->OpBottom = INT16_MIN;
  5118. }
  5119. // Slow-field-encode the order with the first clip rect
  5120. // (if present).
  5121. pOrder->OrderLength = OE2_EncodeOrder(pOrder->OrderData,
  5122. TS_ENC_FAST_GLYPH_ORDER, NUM_FAST_GLYPH_FIELDS,
  5123. (BYTE *)pFastGlyphOrder, (BYTE *)&PrevFastGlyph, etable_FG,
  5124. (IntersectRects.rects.c == 0 ? NULL :
  5125. &IntersectRects.rects.arcl[0]));
  5126. INC_OUTCOUNTER(OUT_TEXTOUT_FAST_GLYPH);
  5127. ADD_INCOUNTER(IN_FASTGLYPH_BYTES, pOrder->OrderLength);
  5128. OA_AppendToOrderList(pOrder);
  5129. // Flush the order.
  5130. if (IntersectRects.rects.c < 2)
  5131. rc = TRUE;
  5132. else
  5133. rc = OEEmitReplayOrders(ppdev, 2, &IntersectRects);
  5134. }
  5135. else {
  5136. rc = FALSE;
  5137. TRC_ERR((TB, "Failed to alloc Fast Index order"));
  5138. }
  5139. DC_EXIT_POINT:
  5140. // If we could not send all the required glyphs, then remove them from
  5141. // the cache (as future hits on this entry will be invalid).
  5142. if (!rc && pglc->nCacheHit == 0)
  5143. CH_RemoveCacheEntry(pfci->cacheHandle, pglc->rgCacheIndex[0]);
  5144. DC_END_FN();
  5145. return rc;
  5146. }
  5147. /****************************************************************************/
  5148. // OESendIndexOrder
  5149. //
  5150. // Sends GlyphIndex and FastIndex orders. Returns FALSE on failure.
  5151. /****************************************************************************/
  5152. unsigned RDPCALL OESendIndexOrder(
  5153. PDD_PDEV ppdev,
  5154. STROBJ *pstro,
  5155. OE_ENUMRECTS *pClipRects,
  5156. PRECTL prclOpaque,
  5157. POE_BRUSH_DATA pCurrentBrush,
  5158. PFONTCACHEINFO pfci,
  5159. PGLYPHCONTEXT pglc,
  5160. unsigned iGlyph,
  5161. unsigned cGlyphs,
  5162. int x,
  5163. int y,
  5164. int cx,
  5165. int cy,
  5166. int cxLast,
  5167. int cyLast,
  5168. PBYTE pjData,
  5169. unsigned cbData)
  5170. {
  5171. UINT32 dwSize;
  5172. LPINDEX_ORDER pIndexOrder;
  5173. LPFAST_INDEX_ORDER pFastIndexOrder;
  5174. PINT_ORDER pOrder;
  5175. BOOL fFastIndex;
  5176. unsigned fStatus, OpEncodeFlags;
  5177. unsigned NumFieldFlagBytes;
  5178. RECTL *pBoundRect;
  5179. RECTL OpaqueRect;
  5180. RECTL BkRect;
  5181. OE_ENUMRECTS IntersectRects;
  5182. DC_BEGIN_FN("OESendIndexOrder");
  5183. fStatus = GH_STATUS_SUCCESS;
  5184. // First determine the opaque rect and background rects we will send
  5185. // on the wire. We'll use these to determine the target bound rect for the
  5186. // GlyphIndex order, to see if it is clipped out by the cliprects.
  5187. if (pstro->flAccel & SO_HORIZONTAL) {
  5188. BkRect.top = pstro->rclBkGround.top;
  5189. BkRect.bottom = pstro->rclBkGround.bottom;
  5190. OpaqueRect.top = prclOpaque->top;
  5191. OpaqueRect.bottom = prclOpaque->bottom;
  5192. // Left to right
  5193. if (x <= cx) {
  5194. if (iGlyph == 0) {
  5195. BkRect.left = pstro->rclBkGround.left;
  5196. OpaqueRect.left = prclOpaque->left;
  5197. }
  5198. else {
  5199. BkRect.left = min(cxLast, x);
  5200. if (OpaqueRect.top == OpaqueRect.bottom)
  5201. OpaqueRect.left = 0;
  5202. else
  5203. OpaqueRect.left = cxLast;
  5204. }
  5205. if (iGlyph + cGlyphs >= pglc->nCacheIndex) {
  5206. BkRect.right = pstro->rclBkGround.right;
  5207. OpaqueRect.right = prclOpaque->right;
  5208. }
  5209. else {
  5210. BkRect.right = cx;
  5211. if (OpaqueRect.top == OpaqueRect.bottom)
  5212. OpaqueRect.right = 0;
  5213. else
  5214. OpaqueRect.right = cx;
  5215. }
  5216. }
  5217. // Right to left
  5218. else {
  5219. if (iGlyph == 0) {
  5220. BkRect.right = pstro->rclBkGround.right;
  5221. OpaqueRect.right = prclOpaque->right;
  5222. }
  5223. else {
  5224. BkRect.right = x;
  5225. if (OpaqueRect.top == OpaqueRect.bottom)
  5226. OpaqueRect.right = 0;
  5227. else
  5228. OpaqueRect.right = x;
  5229. }
  5230. if (iGlyph + cGlyphs >= pglc->nCacheIndex) {
  5231. BkRect.left = pstro->rclBkGround.left;
  5232. OpaqueRect.left = prclOpaque->left;
  5233. }
  5234. else {
  5235. BkRect.left = cx;
  5236. if (prclOpaque->top == prclOpaque->bottom)
  5237. OpaqueRect.left = 0;
  5238. else
  5239. OpaqueRect.left = cx;
  5240. }
  5241. }
  5242. }
  5243. else {
  5244. BkRect.left = pstro->rclBkGround.left;
  5245. BkRect.right = pstro->rclBkGround.right;
  5246. OpaqueRect.left = prclOpaque->left;
  5247. OpaqueRect.right = prclOpaque->right;
  5248. // Top to bottom
  5249. if (y <= cy) {
  5250. if (iGlyph == 0) {
  5251. BkRect.top = pstro->rclBkGround.top;
  5252. OpaqueRect.top = prclOpaque->top;
  5253. }
  5254. else {
  5255. BkRect.top = cyLast;
  5256. if (prclOpaque->top == prclOpaque->bottom)
  5257. OpaqueRect.top = 0;
  5258. else
  5259. OpaqueRect.top = cyLast;
  5260. }
  5261. if (iGlyph + cGlyphs >= pglc->nCacheIndex) {
  5262. BkRect.bottom = pstro->rclBkGround.bottom;
  5263. OpaqueRect.bottom = prclOpaque->bottom;
  5264. }
  5265. else {
  5266. BkRect.bottom = cy;
  5267. if (prclOpaque->top == prclOpaque->bottom)
  5268. OpaqueRect.bottom = 0;
  5269. else
  5270. OpaqueRect.bottom = cy;
  5271. }
  5272. }
  5273. else {
  5274. // Bottom to top
  5275. if (iGlyph == 0) {
  5276. BkRect.bottom = pstro->rclBkGround.bottom;
  5277. OpaqueRect.bottom = prclOpaque->bottom;
  5278. }
  5279. else {
  5280. BkRect.bottom = y;
  5281. if (prclOpaque->top == prclOpaque->bottom)
  5282. OpaqueRect.bottom = 0;
  5283. else
  5284. OpaqueRect.bottom = y;
  5285. }
  5286. if (iGlyph + cGlyphs >= pglc->nCacheIndex) {
  5287. BkRect.top = pstro->rclBkGround.top;
  5288. OpaqueRect.top = prclOpaque->top;
  5289. }
  5290. else {
  5291. BkRect.top = cy;
  5292. if (prclOpaque->top == prclOpaque->bottom)
  5293. OpaqueRect.top = 0;
  5294. else
  5295. OpaqueRect.top = cy;
  5296. }
  5297. }
  5298. }
  5299. // If the opaque rect is normally-ordered, it is our bound rect.
  5300. // Otherwise use the target background string rect.
  5301. if (OpaqueRect.top < OpaqueRect.bottom)
  5302. pBoundRect = &OpaqueRect;
  5303. else
  5304. pBoundRect = &BkRect;
  5305. IntersectRects.rects.c = 0;
  5306. if (pClipRects->rects.c == 0 ||
  5307. OEGetIntersectionsWithClipRects(pBoundRect, pClipRects,
  5308. &IntersectRects) > 0) {
  5309. fFastIndex = OE_SendAsOrder(TS_ENC_FAST_INDEX_ORDER);
  5310. // Calculate and allocate the req memory for this order.
  5311. if (fFastIndex) {
  5312. dwSize = MAX_FAST_INDEX_FIELD_SIZE_DATASIZE(cbData);
  5313. NumFieldFlagBytes = 2;
  5314. }
  5315. else {
  5316. dwSize = MAX_INDEX_FIELD_SIZE_DATASIZE(cbData);
  5317. NumFieldFlagBytes = 3;
  5318. }
  5319. pOrder = OA_AllocOrderMem(ppdev, MAX_ORDER_SIZE(IntersectRects.rects.c,
  5320. NumFieldFlagBytes, dwSize));
  5321. if (pOrder != NULL) {
  5322. // Since most of the fields are the same between Index order and
  5323. // fast index order. We arrange them in such a way that they can
  5324. // both be cast to the Index order in a lot of cases.
  5325. pIndexOrder = (LPINDEX_ORDER)oeTempOrderBuffer;
  5326. pFastIndexOrder = (LPFAST_INDEX_ORDER)oeTempOrderBuffer;
  5327. pIndexOrder->cacheId = (BYTE)pfci->cacheId;
  5328. pIndexOrder->ForeColor = pCurrentBrush->fore;
  5329. pIndexOrder->BackColor = pCurrentBrush->back;
  5330. pIndexOrder->x = x;
  5331. pIndexOrder->y = y;
  5332. pIndexOrder->BkLeft = BkRect.left;
  5333. pIndexOrder->BkTop = BkRect.top;
  5334. pIndexOrder->BkRight = BkRect.right;
  5335. pIndexOrder->BkBottom = BkRect.bottom;
  5336. pIndexOrder->OpLeft = OpaqueRect.left;
  5337. pIndexOrder->OpTop = OpaqueRect.top;
  5338. pIndexOrder->OpRight = OpaqueRect.right;
  5339. pIndexOrder->OpBottom = OpaqueRect.bottom;
  5340. // Is the Opaque rect redundant?
  5341. // We use 4 bits in OpTop field to encode Opaque Rect. 1 means
  5342. // a field is same as BkRect's field. 0 means a field is supplied
  5343. // in OpLeft or OpRight.
  5344. // bit 0: OpBottom
  5345. // bit 1: OpRight
  5346. // bit 2: OpTop
  5347. // bit 3: OpLeft
  5348. OpEncodeFlags = ((OpaqueRect.left == BkRect.left) << 3) |
  5349. ((OpaqueRect.top == BkRect.top) << 2) |
  5350. ((OpaqueRect.right == BkRect.right) << 1) |
  5351. (OpaqueRect.bottom == BkRect.bottom);
  5352. if (fFastIndex) {
  5353. pFastIndexOrder->fDrawing = (((BYTE) pstro->flAccel) << 8) |
  5354. ((BYTE) pstro->ulCharInc);
  5355. // For Fast Index order, we can encode even better for x, y and
  5356. // opaque rect. We use INT16_MIN when possible to let the
  5357. // field encoder not send that field more often.
  5358. if (OpEncodeFlags == 0xf) {
  5359. // All 4 bits present, Opaque rect is same as Bk rect.
  5360. pFastIndexOrder->OpLeft = 0;
  5361. pFastIndexOrder->OpTop = OpEncodeFlags;
  5362. pFastIndexOrder->OpRight = 0;
  5363. pFastIndexOrder->OpBottom = INT16_MIN;
  5364. }
  5365. else if (OpEncodeFlags == 0xd) {
  5366. // Bit 1 is 0, others are 1.
  5367. // Opaque rect matches Bk rect except OpRight
  5368. // we store OpRight at OpRight field
  5369. pFastIndexOrder->OpLeft = 0;
  5370. pFastIndexOrder->OpTop = OpEncodeFlags;
  5371. pFastIndexOrder->OpRight = pFastIndexOrder->OpRight;
  5372. pFastIndexOrder->OpBottom = INT16_MIN;
  5373. }
  5374. // Set to same val if x coordinate same as BkLeft or y same as
  5375. // BkTop. This lets field encoding not send the value more often.
  5376. if (pFastIndexOrder->x == pFastIndexOrder->BkLeft)
  5377. pFastIndexOrder->x = INT16_MIN;
  5378. if (pFastIndexOrder->y == pFastIndexOrder->BkTop)
  5379. pFastIndexOrder->y = INT16_MIN;
  5380. // Store the order data and encode the order.
  5381. memcpy(pFastIndexOrder->variableBytes.arecs, pjData, cbData);
  5382. pFastIndexOrder->variableBytes.len = cbData;
  5383. // Slow-field-encode the order with the first clip rect
  5384. // (if present).
  5385. pOrder->OrderLength = OE2_EncodeOrder(pOrder->OrderData,
  5386. TS_ENC_FAST_INDEX_ORDER, NUM_FAST_INDEX_FIELDS,
  5387. (BYTE *)pFastIndexOrder, (BYTE *)&PrevFastIndex,
  5388. etable_FI,
  5389. (IntersectRects.rects.c == 0 ? NULL :
  5390. &IntersectRects.rects.arcl[0]));
  5391. INC_OUTCOUNTER(OUT_TEXTOUT_FAST_INDEX);
  5392. ADD_INCOUNTER(IN_FASTINDEX_BYTES, pOrder->OrderLength);
  5393. OA_AppendToOrderList(pOrder);
  5394. // Flush the order.
  5395. if (IntersectRects.rects.c >= 2)
  5396. if (!OEEmitReplayOrders(ppdev, 2, &IntersectRects))
  5397. fStatus = GH_STATUS_CLIPPED;
  5398. }
  5399. else {
  5400. pIndexOrder->flAccel = (BYTE)pstro->flAccel;
  5401. pIndexOrder->ulCharInc = (BYTE)pstro->ulCharInc;
  5402. pIndexOrder->BrushStyle = pCurrentBrush->style;
  5403. TRC_ASSERT((pIndexOrder->BrushStyle == BS_SOLID),
  5404. (TB,"Non solid brush"));
  5405. if (OpEncodeFlags == 0xf) {
  5406. pIndexOrder->OpTop = 0;
  5407. pIndexOrder->OpRight = 0;
  5408. pIndexOrder->OpBottom = 0;
  5409. pIndexOrder->OpLeft = 0;
  5410. pIndexOrder->fOpRedundant = TRUE;
  5411. }
  5412. else {
  5413. pIndexOrder->fOpRedundant = FALSE;
  5414. }
  5415. // Store the order data and encode the order.
  5416. memcpy(pIndexOrder->variableBytes.arecs, pjData, cbData);
  5417. pIndexOrder->variableBytes.len = cbData;
  5418. // Slow-field-encode the order with the first clip rect
  5419. // (if present).
  5420. pOrder->OrderLength = OE2_EncodeOrder(pOrder->OrderData,
  5421. TS_ENC_INDEX_ORDER, NUM_INDEX_FIELDS,
  5422. (BYTE *)pIndexOrder, (BYTE *)&PrevGlyphIndex,
  5423. etable_GI,
  5424. (IntersectRects.rects.c == 0 ? NULL :
  5425. &IntersectRects.rects.arcl[0]));
  5426. INC_OUTCOUNTER(OUT_TEXTOUT_GLYPH_INDEX);
  5427. ADD_INCOUNTER(IN_GLYPHINDEX_BYTES, pOrder->OrderLength);
  5428. OA_AppendToOrderList(pOrder);
  5429. // Flush the order.
  5430. if (IntersectRects.rects.c >= 2)
  5431. if (!OEEmitReplayOrders(ppdev, 3, &IntersectRects))
  5432. fStatus = GH_STATUS_CLIPPED;
  5433. }
  5434. }
  5435. else {
  5436. fStatus = GH_STATUS_NO_MEMORY;
  5437. TRC_ERR((TB, "Failed to alloc Index order"));
  5438. }
  5439. }
  5440. else {
  5441. TRC_NRM((TB,"(Fast)Index order completely clipped, not sending"));
  5442. fStatus = GH_STATUS_CLIPPED;
  5443. }
  5444. DC_END_FN();
  5445. return fStatus;
  5446. }
  5447. /****************************************************************************/
  5448. // OEGetFragment
  5449. //
  5450. // Retrieves text fragments (run of contig glyphs). Returns number of bytes
  5451. // copied into fragment buffer.
  5452. /****************************************************************************/
  5453. unsigned RDPCALL OEGetFragment(
  5454. STROBJ *pstro,
  5455. FONTOBJ *pfo,
  5456. GLYPHPOS **ppGlyphPos,
  5457. PGLYPHCONTEXT pglc,
  5458. PUINT pcGlyphs,
  5459. PUINT pcCurGlyphs,
  5460. PINT px,
  5461. PINT py,
  5462. PINT pcx,
  5463. PINT pcy,
  5464. PBYTE pjFrag,
  5465. unsigned maxFrag)
  5466. {
  5467. unsigned cbFrag;
  5468. unsigned cbEntrySize;
  5469. unsigned cacheIndex;
  5470. int delta;
  5471. BOOL fMore;
  5472. DC_BEGIN_FN("OEGetFragment");
  5473. // Loop through each glyph index accumulating the fragment.
  5474. cbFrag = 0;
  5475. cbEntrySize = (pstro->flAccel & SO_CHAR_INC_EQUAL_BM_BASE) ? 1 : 2;
  5476. while (*pcGlyphs < pglc->nCacheIndex) {
  5477. // If we have exhausted our fragment space, then exit.
  5478. if (cbFrag + cbEntrySize >= maxFrag)
  5479. break;
  5480. // We may need to get a new batch of current glyphs.
  5481. if (*pcCurGlyphs == 0) {
  5482. fMore = STROBJ_bEnum(pstro, pcCurGlyphs, ppGlyphPos);
  5483. if (*pcCurGlyphs == 0) {
  5484. cbFrag = 0;
  5485. TRC_NRM((TB, "STROBJ_bEnum - 0 glyphs"));
  5486. DC_QUIT;
  5487. }
  5488. }
  5489. // Place the glyph cache index into the fragment.
  5490. cacheIndex = pglc->rgCacheIndex[*pcGlyphs];
  5491. if (cacheIndex > SBC_GL_MAX_CACHE_ENTRIES)
  5492. cacheIndex = ~cacheIndex;
  5493. if (!(pstro->flAccel & SO_GLYPHINDEX_TEXTOUT) && (cbFrag > 0) &&
  5494. (pstro->pwszOrg[*pcGlyphs] == 0x20)) {
  5495. if (pstro->ulCharInc || (pstro->flAccel & SO_CHAR_INC_EQUAL_BM_BASE))
  5496. pjFrag[cbFrag++] = (BYTE) cacheIndex;
  5497. }
  5498. else {
  5499. pjFrag[cbFrag++] = (BYTE) cacheIndex;
  5500. // If we do not have a mono-spaced font, nor an equal base font,
  5501. // then we need to also provide a delta coordinate.
  5502. if (pstro->ulCharInc == 0) {
  5503. if ((pstro->flAccel & SO_CHAR_INC_EQUAL_BM_BASE) == 0) {
  5504. // The delta coordinate is either the x-delta or the
  5505. // y-delta, based upon whether the text is horizontal
  5506. // or vertical.
  5507. if (pstro->flAccel & SO_HORIZONTAL)
  5508. delta = ((*ppGlyphPos)->ptl.x - *px);
  5509. else
  5510. delta = ((*ppGlyphPos)->ptl.y - *py);
  5511. if (delta >= 0 && delta <= 127) {
  5512. pjFrag[cbFrag++] = (char) delta;
  5513. }
  5514. else {
  5515. pjFrag[cbFrag++] = 0x80;
  5516. *(UNALIGNED short *)(&pjFrag[cbFrag]) = (SHORT)delta;
  5517. cbFrag += sizeof(INT16);
  5518. }
  5519. }
  5520. // Return the new glyph spacing coordinates to the main
  5521. // routine.
  5522. *px = (*ppGlyphPos)->ptl.x;
  5523. *py = (*ppGlyphPos)->ptl.y;
  5524. *pcx = (*ppGlyphPos)->ptl.x +
  5525. (*ppGlyphPos)->pgdf->pgb->ptlOrigin.x +
  5526. (*ppGlyphPos)->pgdf->pgb->sizlBitmap.cx;
  5527. *pcy = (*ppGlyphPos)->ptl.y +
  5528. (*ppGlyphPos)->pgdf->pgb->ptlOrigin.y +
  5529. (*ppGlyphPos)->pgdf->pgb->sizlBitmap.cy;
  5530. }
  5531. }
  5532. // Next glyph.
  5533. (*pcGlyphs)++;
  5534. (*ppGlyphPos)++;
  5535. (*pcCurGlyphs)--;
  5536. }
  5537. DC_EXIT_POINT:
  5538. DC_END_FN();
  5539. return cbFrag;
  5540. }
  5541. /****************************************************************************/
  5542. // OEMatchFragment
  5543. //
  5544. // Matches text fragments with cached fragments. Returns the number of bytes
  5545. // in the fragment index returned in *pNewFragIndex.
  5546. /****************************************************************************/
  5547. unsigned RDPCALL OEMatchFragment(
  5548. STROBJ *pstro,
  5549. FONTOBJ *pfo,
  5550. PFONTCACHEINFO pfci,
  5551. PFRAGCONTEXT pfgc,
  5552. PBYTE pjFrag,
  5553. unsigned cbFrag,
  5554. PUINT pNewFragIndex,
  5555. unsigned cx,
  5556. unsigned cy,
  5557. unsigned cxLast,
  5558. unsigned cyLast)
  5559. {
  5560. unsigned cacheIndex;
  5561. UINT16 delta;
  5562. unsigned i;
  5563. void *UserDefined;
  5564. CHDataKeyContext CHContext;
  5565. INT16 dx, dy;
  5566. DC_BEGIN_FN("OEMatchFragment");
  5567. if (pfgc->cacheHandle) {
  5568. // If this is not a mono-spaced font, nor an equal base font, then
  5569. // we need to normalize the first delta, and the trailing padding.
  5570. if (pstro->ulCharInc == 0) {
  5571. if ((pstro->flAccel & SO_CHAR_INC_EQUAL_BM_BASE) == 0) {
  5572. if (pjFrag[1] != 0x80) {
  5573. delta = pjFrag[1];
  5574. pjFrag[1] = (BYTE) (pfci->cacheId);
  5575. }
  5576. else {
  5577. delta = *(UNALIGNED short *)(&pjFrag[2]);
  5578. pjFrag[2] = (BYTE) (pfci->cacheId);
  5579. pjFrag[3] = (BYTE) (pfci->cacheId);
  5580. }
  5581. }
  5582. }
  5583. i = (cbFrag + 3) & ~3;
  5584. memset(&pjFrag[cbFrag], (0xff), i - cbFrag);
  5585. // Multiple fonts can fall into the same cacheId, so two fragments
  5586. // of different fonts may collide if we use cacheId instead of fontId.
  5587. // memset(&pjFrag[i], (BYTE) (pfci->cacheId), sizeof(DWORD));
  5588. *(PUINT32)(&pjFrag[i]) = pfci->fontId;
  5589. i += sizeof(UINT32);
  5590. // Restore the normalized first delta.
  5591. if (pstro->ulCharInc == 0) {
  5592. if ((pstro->flAccel & SO_CHAR_INC_EQUAL_BM_BASE) == 0) {
  5593. if (delta >= 0 && delta <= 127)
  5594. pjFrag[1] = (char) delta;
  5595. else
  5596. *(UNALIGNED short *)(&pjFrag[2]) = delta;
  5597. }
  5598. }
  5599. // Make the default key for this fragment, and then search the
  5600. // fragment cache for a match.
  5601. CH_CreateKeyFromFirstData(&CHContext, pjFrag, i);
  5602. // Check if it is a fragment cache key collision by verifying the
  5603. // bounding background rectangle.
  5604. if (pstro->flAccel & SO_HORIZONTAL) {
  5605. dy = (INT16) (pstro->rclBkGround.bottom - pstro->rclBkGround.top);
  5606. if (cxLast == 0)
  5607. dx = (INT16)(cx - pstro->rclBkGround.left);
  5608. else
  5609. dx = (INT16)(cx - cxLast);
  5610. }
  5611. else {
  5612. dx = (INT16) (pstro->rclBkGround.right - pstro->rclBkGround.left);
  5613. if (cyLast == 0)
  5614. dy = (INT16)(cy - pstro->rclBkGround.top);
  5615. else
  5616. dy = (INT16)(cy - cyLast);
  5617. }
  5618. if (CH_SearchCache(pfgc->cacheHandle, CHContext.Key1,
  5619. CHContext.Key2, &UserDefined, &cacheIndex)) {
  5620. if (dx == (INT16) HIWORD((UINT32)(UINT_PTR)UserDefined) &&
  5621. dy == (INT16) LOWORD((UINT32)(UINT_PTR)UserDefined)) {
  5622. // If the entry already exists, then we can use it.
  5623. for (i = 0; i < pfgc->nCacheIndex; i++) {
  5624. if (cacheIndex == pfgc->rgCacheIndex[i])
  5625. DC_QUIT;
  5626. }
  5627. cbFrag = 0;
  5628. pjFrag[cbFrag++] = ORD_INDEX_FRAGMENT_USE;
  5629. pjFrag[cbFrag++] = (BYTE)cacheIndex;
  5630. if (pstro->ulCharInc == 0) {
  5631. if ((pstro->flAccel & SO_CHAR_INC_EQUAL_BM_BASE) == 0) {
  5632. if (delta >= 0 && delta <= 127) {
  5633. pjFrag[cbFrag++] = (char) delta;
  5634. }
  5635. else {
  5636. pjFrag[cbFrag++] = 0x80;
  5637. *(UNALIGNED short *)(&pjFrag[cbFrag]) = delta;
  5638. cbFrag += sizeof(INT16);
  5639. }
  5640. }
  5641. }
  5642. }
  5643. else {
  5644. TRC_ALT((TB, "Fragment cache Key collision at index %d",
  5645. cacheIndex));
  5646. UserDefined = (void *) ULongToPtr((((((UINT32) ((UINT16) dx)) << 16) |
  5647. (UINT32) ((UINT16) dy))));
  5648. CH_SetUserDefined(pfgc->cacheHandle, cacheIndex, UserDefined);
  5649. // Pass the entry along to the client.
  5650. i = cbFrag;
  5651. pjFrag[cbFrag++] = ORD_INDEX_FRAGMENT_ADD;
  5652. pjFrag[cbFrag++] = (BYTE)cacheIndex;
  5653. pjFrag[cbFrag++] = (BYTE)i;
  5654. *pNewFragIndex = cacheIndex;
  5655. }
  5656. }
  5657. else {
  5658. UserDefined = (void *) ULongToPtr((((((UINT32) ((UINT16) dx)) << 16) |
  5659. (UINT32) ((UINT16) dy))));
  5660. cacheIndex = CH_CacheKey(pfgc->cacheHandle, CHContext.Key1,
  5661. CHContext.Key2, UserDefined);
  5662. // If we could not add the cache entry, then bail.
  5663. if (cacheIndex != CH_KEY_UNCACHABLE) {
  5664. // Pass the entry along to the client.
  5665. i = cbFrag;
  5666. pjFrag[cbFrag++] = ORD_INDEX_FRAGMENT_ADD;
  5667. pjFrag[cbFrag++] = (BYTE)cacheIndex;
  5668. pjFrag[cbFrag++] = (BYTE)i;
  5669. *pNewFragIndex = cacheIndex;
  5670. }
  5671. else {
  5672. TRC_NRM((TB, "Fragment could not be added to cache"));
  5673. DC_QUIT;
  5674. }
  5675. }
  5676. }
  5677. DC_EXIT_POINT:
  5678. DC_END_FN();
  5679. return cbFrag;
  5680. }
  5681. /****************************************************************************/
  5682. // OEClearFragments
  5683. //
  5684. // Clears the newly added cache fragments.
  5685. /****************************************************************************/
  5686. void RDPCALL OEClearFragments(PFRAGCONTEXT pfgc)
  5687. {
  5688. unsigned i;
  5689. DC_BEGIN_FN("OEClearFragments");
  5690. // Remove all fragment cache entries that were being newly defined to
  5691. // to the client.
  5692. for (i = 0; i < pfgc->nCacheIndex; i++)
  5693. CH_RemoveCacheEntry(pfgc->cacheHandle, pfgc->rgCacheIndex[i]);
  5694. pfgc->nCacheIndex = 0;
  5695. DC_END_FN();
  5696. }
  5697. /****************************************************************************/
  5698. // OEMatchFragment
  5699. //
  5700. // Matches text fragments with cached fragments. Returns FALSE on failure.
  5701. /****************************************************************************/
  5702. BOOL RDPCALL OESendIndexes(
  5703. SURFOBJ *pso,
  5704. STROBJ *pstro,
  5705. FONTOBJ *pfo,
  5706. OE_ENUMRECTS *pClipRects,
  5707. PRECTL prclOpaque,
  5708. POE_BRUSH_DATA pbdOpaque,
  5709. POINTL *pptlOrg,
  5710. PFONTCACHEINFO pfci,
  5711. PGLYPHCONTEXT pglc)
  5712. {
  5713. BOOL rc;
  5714. unsigned iGlyph;
  5715. UINT32 cGlyphs;
  5716. RECTL rclOpaque;
  5717. LPINDEX_ORDER pIndexOrder;
  5718. GLYPHPOS *pGlyphPos;
  5719. FRAGCONTEXT fgc;
  5720. unsigned cCurGlyphs;
  5721. unsigned cbData;
  5722. unsigned cbFrag;
  5723. BYTE ajFrag[255];
  5724. BYTE ajData[255];
  5725. int x, y;
  5726. int cx, cy;
  5727. int cxPre, cyPre;
  5728. int cxLast, cyLast;
  5729. int dx, dy;
  5730. int cdx, cdy;
  5731. int xFrag, yFrag;
  5732. unsigned maxFrag;
  5733. unsigned minFrag;
  5734. unsigned fStatus;
  5735. PDD_PDEV ppdev;
  5736. BOOL fMore;
  5737. unsigned newFragIndex;
  5738. DC_BEGIN_FN("OEMatchFragment");
  5739. rc = FALSE;
  5740. fStatus = GH_STATUS_NO_MEMORY;
  5741. ppdev = (PDD_PDEV)pso->dhpdev;
  5742. // If no opaque rect is specified, default to the null rect.
  5743. if (prclOpaque == NULL) {
  5744. prclOpaque = &rclOpaque;
  5745. prclOpaque->left = 0;
  5746. prclOpaque->top = 0;
  5747. prclOpaque->right = 0;
  5748. prclOpaque->bottom = 0;
  5749. }
  5750. else {
  5751. if (prclOpaque->right > OE_MAX_COORD)
  5752. prclOpaque->right = OE_MAX_COORD;
  5753. if (prclOpaque->bottom > OE_MAX_COORD)
  5754. prclOpaque->bottom = OE_MAX_COORD;
  5755. }
  5756. // Establish min and max fragment limits.
  5757. fgc.nCacheIndex = 0;
  5758. fgc.cacheHandle = pddShm->sbc.fragCacheInfo[0].cacheHandle;
  5759. fgc.cbCellSize = pddShm->sbc.fragCacheInfo[0].cbCellSize;
  5760. maxFrag = fgc.cacheHandle ? fgc.cbCellSize : sizeof(ajFrag);
  5761. maxFrag = min(maxFrag, sizeof(ajFrag) - 2 * sizeof(DWORD) - 4);
  5762. minFrag = 3 * ((pstro->flAccel & SO_CHAR_INC_EQUAL_BM_BASE) ? 1 : 2);
  5763. // Loop through each glyph index, sending as many entries as
  5764. // possible per each order.
  5765. if (pstro->pgp != NULL) {
  5766. pGlyphPos = pstro->pgp;
  5767. cCurGlyphs = pglc->nCacheIndex;
  5768. }
  5769. else {
  5770. STROBJ_vEnumStart(pstro);
  5771. fMore = STROBJ_bEnum(pstro, &cCurGlyphs, &pGlyphPos);
  5772. if (cCurGlyphs == 0) {
  5773. TRC_NRM((TB, "STROBJ_bEnum - 0 glyphs"));
  5774. DC_QUIT;
  5775. }
  5776. }
  5777. cbData = 0;
  5778. iGlyph = 0;
  5779. cGlyphs = 0;
  5780. x = dx = pGlyphPos->ptl.x;
  5781. y = dy = pGlyphPos->ptl.y;
  5782. cx = cy = cxLast = cyLast = 0;
  5783. while (cGlyphs < pglc->nCacheIndex) {
  5784. xFrag = pGlyphPos->ptl.x;
  5785. yFrag = pGlyphPos->ptl.y;
  5786. // Get the next available fragment.
  5787. cbFrag = OEGetFragment(pstro, pfo, &pGlyphPos,
  5788. pglc, &cGlyphs, &cCurGlyphs,
  5789. &dx, &dy, &cdx, &cdy, ajFrag, maxFrag);
  5790. if (cbFrag == 0) {
  5791. if (fgc.nCacheIndex > 0)
  5792. OEClearFragments(&fgc);
  5793. TRC_NRM((TB, "Fragment could not be gotten"));
  5794. DC_QUIT;
  5795. }
  5796. // Keep track of the running coordinates.
  5797. cxPre = cx;
  5798. cyPre = cy;
  5799. if (pstro->ulCharInc == 0) {
  5800. cx = cdx;
  5801. cy = cdy;
  5802. }
  5803. else {
  5804. if (pstro->flAccel & SO_HORIZONTAL)
  5805. cx = x + (pstro->ulCharInc * (cGlyphs - iGlyph));
  5806. else
  5807. cy = y + (pstro->ulCharInc * (cGlyphs - iGlyph));
  5808. }
  5809. // If the fragment size is within limits, then attempt to match it
  5810. // with a previously defined fragment.
  5811. newFragIndex = BAD_FRAG_INDEX;
  5812. if (cbFrag >= minFrag)
  5813. cbFrag = OEMatchFragment(pstro, pfo, pfci, &fgc,
  5814. ajFrag, cbFrag, &newFragIndex, cx, cy, cxPre, cyPre);
  5815. // If this fragment will not fit into the current index order, then
  5816. // send the current buffered index data.
  5817. if (cbData + cbFrag > sizeof(pIndexOrder->variableBytes.arecs)) {
  5818. fStatus = OESendIndexOrder(ppdev, pstro, pClipRects,
  5819. prclOpaque, pbdOpaque, pfci, pglc,
  5820. iGlyph, cGlyphs - iGlyph, x, y,
  5821. cx, cy, cxLast, cyLast, ajData, cbData);
  5822. if (fStatus != GH_STATUS_SUCCESS) {
  5823. if (fgc.nCacheIndex > 0)
  5824. OEClearFragments(&fgc);
  5825. if (fStatus == GH_STATUS_NO_MEMORY) {
  5826. if (newFragIndex != BAD_FRAG_INDEX)
  5827. CH_RemoveCacheEntry(fgc.cacheHandle, newFragIndex);
  5828. TRC_NRM((TB, "Index order could not be sent - no memory"));
  5829. DC_QUIT;
  5830. }
  5831. }
  5832. // Reset the process.
  5833. cbData = 0;
  5834. iGlyph += cGlyphs;
  5835. cxLast = cxPre;
  5836. cyLast = cyPre;
  5837. if (pstro->ulCharInc == 0) {
  5838. x = xFrag;
  5839. y = yFrag;
  5840. }
  5841. else {
  5842. if (pstro->flAccel & SO_HORIZONTAL)
  5843. x = cxLast;
  5844. else
  5845. y = cyLast;
  5846. }
  5847. if (pstro->ulCharInc == 0) {
  5848. if ((pstro->flAccel & SO_CHAR_INC_EQUAL_BM_BASE) == 0) {
  5849. if (ajFrag[1] != 0x80) {
  5850. ajFrag[1] = 0;
  5851. }
  5852. else {
  5853. ajFrag[2] = 0;
  5854. ajFrag[3] = 0;
  5855. }
  5856. }
  5857. }
  5858. fgc.nCacheIndex = 0;
  5859. }
  5860. // Copy the fragment into the order data buffer.
  5861. memcpy(&ajData[cbData], ajFrag, cbFrag);
  5862. cbData += cbFrag;
  5863. if (newFragIndex != BAD_FRAG_INDEX)
  5864. fgc.rgCacheIndex[fgc.nCacheIndex++] = newFragIndex;
  5865. }
  5866. // Flush out any remaining buffered fragments.
  5867. if (cbData > 0) {
  5868. fStatus = OESendIndexOrder(ppdev, pstro, pClipRects,
  5869. prclOpaque, pbdOpaque, pfci, pglc,
  5870. iGlyph, cGlyphs - iGlyph, x, y, cx, cy, cxLast, cyLast,
  5871. ajData, cbData);
  5872. if (fStatus != GH_STATUS_SUCCESS) {
  5873. if (fgc.nCacheIndex > 0)
  5874. OEClearFragments(&fgc);
  5875. }
  5876. }
  5877. rc = TRUE;
  5878. DC_EXIT_POINT:
  5879. DC_END_FN();
  5880. return rc;
  5881. }