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.

4964 lines
193 KiB

  1. /****************************************************************************/
  2. // noeapi.c
  3. //
  4. // RDP Order Encoder functions
  5. //
  6. // Copyright (C) 1996-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include <precmpdd.h>
  9. #pragma hdrstop
  10. #define TRC_FILE "noeapi"
  11. #include <adcg.h>
  12. #include <atrcapi.h>
  13. #include <nshmapi.h>
  14. #include <tsrvexp.h>
  15. #include <nschdisp.h>
  16. #include <noadisp.h>
  17. #include <nsbcdisp.h>
  18. #include <nprcount.h>
  19. #include <noedisp.h>
  20. #include <oe2.h>
  21. #define DC_INCLUDE_DATA
  22. #include <ndddata.c>
  23. #include <noedata.c>
  24. #include <nsbcddat.c>
  25. #include <oe2data.c>
  26. #undef DC_INCLUDE_DATA
  27. #include <nbadisp.h>
  28. #include <nbainl.h>
  29. #include <noeinl.h>
  30. #include <nsbcinl.h>
  31. #include <nchdisp.h>
  32. #include <tsgdiplusenums.h>
  33. /****************************************************************************/
  34. // OE_InitShm
  35. //
  36. // Alloc-time SHM init.
  37. /****************************************************************************/
  38. void OE_InitShm(void)
  39. {
  40. DC_BEGIN_FN("OE_InitShm");
  41. memset(&pddShm->oe, 0, sizeof(OE_SHARED_DATA));
  42. DC_END_FN();
  43. }
  44. /****************************************************************************/
  45. // OE_Reset
  46. //
  47. // Reset oe components as necessary
  48. /****************************************************************************/
  49. void OE_Reset(void)
  50. {
  51. DC_BEGIN_FN("OE_Reset");
  52. oeLastDstSurface = 0;
  53. DC_END_FN();
  54. }
  55. /****************************************************************************/
  56. // OE_Update
  57. //
  58. // Called when the share is reset on logon or reconnect.
  59. // Sets new capabilities.
  60. /****************************************************************************/
  61. void RDPCALL OE_Update()
  62. {
  63. if (pddShm->oe.newCapsData) {
  64. oeSendSolidPatternBrushOnly = pddShm->oe.sendSolidPatternBrushOnly;
  65. oeColorIndexSupported = pddShm->oe.colorIndices;
  66. // The share core has passed down a pointer to its copy of the order
  67. // support array. We take a copy for the kernel here.
  68. memcpy(&oeOrderSupported, pddShm->oe.orderSupported,
  69. sizeof(oeOrderSupported));
  70. pddShm->oe.newCapsData = FALSE;
  71. }
  72. DC_END_FN();
  73. }
  74. /****************************************************************************/
  75. // OE_ClearOrderEncoding
  76. //
  77. // Called on a share state toggle to clear the order encoding states held
  78. // in the DD data segment.
  79. /****************************************************************************/
  80. void OE_ClearOrderEncoding()
  81. {
  82. DC_BEGIN_FN("OE_ClearOrderEncoding");
  83. memset(&PrevMemBlt, 0, sizeof(PrevMemBlt));
  84. memset(&PrevMem3Blt, 0, sizeof(PrevMem3Blt));
  85. memset(&PrevDstBlt, 0, sizeof(PrevDstBlt));
  86. memset(&PrevMultiDstBlt, 0, sizeof(PrevMultiDstBlt));
  87. memset(&PrevPatBlt, 0, sizeof(PrevPatBlt));
  88. memset(&PrevMultiPatBlt, 0, sizeof(PrevMultiPatBlt));
  89. memset(&PrevScrBlt, 0, sizeof(PrevScrBlt));
  90. memset(&PrevMultiScrBlt, 0, sizeof(PrevMultiScrBlt));
  91. memset(&PrevOpaqueRect, 0, sizeof(PrevOpaqueRect));
  92. memset(&PrevMultiOpaqueRect, 0, sizeof(PrevMultiOpaqueRect));
  93. memset(&PrevLineTo, 0, sizeof(PrevLineTo));
  94. memset(&PrevPolyLine, 0, sizeof(PrevPolyLine));
  95. memset(&PrevPolygonSC, 0, sizeof(PrevPolygonSC));
  96. memset(&PrevPolygonCB, 0, sizeof(PrevPolygonCB));
  97. memset(&PrevEllipseSC, 0, sizeof(PrevEllipseSC));
  98. memset(&PrevEllipseCB, 0, sizeof(PrevEllipseCB));
  99. memset(&PrevFastIndex, 0, sizeof(PrevFastIndex));
  100. memset(&PrevFastGlyph, 0, sizeof(PrevFastGlyph));
  101. memset(&PrevGlyphIndex, 0, sizeof(PrevGlyphIndex));
  102. #ifdef DRAW_NINEGRID
  103. memset(&PrevDrawNineGrid, 0, sizeof(PrevDrawNineGrid));
  104. memset(&PrevMultiDrawNineGrid, 0, sizeof(PrevMultiDrawNineGrid));
  105. #endif
  106. DC_END_FN();
  107. }
  108. /****************************************************************************/
  109. /* OE_SendGlyphs - Send text glyphs to the client */
  110. /****************************************************************************/
  111. BOOL RDPCALL OE_SendGlyphs(
  112. SURFOBJ *pso,
  113. STROBJ *pstro,
  114. FONTOBJ *pfo,
  115. OE_ENUMRECTS *pClipRects,
  116. RECTL *prclOpaque,
  117. BRUSHOBJ *pboFore,
  118. BRUSHOBJ *pboOpaque,
  119. POINTL *pptlOrg,
  120. PFONTCACHEINFO pfci)
  121. {
  122. BOOL rc;
  123. GLYPHCONTEXT glc;
  124. POE_BRUSH_DATA pbdOpaque;
  125. PDD_PDEV ppdev;
  126. DC_BEGIN_FN("OE_SendGlyphs");
  127. rc = FALSE;
  128. // Rasterized fonts are bitmaps - others are PATHOBJ structures.
  129. if (pfo->flFontType & RASTER_FONTTYPE) {
  130. ppdev = (PDD_PDEV)pso->dhpdev;
  131. pddCacheStats[GLYPH].CacheReads += pstro->cGlyphs;
  132. // Make sure we don't exceed our max glyph_out capacity.
  133. if (pstro->cGlyphs <= OE_GL_MAX_INDEX_ENTRIES) {
  134. // The system can only handle 'simple' brushes.
  135. if (OECheckBrushIsSimple(ppdev, pboOpaque, &pbdOpaque)) {
  136. // Get the text fore color.
  137. OEConvertColor(ppdev, &pbdOpaque->back,
  138. pboFore->iSolidColor, NULL);
  139. // Initialize our glyph context structure.
  140. glc.fontId = pfci->fontId;
  141. glc.cacheTag = oeTextOut++;
  142. glc.nCacheHit = 0;
  143. glc.nCacheIndex = 0;
  144. glc.indexNextSend = 0;
  145. glc.cbDataSize = 0;
  146. glc.cbTotalDataSize = 0;
  147. glc.cbBufferSize = 0;
  148. // Cache all glyphs for this message .
  149. if (OECacheGlyphs(pstro, pfo, pfci, &glc)) {
  150. // Send all newly cached glyphs to the client.
  151. // If this is single glyph and we support fast glyph order
  152. // and the glyph data length can fit in one byte. We will
  153. // send the glyph index and data in one order. Note we
  154. // can bypass fragment caching in this case since we don't
  155. // cache fragment of length less than 3 glyphs.
  156. if (OE_SendAsOrder(TS_ENC_FAST_GLYPH_ORDER) &&
  157. (pstro->cGlyphs == 1) && (glc.cbTotalDataSize +
  158. sizeof(UINT16)) <= FIELDSIZE(VARIABLE_GLYPHBYTES,
  159. glyphData)) {
  160. rc = OESendGlyphAndIndexOrder(ppdev, pstro,
  161. pClipRects, prclOpaque, pbdOpaque,
  162. pfci, &glc);
  163. }
  164. else {
  165. if (OESendGlyphs(pso, pstro, pfo, pfci, &glc)) {
  166. // Send glyph index orders to the client.
  167. rc = OESendIndexes(pso, pstro, pfo, pClipRects,
  168. prclOpaque, pbdOpaque, pptlOrg, pfci,
  169. &glc);
  170. }
  171. }
  172. }
  173. }
  174. }
  175. }
  176. DC_END_FN();
  177. return rc;
  178. }
  179. /****************************************************************************/
  180. // DrvBitBlt - see NT DDK documentation.
  181. /****************************************************************************/
  182. BOOL RDPCALL DrvBitBlt(
  183. SURFOBJ *psoTrg,
  184. SURFOBJ *psoSrc,
  185. SURFOBJ *psoMask,
  186. CLIPOBJ *pco,
  187. XLATEOBJ *pxlo,
  188. RECTL *prclTrg,
  189. POINTL *pptlSrc,
  190. POINTL *pptlMask,
  191. BRUSHOBJ *pbo,
  192. POINTL *pptlBrush,
  193. ROP4 rop4)
  194. {
  195. PDD_PDEV ppdev = (PDD_PDEV)psoTrg->dhpdev;
  196. PDD_DSURF pdsurfTrg = NULL;
  197. PDD_DSURF pdsurfSrc = NULL;
  198. SURFOBJ *psoSrcArg = NULL;
  199. SURFOBJ *psoTrgArg = NULL;
  200. BOOL rc;
  201. BYTE rop3;
  202. RECTL bounds;
  203. OE_ENUMRECTS ClipRects;
  204. DC_BEGIN_FN("DrvBitBlt");
  205. // Sometimes we're called after being disconnected.
  206. if (ddConnected && pddShm != NULL) {
  207. psoSrcArg = psoSrc;
  208. psoTrgArg = psoTrg;
  209. psoTrg = OEGetSurfObjBitmap(psoTrg, &pdsurfTrg);
  210. if (psoSrc != NULL)
  211. psoSrc = OEGetSurfObjBitmap(psoSrc, &pdsurfSrc);
  212. DD_UPD_STATE(DD_BITBLT);
  213. INC_OUTCOUNTER(OUT_BITBLT_ALL);
  214. if (((pco == NULL) && (psoTrg->sizlBitmap.cx >= prclTrg->right) &&
  215. (psoTrg->sizlBitmap.cy >= prclTrg->bottom)) ||
  216. ((pco != NULL) && (psoTrg->sizlBitmap.cx >= pco->rclBounds.right) &&
  217. (psoTrg->sizlBitmap.cy >= pco->rclBounds.bottom))) {
  218. // Punt the call back to GDI to do the drawing.
  219. rc = EngBitBlt(psoTrg, psoSrc, psoMask, pco, pxlo, prclTrg, pptlSrc,
  220. pptlMask, pbo, pptlBrush, rop4);
  221. }
  222. else {
  223. // If the bounding rectangle is greater the frame buffer, something
  224. // is really wrong here. This means the desktop surface size and
  225. // the framebuffer is not matched up. We need to bail out here.
  226. rc = FALSE;
  227. }
  228. if (rc) {
  229. TRC_DBG((TB, "ppdev(%p) psoSrc(%p) psoTrg(%p)"
  230. "s[sizl(%d,%d) format(%d) type(%d)]"
  231. "d[sizl(%d,%d) format(%d) type(%d)]"
  232. "src(%d,%d) dst(%d,%d,%d,%d), rop %#x",
  233. ppdev, psoSrc, psoTrg,
  234. (psoSrc != NULL) ? psoSrc->sizlBitmap.cx : -1,
  235. (psoSrc != NULL) ? psoSrc->sizlBitmap.cy : -1,
  236. (psoSrc != NULL) ? psoSrc->iBitmapFormat : -1,
  237. (psoSrc != NULL) ? psoSrc->iType : -1,
  238. (psoTrg != NULL) ? psoTrg->sizlBitmap.cx : -1,
  239. (psoTrg != NULL) ? psoTrg->sizlBitmap.cy : -1,
  240. (psoTrg != NULL) ? psoTrg->iBitmapFormat : -1,
  241. (psoTrg != NULL) ? psoTrg->iType : -1,
  242. (pptlSrc != NULL) ? pptlSrc->x : -1,
  243. (pptlSrc != NULL) ? pptlSrc->y : -1,
  244. prclTrg->left,
  245. prclTrg->top,
  246. prclTrg->right,
  247. prclTrg->bottom,
  248. rop4));
  249. // If ppdev is NULL then this is a blt to GDI managed memory bitmap,
  250. // so there is no need to accumulate any output.
  251. if (ppdev != NULL) {
  252. // Get the bounding rectangle for the operation. According to
  253. // the DDK, this rectangle is always well-ordered and does not
  254. // need to be rearranged. Clip it to 16 bits.
  255. bounds = *prclTrg;
  256. OEClipRect(&bounds);
  257. // If this function is changed, need to know that psoTrg points
  258. // to the GDI DIB bitmap in offscreen bitmap case.
  259. }
  260. else {
  261. // if ppdev is NULL, we are blt to GDI managed bitmap,
  262. // so, the dhurf of the target surface should be NULL
  263. TRC_ASSERT((pdsurfTrg == NULL),
  264. (TB, "NULL ppdev - psoTrg has non NULL dhsurf"));
  265. TRC_NRM((TB, "NULL ppdev - blt to GDI managed bitmap"));
  266. DC_QUIT;
  267. }
  268. }
  269. else {
  270. TRC_ERR((TB, "EngBitBlt failed"));
  271. DC_QUIT;
  272. }
  273. }
  274. else {
  275. if (psoTrg->iType == STYPE_DEVBITMAP) {
  276. psoTrg = OEGetSurfObjBitmap(psoTrg, &pdsurfTrg);
  277. if (psoSrc != NULL)
  278. psoSrc = OEGetSurfObjBitmap(psoSrc, &pdsurfSrc);
  279. // Punt the call back to GDI to do the drawing.
  280. rc = EngBitBlt(psoTrg, psoSrc, psoMask, pco, pxlo, prclTrg, pptlSrc,
  281. pptlMask, pbo, pptlBrush, rop4);
  282. }
  283. else {
  284. TRC_ERR((TB, "Called when disconnected"));
  285. rc = TRUE;
  286. }
  287. goto CalledOnDisconnected;
  288. }
  289. if ((psoTrg->hsurf == ppdev->hsurfFrameBuf) ||
  290. (!(pdsurfTrg->flags & DD_NO_OFFSCREEN))) {
  291. // Send a switch surface PDU if the destination surface is different
  292. // from last drawing order. If we failed to send the PDU, we will
  293. // just have to bail on this drawing order.
  294. if (!OESendSwitchSurfacePDU(ppdev, pdsurfTrg)) {
  295. TRC_ERR((TB, "failed to send the switch surface PDU"));
  296. DC_QUIT;
  297. }
  298. }
  299. else {
  300. // If noOffscreen flag is on, we will bail on sending
  301. // the client any further offscreen rendering. And we'll send the
  302. // final offscreen to screen blt as regular memblt.
  303. TRC_NRM((TB, "Offscreen blt bail"));
  304. INC_OUTCOUNTER(OUT_BITBLT_NOOFFSCR);
  305. DC_QUIT;
  306. }
  307. // Check if this 4-way ROP simplifies to a 3-way ROP. A 4-way ROP
  308. // contains two 3-way ROPS, one for each setting of a mask bit - the
  309. // high ROP3 corresponds to a value of zero in the mask bit. If the two
  310. // 3-way ROPs are the same, we know the 4-way ROP is a 3-way ROP.
  311. rop3 = ROP3_HIGH_FROM_ROP4(rop4);
  312. if (ROP3_LOW_FROM_ROP4(rop4) == rop3) {
  313. // Take the high byte as the 3-way ROP.
  314. TRC_DBG((TB, "4-way ROP %04x is really 3-way %02x", rop4, rop3));
  315. // Check if we are allowed to send the ROP.
  316. if (OESendRop3AsOrder(rop3)) {
  317. unsigned RetVal;
  318. // Get the intersection between the dest rect and the
  319. // clip rects. Check for overcomplicated or nonintersecting
  320. // clipping.
  321. RetVal = OEGetIntersectingClipRects(pco, &bounds, CD_ANY,
  322. &ClipRects);
  323. if (RetVal == CLIPRECTS_TOO_COMPLEX) {
  324. TRC_NRM((TB, "Clipping is too complex"));
  325. INC_OUTCOUNTER(OUT_BITBLT_SDA_COMPLEXCLIP);
  326. if (oeLastDstSurface == NULL)
  327. ADD_INCOUNTER(IN_SDA_BITBLT_COMPLEXCLIP_AREA,
  328. COM_SIZEOF_RECT(bounds));
  329. goto SendScreenData;
  330. }
  331. else if (RetVal == CLIPRECTS_NO_INTERSECTIONS) {
  332. TRC_NRM((TB, "Clipping does not intersect destrect"));
  333. DC_QUIT;
  334. }
  335. #ifdef PERF_SPOILING
  336. else if (psoTrg->hsurf == ppdev->hsurfFrameBuf) {
  337. // This is the case where the bitblt lies completely within
  338. // the current screen-data dirty-rect, so we can just send
  339. // it as screendata. (Actually, it's benign to goto
  340. // SendScreenData, since the new RECT will just be collapsed
  341. // into the current screen-data dirty-rects.)
  342. if (ClipRects.rects.c==0) {
  343. if (OEIsSDAIncluded(&bounds, 1)) {
  344. goto SendScreenData;
  345. }
  346. } else {
  347. if (OEIsSDAIncluded(&ClipRects.rects.arcl[0],
  348. ClipRects.rects.c)) {
  349. goto SendScreenData;
  350. }
  351. }
  352. }
  353. #endif
  354. }
  355. else {
  356. TRC_NRM((TB, "Cannot send ROP %d", rop3));
  357. INC_OUTCOUNTER(OUT_BITBLT_SDA_NOROP3);
  358. if (oeLastDstSurface == NULL)
  359. ADD_INCOUNTER(IN_SDA_BITBLT_NOROP3_AREA,
  360. COM_SIZEOF_RECT(bounds));
  361. goto SendScreenData;
  362. }
  363. }
  364. else {
  365. TRC_NRM((TB, "4-way ROP %08x", rop4));
  366. INC_OUTCOUNTER(OUT_BITBLT_SDA_ROP4);
  367. if (oeLastDstSurface == NULL)
  368. ADD_INCOUNTER(IN_SDA_BITBLT_ROP4_AREA, COM_SIZEOF_RECT(bounds));
  369. goto SendScreenData;
  370. }
  371. // Determine the blt type. It can be one of the following. Note that the
  372. // following if statements are carefully tuned based on the most common
  373. // blt types seen in WinStone/WinBench, to minimize mispredictions.
  374. // In order of frequency:
  375. //
  376. // OpaqueRect: A destination-only blt where the output bits are overlaid
  377. // on the output screen and the pattern is a solid color.
  378. // PatBlt: An OpaqueRect with a non-solid-color pattern.
  379. // MemBlt: A memory-to-memory/screen blt with no pattern.
  380. // Mem3Blt: A memory-to-memory/screen blt with an accompanying pattern.
  381. // DstBlt: Destination-only blt; the output is dependent on the screen
  382. // contents.
  383. // ScrBlt: A screen-to-screen blt (copy screen contents).
  384. // Check for destination only BLTs (ie. independent of source bits).
  385. if ((psoSrc == NULL) || ROP3_NO_SOURCE(rop3)) {
  386. // Check for a pattern or true destination BLT.
  387. if (!ROP3_NO_PATTERN(rop3)) {
  388. // Check whether we can encode the PatBlt as an OpaqueRect.
  389. // It must be solid with a PATCOPY rop.
  390. if (pbo->iSolidColor != -1 && rop3 == OE_PATCOPY_ROP) {
  391. if (!OEEncodeOpaqueRect(&bounds, pbo, ppdev, &ClipRects)) {
  392. // Something went wrong with the encoding, so skip
  393. // to the end to add this operation to the SDA.
  394. if (oeLastDstSurface == NULL)
  395. ADD_INCOUNTER(IN_SDA_OPAQUERECT_AREA,
  396. COM_SIZEOF_RECT(bounds));
  397. goto SendScreenData;
  398. }
  399. }
  400. else if (!OEEncodePatBlt(ppdev, pbo, &bounds, pptlBrush, rop3,
  401. &ClipRects)) {
  402. // Something went wrong with the encoding, so skip to
  403. // the end to add this operation to the SDA.
  404. if (oeLastDstSurface == NULL)
  405. ADD_INCOUNTER(IN_SDA_PATBLT_AREA,
  406. COM_SIZEOF_RECT(bounds));
  407. goto SendScreenData;
  408. }
  409. }
  410. else {
  411. if (!OEEncodeDstBlt(&bounds, rop3, ppdev, &ClipRects)) {
  412. if (oeLastDstSurface == NULL)
  413. ADD_INCOUNTER(IN_SDA_DSTBLT_AREA,
  414. COM_SIZEOF_RECT(bounds));
  415. goto SendScreenData;
  416. }
  417. }
  418. }
  419. else {
  420. // We have a source BLT, check whether we have screen or memory BLTs.
  421. if (psoSrc->hsurf != ppdev->hsurfFrameBuf) {
  422. // The source surface is memory, so this is either memory to screen
  423. // blt or memory to offscreen blt
  424. if (psoTrg->hsurf == ppdev->hsurfFrameBuf || pdsurfTrg != NULL) {
  425. // We only support destination surface as the screen surface
  426. // or driver managed offscreen surface
  427. unsigned OffscrBitmapId = 0;
  428. MEMBLT_ORDER_EXTRA_INFO MemBltExtraInfo;
  429. // Fill in extra info structure.
  430. MemBltExtraInfo.pSource = psoSrc;
  431. MemBltExtraInfo.pDest = psoTrg;
  432. MemBltExtraInfo.pXlateObj = pxlo;
  433. MemBltExtraInfo.bNoFastPathCaching = FALSE;
  434. MemBltExtraInfo.iDeviceUniq = psoSrcArg ? (psoSrcArg->iUniq) : 0;
  435. #ifdef PERF_SPOILING
  436. MemBltExtraInfo.bIsPrimarySurface = (psoTrg->hsurf == ppdev->hsurfFrameBuf);
  437. #endif
  438. if (pdsurfSrc != NULL &&
  439. (psoTrg->hsurf == ppdev->hsurfFrameBuf ||
  440. pdsurfSrc == pdsurfTrg)) {
  441. if ((pddShm->sbc.offscreenCacheInfo.supportLevel > TS_OFFSCREEN_DEFAULT) &&
  442. (sbcEnabled & SBC_OFFSCREEN_CACHE_ENABLED)) {
  443. if (pdsurfSrc->shareId == pddShm->shareId) {
  444. // We are blting from an offscreen surface to client screen,
  445. // Or from one area of an offscreen to another area of the
  446. // same offscreen bitmap
  447. if (!(pdsurfSrc->flags & DD_NO_OFFSCREEN)) {
  448. OffscrBitmapId = pdsurfSrc->bitmapId;
  449. CH_TouchCacheEntry(sbcOffscreenBitmapCacheHandle,
  450. OffscrBitmapId);
  451. }
  452. else {
  453. // If the source surface is offscreen surface, and we
  454. // have the noOffscreen flag on, this means we will
  455. // send the bitmap bits as regular memory bitmap bits
  456. // This means that the offscreen bitmap has been evicted
  457. // out of the offscreen cache or screen data needs to be
  458. // sent for the offscreen bitmap
  459. TRC_ALT((TB, "noOffscreen flag is on for %p", pdsurfSrc));
  460. OffscrBitmapId = CH_KEY_UNCACHABLE;
  461. }
  462. }
  463. else {
  464. // This is the stale offscreen bitmap from last disconnected
  465. // session. We need to turn off the offscreen flag on this
  466. TRC_ALT((TB, "Need to turn off this offscreen bitmap"));
  467. pdsurfSrc->flags |= DD_NO_OFFSCREEN;
  468. OffscrBitmapId = CH_KEY_UNCACHABLE;
  469. }
  470. }
  471. else {
  472. // These are offscreen bitmaps from the disconnected session
  473. // or client has sent an error pdu,
  474. // We have to treat them as memory bitmap now since the client
  475. // doesn't have the offscreen bitmap locally
  476. TRC_ALT((TB, "Need to turn off this offscreen bitmap"));
  477. pdsurfSrc->flags |= DD_NO_OFFSCREEN;
  478. OffscrBitmapId = CH_KEY_UNCACHABLE;
  479. }
  480. }
  481. else {
  482. OffscrBitmapId = CH_KEY_UNCACHABLE;
  483. }
  484. // We send MemBlts for clients that allow offscreen rendering
  485. // or if iUniq is nonzero. Zero iUniq is supposed to be a GDI
  486. // hack in NT5 that tells us that Windows Layering for window
  487. // borders is being used. We would want to send screen data
  488. // for these cases to prevent flushing the bitmap cache.
  489. // Unfortunately, quite a few bitmaps seem to also have
  490. // iUniq==0, so for 5.1 clients using offscreen we save some
  491. // bandwidth instead of sending screen data. The Windows
  492. // Layering stuff uses offscreen rendering anyway...
  493. if (psoSrcArg->iUniq != 0) {
  494. // We have a memory to screen BLT, check which type.
  495. if (ROP3_NO_PATTERN(rop3)) {
  496. // Make sure orders are not turned off.
  497. if (OE_SendAsOrder(TS_ENC_MEMBLT_R2_ORDER)) {
  498. if (!OEEncodeMemBlt(&bounds, &MemBltExtraInfo,
  499. TS_ENC_MEMBLT_R2_ORDER, OffscrBitmapId,
  500. rop3, pptlSrc, pptlBrush, pbo, ppdev,
  501. &ClipRects)) {
  502. if (oeLastDstSurface == NULL)
  503. ADD_INCOUNTER(IN_SDA_MEMBLT_AREA,
  504. COM_SIZEOF_RECT(bounds));
  505. goto SendScreenData;
  506. }
  507. }
  508. else {
  509. TRC_NRM((TB, "MemBlt order not allowed"));
  510. INC_OUTCOUNTER(OUT_BITBLT_SDA_UNSUPPORTED);
  511. goto SendScreenData;
  512. }
  513. }
  514. else {
  515. // Make sure orders are not turned off.
  516. if (OE_SendAsOrder(TS_ENC_MEM3BLT_R2_ORDER)) {
  517. if (!OEEncodeMemBlt(&bounds, &MemBltExtraInfo,
  518. TS_ENC_MEM3BLT_R2_ORDER, OffscrBitmapId,
  519. rop3, pptlSrc, pptlBrush, pbo, ppdev,
  520. &ClipRects)) {
  521. if (oeLastDstSurface == NULL)
  522. ADD_INCOUNTER(IN_SDA_MEM3BLT_AREA,
  523. COM_SIZEOF_RECT(bounds));
  524. goto SendScreenData;
  525. }
  526. }
  527. else {
  528. TRC_NRM((TB, "Mem3Blt order not allowed"));
  529. INC_OUTCOUNTER(OUT_BITBLT_SDA_UNSUPPORTED);
  530. goto SendScreenData;
  531. }
  532. }
  533. }
  534. else {
  535. // To avoid Windows Layering Mem to Mem Blt flush bitmap caches
  536. // on the client, we have to send it as screen data instead
  537. TRC_NRM((TB, "Get a windows layering mem-mem blt, "
  538. "send as screen data"));
  539. INC_OUTCOUNTER(OUT_BITBLT_SDA_WINDOWSAYERING);
  540. goto SendScreenData;
  541. }
  542. }
  543. else {
  544. TRC_ALT((TB, "Unsupported MEM to MEM blt!"));
  545. DC_QUIT;
  546. }
  547. }
  548. else {
  549. // The source surface is screen, so this is either screen to screen
  550. // blt or screen to offscreen memory blt
  551. if (psoTrg->hsurf == ppdev->hsurfFrameBuf || pdsurfTrg != NULL) {
  552. // We only support destination only screen BLTs (ie. no
  553. // patterns allowed).
  554. if (ROP3_NO_PATTERN(rop3)) {
  555. if (!OEEncodeScrBlt(&bounds, rop3, pptlSrc, ppdev,
  556. &ClipRects, pco)) {
  557. if (oeLastDstSurface == NULL)
  558. ADD_INCOUNTER(IN_SDA_SCRBLT_AREA,
  559. COM_SIZEOF_RECT(bounds));
  560. goto SendScreenData;
  561. }
  562. }
  563. else {
  564. TRC_ALT((TB, "Unsupported screen ROP %x", rop3));
  565. if (oeLastDstSurface == NULL)
  566. ADD_INCOUNTER(IN_SDA_SCRSCR_FAILROP_AREA,
  567. COM_SIZEOF_RECT(bounds));
  568. INC_OUTCOUNTER(OUT_BITBLT_SDA_UNSUPPORTED);
  569. goto SendScreenData;
  570. }
  571. }
  572. else {
  573. TRC_NRM((TB, "Unsupported SCR to MEM blt!"));
  574. DC_QUIT;
  575. }
  576. }
  577. }
  578. // We added an order to the list, increment global counts.
  579. goto PostSDA;
  580. SendScreenData:
  581. if (psoTrg->hsurf == ppdev->hsurfFrameBuf) {
  582. INC_OUTCOUNTER(OUT_BITBLT_SDA);
  583. OEClipAndAddScreenDataArea(&bounds, pco);
  584. }
  585. else {
  586. // if we can't send orders for offscreen rendering, we will
  587. // bail offscreen support for this bitmap
  588. TRC_ALT((TB, "screen data call for offscreen rendering"));
  589. // Remove the bitmap from the offscreen bitmap cache
  590. if (!(pdsurfTrg->flags & DD_NO_OFFSCREEN))
  591. CH_RemoveCacheEntry(sbcOffscreenBitmapCacheHandle,
  592. pdsurfTrg->bitmapId);
  593. DC_QUIT;
  594. }
  595. PostSDA:
  596. SCH_DDOutputAvailable(ppdev, FALSE);
  597. DC_EXIT_POINT:
  598. // EngStretchBlt called from DrvStretchBlt sometimes calls DrvBitBlt to
  599. // do its drawing. Clear the flag here to tell DrvStretchBlt that it
  600. // doesn't need to send any output.
  601. oeAccumulateStretchBlt = FALSE;
  602. CalledOnDisconnected:
  603. DC_END_FN();
  604. return rc;
  605. }
  606. /****************************************************************************/
  607. // DrvStretchBlt - see NT DDK documentation.
  608. /****************************************************************************/
  609. BOOL RDPCALL DrvStretchBlt(
  610. SURFOBJ *psoTrg,
  611. SURFOBJ *psoSrc,
  612. SURFOBJ *psoMask,
  613. CLIPOBJ *pco,
  614. XLATEOBJ *pxlo,
  615. COLORADJUSTMENT *pca,
  616. POINTL *pptlHTOrg,
  617. RECTL *prclTrg,
  618. RECTL *prclSrc,
  619. POINTL *pptlMask,
  620. ULONG iMode)
  621. {
  622. PDD_PDEV ppdev = (PDD_PDEV)psoTrg->dhpdev;
  623. PDD_DSURF pdsurfTrg = NULL;
  624. PDD_DSURF pdsurfSrc = NULL;
  625. SURFOBJ *psoTrgBitmap, *psoSrcBitmap;
  626. BOOL rc = TRUE;
  627. POINTL ptlSrc;
  628. RECTL rclTrg;
  629. int bltWidth;
  630. int bltHeight;
  631. OE_ENUMRECTS ClipRects;
  632. MEMBLT_ORDER_EXTRA_INFO MemBltExtraInfo;
  633. DC_BEGIN_FN("DrvStretchBlt");
  634. // psoTrg and psoSrc should not be NULL.
  635. psoTrgBitmap = OEGetSurfObjBitmap(psoTrg, &pdsurfTrg);
  636. psoSrcBitmap = OEGetSurfObjBitmap(psoSrc, &pdsurfSrc);
  637. // Sometimes, we're called after being disconnected. This is a pain,
  638. // but we can trap it here.
  639. if (ddConnected && pddShm != NULL) {
  640. INC_OUTCOUNTER(OUT_STRTCHBLT_ALL);
  641. // Get the destination rectangle, ordering it properly if necessary.
  642. // Note we don't have to order the src rect -- according to the
  643. // DDK it is guaranteed well-ordered. Clip the result to 16 bits.
  644. RECT_FROM_RECTL(rclTrg, (*prclTrg));
  645. OEClipRect(&rclTrg);
  646. if ((psoTrgBitmap->hsurf == ppdev->hsurfFrameBuf) ||
  647. (!(pdsurfTrg->flags & DD_NO_OFFSCREEN))) {
  648. // Send a switch surface PDU if the destination surface is different
  649. // from last drawing order. If we failed to send the PDU, we will
  650. // just have to bail on this drawing order.
  651. if (!OESendSwitchSurfacePDU(ppdev, pdsurfTrg)) {
  652. TRC_ERR((TB, "failed to send the switch surface PDU"));
  653. goto SendSDA;
  654. }
  655. }
  656. else {
  657. // if noOffscreen flag is on, we will bail on sending
  658. // the client any further offscreen rendering. And will send the
  659. // final offscreen to screen blt as regular memblt.
  660. TRC_NRM((TB, "Offscreen blt bail"));
  661. goto SendSDA;
  662. }
  663. // Check that we have a valid ROP code. The NT DDK states that
  664. // the ROP code for the StretchBlt is implicit in the mask
  665. // specification. If a mask is specified, we have an implicit
  666. // ROP4 of 0xCCAA, otherwise the code is 0xCCCC.
  667. //
  668. // Our BitBlt code only encodes orders for ROP3s, so we must
  669. // throw any StretchBlts with a mask.
  670. if (psoMask == NULL) {
  671. unsigned RetVal;
  672. // Get the intersection between the dest rect and the
  673. // clip rects. Check for overcomplicated or nonintersecting
  674. // clipping.
  675. RetVal = OEGetIntersectingClipRects(pco, &rclTrg, CD_ANY,
  676. &ClipRects);
  677. if (RetVal == CLIPRECTS_TOO_COMPLEX) {
  678. TRC_NRM((TB, "Clipping is too complex"));
  679. INC_OUTCOUNTER(OUT_STRTCHBLT_SDA_COMPLEXCLIP);
  680. goto SendSDA;
  681. }
  682. else if (RetVal == CLIPRECTS_NO_INTERSECTIONS) {
  683. TRC_NRM((TB, "Clipping does not intersect destrect"));
  684. goto PostSDA;
  685. }
  686. }
  687. else {
  688. TRC_NRM((TB, "Mask specified"));
  689. INC_OUTCOUNTER(OUT_STRTCHBLT_SDA_MASK);
  690. goto SendSDA;
  691. }
  692. }
  693. else {
  694. if (psoTrg->iType == STYPE_DEVBITMAP) {
  695. rc = EngStretchBlt(psoTrgBitmap, psoSrcBitmap, psoMask, pco, pxlo,
  696. pca, pptlHTOrg, prclTrg, prclSrc, pptlMask, iMode);
  697. }
  698. else {
  699. TRC_ERR((TB, "Called when disconnected"));
  700. }
  701. goto CalledOnDisconnected;
  702. }
  703. // DrvStretchBlt can be called with unclipped coords, but we need clipped
  704. // coords. We must therefore perform clipping here to avoid faults in
  705. // callbacks to EngBitBlt from DrvBitBlt.
  706. // First clip the destination rect to the destination surface.
  707. ptlSrc.x = prclSrc->left;
  708. ptlSrc.y = prclSrc->top;
  709. if (rclTrg.left < 0) {
  710. ptlSrc.x += (-rclTrg.left);
  711. rclTrg.left = 0;
  712. TRC_NRM((TB, "Clip trg left"));
  713. }
  714. if (rclTrg.top < 0) {
  715. ptlSrc.y += (-rclTrg.top);
  716. rclTrg.top = 0;
  717. TRC_NRM((TB, "Clip trg top"));
  718. }
  719. // We need to clip to the screen size instead of the size of psoTrg
  720. // (the screen surface) here - after reconnection at lower resolution
  721. // psoTrg->sizlBitmap can be larger than the real screen size.
  722. rclTrg.right = min(rclTrg.right, ppdev->cxScreen);
  723. rclTrg.bottom = min(rclTrg.bottom, ppdev->cyScreen);
  724. // Check if we have a degenerate (ie. no stretch) case. Use the
  725. // original coords, because it is possible for one of the rects to
  726. // be flipped to perform an inverted blt.
  727. if ((prclSrc->right - prclSrc->left == prclTrg->right - prclTrg->left) &&
  728. (prclSrc->bottom - prclSrc->top == prclTrg->bottom - prclTrg->top)) {
  729. // Adjust the destination blt size to keep the source rect within
  730. // the source bitmap, if necessary. Note this should be done here
  731. // instead of before determining 1:1 stretch since the amount to
  732. // change rclTrg by would vary according to the stretch ratio.
  733. if (ptlSrc.x < 0) {
  734. rclTrg.left += (-ptlSrc.x);
  735. ptlSrc.x = 0;
  736. TRC_NRM((TB, "Clip src left"));
  737. }
  738. if (ptlSrc.y < 0) {
  739. rclTrg.top += (-ptlSrc.y);
  740. ptlSrc.y = 0;
  741. TRC_NRM((TB, "Clip src top"));
  742. }
  743. bltWidth = rclTrg.right - rclTrg.left;
  744. if ((ptlSrc.x + bltWidth) > psoSrcBitmap->sizlBitmap.cx) {
  745. rclTrg.right -= ((ptlSrc.x + bltWidth) -
  746. psoSrcBitmap->sizlBitmap.cx);
  747. TRC_NRM((TB, "Clip src right"));
  748. }
  749. bltHeight = rclTrg.bottom - rclTrg.top;
  750. if ((ptlSrc.y + bltHeight) > psoSrcBitmap->sizlBitmap.cy) {
  751. rclTrg.bottom -= ((ptlSrc.y + bltHeight) -
  752. psoSrcBitmap->sizlBitmap.cy);
  753. TRC_NRM((TB, "Clip src bottom"));
  754. }
  755. // Check again for complete clipping out.
  756. if (rclTrg.right > rclTrg.left && rclTrg.bottom > rclTrg.top) {
  757. INC_OUTCOUNTER(OUT_STRTCHBLT_BITBLT);
  758. rc = DrvBitBlt(psoTrg, psoSrc, psoMask, pco, pxlo, &rclTrg,
  759. &ptlSrc, pptlMask, NULL, NULL, 0xCCCC);
  760. }
  761. else {
  762. TRC_NRM((TB, "StretchBlt completely clipped"));
  763. }
  764. goto PostSDA;
  765. }
  766. else {
  767. // Non-degenerate case -- we are really stretching.
  768. // Here we simply blt to the screen, then do a bitblt specifying the
  769. // destination rect to the screen as the source rect.
  770. // EngStretchBlt sometimes calls DrvBitBlt to do its drawing. Set
  771. // the flag here before we call to default to sending SDA output.
  772. // If DrvBitBlt has done all the processing it needs to it will
  773. // clear the flag.
  774. oeAccumulateStretchBlt = TRUE;
  775. rc = EngStretchBlt(psoTrgBitmap, psoSrcBitmap, psoMask, pco, pxlo,
  776. pca, pptlHTOrg, prclTrg, prclSrc, pptlMask, iMode);
  777. if (rc && oeAccumulateStretchBlt) {
  778. // DrvBitBlt was not called already, and we're drawing to our
  779. // screen surface.
  780. // Fill in extra info structure. Note NULL pxlo meaning no
  781. // color translation -- we're drawing from screen to screen.
  782. // Also, because we are caching directly from the screen
  783. // we need to turn off fast-path caching -- sometimes we
  784. // get multiple StretchBlts to nearby areas of the screen,
  785. // where we may fast-path cache a block that is drawn again
  786. // on a successive StretchBlt, thereby drawing the wrong tile
  787. // at the client.
  788. MemBltExtraInfo.pSource = psoTrgBitmap;
  789. MemBltExtraInfo.pDest = psoTrgBitmap;
  790. MemBltExtraInfo.pXlateObj = NULL;
  791. MemBltExtraInfo.bNoFastPathCaching = TRUE;
  792. MemBltExtraInfo.iDeviceUniq = psoTrg ? (psoTrg->iUniq) : 0;
  793. #ifdef PERF_SPOILING
  794. MemBltExtraInfo.bIsPrimarySurface = (psoTrgBitmap->hsurf == ppdev->hsurfFrameBuf);
  795. #endif
  796. // Make sure orders are not turned off.
  797. if (OE_SendAsOrder(TS_ENC_MEMBLT_R2_ORDER)) {
  798. // Note pco is clip obj for destination and so is applicable
  799. // here. We also use ROP3 of 0xCC meaning copy src->dest.
  800. if (!OEEncodeMemBlt(&rclTrg, &MemBltExtraInfo,
  801. TS_ENC_MEMBLT_R2_ORDER, CH_KEY_UNCACHABLE, 0xCC,
  802. (PPOINTL)&rclTrg.left, NULL, NULL, ppdev,
  803. &ClipRects))
  804. goto SendSDAPostEngStretchBlt;
  805. }
  806. else {
  807. TRC_NRM((TB, "MemBlt order not allowed"));
  808. INC_OUTCOUNTER(OUT_BITBLT_SDA_UNSUPPORTED);
  809. goto SendSDAPostEngStretchBlt;
  810. }
  811. }
  812. goto PostSDA;
  813. }
  814. SendSDA:
  815. // Accumulate screen data if necessary. EngStretchBlt may have
  816. // called DrvCopyBits or DrvBitblt to do the work. These two will
  817. // have accumulated the data, so no need to do it here.
  818. TRC_NRM((TB, "***Add SDA for STRETCHBLT"));
  819. // EngStretchBlt sometimes calls DrvBitBlt to do its drawing. Set
  820. // the flag here before we call to default to sending SDA output.
  821. // If DrvBitBlt has done all the processing it needs to it will
  822. // clear the flag.
  823. oeAccumulateStretchBlt = TRUE;
  824. rc = EngStretchBlt(psoTrgBitmap, psoSrcBitmap, psoMask, pco, pxlo, pca,
  825. pptlHTOrg, prclTrg, prclSrc, pptlMask, iMode);
  826. if (oeAccumulateStretchBlt) {
  827. SendSDAPostEngStretchBlt:
  828. if (psoTrgBitmap->hsurf == ppdev->hsurfFrameBuf) {
  829. INC_OUTCOUNTER(OUT_STRTCHBLT_SDA);
  830. SCH_DDOutputAvailable(ppdev, FALSE);
  831. }
  832. else {
  833. // if we can't send orders for offscreen rendering, we will
  834. // bail offscreen support for this bitmap
  835. TRC_ALT((TB, "screen data call for offscreen rendering"));
  836. if (!(pdsurfTrg->flags & DD_NO_OFFSCREEN))
  837. CH_RemoveCacheEntry(sbcOffscreenBitmapCacheHandle,
  838. pdsurfTrg->bitmapId);
  839. }
  840. }
  841. PostSDA:
  842. CalledOnDisconnected:
  843. DC_END_FN();
  844. return rc;
  845. }
  846. /****************************************************************************/
  847. // DrvCopyBits - see NT DDK documentation.
  848. /****************************************************************************/
  849. BOOL RDPCALL DrvCopyBits(
  850. SURFOBJ *psoTrg,
  851. SURFOBJ *psoSrc,
  852. CLIPOBJ *pco,
  853. XLATEOBJ *pxlo,
  854. RECTL *prclTrg,
  855. POINTL *pptlSrc)
  856. {
  857. BOOL rc;
  858. DC_BEGIN_FN("DrvCopyBits");
  859. if (ddConnected) {
  860. INC_OUTCOUNTER(OUT_COPYBITS_ALL);
  861. // CopyBits is a fast path for the NT display drivers. In our case it
  862. // can always be processed as a BitBlt with copy ROP.
  863. rc = DrvBitBlt(psoTrg, psoSrc, NULL, pco, pxlo, prclTrg, pptlSrc,
  864. NULL, NULL, NULL, 0xCCCC);
  865. }
  866. else {
  867. PDD_DSURF pdsurfTrg;
  868. PDD_DSURF pdsurfSrc;
  869. TRC_NRM((TB, "Called when disconnected"));
  870. TRC_ASSERT((psoSrc != NULL),(TB,"NULL source surface!"));
  871. // We can get called by GDI after disconnection to translate offscreen
  872. // bitmap surfaces from the DD-specific representation to a GDI surface,
  873. // for reuse with a different DD. Most often this occurs with Personal
  874. // TS switching between a remote DD, the disconnected DD (tsddd.dll),
  875. // and a hardware DD. For this case we really do need to do the
  876. // CopyBits action. So, we have GDI do it for us since we're really
  877. // already having GDI manage our "internal" representation.
  878. psoTrg = OEGetSurfObjBitmap(psoTrg, &pdsurfTrg);
  879. psoSrc = OEGetSurfObjBitmap(psoSrc, &pdsurfSrc);
  880. rc = EngCopyBits(psoTrg, psoSrc, pco, pxlo, prclTrg, pptlSrc);
  881. if (!rc) {
  882. TRC_ERR((TB,"Post-disc copy: rc=FALSE"));
  883. }
  884. // Must return TRUE to ensure that the PTS console will reconnect
  885. // properly, otherwise the user's machine gets stuck in limbo.
  886. rc = TRUE;
  887. }
  888. DC_END_FN();
  889. return rc;
  890. }
  891. /***************************************************************************/
  892. // OE_SendCreateOffscrBitmapOrder
  893. //
  894. // Send create offscreen bitmap request to client
  895. /***************************************************************************/
  896. BOOL RDPCALL OE_SendCreateOffscrBitmapOrder(
  897. PDD_PDEV ppdev,
  898. SIZEL sizl,
  899. ULONG iFormat,
  900. unsigned clientBitmapId)
  901. {
  902. BOOL rc;
  903. unsigned cbOrderSize, bitmapSize;
  904. PINT_ORDER pOrder;
  905. PTS_CREATE_OFFSCR_BITMAP_ORDER pOffscrBitmapOrder;
  906. DC_BEGIN_FN("OE_SendCreateOffscrBitmapOrder");
  907. // Get the current bitmap Size
  908. if (iFormat < 5) {
  909. bitmapSize = sizl.cx * sizl.cy * (1 << iFormat) / 8;
  910. } else if (iFormat == 5) {
  911. bitmapSize = sizl.cx * sizl.cy * 24 / 8;
  912. } else if (iFormat == 6) {
  913. bitmapSize = sizl.cx * sizl.cy * 32 / 8;
  914. } else {
  915. TRC_NRM((TB, "Bitmap format not supported"));
  916. return FALSE;
  917. }
  918. // The last entry in the delete list will always be the entry we are using
  919. // for create this bitmap. So, remove this from the delete list.
  920. if (sbcNumOffscrBitmapsToDelete) {
  921. TRC_ASSERT((sbcOffscrBitmapsDelList[sbcNumOffscrBitmapsToDelete-1].bitmapId ==
  922. clientBitmapId), (TB, "different bitmap id"));
  923. sbcOffscrBitmapsToDeleteSize -=
  924. sbcOffscrBitmapsDelList[sbcNumOffscrBitmapsToDelete - 1].bitmapSize;
  925. sbcNumOffscrBitmapsToDelete--;
  926. }
  927. // check if we need to send the delete bitmap list. We only need to
  928. // send the list if we are about to exceed client offscreen cache size
  929. // limit.
  930. if (bitmapSize + oeCurrentOffscreenCacheSize + sbcOffscrBitmapsToDeleteSize <=
  931. (pddShm->sbc.offscreenCacheInfo.cacheSize * 1024)) {
  932. cbOrderSize = sizeof(TS_CREATE_OFFSCR_BITMAP_ORDER) -
  933. sizeof(pOffscrBitmapOrder->variableBytes);
  934. } else {
  935. // Note we use the UINT16 at variableBytes for the number of
  936. // bitmaps. Hence, we don't subtract the size of variableBytes here.
  937. cbOrderSize = sizeof(TS_CREATE_OFFSCR_BITMAP_ORDER) + sizeof(UINT16) *
  938. sbcNumOffscrBitmapsToDelete;
  939. }
  940. pOrder = OA_AllocOrderMem(ppdev, cbOrderSize);
  941. if (pOrder != NULL) {
  942. // Fill in the details. This is an alternate secondary order
  943. // type.
  944. pOffscrBitmapOrder = (PTS_CREATE_OFFSCR_BITMAP_ORDER)pOrder->OrderData;
  945. pOffscrBitmapOrder->ControlFlags = (TS_ALTSEC_CREATE_OFFSCR_BITMAP <<
  946. TS_ALTSEC_ORDER_TYPE_SHIFT) | TS_SECONDARY;
  947. pOffscrBitmapOrder->Flags = (UINT16)clientBitmapId;
  948. pOffscrBitmapOrder->cx = (UINT16)sizl.cx;
  949. pOffscrBitmapOrder->cy = (UINT16)sizl.cy;
  950. // Send the delete bitmap list
  951. if (cbOrderSize > sizeof(TS_CREATE_OFFSCR_BITMAP_ORDER)) {
  952. PUINT16_UA pData;
  953. unsigned i;
  954. // This flag indicates that the delete bitmap list is appended.
  955. pOffscrBitmapOrder->Flags |= 0x8000;
  956. pData = (PUINT16_UA)pOffscrBitmapOrder->variableBytes;
  957. *pData++ = (UINT16)sbcNumOffscrBitmapsToDelete;
  958. for (i = 0; i < sbcNumOffscrBitmapsToDelete; i++)
  959. *pData++ = (UINT16)sbcOffscrBitmapsDelList[i].bitmapId;
  960. // Reset the flags.
  961. sbcNumOffscrBitmapsToDelete = 0;
  962. sbcOffscrBitmapsToDeleteSize = 0;
  963. }
  964. INC_OUTCOUNTER(OUT_OFFSCREEN_BITMAP_ORDER);
  965. ADD_OUTCOUNTER(OUT_OFFSCREEN_BITMAP_ORDER_BYTES, cbOrderSize);
  966. OA_AppendToOrderList(pOrder);
  967. rc = TRUE;
  968. }
  969. else {
  970. TRC_ERR((TB,"Unable to alloc heap space"));
  971. rc = FALSE;
  972. }
  973. DC_END_FN();
  974. return rc;
  975. }
  976. /****************************************************************************/
  977. // DrvCreateDeviceBitmap - See NT DDK for documentation
  978. /****************************************************************************/
  979. HBITMAP DrvCreateDeviceBitmap(DHPDEV dhpdev, SIZEL sizl, ULONG iFormat)
  980. {
  981. PDD_PDEV ppdev;
  982. PDD_DSURF pdsurf;
  983. HBITMAP hbmDevice = NULL;
  984. HBITMAP hbmDib;
  985. FLONG flHooks;
  986. SURFOBJ *pso;
  987. unsigned bitmapSize;
  988. ULONG iFormatArg = iFormat;
  989. DC_BEGIN_FN("DrvCreateDeviceBitmap");
  990. if (ddConnected && pddShm != NULL) {
  991. INC_OUTCOUNTER(OUT_OFFSCREEN_BITMAP_ALL);
  992. ppdev = (PDD_PDEV) dhpdev;
  993. if (ddConsole) {
  994. //
  995. // For the console case, since we accept any Format by overwritting it,
  996. // we accept Format=1 (1bpp). This case is not fully supported by GDI.
  997. // So skip it and do as a regular remote session.
  998. //
  999. if (iFormat == 1)
  1000. DC_QUIT;
  1001. iFormat = ppdev->iBitmapFormat;
  1002. }
  1003. if (OEDeviceBitmapCachable(ppdev, sizl, iFormat)) {
  1004. if (iFormat < 5)
  1005. bitmapSize = sizl.cx * sizl.cy * (1 << iFormat) / 8;
  1006. else if (iFormat == 5)
  1007. bitmapSize = sizl.cx * sizl.cy * 24 / 8;
  1008. else if (iFormat == 6)
  1009. bitmapSize = sizl.cx * sizl.cy * 32 / 8;
  1010. else {
  1011. TRC_NRM((TB, "Bitmap format not supported"));
  1012. DC_QUIT;
  1013. }
  1014. goto CreateBitmap;
  1015. }
  1016. else {
  1017. TRC_DBG((TB, "OEDeviceBitmapCachable returns FALSE"));
  1018. DC_QUIT;
  1019. }
  1020. }
  1021. else {
  1022. //TRC_DBG((TB, "Call on disconnected"));
  1023. DC_QUIT;
  1024. }
  1025. CreateBitmap:
  1026. // Create the device surface for this offscreen bitmap.
  1027. // This device surface handle is used to identify the offscreen
  1028. // bitmap in all DrvXXX calls.
  1029. pdsurf = EngAllocMem(FL_ZERO_MEMORY, sizeof(DD_DSURF), DD_ALLOC_TAG);
  1030. if (pdsurf != NULL) {
  1031. // initialize the DD_DSURF fields
  1032. memset(pdsurf, 0, sizeof(DD_DSURF));
  1033. // Create a device bitmap for this offscreen bitmap
  1034. hbmDevice = EngCreateDeviceBitmap((DHSURF) pdsurf, sizl, iFormat);
  1035. if (hbmDevice != NULL) {
  1036. // Get the flHooks flag from the PDEV struct
  1037. flHooks = ppdev->flHooks;
  1038. // Associate the bitmap to the PDEV device
  1039. if (EngAssociateSurface((HSURF) hbmDevice, ppdev->hdevEng,
  1040. flHooks)) {
  1041. // Create a DIB backup bitmap for this offscreen bitmap
  1042. hbmDib = EngCreateBitmap(sizl,
  1043. TS_BYTES_IN_SCANLINE(sizl.cx, ppdev->cClientBitsPerPel),
  1044. ppdev->iBitmapFormat, BMF_TOPDOWN, NULL);
  1045. if (hbmDib) {
  1046. // Associate the bitmap to the PDEV device
  1047. if (EngAssociateSurface((HSURF) hbmDib, ppdev->hdevEng, 0)) {
  1048. // Lock the surface to get the surf obj
  1049. pso = EngLockSurface((HSURF) hbmDib);
  1050. if (pso != NULL)
  1051. {
  1052. int i;
  1053. unsigned clientBitmapId;
  1054. CHDataKeyContext CHContext;
  1055. // Setup offscreen device surface struct
  1056. pdsurf->shareId = pddShm->shareId;
  1057. pdsurf->sizl = sizl;
  1058. pdsurf->iBitmapFormat = iFormat;
  1059. pdsurf->ppdev = ppdev;
  1060. pdsurf->pso = pso;
  1061. pdsurf->flags = 0;
  1062. CH_CreateKeyFromFirstData(&CHContext,
  1063. (BYTE *)(&pdsurf), sizeof(pdsurf));
  1064. // Cache the offscreen bitmap in the cache
  1065. clientBitmapId = CH_CacheKey(
  1066. sbcOffscreenBitmapCacheHandle,
  1067. CHContext.Key1, CHContext.Key2,
  1068. (VOID *)pdsurf);
  1069. if (clientBitmapId != CH_KEY_UNCACHABLE) {
  1070. // send a create offscreen bitmap pdu
  1071. if (OE_SendCreateOffscrBitmapOrder(ppdev,
  1072. sizl, iFormat, clientBitmapId)) {
  1073. // Update the current offscreen cache size
  1074. oeCurrentOffscreenCacheSize += bitmapSize;
  1075. pdsurf->bitmapId = clientBitmapId;
  1076. TRC_NRM((TB, "Created an offscreen bitmap"));
  1077. DC_QUIT;
  1078. } else {
  1079. TRC_ERR((TB, "Failed to send the create bitmap pdu"));
  1080. CH_RemoveCacheEntry(
  1081. sbcOffscreenBitmapCacheHandle, clientBitmapId);
  1082. EngDeleteSurface((HSURF)hbmDevice);
  1083. hbmDevice = NULL;
  1084. DC_QUIT;
  1085. }
  1086. } else {
  1087. TRC_ERR((TB, "Failed to cache the bitmap"));
  1088. EngDeleteSurface((HSURF)hbmDevice);
  1089. hbmDevice = NULL;
  1090. DC_QUIT;
  1091. }
  1092. } else {
  1093. TRC_ERR((TB, "Failed to lock the surfac"));
  1094. EngDeleteSurface((HSURF)hbmDib);
  1095. EngDeleteSurface((HSURF)hbmDevice);
  1096. hbmDevice = NULL;
  1097. DC_QUIT;
  1098. }
  1099. } else {
  1100. TRC_ERR((TB, "Failed to associate the surface to device"));
  1101. EngDeleteSurface((HSURF)hbmDib);
  1102. EngDeleteSurface((HSURF)hbmDevice);
  1103. hbmDevice = NULL;
  1104. DC_QUIT;
  1105. }
  1106. } else {
  1107. TRC_ERR((TB, "Failed to create backup DIB bitmap"));
  1108. EngDeleteSurface((HSURF)hbmDevice);
  1109. hbmDevice = NULL;
  1110. DC_QUIT;
  1111. }
  1112. } else {
  1113. TRC_ERR((TB, "Failed to associate the device surface to the device"));
  1114. EngDeleteSurface((HSURF)hbmDevice);
  1115. hbmDevice = NULL;
  1116. DC_QUIT;
  1117. }
  1118. } else {
  1119. TRC_ERR((TB, "Failed to allocate memory for the device surface"));
  1120. EngFreeMem(pdsurf);
  1121. DC_QUIT;
  1122. }
  1123. } else {
  1124. TRC_ERR((TB, "Failed to allocate memory for the device surface"));
  1125. DC_QUIT;
  1126. }
  1127. DC_EXIT_POINT:
  1128. DC_END_FN();
  1129. return hbmDevice;
  1130. }
  1131. /****************************************************************************/
  1132. // DrvDeleteDeviceBitmap - See NT DDK for documentation
  1133. /****************************************************************************/
  1134. VOID DrvDeleteDeviceBitmap(DHSURF dhsurf)
  1135. {
  1136. PDD_DSURF pdsurf;
  1137. PDD_PDEV ppdev;
  1138. SURFOBJ *psoDib;
  1139. HSURF hsurfDib;
  1140. DC_BEGIN_FN("DrvDeleteDeviceBitmap");
  1141. pdsurf = (PDD_DSURF)dhsurf;
  1142. ppdev = pdsurf->ppdev;
  1143. if (ddConnected && pddShm != NULL) {
  1144. if ((pddShm->sbc.offscreenCacheInfo.supportLevel > TS_OFFSCREEN_DEFAULT) &&
  1145. (sbcEnabled & SBC_OFFSCREEN_CACHE_ENABLED)) {
  1146. if (!(pdsurf->flags & DD_NO_OFFSCREEN) &&
  1147. (pdsurf->shareId == pddShm->shareId)) {
  1148. CH_RemoveCacheEntry(sbcOffscreenBitmapCacheHandle, pdsurf->bitmapId);
  1149. } else {
  1150. // This is when the bitmap is bumped out of the cache
  1151. TRC_NRM((TB, "Failed to find the offscreen bitmap in the cache"));
  1152. DC_QUIT;
  1153. }
  1154. }
  1155. else {
  1156. TRC_ERR((TB, "offscreen rendering is not supported"));
  1157. DC_QUIT;
  1158. }
  1159. }
  1160. else {
  1161. TRC_ERR((TB, "Call on disconnected"));
  1162. DC_QUIT;
  1163. }
  1164. DC_EXIT_POINT:
  1165. // Get the hsurf from the SURFOBJ before we unlock it (it's not
  1166. // legal to dereference psoDib when it's unlocked):
  1167. psoDib = pdsurf->pso;
  1168. if (psoDib) {
  1169. hsurfDib = psoDib->hsurf;
  1170. EngUnlockSurface(psoDib);
  1171. EngDeleteSurface(hsurfDib);
  1172. }
  1173. EngFreeMem(pdsurf);
  1174. DC_END_FN();
  1175. }
  1176. #ifdef DRAW_NINEGRID
  1177. /****************************************************************************/
  1178. // DrvNineGrid - This is to support Whistler Luna Draw9Grid operation
  1179. /****************************************************************************/
  1180. BOOL DrvNineGrid(
  1181. SURFOBJ *psoTrg,
  1182. SURFOBJ *psoSrc,
  1183. CLIPOBJ *pco,
  1184. XLATEOBJ *pxlo,
  1185. PRECTL prclTrg,
  1186. PRECTL prclSrc,
  1187. PNINEGRID png,
  1188. BLENDOBJ* pBlendObj,
  1189. PVOID pvReserved)
  1190. {
  1191. BOOL rc = TRUE;
  1192. SURFOBJ *psoTrgArg;
  1193. SURFOBJ *psoSrcArg;
  1194. PDD_PDEV ppdev = (PDD_PDEV)psoTrg->dhpdev;
  1195. PDD_DSURF pdsurfTrg = NULL;
  1196. PDD_DSURF pdsurfSrc = NULL;
  1197. RECTL bounds;
  1198. OE_ENUMRECTS clipRects;
  1199. unsigned nineGridBitmapId = 0;
  1200. unsigned clipVal;
  1201. DC_BEGIN_FN("DrvNineGrid")
  1202. if (ddConnected && pddShm != NULL) {
  1203. psoTrgArg = psoTrg;
  1204. psoSrcArg = psoSrc;
  1205. // Get the GDI format source and destination bitmaps
  1206. psoTrg = OEGetSurfObjBitmap(psoTrg, &pdsurfTrg);
  1207. if (psoSrc != NULL)
  1208. psoSrc = OEGetSurfObjBitmap(psoSrc, &pdsurfSrc);
  1209. // if the client doesn't support drawninegrid, return false to reroute
  1210. if (sbcDrawNineGridBitmapCacheHandle == NULL || (pddShm != NULL &&
  1211. pddShm->sbc.drawNineGridCacheInfo.supportLevel <= TS_DRAW_NINEGRID_DEFAULT) ||
  1212. !OE_SendAsOrder(TS_ENC_DRAWNINEGRID_ORDER) ||
  1213. !OE_SendAsOrder(TS_ENC_MULTI_DRAWNINEGRID_ORDER) ||
  1214. (ppdev != NULL && !((psoTrg->hsurf == ppdev->hsurfFrameBuf) ||
  1215. (!(pdsurfTrg->flags & DD_NO_OFFSCREEN))))) {
  1216. return EngNineGrid(psoTrgArg, psoSrcArg, pco, pxlo, prclTrg, prclSrc, png,
  1217. pBlendObj, pvReserved);
  1218. }
  1219. //DD_UPD_STATE(DD_BITBLT);
  1220. //INC_OUTCOUNTER(OUT_BITBLT_ALL);
  1221. // Punt the call back to GDI to do the drawing.
  1222. rc = EngNineGrid(psoTrg, psoSrc, pco, pxlo, prclTrg, prclSrc, png,
  1223. pBlendObj, pvReserved);
  1224. if (rc) {
  1225. // If ppdev is NULL then this is a blt to GDI managed memory bitmap,
  1226. // so there is no need to accumulate any output.
  1227. if (ppdev != NULL) {
  1228. BOOL bMirror;
  1229. // The following is true for DrvBitBlt, need to find out for
  1230. // get the bounding rectangle for the operation. According to
  1231. // the DDK, this rectangle is always well-ordered and does not
  1232. // need to be rearranged.
  1233. // Clip it to 16 bits.
  1234. bounds = *prclTrg;
  1235. OEClipRect(&bounds);
  1236. // If the bound is right to left, we need to switch it.
  1237. bMirror = bounds.left > bounds.right;
  1238. if (bMirror)
  1239. {
  1240. LONG lRight = bounds.left;
  1241. bounds.left = bounds.right;
  1242. bounds.right = lRight;
  1243. }
  1244. }
  1245. else {
  1246. // if ppdev is NULL, we are blt to GDI managed bitmap,
  1247. // so, the dhurf of the target surface should be NULL
  1248. TRC_ASSERT((pdsurfTrg == NULL),
  1249. (TB, "NULL ppdev - psoTrg has non NULL dhsurf"));
  1250. TRC_NRM((TB, "NULL ppdev - blt to GDI managed bitmap"));
  1251. DC_QUIT;
  1252. }
  1253. }
  1254. else {
  1255. TRC_ERR((TB, "EngBitBlt failed"));
  1256. DC_QUIT;
  1257. }
  1258. }
  1259. else {
  1260. if (psoTrg->iType == STYPE_DEVBITMAP) {
  1261. psoTrg = OEGetSurfObjBitmap(psoTrg, &pdsurfTrg);
  1262. if (psoSrc != NULL)
  1263. psoSrc = OEGetSurfObjBitmap(psoSrc, &pdsurfSrc);
  1264. // Punt the call back to GDI to do the drawing.
  1265. rc = EngNineGrid(psoTrg, psoSrc, pco, pxlo, prclTrg, prclSrc, png,
  1266. pBlendObj, pvReserved);
  1267. }
  1268. else {
  1269. TRC_ERR((TB, "Called when disconnected"));
  1270. rc = TRUE;
  1271. }
  1272. DC_QUIT;
  1273. }
  1274. if (!((psoTrg->hsurf == ppdev->hsurfFrameBuf) ||
  1275. (!(pdsurfTrg->flags & DD_NO_OFFSCREEN)))) {
  1276. // If noOffscreen flag is on, we will bail on sending
  1277. // the client any further offscreen rendering. And we'll send the
  1278. // final offscreen to screen blt as regular memblt.
  1279. TRC_NRM((TB, "Offscreen blt bail"));
  1280. //INC_OUTCOUNTER(OUT_BITBLT_NOOFFSCR);
  1281. DC_QUIT;
  1282. }
  1283. // Get the intersection between the dest rect and the
  1284. // clip rects. Check for overcomplicated or nonintersecting
  1285. // clipping.
  1286. clipVal = OEGetIntersectingClipRects(pco, &bounds, CD_ANY,
  1287. &clipRects);
  1288. if (clipVal == CLIPRECTS_TOO_COMPLEX) {
  1289. TRC_NRM((TB, "Clipping is too complex"));
  1290. //INC_OUTCOUNTER(OUT_BITBLT_SDA_COMPLEXCLIP);
  1291. //if (oeLastDstSurface == NULL)
  1292. // ADD_INCOUNTER(IN_SDA_BITBLT_COMPLEXCLIP_AREA,
  1293. // COM_SIZEOF_RECT(bounds));
  1294. goto SendScreenData;
  1295. }
  1296. else if (clipVal == CLIPRECTS_NO_INTERSECTIONS) {
  1297. TRC_NRM((TB, "Clipping does not intersect destrect"));
  1298. DC_QUIT;
  1299. }
  1300. // Cache the source bitmap
  1301. TRC_ASSERT((psoSrcArg->iUniq != 0), (TB, "Source bitmap should be cachable"));
  1302. TRC_ASSERT((pdsurfSrc == NULL), (TB, "The source bitmap for this should be GDI managed bitmap"));
  1303. TRC_ASSERT((psoSrc->iBitmapFormat == BMF_32BPP), (TB, "for now, we always get 32bpp bitmap"));
  1304. TRC_ASSERT((pBlendObj->BlendFunction.BlendOp == 0 &&
  1305. pBlendObj->BlendFunction.BlendFlags == 0 &&
  1306. pBlendObj->BlendFunction.SourceConstantAlpha == 255 &&
  1307. pBlendObj->BlendFunction.AlphaFormat == 1), (TB, "Received unknown blend function"));
  1308. if (!OECacheDrawNineGridBitmap(ppdev, psoSrc, png, &nineGridBitmapId)) {
  1309. TRC_ERR((TB, "Failed to cache drawninegrid bitmap"));
  1310. goto SendScreenData;
  1311. }
  1312. // Switch drawing surface if needed
  1313. if ((psoTrg->hsurf == ppdev->hsurfFrameBuf) ||
  1314. (!(pdsurfTrg->flags & DD_NO_OFFSCREEN))) {
  1315. // Send a switch surface PDU if the destination surface is different
  1316. // from last drawing order. If we failed to send the PDU, we will
  1317. // just have to bail on this drawing order.
  1318. if (!OESendSwitchSurfacePDU(ppdev, pdsurfTrg)) {
  1319. TRC_ERR((TB, "failed to send the switch surface PDU"));
  1320. goto SendScreenData;
  1321. }
  1322. }
  1323. else {
  1324. // if noOffscreen flag is on, we will bail on sending
  1325. // the client any further offscreen rendering. And will send the
  1326. // final offscreen to screen blt as regular memblt.
  1327. TRC_NRM((TB, "Offscreen blt bail"));
  1328. goto SendScreenData;
  1329. }
  1330. // Send the drawninegrid encoded primary order
  1331. if (OEEncodeDrawNineGrid(&bounds, prclSrc, nineGridBitmapId, ppdev, &clipRects)) {
  1332. // We added an order to the list, increment global counts.
  1333. goto PostSDA;
  1334. }
  1335. else {
  1336. goto SendScreenData;
  1337. }
  1338. SendScreenData:
  1339. if ((psoTrg->hsurf == ppdev->hsurfFrameBuf) ||
  1340. (!(pdsurfTrg->flags & DD_NO_OFFSCREEN))) {
  1341. // Send a switch surface PDU if the destination surface is different
  1342. // from last drawing order. If we failed to send the PDU, we will
  1343. // just have to bail on this drawing order.
  1344. if (!OESendSwitchSurfacePDU(ppdev, pdsurfTrg)) {
  1345. TRC_ERR((TB, "failed to send the switch surface PDU"));
  1346. DC_QUIT;
  1347. }
  1348. }
  1349. else {
  1350. // If noOffscreen flag is on, we will bail on sending
  1351. // the client any further offscreen rendering. And we'll send the
  1352. // final offscreen to screen blt as regular memblt.
  1353. TRC_NRM((TB, "Offscreen blt bail"));
  1354. //INC_OUTCOUNTER(OUT_BITBLT_NOOFFSCR);
  1355. DC_QUIT;
  1356. }
  1357. if (psoTrg->hsurf == ppdev->hsurfFrameBuf) {
  1358. //INC_OUTCOUNTER(OUT_BITBLT_SDA);
  1359. OEClipAndAddScreenDataArea(&bounds, pco);
  1360. }
  1361. else {
  1362. // if we can't send orders for offscreen rendering, we will
  1363. // bail offscreen support for this bitmap
  1364. TRC_ALT((TB, "screen data call for offscreen rendering"));
  1365. // Remove the bitmap from the offscreen bitmap cache
  1366. if (!(pdsurfTrg->flags & DD_NO_OFFSCREEN))
  1367. CH_RemoveCacheEntry(sbcOffscreenBitmapCacheHandle,
  1368. pdsurfTrg->bitmapId);
  1369. DC_QUIT;
  1370. }
  1371. PostSDA:
  1372. SCH_DDOutputAvailable(ppdev, FALSE);
  1373. DC_EXIT_POINT:
  1374. DC_END_FN();
  1375. return rc;
  1376. }
  1377. #if 0
  1378. BOOL DrvDrawStream(
  1379. SURFOBJ *psoTrg,
  1380. SURFOBJ *psoSrc,
  1381. CLIPOBJ *pco,
  1382. XLATEOBJ *pxlo,
  1383. RECTL *prclTrg,
  1384. POINTL *pptlDstOffset,
  1385. ULONG ulIn,
  1386. PVOID pvIn,
  1387. PVOID pvReserved)
  1388. {
  1389. BOOL rc = TRUE;
  1390. SURFOBJ *psoTrgArg;
  1391. SURFOBJ *psoSrcArg;
  1392. PDD_PDEV ppdev = (PDD_PDEV)psoTrg->dhpdev;
  1393. PDD_DSURF pdsurfTrg = NULL;
  1394. PDD_DSURF pdsurfSrc = NULL;
  1395. RECTL bounds;
  1396. OE_ENUMRECTS clipRects;
  1397. unsigned drawStreamBitmapId = 0;
  1398. unsigned offscrBitmapId = 0;
  1399. unsigned RetVal;
  1400. DC_BEGIN_FN("DrvDrawStream")
  1401. if (ddConnected) {
  1402. psoTrgArg = psoTrg;
  1403. psoSrcArg = psoSrc;
  1404. // Get the GDI format source and destination bitmaps
  1405. psoTrg = OEGetSurfObjBitmap(psoTrg, &pdsurfTrg);
  1406. if (psoSrc != NULL)
  1407. psoSrc = OEGetSurfObjBitmap(psoSrc, &pdsurfSrc);
  1408. //DD_UPD_STATE(DD_BITBLT);
  1409. //INC_OUTCOUNTER(OUT_BITBLT_ALL);
  1410. // Punt the call back to GDI to do the drawing.
  1411. rc = EngDrawStream(psoTrg, psoSrc, pco, pxlo, prclTrg, pptlDstOffset,
  1412. ulIn, pvIn, pvReserved);
  1413. if (rc) {
  1414. // If ppdev is NULL then this is a blt to GDI managed memory bitmap,
  1415. // so there is no need to accumulate any output.
  1416. if (ppdev != NULL) {
  1417. // The following is true for DrvBitBlt, need to find out for Get
  1418. // the bounding rectangle for the operation. According to
  1419. // the DDK, this rectangle is always well-ordered and does not
  1420. // need to be rearranged.
  1421. // Clip it to 16 bits.
  1422. bounds = *prclTrg;
  1423. OEClipRect(&bounds);
  1424. }
  1425. else {
  1426. // if ppdev is NULL, we are blt to GDI managed bitmap,
  1427. // so, the dhurf of the target surface should be NULL
  1428. TRC_ASSERT((pdsurfTrg == NULL),
  1429. (TB, "NULL ppdev - psoTrg has non NULL dhsurf"));
  1430. TRC_NRM((TB, "NULL ppdev - blt to GDI managed bitmap"));
  1431. DC_QUIT;
  1432. }
  1433. }
  1434. else {
  1435. TRC_ERR((TB, "EngBitBlt failed"));
  1436. DC_QUIT;
  1437. }
  1438. }
  1439. else {
  1440. if (psoTrg->iType == STYPE_DEVBITMAP) {
  1441. psoTrg = OEGetSurfObjBitmap(psoTrg, &pdsurfTrg);
  1442. if (psoSrc != NULL)
  1443. psoSrc = OEGetSurfObjBitmap(psoSrc, &pdsurfSrc);
  1444. // Punt the call back to GDI to do the drawing.
  1445. rc = EngDrawStream(psoTrg, psoSrc, pco, pxlo, prclTrg, pptlDstOffset,
  1446. ulIn, pvIn, pvReserved);
  1447. }
  1448. else {
  1449. TRC_ERR((TB, "Called when disconnected"));
  1450. rc = TRUE;
  1451. }
  1452. DC_QUIT;
  1453. }
  1454. if (!((psoTrg->hsurf == ppdev->hsurfFrameBuf) ||
  1455. (!(pdsurfTrg->flags & DD_NO_OFFSCREEN)))) {
  1456. // If noOffscreen flag is on, we will bail on sending
  1457. // the client any further offscreen rendering. And we'll send the
  1458. // final offscreen to screen blt as regular memblt.
  1459. TRC_NRM((TB, "Offscreen blt bail"));
  1460. //INC_OUTCOUNTER(OUT_BITBLT_NOOFFSCR);
  1461. DC_QUIT;
  1462. }
  1463. // Get the intersection between the dest rect and the
  1464. // clip rects. Check for overcomplicated or nonintersecting
  1465. // clipping.
  1466. RetVal = OEGetIntersectingClipRects(pco, &bounds, CD_ANY,
  1467. &clipRects);
  1468. if (RetVal == CLIPRECTS_TOO_COMPLEX) {
  1469. TRC_NRM((TB, "Clipping is too complex"));
  1470. //INC_OUTCOUNTER(OUT_BITBLT_SDA_COMPLEXCLIP);
  1471. //if (oeLastDstSurface == NULL)
  1472. // ADD_INCOUNTER(IN_SDA_BITBLT_COMPLEXCLIP_AREA,
  1473. // COM_SIZEOF_RECT(bounds));
  1474. goto SendScreenData;
  1475. }
  1476. else if (RetVal == CLIPRECTS_NO_INTERSECTIONS) {
  1477. TRC_NRM((TB, "Clipping does not intersect destrect"));
  1478. DC_QUIT;
  1479. }
  1480. // Cache the source bitmap
  1481. TRC_ASSERT((psoSrcArg->iUniq != 0), (TB, "Source bitmap should be cachable"));
  1482. // For the source bitmap
  1483. //
  1484. // Case 1: This is an RDP managed device bitmap and the bitmap
  1485. // is still cached at the client and we can just use the bitmapId
  1486. //
  1487. // Case 2: This is an RDP managed device bitmap, but no longer
  1488. // cached at the client side
  1489. //
  1490. // Case 3: This is a GDI managed bitmap
  1491. //
  1492. // For case 2 and 3, we need to cache the bitmap first
  1493. //
  1494. if (pdsurfSrc != NULL) {
  1495. if ((pddShm->sbc.offscreenCacheInfo.supportLevel > TS_OFFSCREEN_DEFAULT) &&
  1496. (sbcEnabled & SBC_OFFSCREEN_CACHE_ENABLED)) {
  1497. if (pdsurfSrc->shareId == pddShm->shareId) {
  1498. // The client has the offscreen bitmap in cache
  1499. if (!(pdsurfSrc->flags & DD_NO_OFFSCREEN)) {
  1500. offscrBitmapId = pdsurfSrc->bitmapId;
  1501. CH_TouchCacheEntry(sbcOffscreenBitmapCacheHandle,
  1502. offscrBitmapId);
  1503. }
  1504. else {
  1505. // If the source surface is offscreen surface, and we
  1506. // have the noOffscreen flag on, this means we will
  1507. // send the bitmap bits as regular memory bitmap bits
  1508. // This means that the offscreen bitmap has been evicted
  1509. // out of the offscreen cache or screen data needs to be
  1510. // sent for the offscreen bitmap
  1511. TRC_ALT((TB, "noOffscreen flag is on for %p", pdsurfSrc));
  1512. offscrBitmapId = CH_KEY_UNCACHABLE;
  1513. }
  1514. }
  1515. else {
  1516. // This is the stale offscreen bitmap from last disconnected
  1517. // session. We need to turn off the offscreen flag on this
  1518. TRC_ALT((TB, "Need to turn off this offscreen bitmap"));
  1519. pdsurfSrc->flags |= DD_NO_OFFSCREEN;
  1520. offscrBitmapId = CH_KEY_UNCACHABLE;
  1521. }
  1522. }
  1523. else {
  1524. // These are offscreen bitmaps from the disconnected session
  1525. // or client has sent an error pdu,
  1526. // We have to treat them as memory bitmap now since the client
  1527. // doesn't have the offscreen bitmap locally
  1528. TRC_ALT((TB, "Need to turn off this offscreen bitmap"));
  1529. pdsurfSrc->flags |= DD_NO_OFFSCREEN;
  1530. offscrBitmapId = CH_KEY_UNCACHABLE;
  1531. }
  1532. }
  1533. else {
  1534. if ((pddShm->sbc.offscreenCacheInfo.supportLevel > TS_OFFSCREEN_DEFAULT) &&
  1535. (sbcEnabled & SBC_OFFSCREEN_CACHE_ENABLED)) {
  1536. offscrBitmapId = CH_KEY_UNCACHABLE;
  1537. }
  1538. else {
  1539. TRC_NRM((TB, "No offscreen support, can't support draw stream"));
  1540. goto SendScreenData;
  1541. }
  1542. }
  1543. // Need to create an offscreen
  1544. if (offscrBitmapId == CH_KEY_UNCACHABLE) {
  1545. MEMBLT_ORDER_EXTRA_INFO MemBltExtraInfo;
  1546. POINTL ptlSrc;
  1547. CHDataKeyContext CHContext;
  1548. void *UserDefined;
  1549. drawStreamBitmapId = CH_KEY_UNCACHABLE;
  1550. CH_CreateKeyFromFirstData(&CHContext, psoSrc->pvBits, psoSrc->cjBits);
  1551. if (!CH_SearchCache(sbcDrawStreamBitmapCacheHandle, CHContext.Key1, CHContext.Key2,
  1552. &UserDefined, &drawStreamBitmapId)) {
  1553. drawStreamBitmapId = CH_CacheKey(
  1554. sbcDrawStreamBitmapCacheHandle,
  1555. CHContext.Key1, CHContext.Key2,
  1556. NULL);
  1557. if (drawStreamBitmapId != CH_KEY_UNCACHABLE) {
  1558. unsigned BitmapRawSize;
  1559. unsigned BitmapBufferSize;
  1560. unsigned BitmapCompSize;
  1561. unsigned BitmapBpp;
  1562. SIZEL size;
  1563. PBYTE BitmapBuffer;
  1564. PBYTE BitmapRawBuffer;
  1565. PINT_ORDER pOrder = NULL;
  1566. unsigned paddedBitmapWidth;
  1567. HSURF hWorkBitmap;
  1568. SURFOBJ *pWorkSurf;
  1569. BOOL rc;
  1570. BitmapBuffer = oeTempBitmapBuffer;
  1571. BitmapBufferSize = TS_MAX_STREAM_BITMAP_SIZE;
  1572. // Convert to the protocol wire bitmap bpp format
  1573. switch (psoSrc->iBitmapFormat)
  1574. {
  1575. case BMF_16BPP:
  1576. BitmapBpp = 16;
  1577. break;
  1578. case BMF_24BPP:
  1579. BitmapBpp = 24;
  1580. break;
  1581. case BMF_32BPP:
  1582. BitmapBpp = 32;
  1583. break;
  1584. default:
  1585. BitmapBpp = 8;
  1586. }
  1587. paddedBitmapWidth = (psoSrc->sizlBitmap.cx + 3) & ~3;
  1588. size.cx = paddedBitmapWidth;
  1589. size.cy = psoSrc->sizlBitmap.cy;
  1590. // We need to copy to a worker bitmap if the bitmap width is
  1591. // not dword aligned, or the color depth is not 32bpp and
  1592. // doesn't match the frame buffer color depth
  1593. if (paddedBitmapWidth != psoSrc->sizlBitmap.cx ||
  1594. (psoSrc->iBitmapFormat != ppdev->iBitmapFormat &&
  1595. psoSrc->iBitmapFormat != BMF_32BPP)) {
  1596. RECTL rect;
  1597. POINTL origin;
  1598. rect.left = 0;
  1599. rect.top = 0;
  1600. rect.right = paddedBitmapWidth;
  1601. rect.bottom = psoSrc->sizlBitmap.cy;
  1602. origin.x = 0;
  1603. origin.y = 0;
  1604. hWorkBitmap = (HSURF)EngCreateBitmap(size,
  1605. TS_BYTES_IN_SCANLINE(size.cx, BitmapBpp),
  1606. psoSrc->iBitmapFormat, 0, NULL);
  1607. pWorkSurf = EngLockSurface(hWorkBitmap);
  1608. if (EngCopyBits(pWorkSurf, psoSrc, NULL, NULL, &rect, &origin)) {
  1609. BitmapRawSize = pWorkSurf->cjBits;
  1610. BitmapRawBuffer = pWorkSurf->pvBits;
  1611. rc = BC_CompressBitmap(BitmapRawBuffer, BitmapBuffer, BitmapBufferSize,
  1612. &BitmapCompSize, paddedBitmapWidth, psoSrc->sizlBitmap.cy,
  1613. BitmapBpp);
  1614. EngUnlockSurface(pWorkSurf);
  1615. EngDeleteSurface(hWorkBitmap);
  1616. }
  1617. else {
  1618. EngUnlockSurface(pWorkSurf);
  1619. EngDeleteSurface(hWorkBitmap);
  1620. goto SendScreenData;
  1621. }
  1622. EngUnlockSurface(pWorkSurf);
  1623. EngDeleteSurface(hWorkBitmap);
  1624. }
  1625. else {
  1626. BitmapRawSize = psoSrc->cjBits;
  1627. BitmapRawBuffer = psoSrc->pvBits;
  1628. rc = BC_CompressBitmap(BitmapRawBuffer, BitmapBuffer, BitmapBufferSize,
  1629. &BitmapCompSize, paddedBitmapWidth, psoSrc->sizlBitmap.cy,
  1630. BitmapBpp);
  1631. }
  1632. if (rc) {
  1633. if (!OESendStreamBitmapOrder(ppdev, TS_DRAW_NINEGRID_BITMAP_CACHE, &size,
  1634. BitmapBpp, BitmapBuffer, BitmapCompSize, TRUE)) {
  1635. goto SendScreenData;
  1636. }
  1637. }
  1638. else {
  1639. // Send uncompressed bitmap
  1640. if (!OESendStreamBitmapOrder(ppdev, TS_DRAW_NINEGRID_BITMAP_CACHE, &size,
  1641. BitmapBpp, BitmapRawBuffer, BitmapRawSize, FALSE))
  1642. {
  1643. goto SendScreenData;
  1644. }
  1645. }
  1646. // send a create drawStream bitmap pdu
  1647. if (OESendCreateDrawStreamOrder(ppdev,drawStreamBitmapId,
  1648. &(psoSrc->sizlBitmap), BitmapBpp)) {
  1649. // Update the current offscreen cache size
  1650. //oeCurrentOffscreenCacheSize += bitmapSize;
  1651. TRC_NRM((TB, "Created an offscreen bitmap"));
  1652. }
  1653. else {
  1654. TRC_ERR((TB, "Failed to send the create bitmap pdu"));
  1655. CH_RemoveCacheEntry(
  1656. sbcDrawStreamBitmapCacheHandle, drawStreamBitmapId);
  1657. goto SendScreenData;
  1658. }
  1659. }
  1660. else {
  1661. TRC_ERR((TB, "Failed to cache the bitmap"));
  1662. goto SendScreenData;
  1663. }
  1664. #if 0
  1665. if (!OESendSwitchSurfacePDU(ppdev, (PDD_DSURF)(&drawStreamBitmapId), DRAW_STREAM_SURFACE)) {
  1666. TRC_ERR((TB, "failed to send the switch surface PDU"));
  1667. goto SendScreenData;
  1668. }
  1669. // Fill in extra info structure.
  1670. MemBltExtraInfo.pSource = psoSrc;
  1671. MemBltExtraInfo.pDest = psoSrc;
  1672. MemBltExtraInfo.pXlateObj = NULL;
  1673. MemBltExtraInfo.bNoFastPathCaching = FALSE;
  1674. MemBltExtraInfo.iDeviceUniq = psoSrcArg ? (psoSrcArg->iUniq) : 0;
  1675. ptlSrc.x = 0;
  1676. ptlSrc.y = 0;
  1677. // Make sure orders are not turned off.
  1678. if (OE_SendAsOrder(TS_ENC_MEMBLT_R2_ORDER)) {
  1679. RECTL srcBound;
  1680. OE_ENUMRECTS srcClipRect;
  1681. // Get the intersection rect.
  1682. srcBound.left = 0;
  1683. srcBound.top = 0;
  1684. srcBound.right = psoSrc->sizlBitmap.cx;
  1685. srcBound.bottom = psoSrc->sizlBitmap.cy;
  1686. srcClipRect.rects.c = 1;
  1687. srcClipRect.rects.arcl[0] = srcBound;
  1688. if (!OEEncodeMemBlt(&srcBound, &MemBltExtraInfo,
  1689. TS_ENC_MEMBLT_R2_ORDER, CH_KEY_UNCACHABLE,
  1690. 0xCC, &ptlSrc, NULL, NULL, ppdev,
  1691. &srcClipRect)) {
  1692. //if (oeLastDstSurface == NULL)
  1693. // ADD_INCOUNTER(IN_SDA_MEMBLT_AREA,
  1694. // COM_SIZEOF_RECT(bounds));
  1695. goto SendScreenData;
  1696. }
  1697. }
  1698. else {
  1699. TRC_NRM((TB, "MemBlt order not allowed"));
  1700. //INC_OUTCOUNTER(OUT_BITBLT_SDA_UNSUPPORTED);
  1701. goto SendScreenData;
  1702. }
  1703. #endif
  1704. }
  1705. else {
  1706. //DrvDebugPrint("JOYC: drawstream source already cached\n");
  1707. }
  1708. }
  1709. else {
  1710. // The client already has the bitmap cached in offscreen bitmap cache
  1711. //DrvDebugPrint("JOYC: offscreen already cached!\n");
  1712. }
  1713. if ((psoTrg->hsurf == ppdev->hsurfFrameBuf) ||
  1714. (!(pdsurfTrg->flags & DD_NO_OFFSCREEN))) {
  1715. // Send a switch surface PDU if the destination surface is different
  1716. // from last drawing order. If we failed to send the PDU, we will
  1717. // just have to bail on this drawing order.
  1718. if (!OESendSwitchSurfacePDU(ppdev, pdsurfTrg, 0)) {
  1719. TRC_ERR((TB, "failed to send the switch surface PDU"));
  1720. goto SendScreenData;
  1721. }
  1722. }
  1723. else {
  1724. // if noOffscreen flag is on, we will bail on sending
  1725. // the client any further offscreen rendering. And will send the
  1726. // final offscreen to screen blt as regular memblt.
  1727. TRC_NRM((TB, "Offscreen blt bail"));
  1728. goto SendScreenData;
  1729. }
  1730. // Send the drawstream bits, first round sending as secondary order
  1731. if (OESendDrawStreamOrder(ppdev, drawStreamBitmapId, ulIn, pvIn, pptlDstOffset,
  1732. &bounds, &clipRects)) {
  1733. //DrvDebugPrint("JOYC: Send DrawStream Order\n");
  1734. // We added an order to the list, increment global counts.
  1735. goto PostSDA;
  1736. }
  1737. else {
  1738. goto SendScreenData;
  1739. }
  1740. SendScreenData:
  1741. DrvDebugPrint("JOYC: DrawStream using SendScreenData\n");
  1742. if ((psoTrg->hsurf == ppdev->hsurfFrameBuf) ||
  1743. (!(pdsurfTrg->flags & DD_NO_OFFSCREEN))) {
  1744. // Send a switch surface PDU if the destination surface is different
  1745. // from last drawing order. If we failed to send the PDU, we will
  1746. // just have to bail on this drawing order.
  1747. if (!OESendSwitchSurfacePDU(ppdev, pdsurfTrg, 0)) {
  1748. TRC_ERR((TB, "failed to send the switch surface PDU"));
  1749. DC_QUIT;
  1750. }
  1751. }
  1752. else {
  1753. // If noOffscreen flag is on, we will bail on sending
  1754. // the client any further offscreen rendering. And we'll send the
  1755. // final offscreen to screen blt as regular memblt.
  1756. TRC_NRM((TB, "Offscreen blt bail"));
  1757. //INC_OUTCOUNTER(OUT_BITBLT_NOOFFSCR);
  1758. DC_QUIT;
  1759. }
  1760. if (psoTrg->hsurf == ppdev->hsurfFrameBuf) {
  1761. //INC_OUTCOUNTER(OUT_BITBLT_SDA);
  1762. OEClipAndAddScreenDataArea(&bounds, pco);
  1763. }
  1764. else {
  1765. // if we can't send orders for offscreen rendering, we will
  1766. // bail offscreen support for this bitmap
  1767. TRC_ALT((TB, "screen data call for offscreen rendering"));
  1768. // Remove the bitmap from the offscreen bitmap cache
  1769. if (!(pdsurfTrg->flags & DD_NO_OFFSCREEN))
  1770. CH_RemoveCacheEntry(sbcOffscreenBitmapCacheHandle,
  1771. pdsurfTrg->bitmapId);
  1772. DC_QUIT;
  1773. }
  1774. PostSDA:
  1775. SCH_DDOutputAvailable(ppdev, FALSE);
  1776. DC_EXIT_POINT:
  1777. DC_END_FN();
  1778. return rc;
  1779. }
  1780. #endif
  1781. #endif //DRAW_NINEGRID
  1782. #ifdef DRAW_GDIPLUS
  1783. // DrawGdiPlus
  1784. ULONG DrawGdiPlus(
  1785. IN SURFOBJ *pso,
  1786. IN ULONG iEsc,
  1787. IN CLIPOBJ *pco,
  1788. IN RECTL *prcl,
  1789. IN ULONG cjIn,
  1790. IN PVOID pvIn)
  1791. {
  1792. SURFOBJ *psoTrgArg;
  1793. SURFOBJ *psoSrcArg;
  1794. PDD_PDEV ppdev = (PDD_PDEV)pso->dhpdev;
  1795. PDD_DSURF pdsurf = NULL;
  1796. BOOL rc = TRUE;
  1797. DC_BEGIN_FN("DrawGdiplus");
  1798. // The callers should check this. Asserting they do.
  1799. TRC_ASSERT((pddShm != NULL),(TB, "DrawGdiPlus called when pddShm is NULL"))
  1800. // Sometimes, we're called after being disconnected.
  1801. if (ddConnected) {
  1802. // Surface is non-NULL.
  1803. pso = OEGetSurfObjBitmap(pso, &pdsurf);
  1804. if ((pso->hsurf == ppdev->hsurfFrameBuf) ||
  1805. (!(pdsurf->flags & DD_NO_OFFSCREEN))) {
  1806. // Send a switch surface PDU if the destination surface is
  1807. // different from last drawing order. If we failed to send the
  1808. // PDU, we will just have to bail on this drawing order.
  1809. if (!OESendSwitchSurfacePDU(ppdev, pdsurf)) {
  1810. TRC_ERR((TB, "failed to send the switch surface PDU"));
  1811. DC_QUIT;
  1812. }
  1813. } else {
  1814. // if noOffscreen flag is on, we will bail on sending
  1815. // the client any further offscreen rendering. And will send the final
  1816. // offscreen to screen blt as regular memblt.
  1817. TRC_NRM((TB, "Offscreen blt bail"));
  1818. DC_QUIT;
  1819. }
  1820. } else {
  1821. TRC_ERR((TB, "Called when disconnected"));
  1822. DC_QUIT;
  1823. }
  1824. // Create and Send DrawGdiplus Order
  1825. if (OECreateDrawGdiplusOrder(ppdev, prcl, cjIn, pvIn)) {
  1826. goto PostSDA;
  1827. }
  1828. // Send screen data when OECreateDrawGdiplusOrder fails
  1829. OEClipAndAddScreenDataArea(prcl, NULL);
  1830. PostSDA:
  1831. // All done: consider sending the output.
  1832. SCH_DDOutputAvailable(ppdev, FALSE);
  1833. DC_EXIT_POINT:
  1834. DC_END_FN();
  1835. return rc;
  1836. }
  1837. /****************************************************************************/
  1838. // DrvDrawEscape - see NT DDK documentation.
  1839. /****************************************************************************/
  1840. ULONG DrvDrawEscape(
  1841. IN SURFOBJ *pso,
  1842. IN ULONG iEsc,
  1843. IN CLIPOBJ *pco,
  1844. IN RECTL *prcl,
  1845. IN ULONG cjIn,
  1846. IN PVOID pvIn)
  1847. {
  1848. PDD_PDEV ppdev = (PDD_PDEV)pso->dhpdev;
  1849. DC_BEGIN_FN("DrvDrawEscape");
  1850. TRC_NRM((TB, "DrvDrawEscape %d", iEsc));
  1851. switch (iEsc) {
  1852. case GDIPLUS_TS_QUERYVER:
  1853. // Query the gdiplus version
  1854. // DDraw only support 8, 16, 24, 32 bpp
  1855. if ((ppdev->cClientBitsPerPel != 8) &&
  1856. (ppdev->cClientBitsPerPel != 16) &&
  1857. (ppdev->cClientBitsPerPel != 24) &&
  1858. (ppdev->cClientBitsPerPel != 32)) {
  1859. TRC_ERR((TB, "The DDrawColor does not support the color depth %d",
  1860. ppdev->cClientBitsPerPel));
  1861. return 0;
  1862. }
  1863. if (ppdev->SectionObject == NULL) {
  1864. TRC_ERR((TB, "The section memory is not allocated"));
  1865. return 0;
  1866. }
  1867. if (pddShm == NULL) {
  1868. TRC_ERR((TB, "The pddShm is NULL"));
  1869. return 0;
  1870. }
  1871. if (pddShm->sbc.drawGdiplusInfo.supportLevel > TS_DRAW_GDIPLUS_DEFAULT) {
  1872. TRC_NRM((TB, "Gdiplus version is %d", pddShm->sbc.drawGdiplusInfo.GdipVersion));
  1873. return pddShm->sbc.drawGdiplusInfo.GdipVersion;
  1874. }
  1875. else {
  1876. TRC_ERR((TB, "TSDrawGdip not supported"));
  1877. return 0;
  1878. }
  1879. break;
  1880. case GDIPLUS_TS_RECORD:
  1881. // Send out the Gdiplus EMF+ record
  1882. // DDraw only support 8, 16, 24, 32 bpp
  1883. if ((ppdev->cClientBitsPerPel != 8) &&
  1884. (ppdev->cClientBitsPerPel != 16) &&
  1885. (ppdev->cClientBitsPerPel != 24) &&
  1886. (ppdev->cClientBitsPerPel != 32)) {
  1887. TRC_ERR((TB, "The DDrawColor does not support the color depth %d",
  1888. ppdev->cClientBitsPerPel));
  1889. return 0;
  1890. }
  1891. if (pddShm == NULL) {
  1892. TRC_ERR((TB, "The pddShm is NULL !"));
  1893. return 0;
  1894. }
  1895. if (ppdev->SectionObject == NULL) {
  1896. TRC_ERR((TB, "Called when Gdiplus is not supported!"));
  1897. return 0;
  1898. }
  1899. if (pddShm->sbc.drawGdiplusInfo.supportLevel > TS_DRAW_GDIPLUS_DEFAULT) {
  1900. TRC_ASSERT((pvIn != NULL), (TB, "DrvDrawEscape gets NULL data"))
  1901. TRC_ASSERT((cjIn != 0), (TB, "DrvDrawEscape gets data with size 0"))
  1902. return DrawGdiPlus(pso, iEsc, pco, prcl, cjIn, pvIn);
  1903. }
  1904. else {
  1905. TRC_ERR((TB, "TSDrawGdip not supported"));
  1906. return 0;
  1907. }
  1908. default :
  1909. TRC_ERR((TB, "DrvDrawEscape %d not supported", iEsc));
  1910. return 0;
  1911. }
  1912. DC_END_FN()
  1913. }
  1914. #endif // DRAW_GDIPLUS
  1915. /****************************************************************************/
  1916. // DrvTextOut - see NT DDK documentation.
  1917. /****************************************************************************/
  1918. BOOL RDPCALL DrvTextOut(
  1919. SURFOBJ *pso,
  1920. STROBJ *pstro,
  1921. FONTOBJ *pfo,
  1922. CLIPOBJ *pco,
  1923. RECTL *prclExtra,
  1924. RECTL *prclOpaque,
  1925. BRUSHOBJ *pboFore,
  1926. BRUSHOBJ *pboOpaque,
  1927. POINTL *pptlOrg,
  1928. MIX mix)
  1929. {
  1930. BOOL rc;
  1931. RECTL rectTrg;
  1932. PDD_PDEV ppdev = (PDD_PDEV)pso->dhpdev;
  1933. PDD_DSURF pdsurf = NULL;
  1934. PFONTCACHEINFO pfci;
  1935. OE_ENUMRECTS ClipRects;
  1936. DC_BEGIN_FN("DrvTextOut");
  1937. rc = TRUE;
  1938. // Sometimes, we're called after being disconnected.
  1939. if (ddConnected && pddShm != NULL) {
  1940. // Surface is non-NULL.
  1941. pso = OEGetSurfObjBitmap(pso, &pdsurf);
  1942. INC_OUTCOUNTER(OUT_TEXTOUT_ALL);
  1943. if (((pco == NULL) && (pso->sizlBitmap.cx >= prclOpaque->right) &&
  1944. (pso->sizlBitmap.cy >= prclOpaque->bottom)) ||
  1945. ((pco != NULL) && (pso->sizlBitmap.cx >= pco->rclBounds.right) &&
  1946. (pso->sizlBitmap.cy >= pco->rclBounds.bottom))) {
  1947. // Let GDI to do the local drawing.
  1948. rc = EngTextOut(pso, pstro, pfo, pco, prclExtra, prclOpaque, pboFore,
  1949. pboOpaque, pptlOrg, mix);
  1950. }
  1951. else {
  1952. // If the bounding rectangle is greater the frame buffer, something
  1953. // is really wrong here. This means the desktop surface size and
  1954. // the framebuffer is not matched up. We need to bail out here.
  1955. rc = FALSE;
  1956. }
  1957. if (rc) {
  1958. if ((pso->hsurf == ppdev->hsurfFrameBuf) ||
  1959. (!(pdsurf->flags & DD_NO_OFFSCREEN))) {
  1960. // Send a switch surface PDU if the destination surface is different
  1961. // from last drawing order. If we failed to send the PDU, we will
  1962. // just have to bail on this drawing order.
  1963. if (!OESendSwitchSurfacePDU(ppdev, pdsurf)) {
  1964. TRC_ERR((TB, "failed to send the switch surface PDU"));
  1965. DC_QUIT;
  1966. }
  1967. } else {
  1968. // if noOffscreen flag is on, we will bail on sending the
  1969. // client any further offscreen rendering. And will send the
  1970. // final offscreen to screen blt as regular memblt.
  1971. TRC_NRM((TB, "Offscreen blt bail"));
  1972. DC_QUIT;
  1973. }
  1974. // Check we have a valid string.
  1975. if (pstro->pwszOrg != NULL) {
  1976. if (OEGetClipRects(pco, &ClipRects)) {
  1977. // Special case when the clipobj is not correct.
  1978. // When rdpdd is used as a mirroring driver the Mul layer
  1979. // will modify the CLIPOBJ and in some cases we get a complex
  1980. // CLIPOBJ but the enumeration gives no rectangles.
  1981. // If it happens then don't draw anything.
  1982. // We test only the DC_COMPLEX case because in that case we
  1983. // are supposed to always get at least one rect.
  1984. // If it's DC_RECT we always have one rect without enumeration,
  1985. // so no need to test it (see OEGetClipRects).
  1986. // If it's DC_TRIVIAL we have to draw it, so don't test it.
  1987. if ((pco != NULL) &&
  1988. (pco->iDComplexity == DC_COMPLEX) &&
  1989. (ClipRects.rects.c == 0)) {
  1990. TRC_NRM((TB, "Complex CLIPOBJ without any rects"));
  1991. DC_QUIT;
  1992. }
  1993. // Check that we don't have any modifier rects on the
  1994. // font.
  1995. if (prclExtra == NULL) {
  1996. // Get a ptr to this font's cached information.
  1997. pfci = OEGetFontCacheInfo(pfo);
  1998. if (pfci == NULL) {
  1999. TRC_NRM((TB, "Cannot allocate font cache info "
  2000. "struct"));
  2001. INC_OUTCOUNTER(OUT_TEXTOUT_SDA_NOFCI);
  2002. goto SendAsSDA;
  2003. }
  2004. }
  2005. else {
  2006. TRC_NRM((TB, "Unsupported rects"));
  2007. INC_OUTCOUNTER(OUT_TEXTOUT_SDA_EXTRARECTS);
  2008. goto SendAsSDA;
  2009. }
  2010. }
  2011. else {
  2012. TRC_NRM((TB, "Clipping is too complex"));
  2013. INC_OUTCOUNTER(OUT_TEXTOUT_SDA_COMPLEXCLIP);
  2014. goto SendAsSDA;
  2015. }
  2016. }
  2017. else {
  2018. TRC_NRM((TB, "No string - opaque %p", prclOpaque));
  2019. INC_OUTCOUNTER(OUT_TEXTOUT_SDA_NOSTRING);
  2020. goto SendAsSDA;
  2021. }
  2022. }
  2023. else {
  2024. TRC_ERR((TB, "EngTextOut failed"));
  2025. DC_QUIT;
  2026. }
  2027. }
  2028. else {
  2029. if (pso->iType == STYPE_DEVBITMAP) {
  2030. pso = OEGetSurfObjBitmap(pso, &pdsurf);
  2031. // Let GDI to do the local drawing.
  2032. rc = EngTextOut(pso, pstro, pfo, pco, prclExtra, prclOpaque, pboFore,
  2033. pboOpaque, pptlOrg, mix);
  2034. }
  2035. else {
  2036. TRC_ERR((TB, "Called when disconnected"));
  2037. }
  2038. goto CalledOnDisconnected;
  2039. }
  2040. // Process the request according to the glyph support level setting
  2041. // we can attempt to send a Glyph order
  2042. if (pddShm->sbc.caps.GlyphSupportLevel >= CAPS_GLYPH_SUPPORT_PARTIAL) {
  2043. if (OE_SendGlyphs(pso, pstro, pfo, &ClipRects, prclOpaque, pboFore,
  2044. pboOpaque, pptlOrg, pfci))
  2045. goto PostSDA;
  2046. }
  2047. SendAsSDA:
  2048. // We reach here in the case we could not send for some reason.
  2049. // Accumulate in screen data area.
  2050. if (pso->hsurf == ppdev->hsurfFrameBuf) {
  2051. INC_OUTCOUNTER(OUT_TEXTOUT_SDA);
  2052. // Get bounding rectangle, convert to a RECT, and convert to
  2053. // inclusive coordinates.
  2054. if (prclOpaque != NULL) {
  2055. RECT_FROM_RECTL(rectTrg, (*prclOpaque));
  2056. } else {
  2057. RECT_FROM_RECTL(rectTrg, pstro->rclBkGround);
  2058. TRC_DBG((TB, "Using STROBJ bgd for size"));
  2059. }
  2060. OEClipRect(&rectTrg);
  2061. ADD_INCOUNTER(IN_SDA_TEXTOUT_AREA, COM_SIZEOF_RECT(rectTrg));
  2062. // Output to SDA
  2063. OEClipAndAddScreenDataArea(&rectTrg, pco);
  2064. }
  2065. else {
  2066. // If we can't send orders for offscreen rendering, we will
  2067. // bail offscreen support for this bitmap.
  2068. TRC_ALT((TB, "screen data call for offscreen rendering"));
  2069. if (!(pdsurf->flags & DD_NO_OFFSCREEN))
  2070. CH_RemoveCacheEntry(sbcOffscreenBitmapCacheHandle,
  2071. pdsurf->bitmapId);
  2072. DC_QUIT;
  2073. }
  2074. PostSDA:
  2075. // All done: consider sending the output.
  2076. SCH_DDOutputAvailable(ppdev, FALSE);
  2077. CalledOnDisconnected:
  2078. DC_EXIT_POINT:
  2079. DC_END_FN();
  2080. return rc;
  2081. }
  2082. /****************************************************************************/
  2083. // DrvDestroyFont - see NT DDK documentation.
  2084. /****************************************************************************/
  2085. VOID DrvDestroyFont(FONTOBJ *pfo)
  2086. {
  2087. FONTCACHEINFO *pfci;
  2088. DC_BEGIN_FN("DrvDestroyFont");
  2089. pfci = pfo->pvConsumer;
  2090. if (pfci != NULL) {
  2091. if (pddShm != NULL && pfci->cacheHandle)
  2092. pddShm->sbc.glyphCacheInfo[pfci->cacheId].cbUseCount--;
  2093. if (sbcFontCacheInfoList != NULL &&
  2094. sbcFontCacheInfoList[pfci->listIndex] == pfci) {
  2095. sbcFontCacheInfoList[pfci->listIndex] = NULL;
  2096. }
  2097. EngFreeMem(pfci);
  2098. pfo->pvConsumer = NULL;
  2099. }
  2100. DC_END_FN();
  2101. }
  2102. /****************************************************************************/
  2103. // DrvLineTo - see NT DDK documentation.
  2104. /****************************************************************************/
  2105. BOOL RDPCALL DrvLineTo(
  2106. SURFOBJ *pso,
  2107. CLIPOBJ *pco,
  2108. BRUSHOBJ *pbo,
  2109. LONG x1,
  2110. LONG y1,
  2111. LONG x2,
  2112. LONG y2,
  2113. RECTL *prclBounds,
  2114. MIX mix)
  2115. {
  2116. PDD_PDEV ppdev = (PDD_PDEV)pso->dhpdev;
  2117. PDD_DSURF pdsurf = NULL;
  2118. BOOL rc = TRUE;
  2119. RECTL rectTrg;
  2120. POINTL startPoint;
  2121. POINTL endPoint;
  2122. OE_ENUMRECTS ClipRects;
  2123. DC_BEGIN_FN("DrvLineTo");
  2124. // Sometimes, we're called after being disconnected.
  2125. if (ddConnected && pddShm != NULL) {
  2126. // Surface is non-NULL.
  2127. pso = OEGetSurfObjBitmap(pso, &pdsurf);
  2128. INC_OUTCOUNTER(OUT_LINETO_ALL);
  2129. // Get bounding rectangle and clip to 16-bit wire size.
  2130. RECT_FROM_RECTL(rectTrg, (*prclBounds));
  2131. OEClipRect(&rectTrg);
  2132. // Punt the call back to GDI to do the drawing.
  2133. rc = EngLineTo(pso, pco, pbo, x1, y1, x2, y2, prclBounds, mix);
  2134. if (rc) {
  2135. if ((pso->hsurf == ppdev->hsurfFrameBuf) ||
  2136. (!(pdsurf->flags & DD_NO_OFFSCREEN))) {
  2137. // Send a switch surface PDU if the destination surface is
  2138. // different from last drawing order. If we failed to send the
  2139. // PDU, we will just have to bail on this drawing order.
  2140. if (!OESendSwitchSurfacePDU(ppdev, pdsurf)) {
  2141. TRC_ERR((TB, "failed to send the switch surface PDU"));
  2142. DC_QUIT;
  2143. }
  2144. } else {
  2145. // if noOffscreen flag is on, we will bail on sending
  2146. // the client any further offscreen rendering. And will send the final
  2147. // offscreen to screen blt as regular memblt.
  2148. TRC_NRM((TB, "Offscreen blt bail"));
  2149. DC_QUIT;
  2150. }
  2151. TRC_NRM((TB, "LINETO"));
  2152. }
  2153. else {
  2154. TRC_ERR((TB, "EngLineTo failed"));
  2155. DC_QUIT;
  2156. }
  2157. }
  2158. else {
  2159. if (pso->iType == STYPE_DEVBITMAP) {
  2160. // Surface is non-NULL.
  2161. pso = OEGetSurfObjBitmap(pso, &pdsurf);
  2162. // Punt the call back to GDI to do the drawing.
  2163. rc = EngLineTo(pso, pco, pbo, x1, y1, x2, y2, prclBounds, mix);
  2164. }
  2165. else {
  2166. TRC_ERR((TB, "Called when disconnected"));
  2167. }
  2168. goto CalledOnDisconnect;
  2169. }
  2170. // Check if we are allowed to send this order.
  2171. if (OE_SendAsOrder(TS_ENC_LINETO_ORDER)) {
  2172. // Check for a solid brush required for the order.
  2173. if (pbo->iSolidColor != -1) {
  2174. unsigned RetVal;
  2175. // Get the intersection between the dest rect and the
  2176. // clip rects. Check for overcomplicated or nonintersecting
  2177. // clipping.
  2178. RetVal = OEGetIntersectingClipRects(pco, &rectTrg,
  2179. CD_ANY, &ClipRects);
  2180. if (RetVal == CLIPRECTS_OK) {
  2181. // Set up data for order.
  2182. startPoint.x = x1;
  2183. startPoint.y = y1;
  2184. endPoint.x = x2;
  2185. endPoint.y = y2;
  2186. }
  2187. else if (RetVal == CLIPRECTS_TOO_COMPLEX) {
  2188. TRC_NRM((TB, "Clipping is too complex"));
  2189. INC_OUTCOUNTER(OUT_LINETO_SDA_COMPLEXCLIP);
  2190. goto SendAsSDA;
  2191. }
  2192. else if (RetVal == CLIPRECTS_NO_INTERSECTIONS) {
  2193. TRC_NRM((TB, "Clipping does not intersect destrect"));
  2194. DC_QUIT;
  2195. }
  2196. }
  2197. else {
  2198. TRC_NRM((TB, "Bad brush for line"));
  2199. INC_OUTCOUNTER(OUT_LINETO_SDA_BADBRUSH);
  2200. goto SendAsSDA;
  2201. }
  2202. }
  2203. else {
  2204. TRC_NRM((TB, "LineTo order not allowed"));
  2205. INC_OUTCOUNTER(OUT_LINETO_SDA_UNSUPPORTED);
  2206. goto SendAsSDA;
  2207. }
  2208. // Store the order.
  2209. if (OEEncodeLineToOrder(ppdev, &startPoint, &endPoint, mix & 0x1F,
  2210. pbo->iSolidColor, &ClipRects)) {
  2211. goto PostSDA;
  2212. }
  2213. else {
  2214. TRC_DBG((TB, "Failed to add order - use SDA"));
  2215. INC_OUTCOUNTER(OUT_LINETO_SDA_FAILEDADD);
  2216. goto SendAsSDA;
  2217. }
  2218. SendAsSDA:
  2219. // If we got here we could not send as an order, send as screen data
  2220. // instead.
  2221. if (pso->hsurf == ppdev->hsurfFrameBuf) {
  2222. INC_OUTCOUNTER(OUT_LINETO_SDA);
  2223. ADD_INCOUNTER(IN_SDA_LINETO_AREA, COM_SIZEOF_RECT(rectTrg));
  2224. OEClipAndAddScreenDataArea(&rectTrg, pco);
  2225. }
  2226. else {
  2227. // if we can't send orders for offscreen rendering, we will
  2228. // bail offscreen support for this bitmap
  2229. TRC_ALT((TB, "screen data call for offscreen rendering"));
  2230. if (!(pdsurf->flags & DD_NO_OFFSCREEN))
  2231. CH_RemoveCacheEntry(sbcOffscreenBitmapCacheHandle, pdsurf->bitmapId);
  2232. DC_QUIT;
  2233. }
  2234. PostSDA:
  2235. // Have the scheduler consider flushing output.
  2236. SCH_DDOutputAvailable(ppdev, FALSE);
  2237. CalledOnDisconnect:
  2238. DC_EXIT_POINT:
  2239. DC_END_FN();
  2240. return rc;
  2241. }
  2242. /****************************************************************************/
  2243. // OEEmitReplayOrders
  2244. //
  2245. // Direct-encodes a series of replay-last primary orders.
  2246. /****************************************************************************/
  2247. BOOL OEEmitReplayOrders(
  2248. PDD_PDEV ppdev,
  2249. unsigned NumFieldFlagBytes,
  2250. OE_ENUMRECTS *pClipRects)
  2251. {
  2252. BOOL rc = TRUE;
  2253. BYTE *pBuffer;
  2254. unsigned i;
  2255. unsigned NumRects;
  2256. PINT_ORDER pOrder;
  2257. DC_BEGIN_FN("OEEmitReplayOrders");
  2258. // Since the first order took the first rect, emit replay orders for the
  2259. // remaining rects.
  2260. NumRects = pClipRects->rects.c;
  2261. for (i = 1; i < NumRects; i++) {
  2262. pOrder = OA_AllocOrderMem(ppdev, MAX_REPLAY_CLIPPED_ORDER_SIZE);
  2263. if (pOrder != NULL) {
  2264. pBuffer = pOrder->OrderData;
  2265. // Control flags are primary order plus all field flag bytes zero.
  2266. *pBuffer++ = TS_STANDARD | TS_BOUNDS |
  2267. (NumFieldFlagBytes << TS_ZERO_FIELD_COUNT_SHIFT);
  2268. // Construct the new bounds rect just after this.
  2269. OE2_EncodeBounds(pBuffer - 1, &pBuffer,
  2270. &pClipRects->rects.arcl[i]);
  2271. pOrder->OrderLength = (unsigned)(pBuffer - pOrder->OrderData);
  2272. INC_INCOUNTER(IN_REPLAY_ORDERS);
  2273. ADD_INCOUNTER(IN_REPLAY_BYTES, pOrder->OrderLength);
  2274. OA_AppendToOrderList(pOrder);
  2275. TRC_DBG((TB,"Emit replay order for cliprect (%d,%d,%d,%d)",
  2276. pClipRects->rects.arcl[i].left,
  2277. pClipRects->rects.arcl[i].top,
  2278. pClipRects->rects.arcl[i].right,
  2279. pClipRects->rects.arcl[i].bottom));
  2280. }
  2281. else {
  2282. TRC_ERR((TB,"Error allocating mem for replay order"));
  2283. rc = FALSE;
  2284. break;
  2285. }
  2286. }
  2287. DC_END_FN();
  2288. return rc;
  2289. }
  2290. /****************************************************************************/
  2291. // DrvStrokePath - see NT DDK documentation.
  2292. /****************************************************************************/
  2293. // Worker function - encodes a delta from one point to another in a minimal
  2294. // form in the PolyLine coded delta list. The encoding follows the
  2295. // following rules:
  2296. // 1. If a coordinate delta is zero, a flag is set saying so. This
  2297. // closely follows the data distribution which tends to have vertical
  2298. // and horizontal lines and so have a lot of zero deltas.
  2299. // 2. If we can pack the delta into 7 bits, do so, with the high bit
  2300. // cleared. This is similar to ASN.1 PER encoding; the high bit is a
  2301. // flag telling us whether the encoding is long.
  2302. // 3. Otherwise, we must be able to pack into 15 bits (fail if not);
  2303. // do so and set the high-order bit to indicate this is a long
  2304. // encoding. This differs from ASN.1 PER encoding in that we don't
  2305. // allow more than 15 bits of data.
  2306. BOOL OEEncodePolyLinePointDelta(
  2307. BYTE **ppCurEncode,
  2308. unsigned *pNumDeltas,
  2309. unsigned *pDeltaSize,
  2310. BYTE *ZeroFlags,
  2311. POINTL *pFromPoint,
  2312. POINTL *pToPoint,
  2313. RECTL *pBoundRect)
  2314. {
  2315. int Delta;
  2316. BYTE Zeros = 0;
  2317. BYTE *pBuffer;
  2318. unsigned EncodeLen;
  2319. DC_BEGIN_FN("OEEncodePolyLinePointDelta");
  2320. pBuffer = *ppCurEncode;
  2321. Delta = pToPoint->x - pFromPoint->x;
  2322. if (Delta == 0) {
  2323. EncodeLen = 0;
  2324. Zeros |= ORD_POLYLINE_XDELTA_ZERO;
  2325. }
  2326. else if (Delta >= -64 && Delta <= 63) {
  2327. *pBuffer++ = (BYTE)(Delta & 0x7F);
  2328. EncodeLen = 1;
  2329. }
  2330. else {
  2331. // This is ugly, but necessitated by some stress-type apps that
  2332. // will send us a large coordinate and expect us to clip it. In an
  2333. // ideal world we would actually clip the line coordinates to the
  2334. // clip rectangle given us in DrvStrokePath and recalc the deltas
  2335. // based on the new line endpoints. However, since no normal apps
  2336. // seem to send these bad lines, we simply clip the delta and hope
  2337. // the slope of the resulting line is similar to the slope from the
  2338. // original delta.
  2339. if (Delta >= -16384 && Delta <= 16384) {
  2340. *pBuffer++ = (BYTE)((Delta >> 8) | ORD_POLYLINE_LONG_DELTA);
  2341. *pBuffer++ = (BYTE)(Delta & 0xFF);
  2342. EncodeLen = 2;
  2343. }
  2344. else {
  2345. TRC_ALT((TB,"X delta %d too large/small to encode", Delta));
  2346. return FALSE;
  2347. }
  2348. }
  2349. Delta = pToPoint->y - pFromPoint->y;
  2350. if (Delta == 0) {
  2351. Zeros |= ORD_POLYLINE_YDELTA_ZERO;
  2352. }
  2353. else if (Delta >= -64 && Delta <= 63) {
  2354. *pBuffer++ = (BYTE)(Delta & 0x7F);
  2355. EncodeLen += 1;
  2356. }
  2357. else {
  2358. // See comments for the similar code above.
  2359. if (Delta >= -16384 && Delta <= 16384) {
  2360. *pBuffer++ = (BYTE)((Delta >> 8) | ORD_POLYLINE_LONG_DELTA);
  2361. *pBuffer++ = (BYTE)(Delta & 0xFF);
  2362. EncodeLen += 2;
  2363. }
  2364. else {
  2365. TRC_ALT((TB,"Y delta %d too large/small to encode", Delta));
  2366. return FALSE;
  2367. }
  2368. }
  2369. // Set the zero flags by shifting the two bits we've accumulated.
  2370. ZeroFlags[(*pNumDeltas / 4)] |= (Zeros >> (2 * (*pNumDeltas & 0x03)));
  2371. *pNumDeltas += 1;
  2372. *pDeltaSize += EncodeLen;
  2373. *ppCurEncode = pBuffer;
  2374. // Update the bounding rect (exclusive coords).
  2375. if (pToPoint->x < pBoundRect->left)
  2376. pBoundRect->left = pToPoint->x;
  2377. else if ((pToPoint->x + 1) >= pBoundRect->right)
  2378. pBoundRect->right = pToPoint->x + 1;
  2379. if (pToPoint->y < pBoundRect->top)
  2380. pBoundRect->top = pToPoint->y;
  2381. else if ((pToPoint->y + 1) >= pBoundRect->bottom)
  2382. pBoundRect->bottom = pToPoint->y + 1;
  2383. DC_END_FN();
  2384. return TRUE;
  2385. }
  2386. // Worker function to allocate and direct-encode a PolyLine order.
  2387. // Note that the subpathing of a PolyLine makes it possible for
  2388. // the entire order to be clipped out by part of the clip rectangles.
  2389. // We cannot encode these clipped orders since they change the
  2390. // direct-encode state. To counter this we receive as a parameter the list of
  2391. // clip rects, and we don't allocate and create the order if it will be
  2392. // entirely clipped. Returns TRUE if there was no problem allocating space
  2393. // for the order (clipping the order completely is not an error).
  2394. BOOL OECreateAndFlushPolyLineOrder(
  2395. PDD_PDEV ppdev,
  2396. RECTL *pBoundRect,
  2397. OE_ENUMRECTS *pClipRects,
  2398. POINTL *pStartPoint,
  2399. BRUSHOBJ *pbo,
  2400. CLIPOBJ *pco,
  2401. unsigned ROP2,
  2402. unsigned NumDeltas,
  2403. unsigned DeltaSize,
  2404. BYTE *Deltas,
  2405. BYTE *ZeroFlags)
  2406. {
  2407. BOOL rc = TRUE;
  2408. unsigned i, NumRects;
  2409. unsigned NumZeroFlagBytes;
  2410. PINT_ORDER pOrder;
  2411. OE_ENUMRECTS IntersectRects;
  2412. DC_BEGIN_FN("OECreateAndFlushPolyLineOrder");
  2413. // First check to see if the order is completely clipped by the
  2414. // rects returned by the clip object. pBoundRect is exclusive.
  2415. IntersectRects.rects.c = 0;
  2416. if (pClipRects->rects.c == 0 ||
  2417. OEGetIntersectionsWithClipRects(pBoundRect, pClipRects,
  2418. &IntersectRects) > 0) {
  2419. // Round the number of zero flag bits actually used upward to the
  2420. // nearest byte. Each point encoded takes two bits.
  2421. NumZeroFlagBytes = (NumDeltas + 3) / 4;
  2422. TRC_ASSERT((NumZeroFlagBytes <= ORD_MAX_POLYLINE_ZERO_FLAGS_BYTES),
  2423. (TB,"Too many zero-flags bytes"));
  2424. TRC_ASSERT((NumDeltas <= ORD_MAX_POLYLINE_ENCODED_POINTS),
  2425. (TB,"Too many encoded orders"));
  2426. TRC_ASSERT((DeltaSize <= ORD_MAX_POLYLINE_CODEDDELTAS_LEN),
  2427. (TB,"Too many encoded delta bytes"));
  2428. // 1 field flag byte.
  2429. pOrder = OA_AllocOrderMem(ppdev, MAX_ORDER_SIZE(IntersectRects.rects.c,
  2430. 1, MAX_POLYLINE_BASE_FIELDS_SIZE + 1 + NumZeroFlagBytes +
  2431. DeltaSize));
  2432. if (pOrder != NULL) {
  2433. BYTE *pControlFlags = pOrder->OrderData;
  2434. BYTE *pBuffer = pControlFlags + 1;
  2435. BYTE *pFieldFlags;
  2436. short Delta, NormalCoordEncoding[2];
  2437. BOOLEAN bUseDeltaCoords;
  2438. unsigned NumFields;
  2439. DCCOLOR Color;
  2440. unsigned TotalSize;
  2441. // Direct-encode the primary order fields. 1 field flag byte.
  2442. *pControlFlags = TS_STANDARD;
  2443. OE2_EncodeOrderType(pControlFlags, &pBuffer,
  2444. TS_ENC_POLYLINE_ORDER);
  2445. pFieldFlags = pBuffer;
  2446. *pFieldFlags = 0;
  2447. pBuffer++;
  2448. if (IntersectRects.rects.c != 0)
  2449. OE2_EncodeBounds(pControlFlags, &pBuffer,
  2450. &IntersectRects.rects.arcl[0]);
  2451. // Inline field encode directly to wire format.
  2452. // Simultaneously determine if each of the coordinate fields has
  2453. // changed, whether we can use delta coordinates, and save changed
  2454. // fields.
  2455. NumFields = 0;
  2456. bUseDeltaCoords = TRUE;
  2457. // XStart
  2458. Delta = (short)(pStartPoint->x - PrevPolyLine.XStart);
  2459. if (Delta) {
  2460. PrevPolyLine.XStart = pStartPoint->x;
  2461. if (Delta != (short)(char)Delta)
  2462. bUseDeltaCoords = FALSE;
  2463. pBuffer[NumFields] = (char)Delta;
  2464. NormalCoordEncoding[NumFields] = (short)pStartPoint->x;
  2465. NumFields++;
  2466. *pFieldFlags |= 0x01;
  2467. }
  2468. // YStart
  2469. Delta = (short)(pStartPoint->y - PrevPolyLine.YStart);
  2470. if (Delta) {
  2471. PrevPolyLine.YStart = pStartPoint->y;
  2472. if (Delta != (short)(char)Delta)
  2473. bUseDeltaCoords = FALSE;
  2474. pBuffer[NumFields] = (char)Delta;
  2475. NormalCoordEncoding[NumFields] = (short)pStartPoint->y;
  2476. NumFields++;
  2477. *pFieldFlags |= 0x02;
  2478. }
  2479. // Copy the final coordinates to the order.
  2480. if (bUseDeltaCoords) {
  2481. *pControlFlags |= TS_DELTA_COORDINATES;
  2482. pBuffer += NumFields;
  2483. }
  2484. else {
  2485. *((DWORD UNALIGNED *)pBuffer) =
  2486. *((DWORD *)NormalCoordEncoding);
  2487. pBuffer += NumFields * sizeof(short);
  2488. }
  2489. // ROP2
  2490. if (ROP2 != PrevPolyLine.ROP2) {
  2491. PrevPolyLine.ROP2 = ROP2;
  2492. *pBuffer++ = (BYTE)ROP2;
  2493. *pFieldFlags |= 0x04;
  2494. }
  2495. // BrushCacheEntry. This field is currently unused. We simply choose
  2496. // always to send zero, which means we can skip the field for
  2497. // the encoding. This is field encoding flag 0x08.
  2498. // PenColor is a 3-byte color field.
  2499. OEConvertColor(ppdev, &Color, pbo->iSolidColor, NULL);
  2500. if (memcmp(&Color, &PrevPolyLine.PenColor, sizeof(Color))) {
  2501. PrevPolyLine.PenColor = Color;
  2502. *pBuffer++ = Color.u.rgb.red;
  2503. *pBuffer++ = Color.u.rgb.green;
  2504. *pBuffer++ = Color.u.rgb.blue;
  2505. *pFieldFlags |= 0x10;
  2506. }
  2507. // NumDeltaEntries
  2508. if (NumDeltas != PrevPolyLine.NumDeltaEntries) {
  2509. PrevPolyLine.NumDeltaEntries = NumDeltas;
  2510. *pBuffer++ = (BYTE)NumDeltas;
  2511. *pFieldFlags |= 0x20;
  2512. }
  2513. // CodedDeltaList - a variable-length byte stream. First 1-byte
  2514. // value is the count of bytes, followed by the zero flags and
  2515. // then the deltas. This field is considered different from the
  2516. // previous if the length or the contents are different.
  2517. *pBuffer = (BYTE)(DeltaSize + NumZeroFlagBytes);
  2518. memcpy(pBuffer + 1, ZeroFlags, NumZeroFlagBytes);
  2519. memcpy(pBuffer + 1 + NumZeroFlagBytes, Deltas, DeltaSize);
  2520. TotalSize = 1 + NumZeroFlagBytes + DeltaSize;
  2521. if (memcmp(pBuffer, &PrevPolyLine.CodedDeltaList, TotalSize)) {
  2522. memcpy(&PrevPolyLine.CodedDeltaList, pBuffer, TotalSize);
  2523. pBuffer += TotalSize;
  2524. *pFieldFlags |= 0x40;
  2525. }
  2526. pOrder->OrderLength = (unsigned)(pBuffer - pOrder->OrderData);
  2527. // See if we can save sending the order field bytes.
  2528. pOrder->OrderLength -= OE2_CheckOneZeroFlagByte(pControlFlags,
  2529. pFieldFlags, (unsigned)(pBuffer - pFieldFlags - 1));
  2530. INC_OUTCOUNTER(OUT_STROKEPATH_POLYLINE);
  2531. ADD_INCOUNTER(IN_POLYLINE_BYTES, pOrder->OrderLength);
  2532. OA_AppendToOrderList(pOrder);
  2533. // Flush the order.
  2534. if (IntersectRects.rects.c < 2)
  2535. rc = TRUE;
  2536. else
  2537. rc = OEEmitReplayOrders(ppdev, 1, &IntersectRects);
  2538. }
  2539. else {
  2540. TRC_ERR((TB,"Failed to alloc space for order"));
  2541. rc = FALSE;
  2542. }
  2543. }
  2544. else {
  2545. TRC_DBG((TB,"Clipping PolyLine order - no intersecting clip rects"));
  2546. }
  2547. DC_END_FN();
  2548. return rc;
  2549. }
  2550. // Worker function - combines the chore of allocating EllipseSC order from
  2551. // the OA heap and contructing the order given the parameters. Then we give
  2552. // the order to OE to finish encoding. Returns TRUE on success (meaning no
  2553. // error allocating from the order heap).
  2554. BOOL OECreateAndFlushEllipseSCOrder(
  2555. PDD_PDEV ppdev,
  2556. RECT *pEllipseRect,
  2557. BRUSHOBJ *pbo,
  2558. OE_ENUMRECTS *pClipRects,
  2559. unsigned ROP2,
  2560. FLONG flOptions)
  2561. {
  2562. BOOL rc = TRUE;
  2563. PINT_ORDER pOrder;
  2564. PELLIPSE_SC_ORDER pEllipseSC;
  2565. OE_ENUMRECTS IntersectRects;
  2566. RECTL ExclusiveRect;
  2567. DC_BEGIN_FN("OECreateAndFlushEllipseSCOrder");
  2568. // EllipseRect is inclusive, we need exclusive for getting clip rects.
  2569. ExclusiveRect = *((RECTL *)pEllipseRect);
  2570. ExclusiveRect.right++;
  2571. ExclusiveRect.bottom++;
  2572. // First make sure the clip rects actually intersect with the ellipse
  2573. // after its target screen rect has been calculated. Note that
  2574. // *pEllipseRect is already in inclusive coords.
  2575. IntersectRects.rects.c = 0;
  2576. if (pClipRects->rects.c == 0 ||
  2577. OEGetIntersectionsWithClipRects(&ExclusiveRect, pClipRects,
  2578. &IntersectRects) > 0) {
  2579. // 1 field flag byte.
  2580. pOrder = OA_AllocOrderMem(ppdev, MAX_ORDER_SIZE(IntersectRects.rects.c,
  2581. 1, MAX_ELLIPSE_SC_FIELD_SIZE));
  2582. if (pOrder != NULL) {
  2583. // Set up the order fields in the temp buffer.
  2584. pEllipseSC = (PELLIPSE_SC_ORDER)oeTempOrderBuffer;
  2585. pEllipseSC->LeftRect = pEllipseRect->left;
  2586. pEllipseSC->RightRect = pEllipseRect->right;
  2587. pEllipseSC->TopRect = pEllipseRect->top;
  2588. pEllipseSC->BottomRect = pEllipseRect->bottom;
  2589. pEllipseSC->ROP2 = ROP2;
  2590. pEllipseSC->FillMode = flOptions;
  2591. OEConvertColor(ppdev, &pEllipseSC->Color, pbo->iSolidColor, NULL);
  2592. // Slow-field-encode the order with the first clip rect
  2593. // (if present).
  2594. pOrder->OrderLength = OE2_EncodeOrder(pOrder->OrderData,
  2595. TS_ENC_ELLIPSE_SC_ORDER, NUM_ELLIPSE_SC_FIELDS,
  2596. (BYTE *)pEllipseSC, (BYTE *)&PrevEllipseSC, etable_EC,
  2597. (IntersectRects.rects.c == 0 ? NULL :
  2598. &IntersectRects.rects.arcl[0]));
  2599. ADD_INCOUNTER(IN_ELLIPSE_SC_BYTES, pOrder->OrderLength);
  2600. OA_AppendToOrderList(pOrder);
  2601. // Flush the order.
  2602. if (IntersectRects.rects.c < 2)
  2603. rc = TRUE;
  2604. else
  2605. rc = OEEmitReplayOrders(ppdev, 1, &IntersectRects);
  2606. }
  2607. else {
  2608. TRC_ERR((TB,"Failed to alloc order heap space for ellipse"));
  2609. rc = FALSE;
  2610. }
  2611. }
  2612. else {
  2613. // We still return TRUE here since the order was handled OK, just not
  2614. // sent.
  2615. TRC_NRM((TB,"Ellipse does not intersect with cliprects"));
  2616. }
  2617. DC_END_FN();
  2618. return rc;
  2619. }
  2620. // The real function.
  2621. BOOL RDPCALL DrvStrokePath(
  2622. SURFOBJ *pso,
  2623. PATHOBJ *ppo,
  2624. CLIPOBJ *pco,
  2625. XFORMOBJ *pxo,
  2626. BRUSHOBJ *pbo,
  2627. POINTL *pptlBrushOrg,
  2628. LINEATTRS *plineattrs,
  2629. MIX mix)
  2630. {
  2631. PDD_PDEV ppdev = (PDD_PDEV)pso->dhpdev;
  2632. PDD_DSURF pdsurf = NULL;
  2633. BOOL rc = TRUE;
  2634. RECTFX rectfxTrg;
  2635. RECTL rectTrg;
  2636. BOOL fMore = TRUE;
  2637. PATHDATA pathData;
  2638. POINTL originPoint;
  2639. POINTL startPoint;
  2640. POINTL nextPoint;
  2641. POINTL endPoint;
  2642. unsigned pathIndex;
  2643. OE_ENUMRECTS ClipRects;
  2644. DC_BEGIN_FN("DrvStrokePath");
  2645. // Sometimes, we're called after being disconnected.
  2646. if (ddConnected && pddShm != NULL) {
  2647. // Surface is non-NULL.
  2648. pso = OEGetSurfObjBitmap(pso, &pdsurf);
  2649. // Get bounding rectangle.
  2650. PATHOBJ_vGetBounds(ppo, &rectfxTrg);
  2651. RECT_FROM_RECTFX(rectTrg, rectfxTrg);
  2652. // Punt the call back to GDI to do the drawing.
  2653. INC_OUTCOUNTER(OUT_STROKEPATH_ALL);
  2654. rc = EngStrokePath(pso, ppo, pco, pxo, pbo, pptlBrushOrg, plineattrs,
  2655. mix);
  2656. if (!rc) {
  2657. TRC_ERR((TB, "EngStrokePath failed"));
  2658. DC_QUIT;
  2659. }
  2660. // if the path bound gives empty rect, we'll just ignore
  2661. if (rectTrg.left == 0 && rectTrg.right == 0 &&
  2662. rectTrg.top == 0 && rectTrg.bottom == 0) {
  2663. TRC_ERR((TB, "Empty Path obj bounding rect, ignore"));
  2664. DC_QUIT;
  2665. }
  2666. }
  2667. else {
  2668. if (pso->iType == STYPE_DEVBITMAP) {
  2669. // Surface is non-NULL.
  2670. pso = OEGetSurfObjBitmap(pso, &pdsurf);
  2671. rc = EngStrokePath(pso, ppo, pco, pxo, pbo, pptlBrushOrg, plineattrs,
  2672. mix);
  2673. }
  2674. else {
  2675. TRC_ERR((TB, "Called when disconnected"));
  2676. }
  2677. goto CalledOnDisconnected;
  2678. }
  2679. if ((pso->hsurf == ppdev->hsurfFrameBuf) ||
  2680. (!(pdsurf->flags & DD_NO_OFFSCREEN))) {
  2681. // Send a switch surface PDU if the destination surface is different
  2682. // from last drawing order. If we failed to send the PDU, we will
  2683. // just have to bail on this drawing order.
  2684. if (!OESendSwitchSurfacePDU(ppdev, pdsurf)) {
  2685. TRC_ERR((TB, "failed to send the switch surface PDU"));
  2686. DC_QUIT;
  2687. }
  2688. } else {
  2689. // if noOffscreen flag is on, we will bail on sending
  2690. // the client any further offscreen rendering. And will send the final
  2691. // offscreen to screen blt as regular memblt.
  2692. TRC_NRM((TB, "Offscreen blt bail"));
  2693. DC_QUIT;
  2694. }
  2695. // Check if we are allowed to send this order.
  2696. if (OE_SendAsOrder(TS_ENC_POLYLINE_ORDER)) {
  2697. // Check for a valid brush for the test operation.
  2698. if (pbo->iSolidColor != -1) {
  2699. unsigned RetVal;
  2700. // Get the intersection between the entire dest rect and
  2701. // the clip rects. Check for overcomplicated or
  2702. // nonintersecting clipping. Note this is a first cut,
  2703. // further interactions are calculated for each PolyLine
  2704. // subpath and ellipse created.
  2705. RetVal = OEGetIntersectingClipRects(pco, &rectTrg, CD_ANY,
  2706. &ClipRects);
  2707. if (RetVal == CLIPRECTS_TOO_COMPLEX) {
  2708. TRC_NRM((TB, "Clipping is too complex"));
  2709. INC_OUTCOUNTER(OUT_STROKEPATH_SDA_COMPLEXCLIP);
  2710. goto SendAsSDA;
  2711. }
  2712. else if (RetVal == CLIPRECTS_NO_INTERSECTIONS) {
  2713. TRC_NRM((TB, "Clipping does not intersect destrect"));
  2714. DC_QUIT;
  2715. }
  2716. }
  2717. else {
  2718. TRC_NRM((TB, "Bad brush for line"));
  2719. INC_OUTCOUNTER(OUT_STROKEPATH_SDA_BADBRUSH);
  2720. goto SendAsSDA;
  2721. }
  2722. }
  2723. else {
  2724. TRC_NRM((TB, "PolyLine order not allowed"));
  2725. INC_OUTCOUNTER(OUT_STROKEPATH_SDA_NOLINETO);
  2726. goto SendAsSDA;
  2727. }
  2728. // See if we can optimize the path...
  2729. // We cannot send beziers, geometric lines, or nonstandard patterns.
  2730. if (ppo->fl & PO_ELLIPSE &&
  2731. OE_SendAsOrder(TS_ENC_ELLIPSE_SC_ORDER)) {
  2732. RECT EllipseRect;
  2733. // Get the inclusive rect covering only the ellipse itself.
  2734. // Add 4/16 to left and top, subtract from right and bottom, to undo
  2735. // the GDI transformation already performed.
  2736. EllipseRect.left = FXTOLROUND(rectfxTrg.xLeft + 4);
  2737. EllipseRect.top = FXTOLROUND(rectfxTrg.yTop + 4);
  2738. EllipseRect.right = FXTOLROUND(rectfxTrg.xRight - 4);
  2739. EllipseRect.bottom = FXTOLROUND(rectfxTrg.yBottom - 4);
  2740. // We use fillmode 0 to indidate this is a polyline ellipse.
  2741. if (OECreateAndFlushEllipseSCOrder(ppdev, &EllipseRect, pbo,
  2742. &ClipRects, mix & 0x1F, 0)) {
  2743. INC_OUTCOUNTER(OUT_STROKEPATH_ELLIPSE_SC);
  2744. goto PostSDA;
  2745. }
  2746. else {
  2747. // No order heap space, send all as SDAs.
  2748. INC_OUTCOUNTER(OUT_STROKEPATH_SDA_FAILEDADD);
  2749. goto SendAsSDA;
  2750. }
  2751. }
  2752. else if (!(ppo->fl & PO_BEZIERS) &&
  2753. !(plineattrs->fl & LA_GEOMETRIC) &&
  2754. plineattrs->pstyle == NULL) {
  2755. BYTE Deltas[ORD_MAX_POLYLINE_CODEDDELTAS_LEN];
  2756. BYTE ZeroFlags[ORD_MAX_POLYLINE_ZERO_FLAGS_BYTES];
  2757. BYTE *pCurEncode;
  2758. RECTL BoundRect;
  2759. POINTL HoldPoint;
  2760. unsigned NumDeltas;
  2761. unsigned DeltaSize;
  2762. // This is a set of solid cosmetic (i.e. no fancy end styles)
  2763. // width-1 lines. NT stores all paths as a set of independent
  2764. // sub-paths. Each sub-path can start at a new point that is NOT
  2765. // linked to the previous sub-path. Paths used for this function
  2766. // (as opposed to DrvFillPath or DrvStrokeAndFillPath) do not need
  2767. // to be closed. We assume that the first enumerated subpath will
  2768. // have the PD_BEGINSUBPATH flag set; this appears to match reality.
  2769. PATHOBJ_vEnumStart(ppo);
  2770. while (fMore) {
  2771. // Get the next set of lines.
  2772. fMore = PATHOBJ_bEnum(ppo, &pathData);
  2773. TRC_DBG((TB, "PTS: %lu FLAG: %08lx",
  2774. pathData.count,
  2775. pathData.flags));
  2776. // If this is the start of a path, remember the origin point in
  2777. // case we need to close the path at the end. startPoint is the
  2778. // start point for the current PolyLine order in the rare case
  2779. // where we have more than MAX_POLYLINE_ENCODED_POINTS points.
  2780. if (pathData.flags & PD_BEGINSUBPATH) {
  2781. POINT_FROM_POINTFIX(originPoint, pathData.pptfx[0]);
  2782. nextPoint = originPoint;
  2783. startPoint = originPoint;
  2784. // Set up encoding variables. Start the bound rect with
  2785. // a zero-size rect.
  2786. BoundRect.left = BoundRect.right = startPoint.x;
  2787. BoundRect.top = BoundRect.bottom = startPoint.y;
  2788. NumDeltas = DeltaSize = 0;
  2789. pCurEncode = Deltas;
  2790. memset(ZeroFlags, 0, sizeof(ZeroFlags));
  2791. pathIndex = 1;
  2792. }
  2793. else {
  2794. // This is a continuation from a previous PATHDATA.
  2795. nextPoint = HoldPoint;
  2796. pathIndex = 0;
  2797. }
  2798. // Generate deltas for each point in the path.
  2799. for (; pathIndex < pathData.count; pathIndex++) {
  2800. POINT_FROM_POINTFIX(endPoint, pathData.pptfx[pathIndex]);
  2801. // Don't try to encode points where both deltas are zero.
  2802. if ((nextPoint.x != endPoint.x) ||
  2803. (nextPoint.y != endPoint.y)) {
  2804. if (OEEncodePolyLinePointDelta(&pCurEncode, &NumDeltas,
  2805. &DeltaSize, ZeroFlags, &nextPoint, &endPoint,
  2806. &BoundRect)) {
  2807. // Check for full order and flush if need be.
  2808. if (NumDeltas == ORD_MAX_POLYLINE_ENCODED_POINTS) {
  2809. if (OECreateAndFlushPolyLineOrder(ppdev,
  2810. &BoundRect, &ClipRects, &startPoint, pbo,
  2811. pco, mix & 0x1F, NumDeltas, DeltaSize,
  2812. Deltas, ZeroFlags)) {
  2813. // We have a new temporary start point in the
  2814. // middle of the path.
  2815. startPoint = endPoint;
  2816. // Reset encoding variables.
  2817. BoundRect.left = BoundRect.right = startPoint.x;
  2818. BoundRect.top = BoundRect.bottom = startPoint.y;
  2819. NumDeltas = DeltaSize = 0;
  2820. pCurEncode = Deltas;
  2821. memset(ZeroFlags, 0, sizeof(ZeroFlags));
  2822. } else {
  2823. // No order heap space, send all as SDAs.
  2824. INC_OUTCOUNTER(OUT_STROKEPATH_SDA_FAILEDADD);
  2825. goto SendAsSDA;
  2826. }
  2827. }
  2828. }
  2829. else {
  2830. goto SendAsSDA;
  2831. }
  2832. }
  2833. nextPoint = endPoint;
  2834. }
  2835. // Close the path if necessary.
  2836. if (pathData.flags & PD_CLOSEFIGURE) {
  2837. // Don't try to encode points where both deltas are zero.
  2838. if ((nextPoint.x != originPoint.x) ||
  2839. (nextPoint.y != originPoint.y)) {
  2840. if (!OEEncodePolyLinePointDelta(&pCurEncode, &NumDeltas,
  2841. &DeltaSize, ZeroFlags, &nextPoint, &originPoint,
  2842. &BoundRect)) {
  2843. goto SendAsSDA;
  2844. }
  2845. }
  2846. // PD_CLOSEFIGURE is present only with PD_ENDSUBPATH but
  2847. // just in case...
  2848. TRC_ASSERT((pathData.flags & PD_ENDSUBPATH),
  2849. (TB,"CLOSEFIGURE received without ENDSUBPATH"));
  2850. }
  2851. if (pathData.flags & PD_ENDSUBPATH) {
  2852. if (NumDeltas > 0) {
  2853. // We are at the end of the subpath. Flush the data we
  2854. // have.
  2855. if (!OECreateAndFlushPolyLineOrder(ppdev, &BoundRect,
  2856. &ClipRects, &startPoint, pbo, pco,
  2857. mix & 0x1F, NumDeltas, DeltaSize, Deltas,
  2858. ZeroFlags)) {
  2859. // No order heap space, send all as SDAs.
  2860. INC_OUTCOUNTER(OUT_STROKEPATH_SDA_FAILEDADD);
  2861. goto SendAsSDA;
  2862. }
  2863. }
  2864. }
  2865. else {
  2866. HoldPoint = endPoint;
  2867. }
  2868. }
  2869. goto PostSDA;
  2870. }
  2871. SendAsSDA:
  2872. if (pso->hsurf == ppdev->hsurfFrameBuf) {
  2873. INC_OUTCOUNTER(OUT_STROKEPATH_SDA);
  2874. ADD_INCOUNTER(IN_SDA_STROKEPATH_AREA, COM_SIZEOF_RECT(rectTrg));
  2875. // Clip the bound rect to 16 bits and add to SDA.
  2876. OEClipRect(&rectTrg);
  2877. TRC_DBG((TB, "SDA: (%d,%d)(%d,%d)", rectTrg.left, rectTrg.top,
  2878. rectTrg.right, rectTrg.bottom));
  2879. OEClipAndAddScreenDataArea(&rectTrg, pco);
  2880. }
  2881. else {
  2882. // If we can't send orders for offscreen rendering, we will
  2883. // bail offscreen support for this bitmap.
  2884. TRC_ALT((TB, "screen data call for offscreen rendering"));
  2885. if (!(pdsurf->flags & DD_NO_OFFSCREEN))
  2886. CH_RemoveCacheEntry(sbcOffscreenBitmapCacheHandle, pdsurf->bitmapId);
  2887. DC_QUIT;
  2888. }
  2889. PostSDA:
  2890. // Have scheduler consider sending output.
  2891. SCH_DDOutputAvailable(ppdev, FALSE);
  2892. CalledOnDisconnected:
  2893. DC_EXIT_POINT:
  2894. DC_END_FN();
  2895. return rc;
  2896. }
  2897. /****************************************************************************/
  2898. /* DrvFillPath - see NT DDK documentation. */
  2899. /****************************************************************************/
  2900. // Worker function - combines the chore of allocating PolyGonCB order from
  2901. // the OA heap and contructing the order given the parameters. Then we give
  2902. // the order to OE to finish encoding. Returns TRUE on success (meaning no
  2903. // error allocating from the order heap).
  2904. BOOL OECreateAndFlushPolygonCBOrder(
  2905. PDD_PDEV ppdev,
  2906. RECTL *pBoundRect,
  2907. POINTL *pStartPoint,
  2908. POE_BRUSH_DATA pCurrentBrush,
  2909. POINTL *pptlBrushOrg,
  2910. OE_ENUMRECTS *pClipRects,
  2911. MIX mix,
  2912. FLONG flOptions,
  2913. unsigned NumDeltas,
  2914. unsigned DeltaSize,
  2915. BYTE *Deltas,
  2916. BYTE *ZeroFlags)
  2917. {
  2918. BOOL rc = TRUE;
  2919. unsigned NumZeroFlagBytes;
  2920. PINT_ORDER pOrder;
  2921. PPOLYGON_CB_ORDER pPolygonCB;
  2922. OE_ENUMRECTS IntersectRects;
  2923. DC_BEGIN_FN("OECreateAndFlushPolygonCBOrder");
  2924. // First make sure the clip rects actually intersect with the polygon
  2925. // after its target screen rect has been calculated. Note that
  2926. // *pBoundRect is in exclusive coords.
  2927. IntersectRects.rects.c = 0;
  2928. if (pClipRects->rects.c == 0 ||
  2929. OEGetIntersectionsWithClipRects(pBoundRect, pClipRects,
  2930. &IntersectRects) > 0) {
  2931. // Round the number of zero flag bits actually used upward to the
  2932. // nearest byte. Each point encoded takes two bits.
  2933. NumZeroFlagBytes = (NumDeltas + 3) / 4;
  2934. TRC_ASSERT((NumZeroFlagBytes <= ORD_MAX_POLYGON_ZERO_FLAGS_BYTES),
  2935. (TB,"Too many zero-flags bytes"));
  2936. TRC_ASSERT((NumDeltas <= ORD_MAX_POLYGON_ENCODED_POINTS),
  2937. (TB,"Too many encoded orders"));
  2938. TRC_ASSERT((DeltaSize <= ORD_MAX_POLYGON_CODEDDELTAS_LEN),
  2939. (TB,"Too many encoded delta bytes"));
  2940. // 2 field flag bytes.
  2941. pOrder = OA_AllocOrderMem(ppdev, MAX_ORDER_SIZE(IntersectRects.rects.c,
  2942. 2, MAX_POLYGON_CB_BASE_FIELDS_SIZE + 1 + NumZeroFlagBytes +
  2943. DeltaSize));
  2944. if (pOrder != NULL) {
  2945. // Set up the order fields.
  2946. pPolygonCB = (PPOLYGON_CB_ORDER)oeTempOrderBuffer;
  2947. pPolygonCB->XStart = pStartPoint->x;
  2948. pPolygonCB->YStart = pStartPoint->y;
  2949. // If this is a hatched brush, the high bit of ROP2 indicates the
  2950. // background fill mode: 1 means transparent, 0 means opaque.
  2951. pPolygonCB->ROP2 = mix & 0x1F;
  2952. if (pCurrentBrush->style == BS_HATCHED &&
  2953. ((mix & 0x1F00) >> 8) == R2_NOP)
  2954. pPolygonCB->ROP2 |= 0x80;
  2955. pPolygonCB->FillMode = flOptions;
  2956. pPolygonCB->NumDeltaEntries = NumDeltas;
  2957. pPolygonCB->CodedDeltaList.len = DeltaSize + NumZeroFlagBytes;
  2958. // Pattern colors.
  2959. pPolygonCB->BackColor = pCurrentBrush->back;
  2960. pPolygonCB->ForeColor = pCurrentBrush->fore;
  2961. // The protocol brush origin is the point on the screen where
  2962. // we want the brush to start being drawn from (tiling where
  2963. // necessary).
  2964. pPolygonCB->BrushOrgX = pptlBrushOrg->x;
  2965. pPolygonCB->BrushOrgY = pptlBrushOrg->y;
  2966. OEClipPoint((PPOINTL)&pPolygonCB->BrushOrgX);
  2967. // Extra brush data from the data when we realised the brush.
  2968. pPolygonCB->BrushStyle = pCurrentBrush->style;
  2969. pPolygonCB->BrushHatch = pCurrentBrush->hatch;
  2970. memcpy(pPolygonCB->BrushExtra, pCurrentBrush->brushData,
  2971. sizeof(pPolygonCB->BrushExtra));
  2972. // Copy the zero flags first.
  2973. memcpy(pPolygonCB->CodedDeltaList.Deltas, ZeroFlags, NumZeroFlagBytes);
  2974. // Next copy the encoded deltas.
  2975. memcpy(pPolygonCB->CodedDeltaList.Deltas + NumZeroFlagBytes, Deltas,
  2976. DeltaSize);
  2977. // Slow-field-encode the order with the first clip rect
  2978. // (if present).
  2979. pOrder->OrderLength = OE2_EncodeOrder(pOrder->OrderData,
  2980. TS_ENC_POLYGON_CB_ORDER, NUM_POLYGON_CB_FIELDS,
  2981. (BYTE *)pPolygonCB, (BYTE *)&PrevPolygonCB, etable_BG,
  2982. (IntersectRects.rects.c == 0 ? NULL :
  2983. &IntersectRects.rects.arcl[0]));
  2984. ADD_INCOUNTER(IN_POLYGON_CB_BYTES, pOrder->OrderLength);
  2985. OA_AppendToOrderList(pOrder);
  2986. // Flush the order.
  2987. if (IntersectRects.rects.c < 2)
  2988. rc = TRUE;
  2989. else
  2990. rc = OEEmitReplayOrders(ppdev, 2, &IntersectRects);
  2991. }
  2992. else {
  2993. TRC_ERR((TB,"Failed to alloc space for PolygonSC"));
  2994. rc = FALSE;
  2995. }
  2996. }
  2997. else {
  2998. // We still return TRUE here since we handled the order by not
  2999. // sending it.
  3000. TRC_NRM((TB,"PolygonCB fully clipped out"));
  3001. }
  3002. DC_END_FN();
  3003. return rc;
  3004. }
  3005. // Worker function - combines the chore of allocating PolygonSC order from
  3006. // the OA heap and contructing the order given the parameters. Then we give
  3007. // the order to OE to finish encoding. Returns TRUE on success (meaning no
  3008. // error allocating from the order heap).
  3009. BOOL OECreateAndFlushPolygonSCOrder(
  3010. PDD_PDEV ppdev,
  3011. RECTL *pBoundRect,
  3012. POINTL *pStartPoint,
  3013. BRUSHOBJ *pbo,
  3014. OE_ENUMRECTS *pClipRects,
  3015. unsigned ROP2,
  3016. FLONG flOptions,
  3017. unsigned NumDeltas,
  3018. unsigned DeltaSize,
  3019. BYTE *Deltas,
  3020. BYTE *ZeroFlags)
  3021. {
  3022. BOOL rc = TRUE;
  3023. unsigned NumZeroFlagBytes;
  3024. PINT_ORDER pOrder;
  3025. PPOLYGON_SC_ORDER pPolygonSC;
  3026. OE_ENUMRECTS IntersectRects;
  3027. DC_BEGIN_FN("OECreateAndFlushPolygonSCOrder");
  3028. // First make sure the clip rects actually intersect with the polygon
  3029. // after its target screen rect has been calculated. Note that
  3030. // *pBoundRect is in exclusive coords.
  3031. IntersectRects.rects.c = 0;
  3032. if (pClipRects->rects.c == 0 ||
  3033. OEGetIntersectionsWithClipRects(pBoundRect, pClipRects,
  3034. &IntersectRects) > 0) {
  3035. // Round the number of zero flag bits actually used upward to the
  3036. // nearest byte. Each point encoded takes two bits.
  3037. NumZeroFlagBytes = (NumDeltas + 3) / 4;
  3038. TRC_ASSERT((NumZeroFlagBytes <= ORD_MAX_POLYGON_ZERO_FLAGS_BYTES),
  3039. (TB,"Too many zero-flags bytes"));
  3040. TRC_ASSERT((NumDeltas <= ORD_MAX_POLYGON_ENCODED_POINTS),
  3041. (TB,"Too many encoded orders"));
  3042. TRC_ASSERT((DeltaSize <= ORD_MAX_POLYGON_CODEDDELTAS_LEN),
  3043. (TB,"Too many encoded delta bytes"));
  3044. // 1 field flag byte.
  3045. pOrder = OA_AllocOrderMem(ppdev, MAX_ORDER_SIZE(IntersectRects.rects.c,
  3046. 1, MAX_POLYGON_SC_BASE_FIELDS_SIZE + 1 + NumZeroFlagBytes +
  3047. DeltaSize));
  3048. if (pOrder != NULL) {
  3049. // Set up the order fields.
  3050. pPolygonSC = (PPOLYGON_SC_ORDER)oeTempOrderBuffer;
  3051. pPolygonSC->XStart = pStartPoint->x;
  3052. pPolygonSC->YStart = pStartPoint->y;
  3053. pPolygonSC->ROP2 = ROP2;
  3054. pPolygonSC->FillMode = flOptions;
  3055. pPolygonSC->NumDeltaEntries = NumDeltas;
  3056. pPolygonSC->CodedDeltaList.len = DeltaSize + NumZeroFlagBytes;
  3057. // Pattern colors.
  3058. OEConvertColor(ppdev, &pPolygonSC->BrushColor, pbo->iSolidColor,
  3059. NULL);
  3060. // Copy the zero flags first.
  3061. memcpy(pPolygonSC->CodedDeltaList.Deltas, ZeroFlags,
  3062. NumZeroFlagBytes);
  3063. // Next copy the encoded deltas.
  3064. memcpy(pPolygonSC->CodedDeltaList.Deltas + NumZeroFlagBytes,
  3065. Deltas, DeltaSize);
  3066. // Slow-field-encode the order with the first clip rect
  3067. // (if present).
  3068. pOrder->OrderLength = OE2_EncodeOrder(pOrder->OrderData,
  3069. TS_ENC_POLYGON_SC_ORDER, NUM_POLYGON_SC_FIELDS,
  3070. (BYTE *)pPolygonSC, (BYTE *)&PrevPolygonSC, etable_CG,
  3071. (IntersectRects.rects.c == 0 ? NULL :
  3072. &IntersectRects.rects.arcl[0]));
  3073. ADD_INCOUNTER(IN_POLYGON_SC_BYTES, pOrder->OrderLength);
  3074. OA_AppendToOrderList(pOrder);
  3075. // Flush the order.
  3076. if (IntersectRects.rects.c < 2)
  3077. rc = TRUE;
  3078. else
  3079. rc = OEEmitReplayOrders(ppdev, 1, &IntersectRects);
  3080. }
  3081. else {
  3082. TRC_ERR((TB,"Failed to alloc space for PolygonCB"));
  3083. rc = FALSE;
  3084. }
  3085. }
  3086. else {
  3087. // We still return TRUE here since we handled the order by not
  3088. // sending it.
  3089. TRC_NRM((TB,"PolygonSC completely clipped"));
  3090. }
  3091. DC_END_FN();
  3092. return rc;
  3093. }
  3094. // Worker function - combines the chore of allocating EllipseCB order from
  3095. // the OA heap and contructing the order given the parameters. Then we give
  3096. // the order to OE to finish encoding. Returns TRUE on success (meaning no
  3097. // error allocating from the order heap).
  3098. BOOL OECreateAndFlushEllipseCBOrder(
  3099. PDD_PDEV ppdev,
  3100. RECT *pEllipseRect,
  3101. POE_BRUSH_DATA pCurrentBrush,
  3102. POINTL *pptlBrushOrg,
  3103. OE_ENUMRECTS *pClipRects,
  3104. MIX mix,
  3105. FLONG flOptions)
  3106. {
  3107. BOOL rc = TRUE;
  3108. PINT_ORDER pOrder;
  3109. PELLIPSE_CB_ORDER pEllipseCB;
  3110. OE_ENUMRECTS IntersectRects;
  3111. RECTL ExclusiveRect;
  3112. DC_BEGIN_FN("OECreateAndFlushEllipseCBOrder");
  3113. // EllipseRect is inclusive, we need exclusive for getting clip rects.
  3114. ExclusiveRect = *((RECTL *)pEllipseRect);
  3115. ExclusiveRect.right++;
  3116. ExclusiveRect.bottom++;
  3117. // First make sure the clip rects actually intersect with the ellipse
  3118. // after its target screen rect has been calculated. Note that
  3119. // *pEllipseRect is already in inclusive coords.
  3120. IntersectRects.rects.c = 0;
  3121. if (pClipRects->rects.c == 0 ||
  3122. OEGetIntersectionsWithClipRects(&ExclusiveRect, pClipRects,
  3123. &IntersectRects) > 0) {
  3124. // 2 field flag bytes.
  3125. pOrder = OA_AllocOrderMem(ppdev, MAX_ORDER_SIZE(IntersectRects.rects.c,
  3126. 2, MAX_ELLIPSE_CB_FIELD_SIZE));
  3127. if (pOrder != NULL) {
  3128. // Set up the order fields.
  3129. pEllipseCB = (PELLIPSE_CB_ORDER)oeTempOrderBuffer;
  3130. pEllipseCB->LeftRect = pEllipseRect->left;
  3131. pEllipseCB->RightRect = pEllipseRect->right;
  3132. pEllipseCB->TopRect = pEllipseRect->top;
  3133. pEllipseCB->BottomRect = pEllipseRect->bottom;
  3134. pEllipseCB->FillMode = flOptions;
  3135. // If this is a hatched brush, the high bit of ROP2 indicates the
  3136. // background fill mode: 1 means transparent, 0 means opaque.
  3137. pEllipseCB->ROP2 = mix & 0x1F;
  3138. if (pCurrentBrush->style == BS_HATCHED &&
  3139. ((mix & 0x1F00) >> 8) == R2_NOP)
  3140. pEllipseCB->ROP2 |= 0x80;
  3141. // Pattern colors.
  3142. pEllipseCB->BackColor = pCurrentBrush->back;
  3143. pEllipseCB->ForeColor = pCurrentBrush->fore;
  3144. // The protocol brush origin is the point on the screen where
  3145. // we want the brush to start being drawn from (tiling where
  3146. // necessary).
  3147. pEllipseCB->BrushOrgX = pptlBrushOrg->x;
  3148. pEllipseCB->BrushOrgY = pptlBrushOrg->y;
  3149. OEClipPoint((PPOINTL)&pEllipseCB->BrushOrgX);
  3150. // Extra brush data from the data when we realised the brush.
  3151. pEllipseCB->BrushStyle = pCurrentBrush->style;
  3152. pEllipseCB->BrushHatch = pCurrentBrush->hatch;
  3153. memcpy(pEllipseCB->BrushExtra, pCurrentBrush->brushData,
  3154. sizeof(pEllipseCB->BrushExtra));
  3155. // Slow-field-encode the order with the first clip rect
  3156. // (if present).
  3157. pOrder->OrderLength = OE2_EncodeOrder(pOrder->OrderData,
  3158. TS_ENC_ELLIPSE_CB_ORDER, NUM_ELLIPSE_CB_FIELDS,
  3159. (BYTE *)pEllipseCB, (BYTE *)&PrevEllipseCB, etable_EB,
  3160. (IntersectRects.rects.c == 0 ? NULL :
  3161. &IntersectRects.rects.arcl[0]));
  3162. ADD_INCOUNTER(IN_ELLIPSE_CB_BYTES, pOrder->OrderLength);
  3163. OA_AppendToOrderList(pOrder);
  3164. // Flush the order.
  3165. if (IntersectRects.rects.c < 2)
  3166. rc = TRUE;
  3167. else
  3168. rc = OEEmitReplayOrders(ppdev, 2, &IntersectRects);
  3169. }
  3170. else {
  3171. TRC_ERR((TB,"Unable to alloc space for EllipseCB"));
  3172. rc = FALSE;
  3173. }
  3174. }
  3175. else {
  3176. // We still return TRUE here since we handled the order by not
  3177. // sending it.
  3178. TRC_NRM((TB,"EllipseCB completely clipped"));
  3179. }
  3180. DC_END_FN();
  3181. return rc;
  3182. }
  3183. //
  3184. // DrvFillPath
  3185. //
  3186. BOOL RDPCALL DrvFillPath(
  3187. SURFOBJ *pso,
  3188. PATHOBJ *ppo,
  3189. CLIPOBJ *pco,
  3190. BRUSHOBJ *pbo,
  3191. POINTL *pptlBrushOrg,
  3192. MIX mix,
  3193. FLONG flOptions)
  3194. {
  3195. PDD_PDEV ppdev = (PDD_PDEV)pso->dhpdev;
  3196. PDD_DSURF pdsurf = NULL;
  3197. BOOL rc = TRUE;
  3198. RECTFX rectfxTrg;
  3199. RECTL rectTrg;
  3200. RECT EllipseRect;
  3201. BOOL fMore = TRUE;
  3202. PATHDATA pathData;
  3203. POINTL startPoint;
  3204. POINTL nextPoint;
  3205. POINTL endPoint;
  3206. unsigned pathIndex;
  3207. POE_BRUSH_DATA pCurrentBrush;
  3208. OE_ENUMRECTS ClipRects;
  3209. DC_BEGIN_FN("DrvFillPath");
  3210. // Sometimes, we're called after being disconnected.
  3211. if (ddConnected && pddShm != NULL) {
  3212. // Surface is non-NULL.
  3213. pso = OEGetSurfObjBitmap(pso, &pdsurf);
  3214. // Get bounding rectangle.
  3215. PATHOBJ_vGetBounds(ppo, &rectfxTrg);
  3216. RECT_FROM_RECTFX(rectTrg, rectfxTrg);
  3217. // Punt the call back to GDI to do the drawing.
  3218. INC_OUTCOUNTER(OUT_FILLPATH_ALL);
  3219. // Check if we are allowed to send this order (determined by the
  3220. // negotiated capabilities of all the machines in the conference).
  3221. // We shouldn't do Eng call if we return FALSE. Otherwise, the frame
  3222. // buffer will be already drawn, and it will cause rendering problems
  3223. // when GDI re-renders it to other drawings.
  3224. if (OE_SendAsOrder(TS_ENC_POLYGON_SC_ORDER) ||
  3225. OE_SendAsOrder(TS_ENC_POLYGON_CB_ORDER)) {
  3226. rc = EngFillPath(pso, ppo, pco, pbo, pptlBrushOrg, mix,
  3227. flOptions);
  3228. }
  3229. else {
  3230. TRC_NRM((TB, "Polygon order not allowed"));
  3231. INC_OUTCOUNTER(OUT_FILLPATH_SDA_NOPOLYGON);
  3232. // If the client doesn't support polygon, we just have
  3233. // to fail DrvFillPath, the GDI will rerender the drawing
  3234. // to other Drv calls
  3235. return FALSE;
  3236. }
  3237. // if the path bound gives empty rect, we'll just ignore
  3238. if (rectTrg.left == 0 && rectTrg.right == 0 &&
  3239. rectTrg.top == 0 && rectTrg.bottom == 0) {
  3240. TRC_ERR((TB, "Empty Path obj bounding rect, ignore"));
  3241. DC_QUIT;
  3242. }
  3243. if (rc) {
  3244. if ((pso->hsurf == ppdev->hsurfFrameBuf) ||
  3245. (!(pdsurf->flags & DD_NO_OFFSCREEN))) {
  3246. // Send a switch surface PDU if the destination surface is different
  3247. // from last drawing order. If we failed to send the PDU, we will
  3248. // just have to bail on this drawing order.
  3249. if (!OESendSwitchSurfacePDU(ppdev, pdsurf)) {
  3250. TRC_ERR((TB, "failed to send the switch surface PDU"));
  3251. DC_QUIT;
  3252. }
  3253. } else {
  3254. // if noOffscreen flag is on, we will bail on sending
  3255. // the client any further offscreen rendering. And will send the final
  3256. // offscreen to screen blt as regular memblt.
  3257. TRC_NRM((TB, "Offscreen blt bail"));
  3258. DC_QUIT;
  3259. }
  3260. // Check for a valid brush for the test operation.
  3261. if (OECheckBrushIsSimple(ppdev, pbo, &pCurrentBrush)) {
  3262. unsigned RetVal;
  3263. // Get the intersection between the dest rect and the
  3264. // clip rects. Check for overcomplicated or
  3265. // nonintersecting clipping. Note that this is an
  3266. // initial pass, we so another intersection with
  3267. // the (possibly smaller) individual order rect
  3268. // generated later.
  3269. RetVal = OEGetIntersectingClipRects(pco, &rectTrg,
  3270. CD_ANY, &ClipRects);
  3271. if (RetVal == CLIPRECTS_TOO_COMPLEX) {
  3272. TRC_NRM((TB, "Clipping is too complex"));
  3273. INC_OUTCOUNTER(OUT_FILLPATH_SDA_COMPLEXCLIP);
  3274. goto SendAsSDA;
  3275. }
  3276. else if (RetVal == CLIPRECTS_NO_INTERSECTIONS) {
  3277. TRC_NRM((TB, "Clipping does not intersect destrect"));
  3278. DC_QUIT;
  3279. }
  3280. }
  3281. else {
  3282. TRC_NRM((TB, "Bad brush for polygon"));
  3283. INC_OUTCOUNTER(OUT_FILLPATH_SDA_BADBRUSH);
  3284. goto SendAsSDA;
  3285. }
  3286. // See if we can optimize the path...
  3287. // We cannot send beziers, and ellipses are sent as a distinct order.
  3288. if (ppo->fl & PO_ELLIPSE &&
  3289. (OE_SendAsOrder(TS_ENC_ELLIPSE_SC_ORDER) ||
  3290. OE_SendAsOrder(TS_ENC_ELLIPSE_CB_ORDER))) {
  3291. // Get the inclusive rect covering only the ellipse itself.
  3292. // Add 4/16 to left and top, subtract from right and bottom,
  3293. // to undo the GDI transformation.
  3294. EllipseRect.left = FXTOLROUND(rectfxTrg.xLeft + 4);
  3295. EllipseRect.top = FXTOLROUND(rectfxTrg.yTop + 4);
  3296. EllipseRect.right = FXTOLROUND(rectfxTrg.xRight - 4);
  3297. EllipseRect.bottom = FXTOLROUND(rectfxTrg.yBottom - 4);
  3298. if (pbo->iSolidColor != -1) {
  3299. // Solid color ellipse.
  3300. if (OECreateAndFlushEllipseSCOrder(ppdev, &EllipseRect,
  3301. pbo, &ClipRects, mix & 0x1F, flOptions)) {
  3302. INC_OUTCOUNTER(OUT_FILLPATH_ELLIPSE_SC);
  3303. goto PostSDA;
  3304. } else {
  3305. // No order heap space, send all as SDAs.
  3306. INC_OUTCOUNTER(OUT_FILLPATH_SDA_FAILEDADD);
  3307. goto SendAsSDA;
  3308. }
  3309. }
  3310. else {
  3311. // Color pattern brush ellipse.
  3312. if (OECreateAndFlushEllipseCBOrder(ppdev, &EllipseRect,
  3313. pCurrentBrush, pptlBrushOrg, &ClipRects, mix,
  3314. flOptions)) {
  3315. INC_OUTCOUNTER(OUT_FILLPATH_ELLIPSE_CB);
  3316. goto PostSDA;
  3317. } else {
  3318. // No order heap space, send all as SDAs.
  3319. INC_OUTCOUNTER(OUT_FILLPATH_SDA_FAILEDADD);
  3320. goto SendAsSDA;
  3321. }
  3322. }
  3323. }
  3324. else if (!(ppo->fl & PO_BEZIERS)) {
  3325. BYTE Deltas[ORD_MAX_POLYGON_CODEDDELTAS_LEN];
  3326. BYTE ZeroFlags[ORD_MAX_POLYGON_ZERO_FLAGS_BYTES];
  3327. POINTL SubPathBoundPts[ORD_MAX_POLYGON_ENCODED_POINTS];
  3328. BYTE *pCurEncode;
  3329. RECTL BoundRect;
  3330. POINTL HoldPoint;
  3331. unsigned NumDeltas;
  3332. unsigned DeltaSize;
  3333. int PointIndex = 0;
  3334. BOOL bPathStart = TRUE;
  3335. // This is a set of solid cosmetic (i.e. no fancy end styles)
  3336. // width-1 lines. NT stores all paths as a set of independent
  3337. // sub-paths. Each sub-path can start at a new point that is
  3338. // NOT linked to the previous sub-path. Paths used for this
  3339. // function need to be closed.
  3340. PATHOBJ_vEnumStart(ppo);
  3341. while (fMore) {
  3342. // Get the next set of lines.
  3343. fMore = PATHOBJ_bEnum(ppo, &pathData);
  3344. TRC_DBG((TB, "PTS: %lu FLAG: %08lx",
  3345. pathData.count,
  3346. pathData.flags));
  3347. // If this is the start of a path, remember the start point as
  3348. // we need to close the path at the end. startPoint is the
  3349. // start point for the current PolyGon order.
  3350. if (bPathStart) {
  3351. POINT_FROM_POINTFIX(startPoint, pathData.pptfx[0]);
  3352. nextPoint = startPoint;
  3353. // Set up encoding variables.
  3354. BoundRect.left = BoundRect.right = startPoint.x;
  3355. BoundRect.top = BoundRect.bottom = startPoint.y;
  3356. NumDeltas = DeltaSize = 0;
  3357. pCurEncode = Deltas;
  3358. memset(ZeroFlags, 0, sizeof(ZeroFlags));
  3359. pathIndex = 1;
  3360. bPathStart = FALSE;
  3361. }
  3362. else {
  3363. // This is a continuation from a previous PATHDATA.
  3364. nextPoint = HoldPoint;
  3365. pathIndex = 0;
  3366. }
  3367. // If NumDeltas is > max, we have to send as screen
  3368. // data unfortunately since we can't encode this.
  3369. if (NumDeltas + pathData.count + PointIndex >
  3370. ORD_MAX_POLYGON_ENCODED_POINTS) {
  3371. // No order heap space, send all as SDAs.
  3372. INC_OUTCOUNTER(OUT_FILLPATH_SDA_FAILEDADD);
  3373. goto SendAsSDA;
  3374. }
  3375. // record subpath's start point
  3376. if (pathData.flags & PD_BEGINSUBPATH) {
  3377. POINT_FROM_POINTFIX(SubPathBoundPts[PointIndex] , pathData.pptfx[0]);
  3378. PointIndex++;
  3379. }
  3380. // Generate deltas for each point in the path.
  3381. for (; pathIndex < pathData.count; pathIndex++) {
  3382. POINT_FROM_POINTFIX(endPoint, pathData.pptfx[pathIndex]);
  3383. // Don't try to encode points where both deltas are zero.
  3384. if ((nextPoint.x != endPoint.x) ||
  3385. (nextPoint.y != endPoint.y)) {
  3386. if (!OEEncodePolyLinePointDelta(&pCurEncode,
  3387. &NumDeltas, &DeltaSize, ZeroFlags,
  3388. &nextPoint, &endPoint, &BoundRect)) {
  3389. goto SendAsSDA;
  3390. }
  3391. }
  3392. nextPoint = endPoint;
  3393. }
  3394. // Record subpath's end point
  3395. if (pathData.flags & PD_ENDSUBPATH) {
  3396. SubPathBoundPts[PointIndex] = endPoint;
  3397. PointIndex++;
  3398. }
  3399. HoldPoint = endPoint;
  3400. }
  3401. if (NumDeltas > 0) {
  3402. // If NumDeltas is > max, we have to send as screen
  3403. // data unfortunately since we can't encode this.
  3404. if (NumDeltas + PointIndex - 2 >
  3405. ORD_MAX_POLYGON_ENCODED_POINTS) {
  3406. // No order heap space, send all as SDAs.
  3407. INC_OUTCOUNTER(OUT_FILLPATH_SDA_FAILEDADD);
  3408. goto SendAsSDA;
  3409. }
  3410. // For Polygon, we append all the subpath together
  3411. // and send as one polygon order. But we need to close
  3412. // each subpath respectively to make sure all the subpath
  3413. // are closed properly
  3414. for (pathIndex = PointIndex - 2; pathIndex > 0; pathIndex--) {
  3415. endPoint = SubPathBoundPts[pathIndex];
  3416. // Don't try to encode points where both deltas are zero.
  3417. if ((nextPoint.x != endPoint.x) ||
  3418. (nextPoint.y != endPoint.y)) {
  3419. if (!OEEncodePolyLinePointDelta(&pCurEncode,
  3420. &NumDeltas, &DeltaSize, ZeroFlags,
  3421. &nextPoint, &endPoint, &BoundRect))
  3422. goto SendAsSDA;
  3423. }
  3424. nextPoint = endPoint;
  3425. }
  3426. // We are at the end of the path. Flush the data we have.
  3427. if (pbo->iSolidColor != -1) {
  3428. // solid color polygon
  3429. if (OECreateAndFlushPolygonSCOrder(ppdev,
  3430. &BoundRect,
  3431. &startPoint,
  3432. pbo,
  3433. &ClipRects,
  3434. mix & 0x1F,
  3435. flOptions,
  3436. NumDeltas,
  3437. DeltaSize,
  3438. Deltas,
  3439. ZeroFlags)) {
  3440. INC_OUTCOUNTER(OUT_FILLPATH_POLYGON_SC);
  3441. } else {
  3442. // No order heap space, send all as SDAs.
  3443. INC_OUTCOUNTER(OUT_FILLPATH_SDA_FAILEDADD);
  3444. goto SendAsSDA;
  3445. }
  3446. } else {
  3447. // color pattern brush polygon
  3448. if (OECreateAndFlushPolygonCBOrder(ppdev,
  3449. &BoundRect,
  3450. &startPoint,
  3451. pCurrentBrush,
  3452. pptlBrushOrg,
  3453. &ClipRects,
  3454. mix,
  3455. flOptions,
  3456. NumDeltas,
  3457. DeltaSize,
  3458. Deltas,
  3459. ZeroFlags)) {
  3460. INC_OUTCOUNTER(OUT_FILLPATH_POLYGON_CB);
  3461. } else {
  3462. // No order heap space, send all as SDAs.
  3463. INC_OUTCOUNTER(OUT_FILLPATH_SDA_FAILEDADD);
  3464. goto SendAsSDA;
  3465. }
  3466. }
  3467. }
  3468. goto PostSDA;
  3469. }
  3470. else {
  3471. TRC_DBG((TB, "Got PO_BEZIERS fill"));
  3472. goto SendAsSDA;
  3473. }
  3474. }
  3475. else {
  3476. TRC_ERR((TB, "EngFillPath failed"));
  3477. DC_QUIT;
  3478. }
  3479. }
  3480. else {
  3481. if (pso->iType == STYPE_DEVBITMAP) {
  3482. // Surface is non-NULL.
  3483. pso = OEGetSurfObjBitmap(pso, &pdsurf);
  3484. rc = EngFillPath(pso, ppo, pco, pbo, pptlBrushOrg, mix,
  3485. flOptions);
  3486. }
  3487. else {
  3488. TRC_ERR((TB, "Called when disconnected"));
  3489. }
  3490. goto CalledOnDisconnected;
  3491. }
  3492. SendAsSDA:
  3493. if (pso->hsurf == ppdev->hsurfFrameBuf) {
  3494. // If we reached here we did not encode as an order, clip the bound
  3495. // rect to 16 bits and add to screen data.
  3496. INC_OUTCOUNTER(OUT_FILLPATH_SDA);
  3497. ADD_INCOUNTER(IN_SDA_FILLPATH_AREA, COM_SIZEOF_RECT(rectTrg));
  3498. OEClipRect(&rectTrg);
  3499. TRC_DBG((TB, "SDA: (%d,%d)(%d,%d)", rectTrg.left, rectTrg.top,
  3500. rectTrg.right, rectTrg.bottom));
  3501. if((rectTrg.right != rectTrg.left) &&
  3502. (rectTrg.bottom != rectTrg.top)) {
  3503. OEClipAndAddScreenDataArea(&rectTrg, pco);
  3504. }
  3505. else {
  3506. TRC_ASSERT(FALSE,(TB,"Invalid Add Rect (%d,%d,%d,%d)",
  3507. rectTrg.left, rectTrg.top, rectTrg.right, rectTrg.bottom));
  3508. DC_QUIT;
  3509. }
  3510. }
  3511. else {
  3512. // For now, if we can't send orders for offscreen rendering, we will
  3513. // bail offscreen support for this bitmap
  3514. TRC_ALT((TB, "screen data call for offscreen rendering"));
  3515. if (!(pdsurf->flags & DD_NO_OFFSCREEN))
  3516. CH_RemoveCacheEntry(sbcOffscreenBitmapCacheHandle, pdsurf->bitmapId);
  3517. DC_QUIT;
  3518. }
  3519. PostSDA:
  3520. // Have scheduler consider sending output.
  3521. SCH_DDOutputAvailable(ppdev, FALSE);
  3522. CalledOnDisconnected:
  3523. DC_EXIT_POINT:
  3524. DC_END_FN();
  3525. return rc;
  3526. }
  3527. /****************************************************************************/
  3528. // DrvPaint - see NT DDK documentation.
  3529. /****************************************************************************/
  3530. BOOL RDPCALL DrvPaint(
  3531. SURFOBJ *pso,
  3532. CLIPOBJ *pco,
  3533. BRUSHOBJ *pbo,
  3534. POINTL *pptlBrushOrg,
  3535. MIX mix)
  3536. {
  3537. PDD_PDEV ppdev = (PDD_PDEV)pso->dhpdev;
  3538. PDD_DSURF pdsurf = NULL;
  3539. SURFOBJ *psoBitmap;
  3540. BOOL rc = TRUE;
  3541. RECTL rectTrg;
  3542. BYTE rop3;
  3543. OE_ENUMRECTS ClipRects;
  3544. DC_BEGIN_FN("DrvPaint");
  3545. // Sometimes, we're called after being disconnected.
  3546. if (ddConnected && pddShm != NULL) {
  3547. // Surface is non-NULL.
  3548. psoBitmap = OEGetSurfObjBitmap(pso, &pdsurf);
  3549. INC_OUTCOUNTER(OUT_PAINT_ALL);
  3550. // Throw the drawing to GDI first.
  3551. rc = EngPaint(psoBitmap, pco, pbo, pptlBrushOrg, mix);
  3552. if (rc) {
  3553. // If ppdev is NULL then this is a blt to GDI managed memory
  3554. // bitmap, so there is no need to send any orders to the client.
  3555. if (ppdev != NULL) {
  3556. unsigned RetVal;
  3557. // Get bounding rectangle and clip to 16 bits.
  3558. RECT_FROM_RECTL(rectTrg, pco->rclBounds);
  3559. OEClipRect(&rectTrg);
  3560. // If this function is changed, need to know that psoTrg
  3561. // points to the GDI DIB bitmap in offscreen bitmap case.
  3562. // Enumerate the clip rects into a usable form.
  3563. RetVal = OEGetIntersectingClipRects(pco, &rectTrg,
  3564. CD_ANY, &ClipRects);
  3565. if (RetVal == CLIPRECTS_TOO_COMPLEX) {
  3566. TRC_NRM((TB, "Clipping is too complex"));
  3567. INC_OUTCOUNTER(OUT_PAINT_SDA_COMPLEXCLIP);
  3568. goto SendAsSDA;
  3569. }
  3570. TRC_ASSERT((RetVal != CLIPRECTS_NO_INTERSECTIONS),
  3571. (TB,"clipobj for DrvPaint is messed up"));
  3572. }
  3573. else {
  3574. // if ppdev is NULL, we are blt to GDI managed bitmap,
  3575. // so, the dhurf of the target surface should be NULL
  3576. TRC_ASSERT((pdsurf == NULL),
  3577. (TB, "NULL ppdev - psoTrg has non NULL dhsurf"));
  3578. TRC_NRM((TB, "NULL ppdev - paint to GDI managed bitmap"));
  3579. INC_OUTCOUNTER(OUT_PAINT_UNSENT);
  3580. DC_QUIT;
  3581. }
  3582. if ((psoBitmap->hsurf == ppdev->hsurfFrameBuf) ||
  3583. (!(pdsurf->flags & DD_NO_OFFSCREEN))) {
  3584. // Send a switch surface PDU if the destination surface is
  3585. // different from last drawing order. If we failed to send
  3586. // the PDU, we will just have to bail on this drawing order.
  3587. if (!OESendSwitchSurfacePDU(ppdev, pdsurf)) {
  3588. TRC_ERR((TB, "failed to send the switch surface PDU"));
  3589. goto SendAsSDA;
  3590. }
  3591. } else {
  3592. // If noOffscreen flag is on, we will bail on sending
  3593. // the client any further offscreen rendering.
  3594. // And will send the final offscreen to screen blt as
  3595. // regular memblt.
  3596. TRC_NRM((TB, "Offscreen blt bail"));
  3597. goto SendAsSDA;
  3598. }
  3599. }
  3600. else {
  3601. TRC_ERR((TB,"Failed EngPaint call"));
  3602. INC_OUTCOUNTER(OUT_PAINT_UNSENT);
  3603. DC_QUIT;
  3604. }
  3605. }
  3606. else {
  3607. if (pso->iType == STYPE_DEVBITMAP) {
  3608. // Surface is non-NULL.
  3609. psoBitmap = OEGetSurfObjBitmap(pso, &pdsurf);
  3610. // Throw the drawing to GDI first.
  3611. rc = EngPaint(psoBitmap, pco, pbo, pptlBrushOrg, mix);
  3612. }
  3613. else {
  3614. TRC_ERR((TB, "Called when disconnected"));
  3615. }
  3616. goto CalledOnDisconnected;
  3617. }
  3618. // The low byte of the mix represents a ROP2. We need a ROP3 for
  3619. // the paint operation, so convert the mix as follows.
  3620. //
  3621. // Remember the definitions of 2, 3 & 4 way ROP codes.
  3622. //
  3623. // Msk Pat Src Dst
  3624. //
  3625. // 1 1 1 1 --------+------+ ROP2 uses P & D only
  3626. // 1 1 1 0 | |
  3627. // 1 1 0 1 -+ | | ROP3 uses P, S & D
  3628. // 1 1 0 0 |ROP2-1|ROP3 |ROP4
  3629. // 1 0 1 1 |(see | | ROP4 uses M, P, S & D
  3630. // 1 0 1 0 -+ note)| |
  3631. // 1 0 0 1 | |
  3632. // 1 0 0 0 --------+ |
  3633. // 0 1 1 1 |
  3634. // 0 1 1 0 | NOTE: Windows defines its
  3635. // 0 1 0 1 | ROP2 codes as the bitwise
  3636. // 0 1 0 0 | value calculated here
  3637. // 0 0 1 1 | plus one. All other ROP
  3638. // 0 0 1 0 | codes are the straight
  3639. // 0 0 0 1 | bitwise value.
  3640. // 0 0 0 0 ---------------+
  3641. //
  3642. // Or, algorithmically...
  3643. // ROP3 = (ROP2 & 0x3) | ((ROP2 & 0xC) << 4) | (ROP2 << 2)
  3644. // ROP4 = (ROP3 << 8) | ROP3
  3645. mix = (mix & 0x1F) - 1;
  3646. rop3 = (BYTE)((mix & 0x3) | ((mix & 0xC) << 4) | (mix << 2));
  3647. // Check if we are allowed to send the ROP3.
  3648. if (OESendRop3AsOrder(rop3)) {
  3649. // Check for a pattern or true destination BLT.
  3650. if (!ROP3_NO_PATTERN(rop3)) {
  3651. // Check whether we can encode the PatBlt as an OpaqueRect.
  3652. // It must be solid with a PATCOPY rop.
  3653. if (pbo->iSolidColor != -1 && rop3 == OE_PATCOPY_ROP) {
  3654. if (!OEEncodeOpaqueRect(&rectTrg, pbo, ppdev, &ClipRects)) {
  3655. // Something went wrong with the encoding, so skip
  3656. // to the end to add this operation to the SDA.
  3657. goto SendAsSDA;
  3658. }
  3659. }
  3660. else if (!OEEncodePatBlt(ppdev, pbo, &rectTrg, pptlBrushOrg, rop3,
  3661. &ClipRects)) {
  3662. // Something went wrong with the encoding, so skip to
  3663. // the end to add this operation to the SDA.
  3664. goto SendAsSDA;
  3665. }
  3666. }
  3667. else {
  3668. if (!OEEncodeDstBlt(&rectTrg, rop3, ppdev, &ClipRects))
  3669. goto SendAsSDA;
  3670. }
  3671. }
  3672. else {
  3673. TRC_NRM((TB, "Cannot send ROP3 %d", rop3));
  3674. INC_OUTCOUNTER(OUT_BITBLT_SDA_NOROP3);
  3675. goto SendAsSDA;
  3676. }
  3677. // Sent the order, skip sending SDA.
  3678. goto PostSDA;
  3679. SendAsSDA:
  3680. // If we reached here we could not send via DrvBitBlt().
  3681. // Use EngPaint to paint the screen backdrop then add the area to the SDA.
  3682. if (psoBitmap->hsurf == ppdev->hsurfFrameBuf) {
  3683. OEClipAndAddScreenDataArea(&rectTrg, pco);
  3684. // All done: consider sending the output.
  3685. SCH_DDOutputAvailable(ppdev, FALSE);
  3686. INC_OUTCOUNTER(OUT_PAINT_SDA);
  3687. }
  3688. else {
  3689. // If we can't send orders for offscreen rendering, we will
  3690. // bail offscreen support for the target bitmap.
  3691. TRC_ALT((TB, "screen data call for offscreen rendering"));
  3692. if (!(pdsurf->flags & DD_NO_OFFSCREEN))
  3693. CH_RemoveCacheEntry(sbcOffscreenBitmapCacheHandle,
  3694. pdsurf->bitmapId);
  3695. }
  3696. PostSDA:
  3697. CalledOnDisconnected:
  3698. DC_EXIT_POINT:
  3699. DC_END_FN();
  3700. return rc;
  3701. }
  3702. /****************************************************************************/
  3703. // DrvRealizeBrush - see NT DDK documentation.
  3704. /****************************************************************************/
  3705. BOOL RDPCALL DrvRealizeBrush(
  3706. BRUSHOBJ *pbo,
  3707. SURFOBJ *psoTarget,
  3708. SURFOBJ *psoPattern,
  3709. SURFOBJ *psoMask,
  3710. XLATEOBJ *pxlo,
  3711. ULONG iHatch)
  3712. {
  3713. PDD_PDEV ppdev = (PDD_PDEV)psoTarget->dhpdev;
  3714. BOOL rc = TRUE;
  3715. PBYTE pData;
  3716. ULONG iBitmapFormat;
  3717. #ifdef DC_HICOLOR
  3718. BYTE brushBits[192];
  3719. BYTE brushIndices[64];
  3720. unsigned pelSizeFactor = 1;
  3721. UINT32 osColor;
  3722. unsigned iColor;
  3723. #else
  3724. BYTE brushBits[64];
  3725. #endif
  3726. UINT32 color1;
  3727. UINT32 color2;
  3728. UINT32 currColor;
  3729. INT i, j, currIndex;
  3730. BOOL brushSupported = TRUE;
  3731. BYTE palette[MAX_UNIQUE_COLORS];
  3732. UINT32 brushSupportLevel;
  3733. UINT32 colors[MAX_BRUSH_ENCODE_COLORS] = {1, 0};
  3734. UINT32 colorCount = 2;
  3735. ULONG iBytes = 0;
  3736. DC_BEGIN_FN("DrvRealizeBrush");
  3737. INC_OUTCOUNTER(OUT_BRUSH_ALL);
  3738. // A valid brush satisfies any of the following criteria.
  3739. // 1) It is a standard hatch brush (as passed by DrvEnablePDEV).
  3740. // 2) It is an 8x8 monochrome bitmap.
  3741. // 3) It is an 8x8 color bitmap and the client can support it.
  3742. // Check for a Windows standard hatch.
  3743. if (iHatch < HS_DDI_MAX) {
  3744. TRC_DBG((TB, "Standard hatch %lu", iHatch));
  3745. rc = OEStoreBrush(ppdev,
  3746. pbo,
  3747. BS_HATCHED,
  3748. 1,
  3749. &psoPattern->sizlBitmap,
  3750. 0,
  3751. NULL,
  3752. pxlo,
  3753. (BYTE)iHatch,
  3754. palette,
  3755. colors,
  3756. colorCount);
  3757. INC_OUTCOUNTER(OUT_BRUSH_STANDARD);
  3758. //standard brushes count as mono, don't double count
  3759. DEC_OUTCOUNTER(OUT_BRUSH_MONO);
  3760. DC_QUIT;
  3761. }
  3762. // If the driver has been passed a dither color brush we can support
  3763. // this by sending a solid color brush definition.
  3764. if ((iHatch & RB_DITHERCOLOR) != 0) {
  3765. TRC_DBG((TB, "Standard hatch %lu", iHatch));
  3766. colors[0] = iHatch & 0x00FFFFFF;
  3767. rc = OEStoreBrush(ppdev,
  3768. pbo,
  3769. BS_SOLID,
  3770. 1,
  3771. &psoPattern->sizlBitmap,
  3772. 0,
  3773. NULL,
  3774. NULL,
  3775. (BYTE)iHatch,
  3776. palette,
  3777. colors,
  3778. colorCount);
  3779. INC_OUTCOUNTER(OUT_BRUSH_STANDARD);
  3780. //standard brushes count as mono, don't double count
  3781. DEC_OUTCOUNTER(OUT_BRUSH_MONO);
  3782. DC_QUIT;
  3783. }
  3784. if ((psoPattern->sizlBitmap.cx == 8) &&
  3785. (psoPattern->sizlBitmap.cy == 8))
  3786. {
  3787. brushSupportLevel = pddShm->sbc.caps.brushSupportLevel;
  3788. // NOTE: There's a flag (BMF_TOPDOWN) in psoPattern->fjBitmap
  3789. // that's supposed to indicate whether the bitmap is top-down or
  3790. // bottom-up, but it is not always set up correctly. In fact, the
  3791. // bitmaps are always the wrong way up for our protocol, so we have
  3792. // to flip them regardless of the flag. Hence the row numbers are
  3793. // reversed ('i' loops) in all the conversions below.
  3794. pData = psoPattern->pvScan0;
  3795. iBitmapFormat = psoPattern->iBitmapFormat;
  3796. #ifdef DC_HICOLOR
  3797. // mono brushes are easy, regardless of operating color depth
  3798. if (iBitmapFormat == BMF_1BPP) {
  3799. // every 8 pixels take a byte @ 1bpp
  3800. iBytes = 8;
  3801. for (i = 7; i >= 0; i--) {
  3802. brushBits[i] = *pData;
  3803. pData += psoPattern->lDelta;
  3804. }
  3805. }
  3806. else if (ppdev->cClientBitsPerPel < 15) {
  3807. // for 4 and 8 bpp sessions, colors end up as indices regardless
  3808. // of the color depth of the brush;
  3809. switch (iBitmapFormat) {
  3810. case BMF_4BPP:
  3811. {
  3812. iBitmapFormat = BMF_8BPP;
  3813. // Copy over the brush bits at 1 byte / pixel and track
  3814. // how many unique colors we have. The vast vast majority
  3815. // of brushes are 4 colors or less.
  3816. iBytes = 64;
  3817. memset(palette, 0, sizeof(palette));
  3818. colorCount = 0;
  3819. for (i = 7; i >= 0; i--) {
  3820. currIndex = i * 8;
  3821. for (j = 0; j < 4; j++) {
  3822. color1 = XLATEOBJ_iXlate(pxlo, (pData[j] >> 4));
  3823. color2 = XLATEOBJ_iXlate(pxlo, (pData[j] & 0x0F));
  3824. brushBits[currIndex] = (BYTE) color1;
  3825. brushBits[currIndex + 1] = (BYTE) color2;
  3826. currIndex += 2;
  3827. if (palette[color1] && palette[color2])
  3828. continue;
  3829. // if possible assign each unique color a four bit index
  3830. if (!palette[color1]) {
  3831. if (colorCount < MAX_BRUSH_ENCODE_COLORS)
  3832. colors[colorCount] = color1;
  3833. colorCount++;
  3834. palette[color1] = (BYTE) colorCount;
  3835. }
  3836. if (!palette[color2]) {
  3837. if (colorCount < MAX_BRUSH_ENCODE_COLORS)
  3838. colors[colorCount] = color2;
  3839. colorCount++;
  3840. palette[color2] = (BYTE) colorCount;
  3841. }
  3842. }
  3843. pData += psoPattern->lDelta;
  3844. }
  3845. // The encoding value was set one larger than it should
  3846. // have been so adjust it
  3847. if (colorCount <= MAX_BRUSH_ENCODE_COLORS) {
  3848. for (currColor = 0; currColor < colorCount; currColor++)
  3849. palette[colors[currColor]]--;
  3850. }
  3851. brushSupported = (colorCount <= 2) ||
  3852. (brushSupportLevel > TS_BRUSH_DEFAULT);
  3853. }
  3854. break;
  3855. case BMF_24BPP:
  3856. case BMF_16BPP:
  3857. case BMF_8BPP:
  3858. {
  3859. // When running at 4/8bpp, the xlateobj will convert the
  3860. // Nbpp bitmap pel values to 8bpp palette indices, so we
  3861. // just have to
  3862. // - set up a multiplier to access the pels correctly
  3863. // - fix up the number of bytes in the bitmap
  3864. // - lie about the color depth of the bitmap
  3865. TRC_DBG((TB, "Examining brush format %d", iBitmapFormat));
  3866. if (iBitmapFormat == BMF_24BPP)
  3867. pelSizeFactor = 3;
  3868. else if (iBitmapFormat == BMF_16BPP)
  3869. pelSizeFactor = 2;
  3870. else
  3871. pelSizeFactor = 1;
  3872. iBytes = 64;
  3873. iBitmapFormat = BMF_8BPP;
  3874. // Copy over the brush bits and track how many unique
  3875. // colors we have. The vast vast majority of brushes are
  3876. // 4 colors or less.
  3877. memset(palette, 0, sizeof(palette));
  3878. colorCount = 0;
  3879. for (i = 7; i >= 0; i--) {
  3880. currIndex = i * 8;
  3881. for (j = 0; j < 8; j++) {
  3882. osColor = 0;
  3883. memcpy(&osColor, &pData[j * pelSizeFactor],
  3884. pelSizeFactor);
  3885. currColor = XLATEOBJ_iXlate(pxlo, osColor);
  3886. TRC_DBG((TB, "This pel: %02x %02x %02x",
  3887. (UINT)pData[j * 3],
  3888. (UINT)pData[j * 3 + 1],
  3889. (UINT)pData[j * 3 + 2] ));
  3890. TRC_DBG((TB, "Color %08lx", currColor));
  3891. brushBits[currIndex] = (BYTE) currColor;
  3892. currIndex++;
  3893. // assign each unique color a two bit index
  3894. if (palette[currColor]) {
  3895. continue;
  3896. }
  3897. else {
  3898. if (colorCount < MAX_BRUSH_ENCODE_COLORS)
  3899. colors[colorCount] = currColor;
  3900. colorCount++;
  3901. palette[currColor] = (BYTE) colorCount;
  3902. }
  3903. }
  3904. pData += psoPattern->lDelta;
  3905. }
  3906. // The encoding value was set one larger than it should
  3907. // have been so adjust it
  3908. if (colorCount <= MAX_BRUSH_ENCODE_COLORS) {
  3909. for (currColor = 0; currColor < colorCount; currColor++)
  3910. palette[colors[currColor]]--;
  3911. }
  3912. brushSupported = (colorCount <= 2) ||
  3913. (brushSupportLevel > TS_BRUSH_DEFAULT);
  3914. }
  3915. break;
  3916. default:
  3917. {
  3918. // Unsupported brush format.
  3919. TRC_ALT((TB, "Brush of unsupported format %d",
  3920. (UINT32)psoPattern->iBitmapFormat));
  3921. iBytes = 0;
  3922. brushSupported = FALSE;
  3923. }
  3924. break;
  3925. }
  3926. }
  3927. else {
  3928. // hicolor makes things a little more complex for us; we have
  3929. // to handle and 3 byte color values instead of color indices
  3930. switch (iBitmapFormat) {
  3931. case BMF_4BPP:
  3932. {
  3933. // Copy over the brush bits at the correct color depth,
  3934. // tracking how many unique colors we have. The vast
  3935. // vast majority of brushes are 4 colors or less.
  3936. // First set up the correct formats
  3937. if (ppdev->cClientBitsPerPel == 24) {
  3938. iBitmapFormat = BMF_24BPP;
  3939. iBytes = 192;
  3940. }
  3941. else {
  3942. iBitmapFormat = BMF_16BPP;
  3943. iBytes = 128;
  3944. }
  3945. colorCount = 0;
  3946. for (i = 7; i >= 0; i--) {
  3947. currIndex = i * 8;
  3948. for (j = 0; j < 4; j++) {
  3949. color1 = XLATEOBJ_iXlate(pxlo, (pData[j] >> 4));
  3950. color2 = XLATEOBJ_iXlate(pxlo, (pData[j] & 0x0F));
  3951. // we will store each pel twice - once 'as is' and
  3952. // once as an index to the in-use color table
  3953. if (ppdev->cClientBitsPerPel == 24) {
  3954. brushBits[currIndex * 3] =
  3955. (TSUINT8)( color1 & 0x000000FF);
  3956. brushBits[currIndex * 3 + 1] =
  3957. (TSUINT8)((color1 >> 8) & 0x000000FF);
  3958. brushBits[currIndex * 3 + 2] =
  3959. (TSUINT8)((color1 >> 16)& 0x000000FF);
  3960. brushBits[currIndex * 3 + 4] =
  3961. (TSUINT8)( color2 & 0x000000FF);
  3962. brushBits[currIndex * 3 + 5] =
  3963. (TSUINT8)((color2 >> 8) & 0x000000FF);
  3964. brushBits[currIndex * 3 + 6] =
  3965. (TSUINT8)((color2 >> 16)& 0x000000FF);
  3966. }
  3967. else {
  3968. brushBits[currIndex * 2] =
  3969. (TSUINT8)( color1 & 0x00FF);
  3970. brushBits[currIndex * 2 + 1] =
  3971. (TSUINT8)((color1 >> 8) & 0x00FF);
  3972. brushBits[currIndex * 2 + 3] =
  3973. (TSUINT8)( color2 & 0x00FF);
  3974. brushBits[currIndex * 2 + 4] =
  3975. (TSUINT8)((color2 >> 8) & 0x00FF);
  3976. }
  3977. if (colorCount <= MAX_BRUSH_ENCODE_COLORS) {
  3978. // we try to assign each unique color a two bit
  3979. // index. We can't just look in the palette
  3980. // this time; we have to actually search the
  3981. // in-use color table
  3982. for (iColor = 0; iColor < colorCount; iColor++) {
  3983. if (colors[iColor] == color1)
  3984. break;
  3985. }
  3986. // Did we find the color in the in-use table?
  3987. if (iColor < colorCount) {
  3988. brushIndices[currIndex] = (BYTE)iColor;
  3989. }
  3990. else {
  3991. // maybe record the new color
  3992. if (colorCount < MAX_BRUSH_ENCODE_COLORS) {
  3993. colors[colorCount] = color1;
  3994. brushIndices[currIndex] = (BYTE)colorCount;
  3995. }
  3996. TRC_DBG((TB, "New color %08lx", color1));
  3997. colorCount++;
  3998. }
  3999. // update the index
  4000. currIndex ++;
  4001. for (iColor = 0; iColor < colorCount; iColor++) {
  4002. if (colors[iColor] == color2)
  4003. break;
  4004. }
  4005. // Did we find the color in the in-use table?
  4006. if (iColor < colorCount) {
  4007. brushIndices[currIndex] = (BYTE)iColor;
  4008. }
  4009. else {
  4010. // maybe record the new color
  4011. if (colorCount < MAX_BRUSH_ENCODE_COLORS) {
  4012. colors[colorCount] = color2;
  4013. brushIndices[currIndex] = (BYTE)colorCount;
  4014. }
  4015. TRC_DBG((TB, "New color %08lx", color2));
  4016. colorCount++;
  4017. }
  4018. currIndex ++;
  4019. }
  4020. else {
  4021. // update the index
  4022. currIndex += 2;
  4023. }
  4024. }
  4025. pData += psoPattern->lDelta;
  4026. }
  4027. TRC_DBG((TB, "Final color count %d", colorCount));
  4028. brushSupported = (colorCount <= 2) ||
  4029. (brushSupportLevel > TS_BRUSH_DEFAULT);
  4030. // Should we use the index versions instead of full RGBs?
  4031. if (brushSupported &&
  4032. (colorCount <= MAX_BRUSH_ENCODE_COLORS)) {
  4033. // yes - copy them over
  4034. memcpy(brushBits, brushIndices, 64);
  4035. iBytes = 64;
  4036. }
  4037. }
  4038. break;
  4039. case BMF_24BPP:
  4040. case BMF_16BPP:
  4041. case BMF_8BPP:
  4042. {
  4043. // When running in hicolor, just as for 8bpp, we have to
  4044. // set up a multiplier to access the bits correctly and
  4045. // fix up the number of bytes in the bitmap and color
  4046. // format of the bitmap
  4047. //
  4048. // The complication is that the xlate object can give us
  4049. // 2 or 3 byte color values depending on the session bpp.
  4050. // Its not practical to use these to build a color table
  4051. // as for the 8bpp case (the color array would have to
  4052. // have 16.4 million entries!), so instead we build a
  4053. // list of the colors used
  4054. TRC_DBG((TB, "Examining brush format %d", iBitmapFormat));
  4055. if (iBitmapFormat == BMF_24BPP)
  4056. pelSizeFactor = 3;
  4057. else if (iBitmapFormat == BMF_16BPP)
  4058. pelSizeFactor = 2;
  4059. else
  4060. pelSizeFactor = 1;
  4061. // now set up the converted formats
  4062. if (ppdev->cClientBitsPerPel == 24) {
  4063. iBitmapFormat = BMF_24BPP;
  4064. iBytes = 192;
  4065. }
  4066. else {
  4067. iBitmapFormat = BMF_16BPP;
  4068. iBytes = 128;
  4069. }
  4070. // Copy over the brush bits and track how many unique colors
  4071. // we have. The vast vast majority of brushes are 4 colors
  4072. // or less.
  4073. colorCount = 0;
  4074. for (i = 7; i >= 0; i--) {
  4075. currIndex = i * 8;
  4076. for (j = 0; j < 8; j++) {
  4077. osColor = 0;
  4078. memcpy(&osColor,
  4079. &pData[j * pelSizeFactor],
  4080. pelSizeFactor);
  4081. currColor = XLATEOBJ_iXlate(pxlo, osColor);
  4082. TRC_DBG((TB, "OS Color : %08lx", osColor));
  4083. TRC_DBG((TB, "Color : %08lx", currColor));
  4084. // we will store each pel twice - once 'as is' and
  4085. // once as an index to the in-use color table
  4086. if (ppdev->cClientBitsPerPel == 24) {
  4087. brushBits[currIndex * 3] =
  4088. (TSUINT8)( currColor & 0x000000FF);
  4089. brushBits[currIndex * 3 + 1] =
  4090. (TSUINT8)((currColor >> 8) & 0x000000FF);
  4091. brushBits[currIndex * 3 + 2] =
  4092. (TSUINT8)((currColor >> 16)& 0x000000FF);
  4093. TRC_DBG((TB, "This pel : %02x %02x %02x",
  4094. (UINT)pData[j * pelSizeFactor],
  4095. (UINT)pData[j * pelSizeFactor + 1],
  4096. (UINT)pData[j * pelSizeFactor + 2] ));
  4097. TRC_DBG((TB, "Brush bits: %02x %02x %02x",
  4098. (UINT)brushBits[currIndex * 3],
  4099. (UINT)brushBits[currIndex * 3 + 1],
  4100. (UINT)brushBits[currIndex * 3 + 2] ));
  4101. }
  4102. else {
  4103. brushBits[currIndex * 2] =
  4104. (TSUINT8)( currColor & 0x00FF);
  4105. brushBits[currIndex * 2 + 1] =
  4106. (TSUINT8)((currColor >> 8) & 0x00FF);
  4107. TRC_DBG((TB, "This pel : %02x %02x",
  4108. (UINT)pData[j * pelSizeFactor],
  4109. (UINT)pData[j * pelSizeFactor + 1] ));
  4110. TRC_DBG((TB, "Brush bits: %02x %02x",
  4111. (UINT)brushBits[currIndex * 2],
  4112. (UINT)brushBits[currIndex * 2 + 1] ));
  4113. }
  4114. if (colorCount <= MAX_BRUSH_ENCODE_COLORS) {
  4115. // we try to assign each unique color a two bit
  4116. // index. We can't just look in the palette
  4117. // this time; we have to actually search the
  4118. // in-use color table
  4119. for (iColor = 0; iColor < colorCount; iColor++) {
  4120. if (colors[iColor] == currColor)
  4121. break; // from for loop
  4122. }
  4123. // Did we find the color in the in-use table?
  4124. if (iColor < colorCount) {
  4125. brushIndices[currIndex] = (BYTE)iColor;
  4126. // safe to update the index now
  4127. currIndex++;
  4128. continue; // next j
  4129. }
  4130. // maybe record the new color
  4131. if (colorCount < MAX_BRUSH_ENCODE_COLORS) {
  4132. colors[colorCount] = currColor;
  4133. brushIndices[currIndex] = (BYTE)colorCount;
  4134. }
  4135. TRC_DBG((TB, "New color %08lx", currColor));
  4136. colorCount++;
  4137. }
  4138. // safe to update the index now
  4139. currIndex++;
  4140. } // next j
  4141. pData += psoPattern->lDelta;
  4142. } // next i
  4143. TRC_DBG((TB, "Final color count %d", colorCount));
  4144. brushSupported = (colorCount <= 2) ||
  4145. (brushSupportLevel > TS_BRUSH_DEFAULT);
  4146. // Should we use the index versions instead of full RGBs?
  4147. if (brushSupported &&
  4148. (colorCount <= MAX_BRUSH_ENCODE_COLORS)) {
  4149. // yes - copy them over
  4150. memcpy(brushBits, brushIndices, 64);
  4151. iBytes = 64;
  4152. }
  4153. }
  4154. break;
  4155. default:
  4156. {
  4157. // Unsupported brush format.
  4158. TRC_ALT((TB, "Brush of unsupported format %d",
  4159. (UINT32)psoPattern->iBitmapFormat));
  4160. iBytes = 0;
  4161. brushSupported = FALSE;
  4162. }
  4163. break;
  4164. }
  4165. }
  4166. #else
  4167. switch (psoPattern->iBitmapFormat)
  4168. {
  4169. case BMF_1BPP:
  4170. {
  4171. // every 8 pixels take a byte @ 1bpp
  4172. iBytes = 8;
  4173. for (i = 7; i >= 0; i--) {
  4174. brushBits[i] = *pData;
  4175. pData += psoPattern->lDelta;
  4176. }
  4177. }
  4178. break;
  4179. case BMF_4BPP:
  4180. {
  4181. // Copy over the brush bits at 1 byte / pixel and track how many
  4182. // unique colors we have. The vast vast majority of brushes are
  4183. // 4 colors or less.
  4184. iBytes = 64;
  4185. memset(palette, 0, sizeof(palette));
  4186. colorCount = 0;
  4187. for (i = 7; i >= 0; i--) {
  4188. currIndex = i * 8;
  4189. for (j = 0; j < 4; j++) {
  4190. color1 = XLATEOBJ_iXlate(pxlo, (pData[j] >> 4));
  4191. color2 = XLATEOBJ_iXlate(pxlo, (pData[j] & 0x0F));
  4192. brushBits[currIndex] = (BYTE) color1;
  4193. brushBits[currIndex + 1] = (BYTE) color2;
  4194. currIndex += 2;
  4195. if (palette[color1] && palette[color2])
  4196. continue;
  4197. // If possible assign each unique color a two bit index
  4198. if (!palette[color1]) {
  4199. if (colorCount < MAX_BRUSH_ENCODE_COLORS)
  4200. colors[colorCount] = color1;
  4201. colorCount++;
  4202. palette[color1] = (BYTE) colorCount;
  4203. }
  4204. if (!palette[color2]) {
  4205. if (colorCount < MAX_BRUSH_ENCODE_COLORS)
  4206. colors[colorCount] = color2;
  4207. colorCount++;
  4208. palette[color2] = (BYTE) colorCount;
  4209. }
  4210. }
  4211. pData += psoPattern->lDelta;
  4212. }
  4213. // The encoding value was set one larger than it should
  4214. // have been so adjust it
  4215. if (colorCount <= MAX_BRUSH_ENCODE_COLORS) {
  4216. for (currColor = 0; currColor < colorCount; currColor++) {
  4217. palette[colors[currColor]]--;
  4218. }
  4219. }
  4220. brushSupported = (colorCount <= 2) ||
  4221. (brushSupportLevel > TS_BRUSH_DEFAULT);
  4222. }
  4223. break;
  4224. case BMF_8BPP:
  4225. {
  4226. // Copy over the brush bits and track how many unique colors
  4227. // we have. The vast vast majority of brushes are 4 colors
  4228. // or less.
  4229. iBytes = 64;
  4230. memset(palette, 0, sizeof(palette));
  4231. colorCount = 0;
  4232. for (i = 7; i >= 0; i--) {
  4233. currIndex = i * 8;
  4234. for (j = 0; j < 8; j++) {
  4235. currColor = XLATEOBJ_iXlate(pxlo, pData[j]);
  4236. brushBits[currIndex] = (BYTE) currColor;
  4237. currIndex++;
  4238. // assign each unique color a two bit index
  4239. if (palette[currColor]) {
  4240. continue;
  4241. }
  4242. else {
  4243. if (colorCount < MAX_BRUSH_ENCODE_COLORS)
  4244. colors[colorCount] = currColor;
  4245. colorCount++;
  4246. palette[currColor] = (BYTE) colorCount;
  4247. }
  4248. }
  4249. pData += psoPattern->lDelta;
  4250. }
  4251. // The encoding value was set one larger than it should
  4252. // have been so adjust it
  4253. if (colorCount <= MAX_BRUSH_ENCODE_COLORS) {
  4254. for (currColor = 0; currColor < colorCount; currColor++)
  4255. palette[colors[currColor]]--;
  4256. }
  4257. brushSupported = (colorCount <= 2) ||
  4258. (brushSupportLevel > TS_BRUSH_DEFAULT);
  4259. }
  4260. break;
  4261. default:
  4262. {
  4263. // Unsupported colour depth.
  4264. iBytes = 0;
  4265. brushSupported = FALSE;
  4266. }
  4267. break;
  4268. }
  4269. #endif
  4270. }
  4271. else {
  4272. iBitmapFormat = psoPattern->iBitmapFormat;
  4273. // The brush is the wrong size or requires dithering and so cannot
  4274. // be sent over the wire.
  4275. #ifdef DC_HICOLOR
  4276. TRC_ALT((TB, "Non-8x8 or dithered brush"));
  4277. #endif
  4278. brushSupported = FALSE;
  4279. }
  4280. // Store the brush.
  4281. if (brushSupported) {
  4282. if (colorCount <= 2)
  4283. INC_OUTCOUNTER(OUT_BRUSH_MONO);
  4284. // Store the brush - note that if we have a monochrome brush the
  4285. // color bit is set up so that 0 = color2 and 1 = color1. This
  4286. // actually corresponds to 0 = fg and 1 = bg for the protocol
  4287. // colors.
  4288. TRC_DBG((TB, "Storing brush: type %d bg %x fg %x",
  4289. psoPattern->iBitmapFormat,
  4290. colors[0],
  4291. colors[1]));
  4292. rc = OEStoreBrush(ppdev,
  4293. pbo,
  4294. BS_PATTERN,
  4295. iBitmapFormat,
  4296. &psoPattern->sizlBitmap,
  4297. iBytes,
  4298. brushBits,
  4299. pxlo,
  4300. 0,
  4301. palette,
  4302. colors,
  4303. colorCount);
  4304. }
  4305. else
  4306. {
  4307. if (!iBytes) {
  4308. TRC_ALT((TB, "Rejected brush h %08lx s (%ld, %ld) fmt %lu",
  4309. iHatch,
  4310. psoPattern != NULL ? psoPattern->sizlBitmap.cx : 0,
  4311. psoPattern != NULL ? psoPattern->sizlBitmap.cy : 0,
  4312. psoPattern != NULL ? psoPattern->iBitmapFormat : 0));
  4313. }
  4314. rc = OEStoreBrush(ppdev, pbo, BS_NULL, iBitmapFormat,
  4315. &psoPattern->sizlBitmap, iBytes, brushBits, pxlo,
  4316. 0, NULL, NULL, 0);
  4317. INC_OUTCOUNTER(OUT_BRUSH_REJECTED);
  4318. }
  4319. DC_EXIT_POINT:
  4320. DC_END_FN();
  4321. return rc;
  4322. }
  4323. /****************************************************************************/
  4324. // OE_RectIntersectsSDA
  4325. //
  4326. // Returns nonzero if the supplied exclusive rect intersects any of the
  4327. // current screen data areas.
  4328. /****************************************************************************/
  4329. BOOL RDPCALL OE_RectIntersectsSDA(PRECTL pRect)
  4330. {
  4331. RECTL aBoundRects[BA_MAX_ACCUMULATED_RECTS];
  4332. unsigned cBounds;
  4333. BOOL fIntersection = FALSE;
  4334. unsigned i;
  4335. DC_BEGIN_FN("OE_RectIntersectsSDA");
  4336. // Fetch the current Screen Data Area (SDA). It is returned in
  4337. // virtual desktop (inclusive) coordinates.
  4338. BA_QueryBounds(aBoundRects, &cBounds);
  4339. // Loop through each of the bounding rectangles checking for
  4340. // an intersection with the supplied rectangle.
  4341. // Note we use '<' for pRect->right and pRect->bottom because *pRect is
  4342. // in exclusive coords.
  4343. for (i = 0; i < cBounds; i++) {
  4344. if (aBoundRects[i].left < pRect->right &&
  4345. aBoundRects[i].top < pRect->bottom &&
  4346. aBoundRects[i].right > pRect->left &&
  4347. aBoundRects[i].bottom > pRect->top) {
  4348. TRC_NRM((TB, "ExclRect(%d,%d)(%d,%d) intersects SDA(%d,%d)(%d,%d)",
  4349. pRect->left, pRect->top, pRect->right, pRect->bottom,
  4350. aBoundRects[i].left, aBoundRects[i].top,
  4351. aBoundRects[i].right, aBoundRects[i].bottom));
  4352. fIntersection = TRUE;
  4353. break;
  4354. }
  4355. }
  4356. DC_END_FN();
  4357. return fIntersection;
  4358. }