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.

785 lines
21 KiB

  1. //
  2. // SSI.C
  3. // Save Screenbits Interceptor
  4. //
  5. // Copyright(c) Microsoft 1997-
  6. //
  7. #include <as16.h>
  8. //
  9. // GENERAL COMMENTS
  10. //
  11. // We patch the display driver's onboard bitmap DDI call if it exists. This
  12. // doesn't exist on newer displays, but we need to fail it on older ones.
  13. // We won't see drawing that happens via calls to it otherwise.
  14. //
  15. // NM 2.0 used to grovel in USER's dataseg to find the variable address of
  16. // the onboard bitmap routine and fill in its own, whether there was one or
  17. // not. Then it used to return TRUE always for saves. Since USER '95 checked
  18. // for a non-zero address to decide if onboard capabilities were present,
  19. // this sort of worked. Except of course that NM 2.0 needed special case
  20. // code for all the flavors of Win95.
  21. //
  22. // With multiple monitor support, there is no single savebits proc address
  23. // anymore. Plus, we're tired of having to alter our code with every
  24. // change in the OS. Our new scheme works based off blts to/from a memory
  25. // bitmap owned by USER. Since we already spy on bitmaps for the SBC
  26. // it doesn't really add overhead to do it this way.
  27. //
  28. // When USER is saving bits
  29. // (1) It creates the SPB bitmap via CreateSpb() (GDI calls it
  30. // CreateUserDiscardableBitmap()),
  31. // the only time it calls this routine. If the bits get discarded,
  32. // the BitBlt back from this bitmap will fail, in which case USER
  33. // will repaint the affected area.
  34. // (2) It does a BitBlt from the screen into this bitmap, after making
  35. // it owned by g_hModUser16. This bitmap is byte-pixel-aligned
  36. // horizontally, so it may be a bit wider than the window about to
  37. // be shown there.
  38. // (3) This happens just before a CS_SAVEBITS window is shown in that
  39. // area. The window gets a private WS_HASSPB style bit set on it.
  40. // (4) After creating the SPB bitmap, USER walks through the windows
  41. // behind where the window is going to be in the z-order and subtracts
  42. // pending updage regions from the "OK" region of the SPB. This
  43. // may result in discarding the SPB right away.
  44. //
  45. // When USER is discarding saved bits
  46. // (1) It deletes the bitmap it created when saving
  47. //
  48. // When USER is restoring saved bits
  49. // (1) It may decide to discard if there's not much saved by restoring
  50. // (2) It will temporarily select in a visrgn for the screen that is
  51. // only the valid part of the SPB
  52. // (3) It will blt from a memory DC with the SPB bitmap selected in
  53. // to the screen, again byte-aligned pixelwise horizontally.
  54. // (4) It will return a region to be invalidated and repainted via
  55. // normal methods (the complement of the valid blt visrgn)
  56. //
  57. // We have to be able to support nested savebits. We do this via a
  58. // stack-like bitmap cache. New save requests get put at the front.
  59. //
  60. //
  61. // SSI_DDProcessRequest()
  62. // Handles SSI escapes
  63. //
  64. BOOL SSI_DDProcessRequest
  65. (
  66. UINT fnEscape,
  67. LPOSI_ESCAPE_HEADER pRequest,
  68. DWORD cbRequest
  69. )
  70. {
  71. BOOL rc;
  72. DebugEntry(SSI_DDProcessRequest);
  73. switch (fnEscape)
  74. {
  75. case SSI_ESC_RESET_LEVEL:
  76. {
  77. ASSERT(cbRequest == sizeof(OSI_ESCAPE_HEADER));
  78. SSIResetSaveScreenBitmap();
  79. rc = TRUE;
  80. }
  81. break;
  82. case SSI_ESC_NEW_CAPABILITIES:
  83. {
  84. ASSERT(cbRequest == sizeof(SSI_NEW_CAPABILITIES));
  85. SSISetNewCapabilities((LPSSI_NEW_CAPABILITIES)pRequest);
  86. rc = TRUE;
  87. }
  88. break;
  89. default:
  90. {
  91. ERROR_OUT(("Unrecognized SSI_ escape"));
  92. rc = FALSE;
  93. }
  94. break;
  95. }
  96. DebugExitBOOL(SSI_DDProcessRequest, rc);
  97. return(rc);
  98. }
  99. //
  100. // SSI_DDInit()
  101. //
  102. BOOL SSI_DDInit(void)
  103. {
  104. BOOL rc = TRUE;
  105. DebugEntry(SSI_DDInit);
  106. //
  107. // Patch the display driver's onboard SaveBits routine, if there is one
  108. //
  109. if (SELECTOROF(g_lpfnSaveBits))
  110. {
  111. if (!CreateFnPatch(g_lpfnSaveBits, DrvSaveBits, &g_ssiSaveBitsPatch, 0))
  112. {
  113. ERROR_OUT(("Unable to patch savebits routine"));
  114. rc = FALSE;
  115. }
  116. }
  117. DebugExitBOOL(SSI_DDInit, rc);
  118. return(rc);
  119. }
  120. //
  121. // SSI_DDTerm()
  122. //
  123. void SSI_DDTerm(void)
  124. {
  125. DebugEntry(SSI_DDTerm);
  126. if (SELECTOROF(g_lpfnSaveBits))
  127. {
  128. DestroyFnPatch(&g_ssiSaveBitsPatch);
  129. }
  130. DebugExitVOID(SSI_DDTerm);
  131. }
  132. //
  133. // SSI_DDViewing()
  134. //
  135. void SSI_DDViewing(BOOL fViewers)
  136. {
  137. DebugEntry(SSI_DDViewing);
  138. //
  139. // Activate our SaveBits patch if we have one
  140. //
  141. if (SELECTOROF(g_lpfnSaveBits))
  142. {
  143. EnableFnPatch(&g_ssiSaveBitsPatch, (fViewers ? PATCH_ACTIVATE :
  144. PATCH_DEACTIVATE));
  145. }
  146. //
  147. // Reset our SSI stack
  148. //
  149. SSIResetSaveScreenBitmap();
  150. DebugExitVOID(SSI_DDViewing);
  151. }
  152. //
  153. // DrvSaveBits()
  154. //
  155. // Since we have to have code to spy on USER spb bitmaps, it doesn't make
  156. // sense to have twice the code. So we simply return FALSE here. This
  157. // also avoids the "enable the patch after a bitmap was saved via a call
  158. // to the driver so on the restore we're confused" problem. The worst that
  159. // will happen now is that USER will blt from a bitmap we've never seen
  160. // to the screen, we'll catch the drawing, and send it over the wire as
  161. // screen update (not cached!). The next full save/restore will use an
  162. // order instead.
  163. //
  164. BOOL WINAPI DrvSaveBits
  165. (
  166. LPRECT lpRect,
  167. UINT uCmd
  168. )
  169. {
  170. return(FALSE);
  171. }
  172. //
  173. // NOTE:
  174. // ssiSBSaveLevel is the index of the NEXT FREE SPB SLOT
  175. //
  176. //
  177. // FUNCTION: SSIResetSaveScreenBitmap.
  178. //
  179. // DESCRIPTION:
  180. //
  181. // Resets the SaveScreenBitmap state.
  182. //
  183. // PARAMETERS: None.
  184. //
  185. // RETURNS: Nothing.
  186. //
  187. //
  188. void SSIResetSaveScreenBitmap(void)
  189. {
  190. DebugEntry(SSIResetSaveScreenBitmap);
  191. //
  192. // Discard all currently saved bits
  193. //
  194. g_ssiLocalSSBState.saveLevel = 0;
  195. //
  196. // Reset the # of pels saved
  197. //
  198. g_ssiRemoteSSBState.pelsSaved = 0;
  199. DebugExitVOID(SSIResetSaveScreenBitmap);
  200. }
  201. //
  202. // FUNCTION: SSISendSaveBitmapOrder
  203. //
  204. // DESCRIPTION:
  205. //
  206. // Attempts to send a SaveBitmap order matching the supplied parameters.
  207. //
  208. //
  209. // PARAMETERS:
  210. //
  211. // lpRect - pointer to the rectangle coords (EXCLUSIVE screen coords)
  212. //
  213. // wCommand - SaveScreenBitmap command (ONBOARD_SAVE, ONBOARD_RESTORE,
  214. // SSB_DISCARDBITS)
  215. //
  216. //
  217. // RETURNS:
  218. //
  219. // TRUE if order successfully sent FALSE if order not sent
  220. //
  221. //
  222. BOOL SSISendSaveBitmapOrder
  223. (
  224. LPRECT lpRect,
  225. UINT wCommand
  226. )
  227. {
  228. DWORD cRemotePelsRequired;
  229. LPSAVEBITMAP_ORDER pSaveBitmapOrder;
  230. LPINT_ORDER pOrder;
  231. BOOL rc = FALSE;
  232. DebugEntry(SSISendSaveBitmapOrder);
  233. //
  234. // If the SaveBitmap order is not supported then return FALSE
  235. // immediately.
  236. //
  237. if (!OE_SendAsOrder(ORD_SAVEBITMAP))
  238. {
  239. TRACE_OUT(( "SaveBmp not supported"));
  240. DC_QUIT;
  241. }
  242. switch (wCommand)
  243. {
  244. case ONBOARD_DISCARD:
  245. //
  246. // We don't transmit DISCARD orders, there's no need since
  247. // saves/restores are paired.
  248. //
  249. g_ssiRemoteSSBState.pelsSaved -=
  250. CURRENT_LOCAL_SSB_STATE.remotePelsRequired;
  251. rc = TRUE;
  252. DC_QUIT;
  253. case ONBOARD_SAVE:
  254. //
  255. // Calculate the number of pels required in the remote Save
  256. // Bitmap to handle this rectangle.
  257. //
  258. cRemotePelsRequired = SSIRemotePelsRequired(lpRect);
  259. //
  260. // If there aren't enough pels in the remote Save Bitmap to
  261. // handle this rectangle then return immediately.
  262. //
  263. if ((g_ssiRemoteSSBState.pelsSaved + cRemotePelsRequired) >
  264. g_ssiSaveBitmapSize)
  265. {
  266. TRACE_OUT(( "no space for %lu pels", cRemotePelsRequired));
  267. DC_QUIT;
  268. }
  269. //
  270. // Allocate memory for the order.
  271. //
  272. pOrder = OA_DDAllocOrderMem(sizeof(SAVEBITMAP_ORDER), 0);
  273. if (!pOrder)
  274. DC_QUIT;
  275. //
  276. // Store the drawing order data.
  277. //
  278. pSaveBitmapOrder = (LPSAVEBITMAP_ORDER)pOrder->abOrderData;
  279. pSaveBitmapOrder->type = LOWORD(ORD_SAVEBITMAP);
  280. pSaveBitmapOrder->Operation = SV_SAVEBITS;
  281. //
  282. // SAVEBITS is a BLOCKER order i.e. it prevents any earlier
  283. // orders from being spoilt by subsequent orders or Screen
  284. // Data.
  285. //
  286. pOrder->OrderHeader.Common.fOrderFlags = OF_BLOCKER;
  287. //
  288. // Copy the rect, converting to inclusive Virtual Desktop
  289. // coords.
  290. //
  291. pSaveBitmapOrder->nLeftRect = lpRect->left;
  292. pSaveBitmapOrder->nTopRect = lpRect->top;
  293. pSaveBitmapOrder->nRightRect = lpRect->right - 1;
  294. pSaveBitmapOrder->nBottomRect = lpRect->bottom - 1;
  295. pSaveBitmapOrder->SavedBitmapPosition = g_ssiRemoteSSBState.pelsSaved;
  296. //
  297. // Store the relevant details in the current entry of the
  298. // local SSB structure.
  299. //
  300. CURRENT_LOCAL_SSB_STATE.remoteSavedPosition =
  301. pSaveBitmapOrder->SavedBitmapPosition;
  302. CURRENT_LOCAL_SSB_STATE.remotePelsRequired = cRemotePelsRequired;
  303. //
  304. // Update the count of remote pels saved.
  305. //
  306. g_ssiRemoteSSBState.pelsSaved += cRemotePelsRequired;
  307. //
  308. // The operation rectangle is NULL.
  309. //
  310. pOrder->OrderHeader.Common.rcsDst.left = 1;
  311. pOrder->OrderHeader.Common.rcsDst.right = 0;
  312. pOrder->OrderHeader.Common.rcsDst.top = 1;
  313. pOrder->OrderHeader.Common.rcsDst.bottom = 0;
  314. break;
  315. case ONBOARD_RESTORE:
  316. //
  317. // Update the remote pel count first. Even if we fail to send
  318. // the order we want to free up the remote pels.
  319. //
  320. g_ssiRemoteSSBState.pelsSaved -=
  321. CURRENT_LOCAL_SSB_STATE.remotePelsRequired;
  322. //
  323. // Allocate memory for the order.
  324. //
  325. pOrder = OA_DDAllocOrderMem(sizeof(SAVEBITMAP_ORDER), 0);
  326. if (!pOrder)
  327. DC_QUIT;
  328. //
  329. // Store the drawing order data.
  330. //
  331. pSaveBitmapOrder = (LPSAVEBITMAP_ORDER)pOrder->abOrderData;
  332. pSaveBitmapOrder->type = LOWORD(ORD_SAVEBITMAP);
  333. pSaveBitmapOrder->Operation = SV_RESTOREBITS;
  334. //
  335. // The order can spoil others (it is opaque).
  336. // It is not SPOILABLE because we want to keep the remote
  337. // save level in a consistent state.
  338. //
  339. pOrder->OrderHeader.Common.fOrderFlags = OF_SPOILER;
  340. //
  341. // Copy the rect, converting to inclusive Virtual Desktop
  342. // coords.
  343. //
  344. pSaveBitmapOrder->nLeftRect = lpRect->left;
  345. pSaveBitmapOrder->nTopRect = lpRect->top;
  346. pSaveBitmapOrder->nRightRect = lpRect->right - 1;
  347. pSaveBitmapOrder->nBottomRect = lpRect->bottom - 1;
  348. pSaveBitmapOrder->SavedBitmapPosition =
  349. CURRENT_LOCAL_SSB_STATE.remoteSavedPosition;
  350. //
  351. // The operation rectangle is also the bounding rectangle of
  352. // the order.
  353. //
  354. pOrder->OrderHeader.Common.rcsDst.left =
  355. pSaveBitmapOrder->nLeftRect;
  356. pOrder->OrderHeader.Common.rcsDst.right =
  357. pSaveBitmapOrder->nRightRect;
  358. pOrder->OrderHeader.Common.rcsDst.top =
  359. pSaveBitmapOrder->nTopRect;
  360. pOrder->OrderHeader.Common.rcsDst.bottom =
  361. pSaveBitmapOrder->nBottomRect;
  362. break;
  363. default:
  364. ERROR_OUT(( "Unexpected wCommand(%d)", wCommand));
  365. break;
  366. }
  367. OTRACE(( "SaveBitmap op %d pos %ld rect {%d %d %d %d}",
  368. pSaveBitmapOrder->Operation, pSaveBitmapOrder->SavedBitmapPosition,
  369. pSaveBitmapOrder->nLeftRect, pSaveBitmapOrder->nTopRect,
  370. pSaveBitmapOrder->nRightRect, pSaveBitmapOrder->nBottomRect ));
  371. //
  372. // Add the order to the order list.
  373. // IT IS NEVER CLIPPED.
  374. //
  375. OA_DDAddOrder(pOrder, NULL);
  376. rc = TRUE;
  377. DC_EXIT_POINT:
  378. DebugExitBOOL(SSISendSaveBitmapOrder, rc);
  379. return(rc);
  380. }
  381. //
  382. // SSISaveBits()
  383. //
  384. // This attemps to save the SPB into our stack. If we have no more room,
  385. // no big deal. We won't find it on a bitblt back to the screen, and that
  386. // info will go as screen data.
  387. //
  388. // The rectangle is EXCLUSIVE screen coords.
  389. //
  390. void SSISaveBits
  391. (
  392. HBITMAP hbmpSpb,
  393. LPRECT lpRect
  394. )
  395. {
  396. DebugEntry(SSISaveBits);
  397. //
  398. // We should never have unbalanced save/restore operations
  399. //
  400. ASSERT(g_ssiLocalSSBState.saveLevel >= 0);
  401. //
  402. // Are we out of space?
  403. //
  404. if (g_ssiLocalSSBState.saveLevel >= SSB_MAX_SAVE_LEVEL)
  405. {
  406. TRACE_OUT(("SaveLevel(%d) exceeds maximum", g_ssiLocalSSBState.saveLevel));
  407. DC_QUIT;
  408. }
  409. //
  410. // If the rectangle to be saved intersects the current SDA, then we will
  411. // have to force a repaint on the restore. This is because orders are
  412. // always sent before Screen Data.
  413. //
  414. // Otherwise mark the bits as saved.
  415. //
  416. if (OE_RectIntersectsSDA(lpRect))
  417. {
  418. CURRENT_LOCAL_SSB_STATE.saveType = ST_FAILED_TO_SAVE;
  419. }
  420. else
  421. {
  422. CURRENT_LOCAL_SSB_STATE.saveType = ST_SAVED_BY_BMP_SIMULATION;
  423. }
  424. //
  425. // Store the bitmap and associated screen rectangle
  426. //
  427. CURRENT_LOCAL_SSB_STATE.hbmpSave = hbmpSpb;
  428. CopyRect(&CURRENT_LOCAL_SSB_STATE.rect, lpRect);
  429. //
  430. // If successfully saved, try to accumulate a SaveBits order
  431. //
  432. if (CURRENT_LOCAL_SSB_STATE.saveType != ST_FAILED_TO_SAVE)
  433. {
  434. CURRENT_LOCAL_SSB_STATE.fSavedRemotely =
  435. SSISendSaveBitmapOrder(lpRect, ONBOARD_SAVE);
  436. }
  437. else
  438. {
  439. //
  440. // We didn't manage to save it. No point in trying to save the
  441. // bitmap remotely.
  442. //
  443. TRACE_OUT(( "Keep track of failed save for restore later"));
  444. CURRENT_LOCAL_SSB_STATE.fSavedRemotely = FALSE;
  445. }
  446. //
  447. // Update the save level
  448. // NOTE this now points to the NEXT free slot
  449. //
  450. g_ssiLocalSSBState.saveLevel++;
  451. DC_EXIT_POINT:
  452. DebugExitVOID(SSISaveBits);
  453. }
  454. //
  455. // SSIFindSlotAndDiscardAbove()
  456. //
  457. // This starts at the topmost valid entry on the SPB stack and works
  458. // backwards. NOTE that saveLevel is the NEXT valid entry.
  459. //
  460. BOOL SSIFindSlotAndDiscardAbove(HBITMAP hbmpSpb)
  461. {
  462. int i;
  463. int iNewSaveLevel;
  464. BOOL rc = FALSE;
  465. DebugEntry(SSIFindSlotAndDiscardAbove);
  466. //
  467. // Look for this SPB. If we find it, then discard the entries after
  468. // it in our stack.
  469. //
  470. iNewSaveLevel = g_ssiLocalSSBState.saveLevel;
  471. for (i = 0; i < g_ssiLocalSSBState.saveLevel; i++)
  472. {
  473. if (rc)
  474. {
  475. //
  476. // We found this SPB, so we are discarding all entries after
  477. // it in the stack. Subtract the saved pixels count for this
  478. // dude.
  479. //
  480. g_ssiRemoteSSBState.pelsSaved -=
  481. g_ssiLocalSSBState.saveState[i].remotePelsRequired;
  482. }
  483. else if (g_ssiLocalSSBState.saveState[i].hbmpSave == hbmpSpb)
  484. {
  485. //
  486. // Found the one we were looking for
  487. //
  488. OTRACE(( "Found SPB %04x at slot %d", hbmpSpb, i));
  489. iNewSaveLevel = i;
  490. rc = TRUE;
  491. }
  492. }
  493. g_ssiLocalSSBState.saveLevel = iNewSaveLevel;
  494. DebugExitBOOL(SSIFindSlotAndDiscardAbove, rc);
  495. return(rc);
  496. }
  497. //
  498. // SSIRestoreBits()
  499. //
  500. // Called when a BitBlt happens to screen from memory. We try to find the
  501. // memory bitmap in our SPB stack. If we can't, we return FALSE, and the OE
  502. // code will save away a screen painting order.
  503. //
  504. // If we find it, we save a small SPB restore order instead.
  505. //
  506. BOOL SSIRestoreBits
  507. (
  508. HBITMAP hbmpSpb
  509. )
  510. {
  511. BOOL rc = FALSE;
  512. DebugEntry(SSIRestoreBits);
  513. ASSERT(g_ssiLocalSSBState.saveLevel >= 0);
  514. //
  515. // Can we find the SPB?
  516. //
  517. if (SSIFindSlotAndDiscardAbove(hbmpSpb))
  518. {
  519. //
  520. // saveLevel is the index of our SPB.
  521. //
  522. if (CURRENT_LOCAL_SSB_STATE.fSavedRemotely)
  523. {
  524. //
  525. // The bits were saved remotely, so send and order.
  526. //
  527. rc = SSISendSaveBitmapOrder(&CURRENT_LOCAL_SSB_STATE.rect,
  528. ONBOARD_RESTORE);
  529. }
  530. else
  531. {
  532. //
  533. // We failed to save the bitmap remotely originally, so now
  534. // we need to return FALSE so that BitBlt() will accumulate
  535. // screen data in the area.
  536. //
  537. TRACE_OUT(( "No remote save, force repaint"));
  538. }
  539. if (g_ssiLocalSSBState.saveLevel == 0)
  540. {
  541. g_ssiRemoteSSBState.pelsSaved = 0;
  542. }
  543. }
  544. DebugExitBOOL(SSIRestoreBits, rc);
  545. return(rc);
  546. }
  547. //
  548. // SSIDiscardBits()
  549. //
  550. // This discards the saved SPB if we have it in our stack.
  551. // NOTE that SSIRestoreBits() also discards the bitmap.
  552. //
  553. // We return TRUE if we found the bitmap.
  554. //
  555. BOOL SSIDiscardBits(HBITMAP hbmpSpb)
  556. {
  557. BOOL rc;
  558. DebugEntry(SSIDiscardBits);
  559. //
  560. // Search for the corresponding save order on our stack.
  561. //
  562. if (rc = SSIFindSlotAndDiscardAbove(hbmpSpb))
  563. {
  564. //
  565. // The save level is now the index to this entry. Since we are
  566. // about to free it, this will be the place the next SAVE goes
  567. // into.
  568. //
  569. //
  570. // If the bits were saved remotely, then send a DISCARD order
  571. //
  572. if (CURRENT_LOCAL_SSB_STATE.fSavedRemotely)
  573. {
  574. //
  575. // NOTE that SSISendSaveBitmapOrder() for DISCARD doesn't have
  576. // a side effect, we can just pass in the address of the rect
  577. // of the SPB we stored.
  578. //
  579. if (!SSISendSaveBitmapOrder(&CURRENT_LOCAL_SSB_STATE.rect, ONBOARD_DISCARD))
  580. {
  581. TRACE_OUT(("Failed to send DISCARDBITS"));
  582. }
  583. }
  584. if (g_ssiLocalSSBState.saveLevel == 0)
  585. {
  586. g_ssiRemoteSSBState.pelsSaved = 0;
  587. }
  588. }
  589. DebugExitBOOL(SSIDiscardBits, rc);
  590. return(rc);
  591. }
  592. //
  593. // FUNCTION: SSIRemotePelsRequired
  594. //
  595. // DESCRIPTION:
  596. //
  597. // Returns the number of remote pels required to store the supplied
  598. // rectangle, taking account of the Save Bitmap granularity.
  599. //
  600. // PARAMETERS:
  601. //
  602. // lpRect - pointer to rectangle position in EXCLUSIVE screen coordinates.
  603. //
  604. // RETURNS: Number of remote pels required.
  605. //
  606. //
  607. DWORD SSIRemotePelsRequired(LPRECT lpRect)
  608. {
  609. UINT rectWidth;
  610. UINT rectHeight;
  611. UINT xGranularity;
  612. UINT yGranularity;
  613. DWORD rc;
  614. DebugEntry(SSIRemotePelsRequired);
  615. ASSERT(lpRect);
  616. //
  617. // Calculate the supplied rectangle size (it is in EXCLUSIVE coords).
  618. //
  619. rectWidth = (DWORD)(lpRect->right - lpRect->left);
  620. rectHeight = (DWORD)(lpRect->bottom - lpRect->top);
  621. xGranularity = g_ssiLocalSSBState.xGranularity;
  622. yGranularity = g_ssiLocalSSBState.yGranularity;
  623. rc = (DWORD)((rectWidth + (xGranularity-1))/xGranularity * xGranularity) *
  624. (DWORD)((rectHeight + (yGranularity-1))/yGranularity * yGranularity);
  625. //
  626. // Return the pels required in the remote SaveBits bitmap to handle
  627. // this rectangle, taking account of its granularity.
  628. //
  629. DebugExitDWORD(SSIRemotePelsRequired, rc);
  630. return(rc);
  631. }
  632. //
  633. // FUNCTION: SSISetNewCapabilities
  634. //
  635. // DESCRIPTION:
  636. //
  637. // Set the new SSI related capabilities
  638. //
  639. // RETURNS:
  640. //
  641. // NONE
  642. //
  643. // PARAMETERS:
  644. //
  645. // pDataIn - pointer to the input buffer
  646. //
  647. //
  648. void SSISetNewCapabilities(LPSSI_NEW_CAPABILITIES pCapabilities)
  649. {
  650. DebugEntry(SSISetNewCapabilities);
  651. //
  652. // Copy the data from the Share Core.
  653. //
  654. g_ssiSaveBitmapSize = pCapabilities->sendSaveBitmapSize;
  655. g_ssiLocalSSBState.xGranularity = pCapabilities->xGranularity;
  656. g_ssiLocalSSBState.yGranularity = pCapabilities->yGranularity;
  657. TRACE_OUT(( "SSI caps: Size %ld X gran %hd Y gran %hd",
  658. g_ssiSaveBitmapSize,
  659. g_ssiLocalSSBState.xGranularity,
  660. g_ssiLocalSSBState.yGranularity));
  661. DebugExitVOID(SSISetNewCapabilities);
  662. }