Source code of Windows XP (NT5)
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.

2190 lines
65 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: multi.c
  3. *
  4. * Supports multiple display boards as a single virtual desktop.
  5. *
  6. * This is implemented by presenting to GDI a single large virtual
  7. * display and adding a layer between GDI and the driver's Drv functions.
  8. * For the most part, the rest of the driver outside of multi.c doesn't
  9. * have to change much, subject to the requirements below.
  10. *
  11. * This implementation requires that each board have the same virtual
  12. * resolution and colour depth (e.g., all be running 1024x768x256), and
  13. * that the boards be arranged in a rectangular configuration.
  14. *
  15. * Each board has its own PDEV, and completely manages its surface
  16. * independently, down to glyph and bitmap caching. The Mul
  17. * routine intercepts the DDI call, and for each board dispatches
  18. * a Drv call with the appropriate PDEV and clip object modifications.
  19. *
  20. * The following support in the main driver is required:
  21. *
  22. * 1) The driver should be able to handle a per-surface offset. For
  23. * example, if two 1024x768 displays are pasted side-by-side, the
  24. * right board will get drawing operations in the range (1024, 768) -
  25. * (2048, 768). The driver has a (-1024, 0) surface offset to convert
  26. * the actual drawing on the right board to the expected (0, 0) -
  27. * (1024, 768).
  28. *
  29. * The current driver already uses this notion to support device-format
  30. * bitmaps drawn in off-screen memory.
  31. *
  32. * Another option would be to handle the surface offsets in this layer,
  33. * but then all parameters including clip objects, paths and glyph
  34. * enumerations would have to be adjusted here as well.
  35. *
  36. * 2) The main driver must be able to share realized pattern information
  37. * between board instances. That is, with the current DDI specification
  38. * GDI entirely handles brush memory allocation via pvAllocRBrush,
  39. * and the driver doesn't get notified when the brush is destroyed, so
  40. * the driver has to keep all information about the brush for all the
  41. * boards in the one brush realization. This isn't too onerous.
  42. *
  43. * Problems:
  44. *
  45. * 1) CompatibleBitmaps would have to be shared between board instances.
  46. * This becomes a problem when the bitmaps are kept by the driver in off-
  47. * screen memory.
  48. *
  49. * Copyright (c) 1993-1996 Microsoft Corporation
  50. * Copyright (c) 1993-1996 Matrox Electronic Systems, Ltd.
  51. \**************************************************************************/
  52. #include "precomp.h"
  53. #if MULTI_BOARDS
  54. #define GO_BOARD(pmdev, pmb) { (pmdev)->pmbCurrent = (pmb); }
  55. #define MAKE_BOARD_CURRENT(pmdev, pmb) \
  56. { \
  57. ULONG ReturnedDataLength; \
  58. \
  59. if (EngDeviceIoControl((pmdev)->hDriver, \
  60. IOCTL_VIDEO_MTX_MAKE_BOARD_CURRENT, \
  61. &(pmb)->iBoard, /* Input */ \
  62. sizeof(LONG), \
  63. NULL, /* Output */ \
  64. 0, \
  65. &ReturnedDataLength)) \
  66. { \
  67. RIP("Failed MTX_MAKE_BOARD_CURRENT"); \
  68. } \
  69. }
  70. struct _MULTI_BOARD;
  71. typedef struct _MULTI_BOARD MULTI_BOARD; /* mb */
  72. struct _MULTI_BOARD
  73. {
  74. LONG iBoard; // Sequentially allocated board number
  75. RECTL rcl; // Board's coordinates
  76. MULTI_BOARD* pmbNext; // For traversing the entire list of boards
  77. MULTI_BOARD* pmbLeft; // For traversing by direction
  78. MULTI_BOARD* pmbUp;
  79. MULTI_BOARD* pmbRight;
  80. MULTI_BOARD* pmbDown;
  81. PDEV* ppdev; // Pointer to the board's PDEV
  82. SURFOBJ* pso; // Surface representing the board
  83. HSURF hsurf; // Handle to surface
  84. }; /* mb, pmb */
  85. typedef struct _MDEV
  86. {
  87. MULTI_BOARD* pmb; // Where to start enumerating
  88. MULTI_BOARD* pmbUpperLeft; // Board in upper-left corner
  89. MULTI_BOARD* pmbUpperRight;
  90. MULTI_BOARD* pmbLowerLeft;
  91. MULTI_BOARD* pmbLowerRight;
  92. LONG cxBoards; // Number of boards per row
  93. LONG cyBoards; // Number of boards per column
  94. LONG cBoards; // Total number of boards
  95. MULTI_BOARD* pmbPointer; // Board where cursor is currently visible
  96. MULTI_BOARD* pmbCurrent; // Currently selected board (needed for
  97. // DrvRealizeBrush)
  98. HANDLE hDriver; // Our handle to miniport
  99. HDEV hdev; // Handle that GDI knows us by
  100. HSURF hsurf; // Handle to our virtual surface
  101. CLIPOBJ* pco; // A temporary CLIPOBJ that we can modify
  102. ULONG iBitmapFormat; // Current colour depth
  103. FLONG flHooks; // Those functions that the main driver
  104. // is hooking
  105. ULONG ulMode; // 'Super' mode for each screen
  106. } MDEV; /* mdev, pmdev */
  107. typedef struct _PVCONSUMER
  108. {
  109. PVOID pvConsumer;
  110. } PVCONSUMER;
  111. typedef struct _FONT_CONSUMER
  112. {
  113. LONG cConsumers; // Total number of boards
  114. PVCONSUMER apvc[MAX_BOARDS]; // Array of structures cConsumers in length
  115. } FONT_CONSUMER; /* fc, pfc */
  116. typedef struct _BITBLTDATA
  117. {
  118. RECTL rclBounds;
  119. MDEV* pmdev;
  120. SURFOBJ* psoDst;
  121. SURFOBJ* psoSrc;
  122. SURFOBJ* psoMask;
  123. CLIPOBJ* pco;
  124. XLATEOBJ* pxlo;
  125. RECTL* prclDst;
  126. POINTL* pptlSrc;
  127. POINTL* pptlMask;
  128. BRUSHOBJ* pbo;
  129. POINTL* pptlBrush;
  130. ROP4 rop4;
  131. } BITBLTDATA; /* bb, pbb */
  132. /******************************Public*Routine******************************\
  133. * BOOL bFindBoard
  134. *
  135. * Returns in ppmb a pointer to the board containing the upper-left
  136. * corner of prcl.
  137. *
  138. * Returns TRUE if prcl is entirely containing on one board; FALSE if
  139. * prcl spans multiple boards.
  140. *
  141. \**************************************************************************/
  142. BOOL bFindBoard(MDEV* pmdev, RECTL* prcl, MULTI_BOARD** ppmb)
  143. {
  144. MULTI_BOARD* pmb;
  145. pmb = pmdev->pmbUpperLeft;
  146. // It should never happen that GDI will give us a call whose bounds
  147. // don't intersect the virtual screen. But so that we don't crash
  148. // should it ever happen, we'll return an intersection with the first
  149. // board -- we can assume GDI at least said the clipping was non-
  150. // trivial, in which case that board's display routine will realize
  151. // nothing had to be done:
  152. *ppmb = pmb;
  153. // First find the row:
  154. while (prcl->top >= pmb->rcl.bottom)
  155. {
  156. pmb = pmb->pmbDown;
  157. if (pmb == NULL)
  158. return(FALSE); // This is a case where the bounds doesn't
  159. // intercept the virtual screen
  160. }
  161. // Now find the column:
  162. while (prcl->left >= pmb->rcl.right)
  163. {
  164. pmb = pmb->pmbRight;
  165. if (pmb == NULL)
  166. return(FALSE); // This is a case where the bounds doesn't
  167. // intercept the virtual screen
  168. }
  169. // So we found the first board:
  170. *ppmb = pmb;
  171. return(prcl->right <= pmb->rcl.right &&
  172. prcl->bottom <= pmb->rcl.bottom);
  173. }
  174. /******************************Public*Routine******************************\
  175. * BOOL bNextBoard
  176. *
  177. * Returns in ppmb a pointer to the next board after intersecting prcl, going
  178. * left-to-right then top-to-bottom.
  179. *
  180. * Returns TRUE if all boards intersecting prcl have been enumerated; FALSE
  181. * if there are more boards.
  182. *
  183. \**************************************************************************/
  184. BOOL bNextBoard(RECTL* prcl, MULTI_BOARD** ppmb)
  185. {
  186. MULTI_BOARD* pmb;
  187. pmb = *ppmb;
  188. // We'll do all the boards in a row first, remembering that the
  189. // bounds rectangle can extend past the end of our virtual screen:
  190. if ((prcl->right > pmb->rcl.right) && (pmb->pmbRight != NULL))
  191. {
  192. *ppmb = pmb->pmbRight;
  193. return(TRUE);
  194. }
  195. // Go to next row if need be, starting at the rcl.left:
  196. if ((prcl->bottom > pmb->rcl.bottom) && (pmb->pmbDown != NULL))
  197. {
  198. pmb = pmb->pmbDown;
  199. while ((prcl->left < pmb->rcl.left) && (pmb->pmbLeft != NULL))
  200. {
  201. pmb = pmb->pmbLeft;
  202. }
  203. *ppmb = pmb;
  204. return(TRUE);
  205. }
  206. return(FALSE);
  207. }
  208. /******************************Public*Routine******************************\
  209. * VOID vIntersect
  210. *
  211. * Returns in prclOut the intersection of rectangles prcl1 and prcl2.
  212. *
  213. \**************************************************************************/
  214. VOID vIntersect(RECTL* prcl1, RECTL* prcl2, RECTL* prclOut)
  215. {
  216. prclOut->left = max(prcl1->left, prcl2->left);
  217. prclOut->top = max(prcl1->top, prcl2->top);
  218. prclOut->right = min(prcl1->right, prcl2->right);
  219. prclOut->bottom = min(prcl1->bottom, prcl2->bottom);
  220. }
  221. /******************************Public*Routine******************************\
  222. * BOOL bBoardCopy
  223. *
  224. * Given the BitBlt parameters in pbb, bitblt's the part of the rectangle
  225. * on the pmbSrc board that must bitblt'ed to the pmbDst board. Bails
  226. * out quickly if nothing actually has to be copied.
  227. *
  228. * Will do a screen-to-screen blt if pmbSrc and pmbDst are the same board;
  229. * otherwise it uses the psoTmp bitmap as temporary storage for transferring
  230. * between the two boards.
  231. *
  232. * NOTE: If your hardware allows you to have all the frame buffers mapped
  233. * into memory simultaneously, you can avoid the 'psoTmp' bitmap
  234. * allocation and extra copy!
  235. *
  236. \**************************************************************************/
  237. BOOL bBoardCopy(
  238. BITBLTDATA* pbb,
  239. SURFOBJ* psoTmp,
  240. MULTI_BOARD* pmbDst,
  241. MULTI_BOARD* pmbSrc)
  242. {
  243. BOOL b;
  244. RECTL rclDst;
  245. LONG dx;
  246. LONG dy;
  247. RECTL rclTmp;
  248. POINTL ptlSrc;
  249. // If there's really no source board, we're guaranteed not to
  250. // have to copy anything from it:
  251. if (pmbSrc == NULL)
  252. return(TRUE);
  253. dx = pbb->prclDst->left - pbb->pptlSrc->x;
  254. dy = pbb->prclDst->top - pbb->pptlSrc->y;
  255. // Pretend we're going to copy the entire source board's screen.
  256. // rclDst would be the destination rectangle:
  257. rclDst.left = pmbSrc->rcl.left + dx;
  258. rclDst.right = pmbSrc->rcl.right + dx;
  259. rclDst.top = pmbSrc->rcl.top + dy;
  260. rclDst.bottom = pmbSrc->rcl.bottom + dy;
  261. // We really want to copy only the part that overlaps the
  262. // destination board's screen:
  263. vIntersect(&pmbDst->rcl, &rclDst, &rclDst);
  264. // Plus we really only want to copy anything to what is contained
  265. // in the original destination rectangle:
  266. vIntersect(&pbb->rclBounds, &rclDst, &rclDst);
  267. // rclDst is now the destination rectangle for our call. We'll
  268. // need a temporary bitmap for copying, so compute its extents:
  269. rclTmp.left = 0;
  270. rclTmp.top = 0;
  271. rclTmp.right = rclDst.right - rclDst.left;
  272. rclTmp.bottom = rclDst.bottom - rclDst.top;
  273. // If it's empty, we're outta here:
  274. if ((rclTmp.right <= 0) || (rclTmp.bottom <= 0))
  275. return(TRUE);
  276. if (pmbDst == pmbSrc)
  277. {
  278. // If the source and destination are the same board, we don't
  279. // need a temporary bitmap:
  280. psoTmp = pmbSrc->pso;
  281. ptlSrc = *pbb->pptlSrc;
  282. }
  283. else
  284. {
  285. ASSERTDD(psoTmp != NULL, "Need non-null bitmap");
  286. ASSERTDD(psoTmp->sizlBitmap.cx >= rclTmp.right, "Bitmap too small in x");
  287. ASSERTDD(psoTmp->sizlBitmap.cy >= rclTmp.bottom, "Bitmap too small in y");
  288. // Figure out the upper-left source corner corresponding to our
  289. // upper-left destination corner:
  290. ptlSrc.x = rclDst.left - dx;
  291. ptlSrc.y = rclDst.top - dy;
  292. // Copy the rectangle from the source to the temporary bitmap:
  293. GO_BOARD(pbb->pmdev, pmbSrc);
  294. b = DrvCopyBits(psoTmp, pmbSrc->pso, NULL, NULL, &rclTmp, &ptlSrc);
  295. // Then get ready to do the copy from the temporary bitmap to
  296. // the destination:
  297. ptlSrc.x = pbb->prclDst->left - rclDst.left;
  298. ptlSrc.y = pbb->prclDst->top - rclDst.top;
  299. }
  300. pbb->pco->rclBounds = rclDst;
  301. GO_BOARD(pbb->pmdev, pmbDst);
  302. b &= DrvBitBlt(pmbDst->pso, psoTmp, pbb->psoMask, pbb->pco, pbb->pxlo,
  303. pbb->prclDst, &ptlSrc, pbb->pptlMask, pbb->pbo,
  304. pbb->pptlBrush, pbb->rop4);
  305. return(b);
  306. }
  307. /******************************Public*Routine******************************\
  308. * BOOL bBitBltBetweenBoards
  309. *
  310. * Handles screen-to-screen blts across multiple boards.
  311. *
  312. \**************************************************************************/
  313. BOOL bBitBltBetweenBoards(
  314. SURFOBJ* psoDst,
  315. SURFOBJ* psoSrc,
  316. SURFOBJ* psoMask,
  317. CLIPOBJ* pco,
  318. XLATEOBJ* pxlo,
  319. RECTL* prclDst,
  320. POINTL* pptlSrc,
  321. POINTL* pptlMask,
  322. BRUSHOBJ* pbo,
  323. POINTL* pptlBrush,
  324. ROP4 rop4,
  325. RECTL* prclUnion, // Rectangular union of source and destination
  326. MULTI_BOARD* pmbUnion) // Board containing upper-left corner of prclUnion
  327. {
  328. BOOL b = TRUE;
  329. BITBLTDATA bb;
  330. RECTL rclOriginalBounds;
  331. SIZEL sizlBoard;
  332. SIZEL sizlDst;
  333. SIZEL sizl;
  334. MULTI_BOARD* pmbSrc;
  335. MULTI_BOARD* pmbDst;
  336. LONG dx;
  337. LONG dy;
  338. RECTL rclStart;
  339. SURFOBJ* pso0 = NULL; // Initialize these first off in case we
  340. SURFOBJ* pso1 = NULL; // early-out
  341. SURFOBJ* pso2 = NULL;
  342. SURFOBJ* pso3 = NULL;
  343. HSURF hsurf0 = 0;
  344. HSURF hsurf1 = 0;
  345. bb.pmdev = (MDEV*) psoDst->dhpdev;
  346. bb.psoDst = psoDst;
  347. bb.psoSrc = psoSrc;
  348. bb.psoMask = psoMask;
  349. bb.pxlo = pxlo;
  350. bb.prclDst = prclDst;
  351. bb.pptlSrc = pptlSrc;
  352. bb.pptlMask = pptlMask;
  353. bb.pbo = pbo;
  354. bb.pptlBrush = pptlBrush;
  355. bb.rop4 = rop4;
  356. bb.pco = pco;
  357. if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
  358. bb.pco = bb.pmdev->pco;
  359. vIntersect(&bb.pco->rclBounds, prclDst, &bb.rclBounds);
  360. rclOriginalBounds = bb.pco->rclBounds;
  361. sizlDst.cx = bb.rclBounds.right - bb.rclBounds.left;
  362. sizlDst.cy = bb.rclBounds.bottom - bb.rclBounds.top;
  363. // This really should never happen, but we'll be paranoid:
  364. if ((sizlDst.cx <= 0) || (sizlDst.cy <= 0))
  365. return(TRUE);
  366. // Compute delta from source to destination:
  367. dx = prclDst->left - pptlSrc->x;
  368. dy = prclDst->top - pptlSrc->y;
  369. // Figure out the size of a board:
  370. sizlBoard.cx = bb.pmdev->pmbUpperLeft->rcl.right;
  371. sizlBoard.cy = bb.pmdev->pmbUpperLeft->rcl.bottom;
  372. // We use temporary bitmaps as intermediaries for copying from one
  373. // board to another. Note that it is much more efficient to allocate
  374. // on the fly, rather than keeping a dedicated bitmap around that
  375. // would have to be swapped in and out.
  376. // When the destination is close to the source, we can accomplish
  377. // most of the blt using screen-to-screen copies, and will need
  378. // only two small temporary bitmaps to temporarily hold the bits
  379. // that must be transferred from one board to another:
  380. if ((abs(dx) < (sizlBoard.cx >> 1)) && (abs(dy) < (sizlBoard.cy >> 1)))
  381. {
  382. // Create a temporary bitmap for the horizontal delta only if
  383. // the blt actually spans boards in the x-direction:
  384. if ((dx != 0) && (prclUnion->right > pmbUnion->rcl.right))
  385. {
  386. sizl.cx = min(sizlDst.cx, abs(dx));
  387. sizl.cy = min(sizlDst.cy, sizlBoard.cy - abs(dy));
  388. hsurf0 = (HSURF) EngCreateBitmap(sizl, 0, bb.pmdev->iBitmapFormat,
  389. 0, NULL);
  390. pso1 = EngLockSurface(hsurf0);
  391. if (pso1 == NULL)
  392. return(FALSE);
  393. // Can use same temporary bitmap for section '3':
  394. pso3 = pso1;
  395. }
  396. // Similarly for the vertical delta:
  397. if ((dy != 0) && (prclUnion->bottom > pmbUnion->rcl.bottom))
  398. {
  399. sizl.cx = min(sizlDst.cx, sizlBoard.cx - abs(dx));
  400. sizl.cy = min(sizlDst.cy, abs(dy));
  401. hsurf1 = (HSURF) EngCreateBitmap(sizl, 0, bb.pmdev->iBitmapFormat,
  402. 0, NULL);
  403. pso2 = EngLockSurface(hsurf1);
  404. if (pso2 == NULL)
  405. {
  406. b = FALSE;
  407. goto OuttaHere;
  408. }
  409. }
  410. }
  411. else
  412. {
  413. // Make the bitmap the size of a board, or the size of the
  414. // destination rectangle, which ever is smaller:
  415. sizl.cx = min(sizlDst.cx, sizlBoard.cx);
  416. sizl.cy = min(sizlDst.cy, sizlBoard.cy);
  417. hsurf0 = (HSURF) EngCreateBitmap(sizl, 0, bb.pmdev->iBitmapFormat,
  418. 0, NULL);
  419. pso0 = EngLockSurface(hsurf0);
  420. if (pso0 == NULL)
  421. return(FALSE);
  422. pso1 = pso0;
  423. pso2 = pso0;
  424. pso3 = pso0;
  425. }
  426. if ((dx <= 0) && (dy <= 0))
  427. {
  428. // Move the rectangle up and to the left:
  429. // Find the board containing the upper-left corner of the destination:
  430. pmbDst = bb.pmdev->pmbUpperLeft;
  431. while (pmbDst->rcl.right <= bb.rclBounds.left)
  432. pmbDst = pmbDst->pmbRight;
  433. while (pmbDst->rcl.bottom <= bb.rclBounds.top)
  434. pmbDst = pmbDst->pmbDown;
  435. // Find the upper-left of the four source boards' rectangles which
  436. // can potentially overlap our destination board's rectangle:
  437. rclStart.left = pmbDst->rcl.left - dx;
  438. rclStart.top = pmbDst->rcl.top - dy;
  439. pmbSrc = pmbDst;
  440. while (pmbSrc->rcl.right <= rclStart.left)
  441. pmbSrc = pmbSrc->pmbRight;
  442. while (pmbSrc->rcl.bottom <= rclStart.top)
  443. pmbSrc = pmbSrc->pmbDown;
  444. while (TRUE)
  445. {
  446. b &= bBoardCopy(&bb, pso0, pmbDst, pmbSrc);
  447. b &= bBoardCopy(&bb, pso1, pmbDst, pmbSrc->pmbRight);
  448. b &= bBoardCopy(&bb, pso2, pmbDst, pmbSrc->pmbDown);
  449. if (pmbSrc->pmbDown != NULL)
  450. b &= bBoardCopy(&bb, pso3, pmbDst, pmbSrc->pmbDown->pmbRight);
  451. if (pmbDst->rcl.right < bb.rclBounds.right)
  452. {
  453. // Move right in the row of boards:
  454. pmbDst = pmbDst->pmbRight;
  455. pmbSrc = pmbSrc->pmbRight;
  456. }
  457. else
  458. {
  459. // We may be all done:
  460. if (pmbDst->rcl.bottom >= bb.rclBounds.bottom)
  461. break;
  462. // Nope, have to go down to left side of next lower row:
  463. while (pmbDst->rcl.left > bb.rclBounds.left)
  464. {
  465. pmbDst = pmbDst->pmbLeft;
  466. pmbSrc = pmbSrc->pmbLeft;
  467. }
  468. pmbDst = pmbDst->pmbDown;
  469. pmbSrc = pmbSrc->pmbDown;
  470. }
  471. }
  472. }
  473. else if ((dx >= 0) && (dy >= 0))
  474. {
  475. // Move the rectangle down and to the right:
  476. // Find the board containing the lower-right corner of the destination:
  477. pmbDst = bb.pmdev->pmbLowerRight;
  478. while (pmbDst->rcl.left >= bb.rclBounds.right)
  479. pmbDst = pmbDst->pmbLeft;
  480. while (pmbDst->rcl.top >= bb.rclBounds.bottom)
  481. pmbDst = pmbDst->pmbUp;
  482. // Find the lower-right of the four source boards' rectangles which
  483. // can potentially overlap our destination board's rectangle:
  484. rclStart.right = pmbDst->rcl.right - dx;
  485. rclStart.bottom = pmbDst->rcl.bottom - dy;
  486. pmbSrc = pmbDst;
  487. while (pmbSrc->rcl.left >= rclStart.right)
  488. pmbSrc = pmbSrc->pmbLeft;
  489. while (pmbSrc->rcl.top >= rclStart.bottom)
  490. pmbSrc = pmbSrc->pmbUp;
  491. while (TRUE)
  492. {
  493. b &= bBoardCopy(&bb, pso0, pmbDst, pmbSrc);
  494. b &= bBoardCopy(&bb, pso1, pmbDst, pmbSrc->pmbLeft);
  495. b &= bBoardCopy(&bb, pso2, pmbDst, pmbSrc->pmbUp);
  496. if (pmbSrc->pmbUp != NULL)
  497. b &= bBoardCopy(&bb, pso3, pmbDst, pmbSrc->pmbUp->pmbLeft);
  498. if (pmbDst->rcl.left > bb.rclBounds.left)
  499. {
  500. // Move left in the row of boards:
  501. pmbDst = pmbDst->pmbLeft;
  502. pmbSrc = pmbSrc->pmbLeft;
  503. }
  504. else
  505. {
  506. // We may be all done:
  507. if (pmbDst->rcl.top <= bb.rclBounds.top)
  508. break;
  509. // Nope, have to go up to right side of next upper row:
  510. while (pmbDst->rcl.right < bb.rclBounds.right)
  511. {
  512. pmbDst = pmbDst->pmbRight;
  513. pmbSrc = pmbSrc->pmbRight;
  514. }
  515. pmbDst = pmbDst->pmbUp;
  516. pmbSrc = pmbSrc->pmbUp;
  517. }
  518. }
  519. }
  520. else if ((dx >= 0) && (dy <= 0))
  521. {
  522. // Move the rectangle up and to the right:
  523. // Find the board containing the upper-right corner of the destination:
  524. pmbDst = bb.pmdev->pmbUpperRight;
  525. while (pmbDst->rcl.left >= bb.rclBounds.right)
  526. pmbDst = pmbDst->pmbLeft;
  527. while (pmbDst->rcl.bottom <= bb.rclBounds.top)
  528. pmbDst = pmbDst->pmbDown;
  529. // Find the upper-right of the four source boards' rectangles which
  530. // can potentially overlap our destination board's rectangle:
  531. rclStart.right = pmbDst->rcl.right - dx;
  532. rclStart.top = pmbDst->rcl.top - dy;
  533. pmbSrc = pmbDst;
  534. while (pmbSrc->rcl.left >= rclStart.right)
  535. pmbSrc = pmbSrc->pmbLeft;
  536. while (pmbSrc->rcl.bottom <= rclStart.top)
  537. pmbSrc = pmbSrc->pmbDown;
  538. while (TRUE)
  539. {
  540. b &= bBoardCopy(&bb, pso0, pmbDst, pmbSrc);
  541. b &= bBoardCopy(&bb, pso1, pmbDst, pmbSrc->pmbLeft);
  542. b &= bBoardCopy(&bb, pso2, pmbDst, pmbSrc->pmbDown);
  543. if (pmbSrc->pmbDown != NULL)
  544. b &= bBoardCopy(&bb, pso3, pmbDst, pmbSrc->pmbDown->pmbLeft);
  545. if (pmbDst->rcl.left > bb.rclBounds.left)
  546. {
  547. // Move left in the row of boards:
  548. pmbDst = pmbDst->pmbLeft;
  549. pmbSrc = pmbSrc->pmbLeft;
  550. }
  551. else
  552. {
  553. // We may be all done:
  554. if (pmbDst->rcl.bottom >= bb.rclBounds.bottom)
  555. break;
  556. // Nope, have to go down to right side of next lower row:
  557. while (pmbDst->rcl.right < bb.rclBounds.right)
  558. {
  559. pmbDst = pmbDst->pmbRight;
  560. pmbSrc = pmbSrc->pmbRight;
  561. }
  562. pmbDst = pmbDst->pmbDown;
  563. pmbSrc = pmbSrc->pmbDown;
  564. }
  565. }
  566. }
  567. else
  568. {
  569. // Move the rectangle down and to the left:
  570. // Find the board containing the lower-left corner of the destination:
  571. pmbDst = bb.pmdev->pmbLowerLeft;
  572. while (pmbDst->rcl.right <= bb.rclBounds.left)
  573. pmbDst = pmbDst->pmbRight;
  574. while (pmbDst->rcl.top >= bb.rclBounds.bottom)
  575. pmbDst = pmbDst->pmbUp;
  576. // Find the lower-left of the four source boards' rectangles which
  577. // can potentially overlap our destination board's rectangle:
  578. rclStart.left = pmbDst->rcl.left - dx;
  579. rclStart.bottom = pmbDst->rcl.bottom - dy;
  580. pmbSrc = pmbDst;
  581. while (pmbSrc->rcl.right <= rclStart.left)
  582. pmbSrc = pmbSrc->pmbRight;
  583. while (pmbSrc->rcl.top >= rclStart.bottom)
  584. pmbSrc = pmbSrc->pmbUp;
  585. while (TRUE)
  586. {
  587. b &= bBoardCopy(&bb, pso0, pmbDst, pmbSrc);
  588. b &= bBoardCopy(&bb, pso1, pmbDst, pmbSrc->pmbRight);
  589. b &= bBoardCopy(&bb, pso2, pmbDst, pmbSrc->pmbUp);
  590. if (pmbSrc->pmbUp != NULL)
  591. b &= bBoardCopy(&bb, pso3, pmbDst, pmbSrc->pmbUp->pmbRight);
  592. if (pmbDst->rcl.right < bb.rclBounds.right)
  593. {
  594. // Move right in the row of boards:
  595. pmbDst = pmbDst->pmbRight;
  596. pmbSrc = pmbSrc->pmbRight;
  597. }
  598. else
  599. {
  600. // We may be all done:
  601. if (pmbDst->rcl.top <= bb.rclBounds.top)
  602. break;
  603. // Nope, have to up down to left side of next upper row:
  604. while (pmbDst->rcl.left > bb.rclBounds.left)
  605. {
  606. pmbDst = pmbDst->pmbLeft;
  607. pmbSrc = pmbSrc->pmbLeft;
  608. }
  609. pmbDst = pmbDst->pmbUp;
  610. pmbSrc = pmbSrc->pmbUp;
  611. }
  612. }
  613. }
  614. bb.pco->rclBounds = rclOriginalBounds;
  615. OuttaHere:
  616. // In one case, pso0 == pso1 == pso2 == pso3, and we don't want to
  617. // unlock the same surface twice:
  618. if (pso1 != pso2)
  619. EngUnlockSurface(pso1);
  620. EngUnlockSurface(pso2);
  621. EngDeleteSurface(hsurf0);
  622. EngDeleteSurface(hsurf1);
  623. return(b);
  624. }
  625. /******************************Public*Routine******************************\
  626. * ULONG MulGetModes
  627. *
  628. \**************************************************************************/
  629. ULONG MulGetModes(
  630. HANDLE hDriver,
  631. ULONG cjSize,
  632. DEVMODEW* pdm)
  633. {
  634. ULONG ulRet;
  635. ulRet = DrvGetModes(hDriver, cjSize, pdm);
  636. return(ulRet);
  637. }
  638. /******************************Public*Routine******************************\
  639. * BOOL bQueryMultiBoards
  640. *
  641. * Performs the minimal initialization required to ask the miniport
  642. * if we'll be supporting multiple boards.
  643. *
  644. \**************************************************************************/
  645. BOOL bQueryMultiBoards(
  646. HANDLE hDriver, // Input
  647. DEVMODEW* pdm, // Input and Output -- updates some fields
  648. SIZEL* pszlBoardArray, // Output
  649. SIZEL* pszlScreen, // Output
  650. ULONG* pulMode) // Output
  651. {
  652. VIDEO_MODE_INFORMATION VideoModeInformation;
  653. ULONG ulBoardId;
  654. ULONG ReturnedDataLength;
  655. SIZEL szlBoardArray;
  656. MULTI_BOARD* pmb;
  657. DWORD cModes;
  658. PVIDEO_MODE_INFORMATION pVideoBuffer;
  659. PVIDEO_MODE_INFORMATION pVideoTemp;
  660. DWORD cbModeSize;
  661. // Figure out the requested virtual desktop size:
  662. if (!bSelectMode(hDriver,
  663. pdm,
  664. &VideoModeInformation,
  665. &ulBoardId))
  666. {
  667. DISPDBG((0, "bQueryMultiBoards -- Failed bSelectMode"));
  668. goto ReturnFailure0;
  669. }
  670. *pulMode = VideoModeInformation.ModeIndex;
  671. // Call the miniport via a public IOCTL to set the graphics mode.
  672. // The MGA miniport requires that we do this before calling
  673. // MTX_QUERY_BOARD_ARRAY:
  674. if (EngDeviceIoControl(hDriver,
  675. IOCTL_VIDEO_SET_CURRENT_MODE,
  676. &VideoModeInformation.ModeIndex, // Input
  677. sizeof(DWORD),
  678. NULL, // Output
  679. 0,
  680. &ReturnedDataLength))
  681. {
  682. DISPDBG((0, "bQueryMultiBoards - Failed VIDEO_SET_CURRENT_MODE"));
  683. goto ReturnFailure0;
  684. }
  685. // Now that we've set the mode, we can query the MGA miniport
  686. // via a private IOCTL to find out how many boards there will be.
  687. if (EngDeviceIoControl(hDriver,
  688. IOCTL_VIDEO_MTX_QUERY_BOARD_ARRAY,
  689. NULL, // Input
  690. 0,
  691. pszlBoardArray, // Output
  692. sizeof(SIZEL),
  693. &ReturnedDataLength))
  694. {
  695. DISPDBG((0, "bQueryMultiBoards -- Failed MTX_QUERY_BOARD_ARRAY"));
  696. goto ReturnFailure0;
  697. }
  698. // Convert the devmode so that it is no longer a request for
  699. // the entire virtual desktop dimension, but is now a request
  700. // for the resolution of each board:
  701. pdm->dmPelsWidth /= pszlBoardArray->cx;
  702. pdm->dmPelsHeight /= pszlBoardArray->cy;
  703. // Remember some stuff about the mode:
  704. pszlScreen->cx = VideoModeInformation.VisScreenWidth / pszlBoardArray->cx;
  705. pszlScreen->cy = VideoModeInformation.VisScreenHeight / pszlBoardArray->cy;
  706. DISPDBG((1, "Board array: %li x %li",
  707. pszlBoardArray->cx, pszlBoardArray->cy));
  708. return(TRUE);
  709. ReturnFailure0:
  710. return(FALSE);
  711. }
  712. /******************************Public*Routine******************************\
  713. * BOOL bInitializeGeometry
  714. *
  715. * Initializes all our multi-board data structures describing the
  716. * geometry of the multiple board configuration.
  717. *
  718. \**************************************************************************/
  719. BOOL bInitializeGeometry(
  720. MDEV* pmdev,
  721. LONG cxBoards,
  722. LONG cyBoards,
  723. LONG cxScreen,
  724. LONG cyScreen)
  725. {
  726. LONG cBoards;
  727. LONG i;
  728. LONG x;
  729. LONG y;
  730. MULTI_BOARD* apmb;
  731. MULTI_BOARD* pmb;
  732. // Create all of our multi-board structures:
  733. cBoards = cxBoards * cyBoards;
  734. pmdev->cBoards = cBoards;
  735. pmdev->cxBoards = cxBoards;
  736. pmdev->cyBoards = cyBoards;
  737. // Allocate and initialize the linked list of structures for every
  738. // board:
  739. apmb = EngAllocMem(FL_ZERO_MEMORY, cBoards * sizeof(MULTI_BOARD), ALLOC_TAG);
  740. if (apmb == NULL)
  741. {
  742. DISPDBG((0, "bInitializeGeometry -- Failed EngAllocMem"));
  743. goto ReturnFailure0;
  744. }
  745. for (pmb = apmb + 1, i = 1; i < cBoards; pmb++, i++)
  746. {
  747. // The first board's 'iBoard' is already set to zero...
  748. (pmb)->iBoard = i;
  749. (pmb - 1)->pmbNext = pmb;
  750. }
  751. pmdev->pmb = apmb;
  752. pmdev->pmbUpperLeft = &apmb[0];
  753. pmdev->pmbUpperRight = &apmb[cxBoards - 1];
  754. pmdev->pmbLowerLeft = &apmb[cBoards - cxBoards];
  755. pmdev->pmbLowerRight = &apmb[cBoards - 1];
  756. // Now set the neighbor pointers. If there is no neighbor for
  757. // a board, the neighbor pointer must be set to NULL (note that
  758. // we rely on the zero initialization to take care of this):
  759. i = 0;
  760. for (x = 1; x <= cxBoards; x++)
  761. {
  762. for (y = 1; y <= cyBoards; y++)
  763. {
  764. if (x > 1)
  765. apmb[i].pmbLeft = &apmb[i - 1];
  766. if (y > 1)
  767. apmb[i].pmbUp = &apmb[i - cxBoards];
  768. if (x < cxBoards)
  769. apmb[i].pmbRight = &apmb[i + 1];
  770. if (y < cyBoards)
  771. apmb[i].pmbDown = &apmb[i + cxBoards];
  772. apmb[i].rcl.right = x * cxScreen;
  773. apmb[i].rcl.left = x * cxScreen - cxScreen;
  774. apmb[i].rcl.bottom = y * cyScreen;
  775. apmb[i].rcl.top = y * cyScreen - cyScreen;
  776. i++;
  777. }
  778. }
  779. return(TRUE);
  780. ReturnFailure0:
  781. DISPDBG((0, "Failed bInitializeGeometry"));
  782. return(FALSE);
  783. }
  784. /******************************Public*Routine******************************\
  785. * DHPDEV MulEnablePDEV
  786. *
  787. \**************************************************************************/
  788. DHPDEV MulEnablePDEV(
  789. DEVMODEW* pdm, // Contains data pertaining to requested mode
  790. PWSTR pwszLogAddr, // Logical address
  791. ULONG cPat, // Count of standard patterns
  792. HSURF* phsurfPatterns, // Buffer for standard patterns
  793. ULONG cjCaps, // Size of buffer for device caps 'pdevcaps'
  794. ULONG* pdevcaps, // Buffer for device caps, also known as 'gdiinfo'
  795. ULONG cjDevInfo, // Number of bytes in device info 'pdi'
  796. DEVINFO* pdi, // Device information
  797. HDEV hdev, // HDEV, used for callbacks
  798. PWSTR pwszDeviceName, // Device name
  799. HANDLE hDriver) // Kernel driver handle
  800. {
  801. MDEV* pmdev; // Multi-board PDEV
  802. PDEV* ppdev; // Per-board PDEV
  803. MULTI_BOARD* pmb;
  804. DEVMODEW dm; // Local copy of requested devmode
  805. SIZEL szlBoardArray; // Configuration of boards
  806. SIZEL szlScreen; // Resolution of each screen
  807. ULONG ulMode;
  808. // Future versions of NT had better supply 'devcaps' and 'devinfo'
  809. // structures that are the same size or larger than the current
  810. // structures:
  811. if ((cjCaps < sizeof(GDIINFO)) || (cjDevInfo < sizeof(DEVINFO)))
  812. {
  813. DISPDBG((0, "MulEnablePDEV -- Buffer size too small"));
  814. goto ReturnFailure0;
  815. }
  816. // Make a local copy of the DEVMODE that we can modify. We need
  817. // to do this because it will, for example, contain a request
  818. // for 2048x768, and we want to convert it to 1024x768:
  819. dm = *pdm;
  820. if (!bQueryMultiBoards(hDriver,
  821. &dm,
  822. &szlBoardArray,
  823. &szlScreen,
  824. &ulMode))
  825. {
  826. DISPDBG((0, "MulEnablePDEV -- Failed bQueryMultiBoards"));
  827. goto ReturnFailure0;
  828. }
  829. // Note that we depend on the zero initialization:
  830. pmdev = (MDEV*) EngAllocMem(FL_ZERO_MEMORY, sizeof(MDEV), ALLOC_TAG);
  831. if (pmdev == NULL)
  832. {
  833. DISPDBG((0, "MulEnablePDEV -- Failed EngAllocMem"));
  834. goto ReturnFailure0;
  835. }
  836. // Remember some stuff:
  837. pmdev->hDriver = hDriver;
  838. pmdev->ulMode = ulMode;
  839. if (!bInitializeGeometry(pmdev,
  840. szlBoardArray.cx,
  841. szlBoardArray.cy,
  842. szlScreen.cx,
  843. szlScreen.cy))
  844. {
  845. DISPDBG((0, "MulEnablePDEV -- Failed bInitializeGeometry"));
  846. goto ReturnFailure1;
  847. }
  848. // For every board, we'll create our own PDEV.
  849. for (pmb = pmdev->pmb; pmb != NULL; pmb = pmb->pmbNext)
  850. {
  851. // Initialize each board and create a surface to go with it:
  852. MAKE_BOARD_CURRENT(pmdev, pmb);
  853. ppdev = (PDEV*) DrvEnablePDEV(&dm, pwszLogAddr,
  854. cPat, phsurfPatterns,
  855. cjCaps, pdevcaps,
  856. cjDevInfo, pdi,
  857. hdev, pwszDeviceName,
  858. hDriver);
  859. if (ppdev == NULL)
  860. goto ReturnFailure1;
  861. pmb->ppdev = ppdev;
  862. // The PDEV sometimes needs to know its board number, and some
  863. // other stuff:
  864. ppdev->iBoard = pmb->iBoard;
  865. ppdev->ulMode = pmdev->ulMode;
  866. }
  867. // Get a copy of what functions we're supposed to hook, sans
  868. // HOOK_STRETCHBLT because I can't be bothered to write its
  869. // MulStretchBlt function. First, choose a board, any board:
  870. pmb = pmdev->pmbLowerLeft;
  871. pmdev->flHooks = pmb->ppdev->flHooks & ~HOOK_STRETCHBLT;
  872. pmdev->iBitmapFormat = pmb->ppdev->iBitmapFormat;
  873. // Adjust the stuff we return back to GDI.
  874. //
  875. // NOTE: By Setting 'DesktopHorzRes' and 'DesktopVertRes' to the
  876. // size of the virtual desktop, but keeping 'HorzRes' and
  877. // 'VertRes' as the size of the individual screens, we
  878. // get dialogs centered on the one primary screen, but
  879. // windows can be dragged to any screen.
  880. // ((GDIINFO*) pdevcaps)->ulDesktopHorzRes *= pmdev->cxBoards;
  881. // ((GDIINFO*) pdevcaps)->ulDesktopVertRes *= pmdev->cyBoards;
  882. // ((GDIINFO*) pdevcaps)->ulHorzSize *= pmdev->cxBoards;
  883. // ((GDIINFO*) pdevcaps)->ulVertSize *= pmdev->cyBoards;
  884. return((DHPDEV) pmdev);
  885. ReturnFailure1:
  886. MulDisablePDEV((DHPDEV) pmdev);
  887. ReturnFailure0:
  888. DISPDBG((0, "Failed MulEnablePDEV"));
  889. return(0);
  890. }
  891. /******************************Public*Routine******************************\
  892. * VOID MulCompletePDEV
  893. *
  894. \**************************************************************************/
  895. VOID MulCompletePDEV(
  896. DHPDEV dhpdev,
  897. HDEV hdev)
  898. {
  899. MDEV* pmdev;
  900. MULTI_BOARD* pmb;
  901. pmdev = (MDEV*) dhpdev;
  902. pmdev->hdev = hdev;
  903. for (pmb = pmdev->pmb; pmb != NULL; pmb = pmb->pmbNext)
  904. {
  905. DrvCompletePDEV((DHPDEV) pmb->ppdev, hdev);
  906. }
  907. }
  908. /******************************Public*Routine******************************\
  909. * HSURF MulEnableSurface
  910. *
  911. \**************************************************************************/
  912. HSURF MulEnableSurface(DHPDEV dhpdev)
  913. {
  914. MDEV* pmdev;
  915. FLONG flStatus;
  916. MULTI_BOARD* pmb;
  917. SIZEL sizlVirtual;
  918. HSURF hsurfBoard; // Gnarly, dude!
  919. SURFOBJ* psoBoard;
  920. DSURF* pdsurfBoard;
  921. HSURF hsurfVirtual;
  922. CLIPOBJ* pco;
  923. pmdev = (MDEV*) dhpdev;
  924. flStatus = (FLONG) -1;
  925. for (pmb = pmdev->pmb; pmb != NULL; pmb = pmb->pmbNext)
  926. {
  927. MAKE_BOARD_CURRENT(pmdev, pmb);
  928. hsurfBoard = DrvEnableSurface((DHPDEV) pmb->ppdev);
  929. if (hsurfBoard == 0)
  930. goto ReturnFailure;
  931. pmb->hsurf = hsurfBoard;
  932. // Every time we draw on a particular board, we'll refer to it
  933. // using this surface:
  934. psoBoard = EngLockSurface(hsurfBoard);
  935. if (psoBoard == NULL)
  936. goto ReturnFailure;
  937. pmb->pso = psoBoard;
  938. // There are a few things in the board's data instances that we
  939. // have to modify:
  940. pdsurfBoard = (DSURF*) psoBoard->dhsurf;
  941. // This is how we change 'xOffset' and 'yOffset' for each
  942. // individual board 'pdev':
  943. pdsurfBoard->poh->x = -pmb->rcl.left;
  944. pdsurfBoard->poh->y = -pmb->rcl.top;
  945. // This is sort of sleazy. Whenever we pass a call on to a board's
  946. // Drv function using 'pmb->pso', it has to be able to retrieve
  947. // its own PDEV pointer from 'dhpdev':
  948. pmb->pso->dhpdev = (DHPDEV) pmb->ppdev;
  949. // Accumulate all the flags:
  950. flStatus &= pmb->ppdev->flStatus;
  951. }
  952. // We may encounter a rare situation where one of the boards does
  953. // not have enough memory for the allocation of a brush cache in
  954. // off-screen memory. The current method of handling this situation
  955. // is to look at 'ppdev->flStatus' in DrvRealizeBrush, and fail it
  956. // if no brush cache has been allocated. With multiple boards,
  957. // that has to be converted to a check to see if brush caches have
  958. // been allocated for all boards. We accomplish this by turning off
  959. // the brush cache flag for every 'pdev'.
  960. //
  961. // (We could add extra logic to our pattern routines to handle some
  962. // boards having a brush cache, and some not, but it's not worth
  963. // slowing down the common case.)
  964. if (!(flStatus & STAT_BRUSH_CACHE))
  965. {
  966. for (pmb = pmdev->pmb; pmb != NULL; pmb = pmb->pmbNext)
  967. {
  968. pmb->ppdev->flStatus &= ~STAT_BRUSH_CACHE;
  969. }
  970. }
  971. // Now create the surface which the engine will use to refer to our
  972. // entire multi-board virtual screen:
  973. sizlVirtual.cx = pmdev->pmbLowerRight->rcl.right;
  974. sizlVirtual.cy = pmdev->pmbLowerRight->rcl.bottom;
  975. hsurfVirtual = EngCreateDeviceSurface((DHSURF) pmdev, sizlVirtual,
  976. pmdev->iBitmapFormat);
  977. if (hsurfVirtual == 0)
  978. goto ReturnFailure;
  979. pmdev->hsurf = hsurfVirtual;
  980. if (!EngAssociateSurface(hsurfVirtual, pmdev->hdev, pmdev->flHooks))
  981. goto ReturnFailure;
  982. // Create a temporary clip object that we can use when a drawing
  983. // operation spans multiple boards:
  984. pco = EngCreateClip();
  985. if (pco == NULL)
  986. goto ReturnFailure;
  987. pmdev->pco = pco;
  988. pmdev->pco->iDComplexity = DC_RECT;
  989. pmdev->pco->iMode = TC_RECTANGLES;
  990. pmdev->pco->rclBounds.left = 0;
  991. pmdev->pco->rclBounds.top = 0;
  992. pmdev->pco->rclBounds.right = pmdev->pmbLowerRight->rcl.right;
  993. pmdev->pco->rclBounds.bottom = pmdev->pmbLowerRight->rcl.bottom;
  994. return(hsurfVirtual);
  995. ReturnFailure:
  996. MulDisableSurface((DHPDEV) pmdev);
  997. DISPDBG((0, "Failed MulEnableSurface"));
  998. return(0);
  999. }
  1000. /******************************Public*Routine******************************\
  1001. * BOOL MulStrokePath
  1002. *
  1003. \**************************************************************************/
  1004. BOOL MulStrokePath(
  1005. SURFOBJ* pso,
  1006. PATHOBJ* ppo,
  1007. CLIPOBJ* pco,
  1008. XFORMOBJ* pxo,
  1009. BRUSHOBJ* pbo,
  1010. POINTL* pptlBrush,
  1011. LINEATTRS* pla,
  1012. MIX mix)
  1013. {
  1014. RECTFX rcfxBounds;
  1015. RECTL rclBounds;
  1016. MDEV* pmdev;
  1017. RECTL rclOriginalBounds;
  1018. MULTI_BOARD* pmb;
  1019. BOOL b;
  1020. FLOAT_LONG elStyleState;
  1021. // Get the path bounds and make it lower-right exclusive:
  1022. PATHOBJ_vGetBounds(ppo, &rcfxBounds);
  1023. rclBounds.left = (rcfxBounds.xLeft >> 4);
  1024. rclBounds.top = (rcfxBounds.yTop >> 4);
  1025. rclBounds.right = (rcfxBounds.xRight >> 4) + 2;
  1026. rclBounds.bottom = (rcfxBounds.yBottom >> 4) + 2;
  1027. pmdev = (MDEV*) pso->dhpdev;
  1028. if (bFindBoard(pmdev, &rclBounds, &pmb))
  1029. {
  1030. GO_BOARD(pmdev, pmb);
  1031. b = DrvStrokePath(pmb->pso, ppo, pco, pxo, pbo, pptlBrush, pla, mix);
  1032. }
  1033. else
  1034. {
  1035. if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
  1036. {
  1037. // If the CLIPOBJ doesn't have at least DC_RECT complexity,
  1038. // substitute one that does:
  1039. pco = pmdev->pco;
  1040. }
  1041. rclOriginalBounds = pco->rclBounds;
  1042. elStyleState = pla->elStyleState;
  1043. b = TRUE;
  1044. do {
  1045. // For each board, make sure the style state gets reset and
  1046. // the path enumeration gets restarted:
  1047. pla->elStyleState = elStyleState;
  1048. PATHOBJ_vEnumStart(ppo);
  1049. if (bIntersect(&rclOriginalBounds, &pmb->rcl, &pco->rclBounds))
  1050. {
  1051. GO_BOARD(pmdev, pmb);
  1052. b &= DrvStrokePath(pmb->pso, ppo, pco, pxo, pbo, pptlBrush, pla,
  1053. mix);
  1054. }
  1055. } while (bNextBoard(&rclBounds, &pmb));
  1056. // Restore the original clip bounds:
  1057. pco->rclBounds = rclOriginalBounds;
  1058. }
  1059. return(b);
  1060. }
  1061. /******************************Public*Routine******************************\
  1062. * BOOL MulFillPath
  1063. *
  1064. \**************************************************************************/
  1065. BOOL MulFillPath(
  1066. SURFOBJ* pso,
  1067. PATHOBJ* ppo,
  1068. CLIPOBJ* pco,
  1069. BRUSHOBJ* pbo,
  1070. POINTL* pptlBrush,
  1071. MIX mix,
  1072. FLONG flOptions)
  1073. {
  1074. RECTFX rcfxBounds;
  1075. RECTL rclBounds;
  1076. MDEV* pmdev;
  1077. RECTL rclOriginalBounds;
  1078. MULTI_BOARD* pmb;
  1079. BOOL b;
  1080. // Get the path bounds and make it lower-right exclusive:
  1081. PATHOBJ_vGetBounds(ppo, &rcfxBounds);
  1082. rclBounds.left = (rcfxBounds.xLeft >> 4);
  1083. rclBounds.top = (rcfxBounds.yTop >> 4);
  1084. rclBounds.right = (rcfxBounds.xRight >> 4) + 2;
  1085. rclBounds.bottom = (rcfxBounds.yBottom >> 4) + 2;
  1086. pmdev = (MDEV*) pso->dhpdev;
  1087. if (bFindBoard(pmdev, &rclBounds, &pmb))
  1088. {
  1089. GO_BOARD(pmdev, pmb);
  1090. b = DrvFillPath(pmb->pso, ppo, pco, pbo, pptlBrush, mix, flOptions);
  1091. }
  1092. else
  1093. {
  1094. if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
  1095. {
  1096. // If the CLIPOBJ doesn't have at least DC_RECT complexity,
  1097. // substitute one that does:
  1098. pco = pmdev->pco;
  1099. }
  1100. rclOriginalBounds = pco->rclBounds;
  1101. b = TRUE;
  1102. do {
  1103. // Make sure we restart the path enumeration if need be:
  1104. PATHOBJ_vEnumStart(ppo);
  1105. if (bIntersect(&rclOriginalBounds, &pmb->rcl, &pco->rclBounds))
  1106. {
  1107. GO_BOARD(pmdev, pmb);
  1108. b &= DrvFillPath(pmb->pso, ppo, pco, pbo, pptlBrush, mix,
  1109. flOptions);
  1110. }
  1111. } while (bNextBoard(&rclBounds, &pmb));
  1112. // Restore the original clip bounds:
  1113. pco->rclBounds = rclOriginalBounds;
  1114. }
  1115. return(b);
  1116. }
  1117. /******************************Public*Routine******************************\
  1118. * BOOL MulBitBlt
  1119. *
  1120. \**************************************************************************/
  1121. BOOL MulBitBlt(
  1122. SURFOBJ* psoDst,
  1123. SURFOBJ* psoSrc,
  1124. SURFOBJ* psoMask,
  1125. CLIPOBJ* pco,
  1126. XLATEOBJ* pxlo,
  1127. RECTL* prclDst,
  1128. POINTL* pptlSrc,
  1129. POINTL* pptlMask,
  1130. BRUSHOBJ* pbo,
  1131. POINTL* pptlBrush,
  1132. ROP4 rop4)
  1133. {
  1134. BOOL bFromScreen;
  1135. BOOL bToScreen;
  1136. MDEV* pmdev;
  1137. MULTI_BOARD* pmb;
  1138. RECTL rclOriginalBounds;
  1139. BOOL b;
  1140. RECTL rclBounds;
  1141. LONG xOffset;
  1142. LONG yOffset;
  1143. RECTL rclDstBounds;
  1144. RECTL rclDst;
  1145. bFromScreen = ((psoSrc != NULL) && (psoSrc->iType == STYPE_DEVICE));
  1146. bToScreen = ((psoDst != NULL) && (psoDst->iType == STYPE_DEVICE));
  1147. // We copy the prclDst rectangle here because sometimes GDI will
  1148. // simply point prclDst to the same rectangle in pco->rclBounds,
  1149. // and we'll be mucking with pco->rclBounds...
  1150. rclDst = *prclDst;
  1151. if (bToScreen && bFromScreen)
  1152. {
  1153. ///////////////////////////////////////////////////////////////
  1154. // Screen-to-screen
  1155. ///////////////////////////////////////////////////////////////
  1156. pmdev = (MDEV*) psoDst->dhpdev;
  1157. // rclBounds is the union of the source and destination rectangles:
  1158. rclBounds.left = min(rclDst.left, pptlSrc->x);
  1159. rclBounds.top = min(rclDst.top, pptlSrc->y);
  1160. rclBounds.right = max(rclDst.right,
  1161. pptlSrc->x + (rclDst.right - rclDst.left));
  1162. rclBounds.bottom = max(rclDst.bottom,
  1163. pptlSrc->y + (rclDst.bottom - rclDst.top));
  1164. if (bFindBoard(pmdev, &rclBounds, &pmb))
  1165. {
  1166. GO_BOARD(pmdev, pmb);
  1167. b = DrvBitBlt(pmb->pso, pmb->pso, psoMask, pco, pxlo, &rclDst,
  1168. pptlSrc, pptlMask, pbo, pptlBrush, rop4);
  1169. }
  1170. else
  1171. {
  1172. return(bBitBltBetweenBoards(psoDst, psoSrc, psoMask, pco, pxlo,
  1173. &rclDst, pptlSrc, pptlMask, pbo,
  1174. pptlBrush, rop4, &rclBounds, pmb));
  1175. }
  1176. }
  1177. else if (bToScreen)
  1178. {
  1179. ///////////////////////////////////////////////////////////////
  1180. // To-screen
  1181. ///////////////////////////////////////////////////////////////
  1182. pmdev = (MDEV*) psoDst->dhpdev;
  1183. if (bFindBoard(pmdev, &rclDst, &pmb))
  1184. {
  1185. GO_BOARD(pmdev, pmb);
  1186. b = DrvBitBlt(pmb->pso, psoSrc, psoMask, pco, pxlo, &rclDst,
  1187. pptlSrc, pptlMask, pbo, pptlBrush, rop4);
  1188. }
  1189. else
  1190. {
  1191. if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
  1192. {
  1193. // If the CLIPOBJ doesn't have at least DC_RECT complexity,
  1194. // substitute one that does:
  1195. pco = pmdev->pco;
  1196. }
  1197. rclOriginalBounds = pco->rclBounds;
  1198. b = TRUE;
  1199. do {
  1200. if (bIntersect(&rclOriginalBounds, &pmb->rcl, &pco->rclBounds))
  1201. {
  1202. GO_BOARD(pmdev, pmb);
  1203. b &= DrvBitBlt(pmb->pso, psoSrc, psoMask, pco, pxlo, &rclDst,
  1204. pptlSrc, pptlMask, pbo, pptlBrush, rop4);
  1205. }
  1206. } while (bNextBoard(&rclDst, &pmb));
  1207. // Restore the original clip bounds:
  1208. pco->rclBounds = rclOriginalBounds;
  1209. }
  1210. }
  1211. else
  1212. {
  1213. ///////////////////////////////////////////////////////////////
  1214. // From-screen
  1215. ///////////////////////////////////////////////////////////////
  1216. pmdev = (MDEV*) psoSrc->dhpdev;
  1217. // rclBounds is the source rectangle:
  1218. rclBounds.left = pptlSrc->x;
  1219. rclBounds.top = pptlSrc->y;
  1220. rclBounds.right = pptlSrc->x + (rclDst.right - rclDst.left);
  1221. rclBounds.bottom = pptlSrc->y + (rclDst.bottom - rclDst.top);
  1222. if (bFindBoard(pmdev, &rclBounds, &pmb))
  1223. {
  1224. GO_BOARD(pmdev, pmb);
  1225. b = DrvBitBlt(psoDst, pmb->pso, psoMask, pco, pxlo, &rclDst,
  1226. pptlSrc, pptlMask, pbo, pptlBrush, rop4);
  1227. }
  1228. else
  1229. {
  1230. if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
  1231. {
  1232. // If the CLIPOBJ doesn't have at least DC_RECT complexity,
  1233. // substitute one that does:
  1234. pco = pmdev->pco;
  1235. }
  1236. rclOriginalBounds = pco->rclBounds;
  1237. // Offset to transform from source rectangle to destination
  1238. // rectangle:
  1239. xOffset = rclDst.left - pptlSrc->x;
  1240. yOffset = rclDst.top - pptlSrc->y;
  1241. b = TRUE;
  1242. do {
  1243. // Since the screen is the source, but the clip bounds applies
  1244. // to the destination, we have to convert our board clipping
  1245. // information to destination coordinates:
  1246. rclDstBounds.left = pmb->rcl.left + xOffset;
  1247. rclDstBounds.right = pmb->rcl.right + xOffset;
  1248. rclDstBounds.top = pmb->rcl.top + yOffset;
  1249. rclDstBounds.bottom = pmb->rcl.bottom + yOffset;
  1250. if (bIntersect(&rclOriginalBounds, &rclDstBounds, &pco->rclBounds))
  1251. {
  1252. GO_BOARD(pmdev, pmb);
  1253. b &= DrvBitBlt(psoDst, pmb->pso, psoMask, pco, pxlo, &rclDst,
  1254. pptlSrc, pptlMask, pbo, pptlBrush, rop4);
  1255. }
  1256. } while (bNextBoard(&rclBounds, &pmb));
  1257. // Restore the original clip bounds:
  1258. pco->rclBounds = rclOriginalBounds;
  1259. }
  1260. }
  1261. return(b);
  1262. }
  1263. /******************************Public*Routine******************************\
  1264. * VOID MulDisablePDEV
  1265. *
  1266. * Note: May be called before MulEnablePDEV successfully completed!
  1267. *
  1268. \**************************************************************************/
  1269. VOID MulDisablePDEV(DHPDEV dhpdev)
  1270. {
  1271. MULTI_BOARD* pmb;
  1272. MDEV* pmdev;
  1273. pmdev = (MDEV*) dhpdev;
  1274. for (pmb = pmdev->pmb; pmb != NULL; pmb = pmb->pmbNext)
  1275. {
  1276. if (pmb->ppdev != NULL)
  1277. {
  1278. GO_BOARD(pmdev, pmb);
  1279. DrvDisablePDEV((DHPDEV) pmb->ppdev);
  1280. }
  1281. }
  1282. EngFreeMem(pmdev->pmb); // Undo 'bInitializeGeometry' allocation
  1283. EngFreeMem(pmdev);
  1284. }
  1285. /******************************Public*Routine******************************\
  1286. * VOID MulDisableSurface
  1287. *
  1288. * Note: May be called before MulEnableSurface successfully completed!
  1289. *
  1290. \**************************************************************************/
  1291. VOID MulDisableSurface(DHPDEV dhpdev)
  1292. {
  1293. MULTI_BOARD* pmb;
  1294. MDEV* pmdev;
  1295. pmdev = (MDEV*) dhpdev;
  1296. if (pmdev->pco != NULL)
  1297. EngDeleteClip(pmdev->pco);
  1298. EngDeleteSurface(pmdev->hsurf);
  1299. for (pmb = pmdev->pmb; pmb != NULL; pmb = pmb->pmbNext)
  1300. {
  1301. GO_BOARD(pmdev, pmb);
  1302. EngUnlockSurface(pmb->pso);
  1303. DrvDisableSurface((DHPDEV) pmb->ppdev);
  1304. }
  1305. }
  1306. /******************************Public*Routine******************************\
  1307. * VOID MulAssertMode
  1308. *
  1309. \**************************************************************************/
  1310. BOOL MulAssertMode(
  1311. DHPDEV dhpdev,
  1312. BOOL bEnable)
  1313. {
  1314. MDEV* pmdev;
  1315. MULTI_BOARD* pmb;
  1316. pmdev = (MDEV*) dhpdev;
  1317. if (!bEnable)
  1318. {
  1319. // When switching to full-screen mode, PatBlt blackness over
  1320. // all the inactive screens (otherwise it looks goofy when
  1321. // the desktop is frozen on the inactive screens and the user
  1322. // can't do anything with it):
  1323. for (pmb = pmdev->pmb; pmb != NULL; pmb = pmb->pmbNext)
  1324. {
  1325. GO_BOARD(pmdev, pmb);
  1326. DrvBitBlt(pmb->pso, NULL, NULL, NULL, NULL, &pmb->rcl, NULL,
  1327. NULL, NULL, NULL, 0);
  1328. }
  1329. }
  1330. for (pmb = pmdev->pmb; pmb != NULL; pmb = pmb->pmbNext)
  1331. {
  1332. GO_BOARD(pmdev, pmb);
  1333. DrvAssertMode((DHPDEV) pmb->ppdev, bEnable);
  1334. }
  1335. return TRUE;
  1336. }
  1337. /******************************Public*Routine******************************\
  1338. * VOID MulMovePointer
  1339. *
  1340. \**************************************************************************/
  1341. VOID MulMovePointer(
  1342. SURFOBJ* pso,
  1343. LONG x,
  1344. LONG y,
  1345. RECTL* prcl)
  1346. {
  1347. MDEV* pmdev;
  1348. MULTI_BOARD* pmbPointer;
  1349. RECTL rclPointer;
  1350. pmdev = (MDEV*) pso->dhpdev;
  1351. pmbPointer = pmdev->pmbPointer;
  1352. if (pmbPointer != NULL)
  1353. {
  1354. // The most common case is when the pointer is moved to a spot
  1355. // on the same board:
  1356. if ((x >= pmbPointer->rcl.left) &&
  1357. (x < pmbPointer->rcl.right) &&
  1358. (y >= pmbPointer->rcl.top) &&
  1359. (y < pmbPointer->rcl.bottom))
  1360. {
  1361. GO_BOARD(pmdev, pmbPointer);
  1362. DrvMovePointer(pmbPointer->pso, x, y, prcl);
  1363. return;
  1364. }
  1365. // Tell the old board to erase its cursor:
  1366. GO_BOARD(pmdev, pmbPointer);
  1367. DrvMovePointer(pmbPointer->pso, -1, -1, NULL);
  1368. }
  1369. if (x == -1)
  1370. {
  1371. pmdev->pmbPointer = NULL;
  1372. return;
  1373. }
  1374. // Find the new board and tell it to draw its new cursor:
  1375. rclPointer.left = x;
  1376. rclPointer.right = x;
  1377. rclPointer.top = y;
  1378. rclPointer.bottom = y;
  1379. bFindBoard(pmdev, &rclPointer, &pmbPointer);
  1380. GO_BOARD(pmdev, pmbPointer);
  1381. DrvMovePointer(pmbPointer->pso, x, y, prcl);
  1382. pmdev->pmbPointer = pmbPointer;
  1383. }
  1384. /******************************Public*Routine******************************\
  1385. * ULONG MulSetPointerShape
  1386. *
  1387. \**************************************************************************/
  1388. ULONG MulSetPointerShape(
  1389. SURFOBJ* pso,
  1390. SURFOBJ* psoMask,
  1391. SURFOBJ* psoColor,
  1392. XLATEOBJ* pxlo,
  1393. LONG xHot,
  1394. LONG yHot,
  1395. LONG x,
  1396. LONG y,
  1397. RECTL* prcl,
  1398. FLONG fl)
  1399. {
  1400. MULTI_BOARD* pmb;
  1401. MDEV* pmdev;
  1402. ULONG ulRet;
  1403. RECTL rclPointer;
  1404. MULTI_BOARD* pmbPointer; // Board on which cursor is visible
  1405. BOOL b;
  1406. pmdev = (MDEV*) pso->dhpdev;
  1407. // Find out which board that the cursor is visible on, if any:
  1408. pmbPointer = NULL;
  1409. if (x != -1)
  1410. {
  1411. rclPointer.left = x;
  1412. rclPointer.right = x;
  1413. rclPointer.top = y;
  1414. rclPointer.bottom = y;
  1415. b = bFindBoard(pmdev, &rclPointer, &pmbPointer);
  1416. ASSERTDD(b, "Woah, couldn't find what board the pointer was on?");
  1417. }
  1418. pmdev->pmbPointer = pmbPointer;
  1419. ulRet = SPS_ACCEPT_NOEXCLUDE;
  1420. for (pmb = pmdev->pmb; pmb != NULL; pmb = pmb->pmbNext)
  1421. {
  1422. // Send the new shape down to every board, and at the same
  1423. // time check to see if each board will support the pointer by
  1424. // creating it as hidden on every one.
  1425. GO_BOARD(pmdev, pmb);
  1426. if (DrvSetPointerShape(pmb->pso, psoMask, psoColor, pxlo,
  1427. xHot, yHot, -1, y, NULL, fl)
  1428. != SPS_ACCEPT_NOEXCLUDE)
  1429. {
  1430. // Oh no, one of the boards won't support this pointer. We'll
  1431. // have to ask GDI to simulate for all boards:
  1432. ulRet = SPS_DECLINE;
  1433. }
  1434. }
  1435. if ((ulRet == SPS_ACCEPT_NOEXCLUDE) && (pmbPointer != NULL))
  1436. {
  1437. // All boards accepted the hardware pointer, so show it on the
  1438. // appropriate board. If 'pmbPointer' is NULL, we're not being
  1439. // asked to show the pointer at all.
  1440. GO_BOARD(pmdev, pmbPointer);
  1441. DrvMovePointer(pmbPointer->pso, x, y, NULL);
  1442. }
  1443. return(ulRet);
  1444. }
  1445. /******************************Public*Routine******************************\
  1446. * ULONG MulDitherColor
  1447. *
  1448. \**************************************************************************/
  1449. ULONG MulDitherColor(
  1450. DHPDEV dhpdev,
  1451. ULONG iMode,
  1452. ULONG rgb,
  1453. ULONG* pul)
  1454. {
  1455. PDEV* ppdev;
  1456. ULONG ulRet;
  1457. // Let the first board's driver do the dithering:
  1458. ppdev = ((MDEV*) dhpdev)->pmb->ppdev;
  1459. ulRet = DrvDitherColor((DHPDEV) ppdev, iMode, rgb, pul);
  1460. return(ulRet);
  1461. }
  1462. /******************************Public*Routine******************************\
  1463. * ULONG MulSetPalette
  1464. *
  1465. \**************************************************************************/
  1466. BOOL MulSetPalette(
  1467. DHPDEV dhpdev,
  1468. PALOBJ* ppalo,
  1469. FLONG fl,
  1470. ULONG iStart,
  1471. ULONG cColors)
  1472. {
  1473. MULTI_BOARD* pmb;
  1474. MDEV* pmdev;
  1475. BOOL bRet = TRUE;
  1476. // Notify all boards of the palette change:
  1477. pmdev = (MDEV*) dhpdev;
  1478. for (pmb = pmdev->pmb; pmb != NULL; pmb = pmb->pmbNext)
  1479. {
  1480. GO_BOARD(pmdev, pmb);
  1481. MAKE_BOARD_CURRENT(pmdev, pmb);
  1482. bRet &= DrvSetPalette((DHPDEV) pmb->ppdev, ppalo, fl, iStart, cColors);
  1483. }
  1484. return(bRet);
  1485. }
  1486. /******************************Public*Routine******************************\
  1487. * BOOL MulCopyBits
  1488. *
  1489. \**************************************************************************/
  1490. BOOL MulCopyBits(
  1491. SURFOBJ* psoDst,
  1492. SURFOBJ* psoSrc,
  1493. CLIPOBJ* pco,
  1494. XLATEOBJ* pxlo,
  1495. RECTL* prclDst,
  1496. POINTL* pptlSrc)
  1497. {
  1498. BOOL bFromScreen;
  1499. BOOL bToScreen;
  1500. MDEV* pmdev;
  1501. MULTI_BOARD* pmb;
  1502. RECTL rclOriginalBounds;
  1503. BOOL b;
  1504. RECTL rclBounds;
  1505. RECTL rclDst;
  1506. bFromScreen = ((psoSrc != NULL) && (psoSrc->iType == STYPE_DEVICE));
  1507. bToScreen = ((psoDst != NULL) && (psoDst->iType == STYPE_DEVICE));
  1508. // We copy the prclDst rectangle here because sometimes GDI will
  1509. // simply point prclDst to the same rectangle in pco->rclBounds,
  1510. // and we'll be mucking with pco->rclBounds...
  1511. rclDst = *prclDst;
  1512. if (bToScreen && bFromScreen)
  1513. {
  1514. ///////////////////////////////////////////////////////////////
  1515. // Screen-to-screen
  1516. ///////////////////////////////////////////////////////////////
  1517. pmdev = (MDEV*) psoDst->dhpdev;
  1518. // rclBounds is the union of the source and destination rectangles:
  1519. rclBounds.left = min(rclDst.left, pptlSrc->x);
  1520. rclBounds.top = min(rclDst.top, pptlSrc->y);
  1521. rclBounds.right = max(rclDst.right,
  1522. pptlSrc->x + (rclDst.right - rclDst.left));
  1523. rclBounds.bottom = max(rclDst.bottom,
  1524. pptlSrc->y + (rclDst.bottom - rclDst.top));
  1525. if (bFindBoard(pmdev, &rclBounds, &pmb))
  1526. {
  1527. GO_BOARD(pmdev, pmb);
  1528. b = DrvCopyBits(pmb->pso, pmb->pso, pco, pxlo, &rclDst, pptlSrc);
  1529. }
  1530. else
  1531. {
  1532. return(bBitBltBetweenBoards(psoDst, psoSrc, NULL, pco, pxlo,
  1533. &rclDst, pptlSrc, NULL, NULL,
  1534. NULL, 0x0000cccc, &rclBounds, pmb));
  1535. }
  1536. }
  1537. else if (bToScreen)
  1538. {
  1539. ///////////////////////////////////////////////////////////////
  1540. // To-screen
  1541. ///////////////////////////////////////////////////////////////
  1542. pmdev = (MDEV*) psoDst->dhpdev;
  1543. if (bFindBoard(pmdev, &rclDst, &pmb))
  1544. {
  1545. GO_BOARD(pmdev, pmb);
  1546. b = DrvCopyBits(pmb->pso, psoSrc, pco, pxlo, &rclDst, pptlSrc);
  1547. }
  1548. else
  1549. {
  1550. if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
  1551. {
  1552. // If the CLIPOBJ doesn't have at least DC_RECT complexity,
  1553. // substitute one that does:
  1554. pco = pmdev->pco;
  1555. }
  1556. rclOriginalBounds = pco->rclBounds;
  1557. b = TRUE;
  1558. do {
  1559. if (bIntersect(&rclOriginalBounds, &pmb->rcl, &pco->rclBounds))
  1560. {
  1561. GO_BOARD(pmdev, pmb);
  1562. b &= DrvCopyBits(pmb->pso, psoSrc, pco, pxlo, &rclDst,
  1563. pptlSrc);
  1564. }
  1565. } while (bNextBoard(&rclDst, &pmb));
  1566. // Restore the original clip bounds:
  1567. pco->rclBounds = rclOriginalBounds;
  1568. }
  1569. }
  1570. else
  1571. {
  1572. ///////////////////////////////////////////////////////////////
  1573. // From-screen
  1574. ///////////////////////////////////////////////////////////////
  1575. // This rarely happens, so save some code space:
  1576. return(MulBitBlt(psoDst, psoSrc, NULL, pco, pxlo, prclDst,
  1577. pptlSrc, NULL, NULL, NULL, 0x0000cccc));
  1578. }
  1579. return(b);
  1580. }
  1581. /******************************Public*Routine******************************\
  1582. * BOOL MulTextOut
  1583. *
  1584. \**************************************************************************/
  1585. BOOL MulTextOut(
  1586. SURFOBJ* pso,
  1587. STROBJ* pstro,
  1588. FONTOBJ* pfo,
  1589. CLIPOBJ* pco,
  1590. RECTL* prclExtra,
  1591. RECTL* prclOpaque,
  1592. BRUSHOBJ* pboFore,
  1593. BRUSHOBJ* pboOpaque,
  1594. POINTL* pptlOrg,
  1595. MIX mix)
  1596. {
  1597. MDEV* pmdev;
  1598. MULTI_BOARD* pmb;
  1599. RECTL rclOriginalBounds;
  1600. BYTE fjOriginalOptions;
  1601. BOOL b;
  1602. RECTL* prclBounds;
  1603. FONT_CONSUMER* pfcArray;
  1604. pmdev = (MDEV*) pso->dhpdev;
  1605. // In keeping with our philosophy for multiple board support, we handle
  1606. // multiple consumers of the same font at this level. We do this by
  1607. // monitoring pfo->pvConsumer, and the first time a board sets the
  1608. // field, we take control of pfo->pvConsumer. We use it to allocate
  1609. // a pvConsumer array where we can keep track of every board's
  1610. // individual pvConsumer.
  1611. pfcArray = pfo->pvConsumer;
  1612. prclBounds = (prclOpaque != NULL) ? prclOpaque : &pstro->rclBkGround;
  1613. bFindBoard(pmdev, prclBounds, &pmb);
  1614. if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
  1615. {
  1616. // If the CLIPOBJ doesn't have at least DC_RECT complexity,
  1617. // substitute one that does:
  1618. pco = pmdev->pco;
  1619. }
  1620. rclOriginalBounds = pco->rclBounds;
  1621. fjOriginalOptions = pco->fjOptions;
  1622. // OR in the OC_BANK_CLIP flag to let GDI know that we may be calling
  1623. // EngTextOut multiple times with the same parameters (EngTextOut
  1624. // is destructive in that it modifies that parameters passed to it,
  1625. // unless this bit is set):
  1626. pco->fjOptions |= OC_BANK_CLIP;
  1627. b = TRUE;
  1628. do {
  1629. if (pfcArray != NULL)
  1630. pfo->pvConsumer = pfcArray->apvc[pmb->iBoard].pvConsumer;
  1631. // Make sure we restart the glyph enumeration if need be:
  1632. STROBJ_vEnumStart(pstro);
  1633. if (bIntersect(&rclOriginalBounds, &pmb->rcl, &pco->rclBounds))
  1634. {
  1635. GO_BOARD(pmdev, pmb);
  1636. b &= DrvTextOut(pmb->pso, pstro, pfo, pco, prclExtra, prclOpaque,
  1637. pboFore, pboOpaque, pptlOrg, mix);
  1638. }
  1639. if (pfcArray != NULL)
  1640. {
  1641. // Copy the pvConsumer, in case the last DrvTextOut changed
  1642. // it:
  1643. pfcArray->apvc[pmb->iBoard].pvConsumer = pfo->pvConsumer;
  1644. }
  1645. else
  1646. {
  1647. if (pfo->pvConsumer != NULL)
  1648. {
  1649. // The board allocated a new consumer, so create our array
  1650. // to keep track of consumers for every board:
  1651. pfcArray = (FONT_CONSUMER*) EngAllocMem(FL_ZERO_MEMORY,
  1652. sizeof(FONT_CONSUMER), ALLOC_TAG);
  1653. if (pfcArray == NULL)
  1654. DrvDestroyFont(pfo);
  1655. else
  1656. {
  1657. pfcArray->cConsumers = pmdev->cBoards;
  1658. pfcArray->apvc[pmb->iBoard].pvConsumer = pfo->pvConsumer;
  1659. }
  1660. }
  1661. }
  1662. } while (bNextBoard(prclBounds, &pmb));
  1663. // Restore the original clip bounds:
  1664. pco->rclBounds = rclOriginalBounds;
  1665. pco->fjOptions = fjOriginalOptions;
  1666. // Make sure we restore/set the font's pvConsumer:
  1667. pfo->pvConsumer = pfcArray;
  1668. return(b);
  1669. }
  1670. /******************************Public*Routine******************************\
  1671. * VOID MulDestroyFont
  1672. *
  1673. \**************************************************************************/
  1674. VOID MulDestroyFont(FONTOBJ *pfo)
  1675. {
  1676. FONT_CONSUMER* pfcArray;
  1677. LONG i;
  1678. PVOID pvConsumer;
  1679. if (pfo->pvConsumer != NULL)
  1680. {
  1681. pfcArray = pfo->pvConsumer;
  1682. for (i = 0; i < pfcArray->cConsumers; i++)
  1683. {
  1684. pvConsumer = pfcArray->apvc[i].pvConsumer;
  1685. if (pvConsumer != NULL)
  1686. {
  1687. pfo->pvConsumer = pvConsumer;
  1688. DrvDestroyFont(pfo);
  1689. }
  1690. }
  1691. EngFreeMem(pfcArray);
  1692. pfo->pvConsumer = NULL;
  1693. }
  1694. }
  1695. /******************************Public*Routine******************************\
  1696. * BOOL MulPaint
  1697. *
  1698. \**************************************************************************/
  1699. BOOL MulPaint(
  1700. SURFOBJ* pso,
  1701. CLIPOBJ* pco,
  1702. BRUSHOBJ* pbo,
  1703. POINTL* pptlBrush,
  1704. MIX mix)
  1705. {
  1706. MDEV* pmdev;
  1707. RECTL rclOriginalBounds;
  1708. MULTI_BOARD* pmb;
  1709. BOOL b;
  1710. pmdev = (MDEV*) pso->dhpdev;
  1711. if (bFindBoard(pmdev, &pco->rclBounds, &pmb))
  1712. {
  1713. GO_BOARD(pmdev, pmb);
  1714. b = DrvPaint(pmb->pso, pco, pbo, pptlBrush, mix);
  1715. }
  1716. else
  1717. {
  1718. rclOriginalBounds = pco->rclBounds;
  1719. b = TRUE;
  1720. do {
  1721. if (bIntersect(&rclOriginalBounds, &pmb->rcl, &pco->rclBounds))
  1722. {
  1723. GO_BOARD(pmdev, pmb);
  1724. b &= DrvPaint(pmb->pso, pco, pbo, pptlBrush, mix);
  1725. }
  1726. } while (bNextBoard(&rclOriginalBounds, &pmb));
  1727. // Restore the original clip bounds:
  1728. pco->rclBounds = rclOriginalBounds;
  1729. }
  1730. return(b);
  1731. }
  1732. /******************************Public*Routine******************************\
  1733. * BOOL MulRealizeBrush
  1734. *
  1735. \**************************************************************************/
  1736. BOOL MulRealizeBrush(
  1737. BRUSHOBJ* pbo,
  1738. SURFOBJ* psoTarget,
  1739. SURFOBJ* psoPattern,
  1740. SURFOBJ* psoMask,
  1741. XLATEOBJ* pxlo,
  1742. ULONG iHatch)
  1743. {
  1744. MDEV* pmdev;
  1745. BOOL b;
  1746. pmdev = (MDEV*) psoTarget->dhpdev;
  1747. // DrvRealizeBrush is only ever called from within a Drv function.
  1748. // 'psoTarget' points to our multi-board surface, but we have to point
  1749. // it to the surface of the board for which the DrvBitBlt call was made.
  1750. b = DrvRealizeBrush(pbo, pmdev->pmbCurrent->pso, psoPattern, psoMask,
  1751. pxlo, iHatch);
  1752. return(b);
  1753. }
  1754. #endif // MULTI_BOARDS