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.

1205 lines
38 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: panning.cxx
  3. *
  4. * Contains the code for a layered 'virtual' driver that emulates panning
  5. * by switching the display device to the requested panning dimensions, and
  6. * creating a shadow buffer the size of the desktop to which GDI does all
  7. * the drawing. To update the physical display, we employ a 'dirty
  8. * rectangles' technique where we simply blt from the shadow buffer to the
  9. * screen for the affected areas.
  10. *
  11. * Created: 15-Sep-96
  12. * Author: J. Andrew Goossen [andrewgo]
  13. *
  14. * Copyright (c) 1996-1999 Microsoft Corporation
  15. *
  16. \**************************************************************************/
  17. #include "precomp.hxx"
  18. extern BOOL G_fDoubleDpi;
  19. // The panning layer's equivalent of a 'PDEV':
  20. typedef struct _PANDEV
  21. {
  22. LONG cxScreen; // The smaller dimensions (the dimensions of
  23. LONG cyScreen; // the physical screen)
  24. LONG cxDesktop; // The larger dimensions (the dimensions of
  25. LONG cyDesktop; // the virtual desktop)
  26. RECTL rclVisible; // Position of panning window on virtual
  27. // desktop
  28. DHPDEV dhpdevDevice; // The device's 'dhpdev'
  29. ULONG iBitmapFormat; // Bitmap format of surface
  30. FLONG flOriginalCaps; // Driver's original flGraphicsCaps setting
  31. HDEV hdev; // Handle to GDI's PDEV
  32. HSURF hsurfScreen; // Handle to GDI's surface
  33. SURFOBJ* psoShadow; // Pointer to our shadow surface
  34. SURFOBJ* psoDevice; // Pointer to device's surface
  35. SURFOBJ* psoShrink; // Pointer to shrink scratch buffer surface
  36. REGION* prgnDirty; // Points to the current dirty region
  37. REGION* prgnOld; // Points to the previous dirty region
  38. REGION* prgnRect; // Points to a rectangular region we cache
  39. BOOL bDirty; // If TRUE, we have some dirty rectangles
  40. // that should be updated at the next tick
  41. PFN apfn[INDEX_LAST]; // Dispatch table to device
  42. } PANDEV;
  43. /******************************Public*Routine******************************\
  44. * VOID vPanningUpdate(ppan, prcl, pco)
  45. *
  46. * Updates the screen from the DIB surface for the given rectangle.
  47. *
  48. \**************************************************************************/
  49. VOID vPanningUpdate(PANDEV* ppan, RECTL* prcl, CLIPOBJ* pco)
  50. {
  51. RECTL rcl;
  52. if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
  53. {
  54. rcl = *prcl;
  55. }
  56. else
  57. {
  58. // We may as well save ourselves some blting by clipping to
  59. // the clip object's maximum extent. The clip object's bounds
  60. // are guaranteed to be contained within the dimensions of the
  61. // desktop:
  62. rcl.left = max(pco->rclBounds.left, prcl->left);
  63. rcl.top = max(pco->rclBounds.top, prcl->top);
  64. rcl.right = min(pco->rclBounds.right, prcl->right);
  65. rcl.bottom = min(pco->rclBounds.bottom, prcl->bottom);
  66. }
  67. if (ppan->psoShrink)
  68. {
  69. rcl.left >>= 1;
  70. rcl.top >>= 1;
  71. rcl.right = (rcl.right + 1) >> 1;
  72. rcl.bottom = (rcl.bottom + 1) >> 1;
  73. }
  74. if ((rcl.left < rcl.right) && (rcl.top < rcl.bottom))
  75. {
  76. // Merge this rectangle into the dirty region. We swap the 'old'
  77. // and 'current' dirty regions in the process, so that we don't
  78. // have to do an extra allocation:
  79. RGNOBJ roRect(ppan->prgnRect);
  80. RGNOBJ roDirty(ppan->prgnOld);
  81. RGNOBJ roOld(ppan->prgnDirty);
  82. roRect.vSet(&rcl);
  83. if (!roDirty.bMerge(roOld, roRect, gafjRgnOp[RGN_OR]))
  84. {
  85. roDirty.vSet();
  86. }
  87. ppan->prgnOld = roOld.prgnGet();
  88. ppan->prgnDirty = roDirty.prgnGet();
  89. ppan->bDirty = TRUE;
  90. }
  91. }
  92. /******************************Public*Routine******************************\
  93. * vFiltered2xShrinkRectangle32bpp
  94. *
  95. * Quick and dirty single rectangle 0.5x shrink with simple color averaging.
  96. *
  97. \**************************************************************************/
  98. VOID vFilteredShrinkRectangle2x32bpp(
  99. SURFOBJ* psoDst,
  100. SURFOBJ* psoSrc,
  101. RECTL* prclDst)
  102. {
  103. LONG cx;
  104. LONG cy;
  105. LONG lSrcDelta;
  106. BYTE* pjSrc;
  107. LONG lSrcSkip;
  108. LONG lDstDelta;
  109. BYTE* pjDst;
  110. LONG lDstSkip;
  111. LONG i;
  112. ULONG ulDst;
  113. ASSERTGDI((psoDst->iBitmapFormat == BMF_32BPP) &&
  114. (psoSrc->iBitmapFormat == BMF_32BPP),
  115. "Unexpected type");
  116. cy = prclDst->bottom - prclDst->top;
  117. cx = prclDst->right - prclDst->left;
  118. lSrcDelta = psoSrc->lDelta;
  119. pjSrc = (BYTE*) psoSrc->pvScan0 + (prclDst->top * 2) * lSrcDelta
  120. + (prclDst->left * 2) * sizeof(ULONG);
  121. lSrcSkip = 2 * lSrcDelta - (cx * 2 * sizeof(ULONG));
  122. lDstDelta = psoDst->lDelta;
  123. pjDst = (BYTE*) psoDst->pvScan0 + prclDst->top * lDstDelta
  124. + prclDst->left * sizeof(ULONG);
  125. lDstSkip = lDstDelta - (cx * sizeof(ULONG));
  126. do {
  127. i = cx;
  128. do {
  129. ulDst = *(pjSrc)
  130. + *(pjSrc + 4)
  131. + *(pjSrc + lSrcDelta)
  132. + *(pjSrc + 4 + lSrcDelta);
  133. *(pjDst) = (BYTE) (ulDst >> 2);
  134. ulDst = *(pjSrc + 1)
  135. + *(pjSrc + 5)
  136. + *(pjSrc + 1 + lSrcDelta)
  137. + *(pjSrc + 5 + lSrcDelta);
  138. *(pjDst + 1) = (BYTE) (ulDst >> 2);
  139. ulDst = *(pjSrc + 2)
  140. + *(pjSrc + 6)
  141. + *(pjSrc + 2 + lSrcDelta)
  142. + *(pjSrc + 6 + lSrcDelta);
  143. *(pjDst + 2) = (BYTE) (ulDst >> 2);
  144. pjDst += 4;
  145. pjSrc += 8;
  146. } while (--i != 0);
  147. pjDst += lDstSkip;
  148. pjSrc += lSrcSkip;
  149. } while (--cy != 0);
  150. }
  151. /******************************Public*Routine******************************\
  152. * vFiltered2xShrink32bpp
  153. *
  154. * Quick and dirty bilinear filtered 2x shrink routine.
  155. *
  156. \**************************************************************************/
  157. VOID vFilteredShrink2x32bpp(
  158. SURFOBJ* psoDst,
  159. SURFOBJ* psoSrc,
  160. ECLIPOBJ* pco,
  161. RECTL* prclDst)
  162. {
  163. BOOL bMore;
  164. ULONG i;
  165. CLIPENUMRECT clenr;
  166. RECTL rclDst;
  167. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  168. do {
  169. bMore = pco->bEnum(sizeof(clenr), &clenr);
  170. for (i = 0; i < clenr.c; i++)
  171. {
  172. if (bIntersect(&clenr.arcl[i], prclDst, &rclDst))
  173. {
  174. vFilteredShrinkRectangle2x32bpp(psoDst, psoSrc, &rclDst);
  175. }
  176. }
  177. } while (bMore);
  178. }
  179. /******************************Public*Routine******************************\
  180. * PanSynchronize
  181. *
  182. * Dumps the list of dirty rectangles to the screen. Because we set
  183. * GCAPS2_SYNCTIMER, this routine is called by User 20 times a second.
  184. *
  185. \**************************************************************************/
  186. VOID PanSynchronize(
  187. DHPDEV dhpdev,
  188. RECTL* prcl)
  189. {
  190. PANDEV* ppan;
  191. SURFACE* psurfDevice;
  192. RECTL* prclVisible;
  193. RECTL rclDevice;
  194. RECTL rclSrc;
  195. PFN_DrvCopyBits pfnCopyBits;
  196. PFN_DrvStretchBlt pfnStretchBlt;
  197. SURFOBJ* psoCopySrc;
  198. SURFOBJ* psoDst;
  199. SURFOBJ* psoDevice;
  200. ppan = (PANDEV*) dhpdev;
  201. if (ppan->bDirty)
  202. {
  203. ECLIPOBJ eco;
  204. ASSERTGDI((ppan->rclVisible.right == ppan->rclVisible.left + ppan->cxScreen) &&
  205. (ppan->rclVisible.bottom == ppan->rclVisible.top + ppan->cyScreen),
  206. "Unexpected rclVisible dimensions");
  207. prclVisible = &ppan->rclVisible;
  208. eco.vSetup(ppan->prgnDirty, *(ERECTL*)prclVisible);
  209. if (!eco.erclExclude().bEmpty())
  210. {
  211. // Now reset the device surface 'dhpdev' field that the any device's
  212. // EngAssociateSurface call so rudely overwrote with the pointer
  213. // to *our* 'ppan' structure!
  214. ppan->psoDevice->dhpdev = ppan->dhpdevDevice;
  215. psurfDevice = SURFOBJ_TO_SURFACE(ppan->psoDevice);
  216. rclDevice.left = 0;
  217. rclDevice.top = 0;
  218. rclDevice.right = psurfDevice->sizl().cx;
  219. rclDevice.bottom = psurfDevice->sizl().cy;
  220. // Assume we'll be calling CopyBits straight from the shadow
  221. // buffer:
  222. psoCopySrc = ppan->psoShadow;
  223. if (ppan->psoShrink)
  224. {
  225. ASSERTGDI(ppan->iBitmapFormat == BMF_32BPP,
  226. "Expected psoShrink only when 32bpp");
  227. // As a small optimization, we can draw directly to the
  228. // frame buffer (and bypass the shrink buffer) if the primary
  229. // surface was created as a GDI-managed surface:
  230. if (psurfDevice->iType() == STYPE_BITMAP)
  231. {
  232. psoDst = psurfDevice->pSurfobj();
  233. psoCopySrc = NULL;
  234. }
  235. else
  236. {
  237. psoDst = ppan->psoShrink;
  238. psoCopySrc = ppan->psoShrink;
  239. }
  240. vFilteredShrink2x32bpp(psoDst,
  241. ppan->psoShadow,
  242. &eco,
  243. &rclDevice);
  244. }
  245. if (psoCopySrc)
  246. {
  247. // Call the device's DrvCopyBits routine to do the copy (noting that
  248. // if it's an engine managed surface, we may have to call EngCopyBits):
  249. pfnCopyBits = (psurfDevice->flags() & HOOK_COPYBITS)
  250. ? PPFNTABLE(ppan->apfn, CopyBits)
  251. : EngCopyBits;
  252. (*pfnCopyBits)(psurfDevice->pSurfobj(),
  253. psoCopySrc,
  254. &eco,
  255. NULL,
  256. &rclDevice,
  257. (POINTL*) prclVisible);
  258. }
  259. }
  260. // Mark the fact that we have no dirty rectangles, and clear the
  261. // dirty region:
  262. ppan->bDirty = FALSE;
  263. RGNOBJ ro(ppan->prgnDirty);
  264. ro.vSet();
  265. }
  266. }
  267. /******************************Public*Routine******************************\
  268. * PanStrokePath
  269. *
  270. \**************************************************************************/
  271. BOOL PanStrokePath(
  272. SURFOBJ* pso,
  273. PATHOBJ* ppo,
  274. CLIPOBJ* pco,
  275. XFORMOBJ* pxo,
  276. BRUSHOBJ* pbo,
  277. POINTL* pptlBrush,
  278. LINEATTRS* pla,
  279. MIX mix)
  280. {
  281. BOOL b;
  282. PANDEV* ppan;
  283. RECTFX rcfxBounds;
  284. RECTL rclBounds;
  285. ppan = (PANDEV*) pso->dhpdev;
  286. b = EngStrokePath(ppan->psoShadow, ppo, pco, pxo, pbo, pptlBrush, pla, mix);
  287. // Get the path bounds and make it lower-right exclusive:
  288. PATHOBJ_vGetBounds(ppo, &rcfxBounds);
  289. rclBounds.left = (rcfxBounds.xLeft >> 4);
  290. rclBounds.top = (rcfxBounds.yTop >> 4);
  291. rclBounds.right = (rcfxBounds.xRight >> 4) + 2;
  292. rclBounds.bottom = (rcfxBounds.yBottom >> 4) + 2;
  293. vPanningUpdate(ppan, &rclBounds, pco);
  294. return(b);
  295. }
  296. /******************************Public*Routine******************************\
  297. * PanTransparentBlt
  298. *
  299. \**************************************************************************/
  300. BOOL PanTransparentBlt(
  301. SURFOBJ* psoDst,
  302. SURFOBJ* psoSrc,
  303. CLIPOBJ* pco,
  304. XLATEOBJ* pxlo,
  305. RECTL* prclDst,
  306. RECTL* prclSrc,
  307. ULONG iTransColor,
  308. ULONG ulReserved)
  309. {
  310. BOOL b;
  311. PANDEV* ppan;
  312. ppan = (PANDEV*) psoDst->dhpdev;
  313. b = EngTransparentBlt(ppan->psoShadow, psoSrc, pco, pxlo, prclDst,
  314. prclSrc, iTransColor, ulReserved);
  315. vPanningUpdate(ppan, prclDst, pco);
  316. return(b);
  317. }
  318. /******************************Public*Routine******************************\
  319. * PanAlphaBlend
  320. *
  321. \**************************************************************************/
  322. BOOL PanAlphaBlend(
  323. SURFOBJ* psoDst,
  324. SURFOBJ* psoSrc,
  325. CLIPOBJ* pco,
  326. XLATEOBJ* pxlo,
  327. RECTL* prclDst,
  328. RECTL* prclSrc,
  329. BLENDOBJ* pBlendObj)
  330. {
  331. BOOL b;
  332. PANDEV* ppan;
  333. ppan = (PANDEV*) psoDst->dhpdev;
  334. b = EngAlphaBlend(ppan->psoShadow, psoSrc, pco, pxlo, prclDst,
  335. prclSrc, pBlendObj);
  336. vPanningUpdate(ppan, prclDst, pco);
  337. return(b);
  338. }
  339. /******************************Public*Routine******************************\
  340. * PanGradientFill
  341. *
  342. \**************************************************************************/
  343. BOOL PanGradientFill(
  344. SURFOBJ* pso,
  345. CLIPOBJ* pco,
  346. XLATEOBJ* pxlo,
  347. TRIVERTEX* pVertex,
  348. ULONG nVertex,
  349. PVOID pMesh,
  350. ULONG nMesh,
  351. RECTL* prclExtents,
  352. POINTL* pptlDitherOrg,
  353. ULONG ulMode)
  354. {
  355. BOOL b;
  356. PANDEV* ppan;
  357. ppan = (PANDEV*) pso->dhpdev;
  358. b = EngGradientFill(ppan->psoShadow, pco, pxlo, pVertex, nVertex, pMesh,
  359. nMesh, prclExtents, pptlDitherOrg, ulMode);
  360. vPanningUpdate(ppan, prclExtents, pco);
  361. return(b);
  362. }
  363. /******************************Public*Routine******************************\
  364. * PanStretchBlt
  365. *
  366. \**************************************************************************/
  367. BOOL PanStretchBlt(
  368. SURFOBJ* psoDst,
  369. SURFOBJ* psoSrc,
  370. SURFOBJ* psoMsk,
  371. CLIPOBJ* pco,
  372. XLATEOBJ* pxlo,
  373. COLORADJUSTMENT* pca,
  374. POINTL* pptlHTOrg,
  375. RECTL* prclDst,
  376. RECTL* prclSrc,
  377. POINTL* pptlMsk,
  378. ULONG iMode)
  379. {
  380. BOOL b;
  381. PANDEV* ppan;
  382. ppan = (PANDEV*) psoDst->dhpdev;
  383. b = EngStretchBlt(ppan->psoShadow, psoSrc, psoMsk, pco, pxlo, pca, pptlHTOrg,
  384. prclDst, prclSrc, pptlMsk, iMode);
  385. vPanningUpdate(ppan, prclDst, pco);
  386. return(b);
  387. }
  388. /******************************Public*Routine******************************\
  389. * PanBitBlt
  390. *
  391. \**************************************************************************/
  392. BOOL PanBitBlt(
  393. SURFOBJ* psoDst,
  394. SURFOBJ* psoSrc,
  395. SURFOBJ* psoMask,
  396. CLIPOBJ* pco,
  397. XLATEOBJ* pxlo,
  398. RECTL* prclDst,
  399. POINTL* pptlSrc,
  400. POINTL* pptlMask,
  401. BRUSHOBJ* pbo,
  402. POINTL* pptlBrush,
  403. ROP4 rop4)
  404. {
  405. BOOL bUpdate;
  406. BOOL b;
  407. PANDEV* ppan;
  408. bUpdate = FALSE;
  409. if (psoDst->iType == STYPE_DEVICE)
  410. {
  411. bUpdate = TRUE;
  412. ppan = (PANDEV*) psoDst->dhpdev;
  413. psoDst = ppan->psoShadow;
  414. }
  415. if ((psoSrc != NULL) && (psoSrc->iType == STYPE_DEVICE))
  416. {
  417. ppan = (PANDEV*) psoSrc->dhpdev;
  418. psoSrc = ppan->psoShadow;
  419. }
  420. b = EngBitBlt(psoDst, psoSrc, psoMask, pco, pxlo, prclDst, pptlSrc,
  421. pptlMask, pbo, pptlBrush, rop4);
  422. if (bUpdate)
  423. {
  424. vPanningUpdate(ppan, prclDst, pco);
  425. }
  426. return(b);
  427. }
  428. /******************************Public*Routine******************************\
  429. * PanCopyBits
  430. *
  431. \**************************************************************************/
  432. BOOL PanCopyBits(
  433. SURFOBJ* psoDst,
  434. SURFOBJ* psoSrc,
  435. CLIPOBJ* pco,
  436. XLATEOBJ* pxlo,
  437. RECTL* prclDst,
  438. POINTL* pptlSrc)
  439. {
  440. BOOL bUpdate;
  441. BOOL b;
  442. PANDEV* ppan;
  443. return(PanBitBlt(psoDst, psoSrc, NULL, pco, pxlo, prclDst, pptlSrc,
  444. NULL, NULL, NULL, 0xcccc));
  445. }
  446. /******************************Public*Routine******************************\
  447. * PanTextOut
  448. *
  449. \**************************************************************************/
  450. BOOL PanTextOut(
  451. SURFOBJ* pso,
  452. STROBJ* pstro,
  453. FONTOBJ* pfo,
  454. CLIPOBJ* pco,
  455. RECTL* prclExtra,
  456. RECTL* prclOpaque,
  457. BRUSHOBJ* pboFore,
  458. BRUSHOBJ* pboOpaque,
  459. POINTL* pptlOrg,
  460. MIX mix)
  461. {
  462. BOOL b;
  463. PANDEV* ppan;
  464. ppan = (PANDEV*) pso->dhpdev;
  465. b = EngTextOut(ppan->psoShadow, pstro, pfo, pco, prclExtra, prclOpaque,
  466. pboFore, pboOpaque, pptlOrg, mix);
  467. vPanningUpdate(ppan,
  468. (prclOpaque != NULL) ? prclOpaque : &pstro->rclBkGround,
  469. pco);
  470. return(b);
  471. }
  472. /******************************Public*Routine******************************\
  473. * VOID PanMovePointer
  474. *
  475. \**************************************************************************/
  476. VOID PanMovePointer(
  477. SURFOBJ* pso,
  478. LONG x,
  479. LONG y,
  480. RECTL* prcl)
  481. {
  482. PANDEV* ppan;
  483. BOOL bUpdate;
  484. PFN_DrvMovePointer pfnMovePointer;
  485. ppan = (PANDEV*) pso->dhpdev;
  486. // A negative 'y' coordinate indicates a positional notification.
  487. // Use this to move the panning coordinates if need be:
  488. ASSERTGDI((y < 0) && (x >= 0), "Unexpected coordinates");
  489. // It's weird, but the display driver may actually be panning
  490. // underneath our virtual panning display driver! (This will
  491. // only happen when all the video driver's accelerations are
  492. // disabled.)
  493. pfnMovePointer = PPFNTABLE(ppan->apfn, MovePointer);
  494. if ((pfnMovePointer != NULL) &&
  495. (ppan->flOriginalCaps & GCAPS_PANNING))
  496. {
  497. (*pfnMovePointer)(ppan->psoDevice,
  498. x,
  499. y,
  500. prcl);
  501. }
  502. // Adjust to positive space:
  503. y += pso->sizlBitmap.cy;
  504. bUpdate = FALSE;
  505. if (x < ppan->rclVisible.left)
  506. {
  507. ppan->rclVisible.left = x;
  508. ppan->rclVisible.right = x + ppan->cxScreen;
  509. bUpdate = TRUE;
  510. }
  511. if (x > ppan->rclVisible.right)
  512. {
  513. ppan->rclVisible.right = x;
  514. ppan->rclVisible.left = x - ppan->cxScreen;
  515. bUpdate = TRUE;
  516. }
  517. if (y < ppan->rclVisible.top)
  518. {
  519. ppan->rclVisible.top = y;
  520. ppan->rclVisible.bottom = y + ppan->cyScreen;
  521. bUpdate = TRUE;
  522. }
  523. if (y > ppan->rclVisible.bottom)
  524. {
  525. ppan->rclVisible.bottom = y;
  526. ppan->rclVisible.top = y - ppan->cyScreen;
  527. bUpdate = TRUE;
  528. }
  529. ASSERTGDI((ppan->rclVisible.left >= 0) &&
  530. (ppan->rclVisible.top >= 0) &&
  531. (ppan->rclVisible.right <= ppan->cxDesktop) &&
  532. (ppan->rclVisible.bottom <= ppan->cyDesktop),
  533. "unexpected pointer coordinates");
  534. if (bUpdate)
  535. {
  536. // The panning coordinates changed, so update the display.
  537. //
  538. // NOTE: A screen-to-screen blt could be done as an optimization.
  539. vPanningUpdate(ppan,
  540. &ppan->rclVisible,
  541. NULL);
  542. }
  543. // Flush anything pending. We do this for a couple of reasons:
  544. //
  545. // 1. To flush the vPanningUpdate we may have just done;
  546. // 2. For smoother mouse movement.
  547. PanSynchronize((DHPDEV) ppan, NULL);
  548. }
  549. /******************************Public*Routine******************************\
  550. * PanDitherColor
  551. *
  552. * Dithers an RGB color to an 8X8 approximation using the reserved VGA
  553. * colors.
  554. *
  555. \**************************************************************************/
  556. ULONG APIENTRY PanDitherColor(
  557. DHPDEV dhpdev,
  558. ULONG iMode,
  559. ULONG rgb,
  560. ULONG* pul)
  561. {
  562. PANDEV* ppan;
  563. ULONG iRet;
  564. ppan = (PANDEV*) dhpdev;
  565. // EngDitherColor supports dithers only for 8bpp and higher, so at
  566. // anything lower we have to call the driver.
  567. if (ppan->iBitmapFormat >= BMF_8BPP)
  568. {
  569. iRet = EngDitherColor(ppan->hdev, iMode, rgb, pul);
  570. }
  571. else
  572. {
  573. iRet = PPFNTABLE(ppan->apfn, DitherColor)(ppan->dhpdevDevice,
  574. iMode,
  575. rgb,
  576. pul);
  577. }
  578. return(iRet);
  579. }
  580. /******************************Public*Routine******************************\
  581. * BOOL PanSetPalette
  582. *
  583. * DDI entry point for manipulating the palette.
  584. *
  585. \**************************************************************************/
  586. BOOL PanSetPalette(
  587. DHPDEV dhpdev,
  588. PALOBJ* ppal,
  589. FLONG fl,
  590. ULONG iStart,
  591. ULONG cColors)
  592. {
  593. PANDEV* ppan;
  594. ppan = (PANDEV*) dhpdev;
  595. return((*PPFNTABLE(ppan->apfn, SetPalette))(ppan->dhpdevDevice,
  596. ppal,
  597. fl,
  598. iStart,
  599. cColors));
  600. }
  601. /******************************Public*Routine******************************\
  602. * VOID PanAssertMode
  603. *
  604. * This asks the device to reset itself to the mode of the pdev passed in.
  605. *
  606. \**************************************************************************/
  607. BOOL PanAssertMode(
  608. DHPDEV dhpdev,
  609. BOOL bEnable)
  610. {
  611. PANDEV* ppan;
  612. BOOL b;
  613. ppan = (PANDEV*) dhpdev;
  614. b = (*PPFNTABLE(ppan->apfn, AssertMode))(ppan->dhpdevDevice,
  615. bEnable);
  616. return(b);
  617. }
  618. /******************************Public*Routine******************************\
  619. * DHPDEV PanEnablePDEV
  620. *
  621. * Initializes a bunch of fields for GDI, based on the mode we've been asked
  622. * to do. This is the first thing called after PanEnableDriver, when GDI
  623. * wants to get some information about us.
  624. *
  625. * (This function mostly returns back information; PanEnableSurface is used
  626. * for initializing the hardware and driver components.)
  627. *
  628. \**************************************************************************/
  629. DHPDEV PanEnablePDEV(
  630. DEVMODEW* pdm, // Contains data pertaining to requested mode
  631. PWSTR pwszLogAddr, // Logical address
  632. ULONG cPat, // Count of standard patterns
  633. HSURF* phsurfPatterns, // Buffer for standard patterns
  634. ULONG cjCaps, // Size of buffer for device caps 'pdevcaps'
  635. ULONG* pdevcaps, // Buffer for device caps, also known as 'gdiinfo'
  636. ULONG cjDevInfo, // Number of bytes in device info 'pdi'
  637. DEVINFO* pdi, // Device information
  638. HDEV hdev, // HDEV, used for callbacks
  639. PWSTR pwszDeviceName, // Device name
  640. HANDLE hDriver) // Kernel driver handle
  641. {
  642. PANDEV* ppan;
  643. PFN* ppfnDevice;
  644. DHPDEV dhpdevDevice;
  645. GDIINFO* pGdiInfo;
  646. DEVMODEW dmTmp;
  647. ASSERTGDI((pdm->dmPanningWidth <= pdm->dmPelsWidth) &&
  648. (pdm->dmPanningHeight <= pdm->dmPelsHeight),
  649. "Bad devmode sizes");
  650. ppan = (PANDEV*) PALLOCMEM(sizeof(PANDEV), 'napG');
  651. if (ppan != NULL)
  652. {
  653. PPDEV ppdev = (PPDEV)hdev;
  654. // Snag a copy of the device's dispatch table, from
  655. // the private PDEV structure, which is the hdev.
  656. ppfnDevice = &ppdev->pldev->apfn[0];
  657. RtlCopyMemory(ppan->apfn, ppfnDevice, sizeof(PFN) * INDEX_LAST);
  658. // Remember our dimensions:
  659. ppan->cxDesktop = pdm->dmPelsWidth;
  660. ppan->cyDesktop = pdm->dmPelsHeight;
  661. if (pdm->dmPanningWidth != 0)
  662. {
  663. ppan->cxScreen = pdm->dmPanningWidth;
  664. ppan->cyScreen = pdm->dmPanningHeight;
  665. }
  666. else
  667. {
  668. ppan->cxScreen = pdm->dmPelsWidth;
  669. ppan->cyScreen = pdm->dmPelsHeight;
  670. }
  671. // Ask the driver to set its physical mode to the panning
  672. // dimensions:
  673. dmTmp = *pdm;
  674. dmTmp.dmPelsWidth = ppan->cxScreen;
  675. dmTmp.dmPelsHeight = ppan->cyScreen;
  676. // But wait, if we're being asked to double the DPI and the
  677. // mode is 32bpp, drvsup.cxx already set up the Devmode so
  678. // that it's double the actual resolution. That means that we
  679. // then have to halve the resolution that we request of the
  680. // driver:
  681. if ((G_fDoubleDpi) && (dmTmp.dmBitsPerPel == 32))
  682. {
  683. dmTmp.dmPelsWidth >>= 1;
  684. dmTmp.dmPelsHeight >>= 1;
  685. }
  686. dhpdevDevice = (*PPFNTABLE(ppan->apfn, EnablePDEV))
  687. (&dmTmp,
  688. pwszLogAddr,
  689. cPat,
  690. phsurfPatterns,
  691. cjCaps,
  692. (GDIINFO*) pdevcaps,
  693. cjDevInfo,
  694. pdi,
  695. hdev,
  696. pwszDeviceName,
  697. hDriver);
  698. if (dhpdevDevice != NULL)
  699. {
  700. ppan->iBitmapFormat = pdi->iDitherFormat;
  701. ppan->dhpdevDevice = dhpdevDevice;
  702. ppan->hdev = hdev;
  703. ppan->flOriginalCaps = pdi->flGraphicsCaps;
  704. // The display driver will have set the desktop coordinates
  705. // to the smaller screen coordinates, so we'll have to
  706. // overwrite that:
  707. pGdiInfo = (GDIINFO*) pdevcaps;
  708. pGdiInfo->ulHorzRes = ppan->cxDesktop;
  709. pGdiInfo->ulVertRes = ppan->cyDesktop;
  710. // Overwrite some of the driver's capabilities:
  711. pdi->flGraphicsCaps &= (GCAPS_PALMANAGED |
  712. GCAPS_MONO_DITHER |
  713. GCAPS_COLOR_DITHER);
  714. pdi->flGraphicsCaps |= GCAPS_PANNING;
  715. // Enable synchronization calls:
  716. pdi->flGraphicsCaps2 = (GCAPS2_SYNCFLUSH |
  717. GCAPS2_SYNCTIMER);
  718. return((DHPDEV) ppan);
  719. }
  720. VFREEMEM(ppan);
  721. }
  722. return(0);
  723. }
  724. /******************************Public*Routine******************************\
  725. * PanDisablePDEV
  726. *
  727. * Release the resources allocated in PanEnablePDEV. If a surface has been
  728. * enabled PanDisableSurface will have already been called.
  729. *
  730. \**************************************************************************/
  731. VOID PanDisablePDEV(
  732. DHPDEV dhpdev)
  733. {
  734. PANDEV* ppan;
  735. ppan = (PANDEV*) dhpdev;
  736. (*PPFNTABLE(ppan->apfn, DisablePDEV))(ppan->dhpdevDevice);
  737. VFREEMEM(ppan);
  738. }
  739. /******************************Public*Routine******************************\
  740. * VOID PanCompletePDEV
  741. *
  742. \**************************************************************************/
  743. VOID PanCompletePDEV(
  744. DHPDEV dhpdev,
  745. HDEV hdev)
  746. {
  747. PANDEV* ppan;
  748. ppan = (PANDEV*) dhpdev;
  749. ppan->hdev = hdev;
  750. (*PPFNTABLE(ppan->apfn, CompletePDEV))(ppan->dhpdevDevice,
  751. hdev);
  752. }
  753. /******************************Public*Routine******************************\
  754. * HSURF PanEnableSurface
  755. *
  756. * Creates the drawing surface, initializes the hardware, and initializes
  757. * driver components. This function is called after PanEnablePDEV, and
  758. * performs the final device initialization.
  759. *
  760. \**************************************************************************/
  761. HSURF PanEnableSurface(
  762. DHPDEV dhpdev)
  763. {
  764. PANDEV* ppan;
  765. HSURF hsurfDevice;
  766. HSURF hsurfScreen;
  767. HSURF hsurfShadow;
  768. HSURF hsurfShrink;
  769. SIZEL sizl;
  770. SIZEL sizlShrink;
  771. SURFOBJ* psoShadow;
  772. SURFOBJ* psoDevice;
  773. SURFOBJ* psoShrink;
  774. BOOL bShrink;
  775. ppan = (PANDEV*) dhpdev;
  776. // Initialize the paning position:
  777. ppan->rclVisible.left = (ppan->cxDesktop - ppan->cxScreen) >> 1;
  778. ppan->rclVisible.top = (ppan->cyDesktop - ppan->cyScreen) >> 1;
  779. ppan->rclVisible.right = (ppan->rclVisible.left + ppan->cxScreen);
  780. ppan->rclVisible.bottom = (ppan->rclVisible.top + ppan->cyScreen);
  781. // Call the device to enable its surface:
  782. hsurfDevice = (*PPFNTABLE(ppan->apfn, EnableSurface))(ppan->dhpdevDevice);
  783. if (hsurfDevice)
  784. {
  785. psoDevice = EngLockSurface(hsurfDevice);
  786. if (psoDevice)
  787. {
  788. SURFACE* pDevSurface = SURFOBJ_TO_SURFACE(psoDevice);
  789. pDevSurface->flags(pDevSurface->flags() & ~(HOOK_SYNCHRONIZE));
  790. ppan->psoDevice = psoDevice;
  791. // Now reset the device's 'dhpdev' field that the device's
  792. // EngAssociateSurface call so rudely overwrote with the pointer
  793. // to *our* 'ppan' structure!
  794. psoDevice->dhpdev = ppan->dhpdevDevice;
  795. // Have GDI create the actual SURFOBJ.
  796. //
  797. // Our drawing surface is going to be 'device-managed', meaning
  798. // that GDI cannot draw on the framebuffer bits directly, and as
  799. // such we create the surface via EngCreateSurface. By doing
  800. // this, we ensure that GDI will only ever access the bitmaps
  801. // bits via the Pan calls that we've HOOKed.
  802. sizl.cx = ppan->cxDesktop;
  803. sizl.cy = ppan->cyDesktop;
  804. hsurfScreen = EngCreateDeviceSurface(NULL,
  805. sizl,
  806. ppan->iBitmapFormat);
  807. if (hsurfScreen != 0)
  808. {
  809. ppan->hsurfScreen = hsurfScreen;
  810. // Now associate the surface and the PANDEV.
  811. //
  812. // We have to associate the surface we just created with our
  813. // physical device so that GDI can get information related to
  814. // the PANDEV when it's drawing to the surface (such as, for
  815. // example, the length of styles on the device when simulating
  816. // styled lines).
  817. if (EngAssociateSurface(hsurfScreen,
  818. ppan->hdev,
  819. (HOOK_BITBLT |
  820. HOOK_TEXTOUT |
  821. HOOK_COPYBITS |
  822. HOOK_STRETCHBLT |
  823. HOOK_ALPHABLEND |
  824. HOOK_TRANSPARENTBLT |
  825. HOOK_GRADIENTFILL |
  826. HOOK_STROKEPATH |
  827. HOOK_SYNCHRONIZE)))
  828. {
  829. // Create the shadow DIB on which we'll have GDI do all
  830. // the drawing. We'll merely occasionally blt portions
  831. // to the screen to update.
  832. hsurfShadow = (HSURF) EngCreateBitmap(sizl,
  833. sizl.cx,
  834. ppan->iBitmapFormat,
  835. BMF_TOPDOWN,
  836. NULL);
  837. psoShadow = EngLockSurface(hsurfShadow);
  838. if (psoShadow != NULL)
  839. {
  840. ppan->psoShadow = psoShadow;
  841. // If we're doing the double-dpi thing, we need to
  842. // create a scratch buffer for the shrink:
  843. hsurfShrink = NULL;
  844. psoShrink = NULL;
  845. bShrink = ((G_fDoubleDpi) &&
  846. (ppan->iBitmapFormat == BMF_32BPP));
  847. if (bShrink)
  848. {
  849. // Create a temporary surface used as the scratch
  850. // buffer destination for our 'shrink' blt:
  851. sizlShrink.cx = sizl.cx >> 1;
  852. sizlShrink.cy = sizl.cy >> 1;
  853. hsurfShrink = (HSURF) EngCreateBitmap(sizlShrink,
  854. sizlShrink.cx,
  855. ppan->iBitmapFormat,
  856. BMF_TOPDOWN,
  857. NULL);
  858. psoShrink = EngLockSurface(hsurfShrink);
  859. }
  860. // If shrinking and couldn't allocate 'psoShrink',
  861. // then fail:
  862. if ((!bShrink) || (psoShrink != NULL))
  863. {
  864. ppan->psoShrink = psoShrink;
  865. if (EngAssociateSurface(hsurfShadow,
  866. ppan->hdev,
  867. 0))
  868. {
  869. RGNMEMOBJ rmoDirty;
  870. RGNMEMOBJ rmoOld;
  871. RGNMEMOBJ rmoRect;
  872. if ((rmoOld.bValid()) &&
  873. (rmoDirty.bValid()) &&
  874. (rmoRect.bValid()))
  875. {
  876. rmoDirty.vSet();
  877. rmoOld.vSet();
  878. ppan->prgnDirty = rmoDirty.prgnGet();
  879. ppan->prgnOld = rmoOld.prgnGet();
  880. ppan->prgnRect = rmoRect.prgnGet();
  881. // Blank the screen:
  882. PanSynchronize(dhpdev, NULL);
  883. // Success!
  884. return(hsurfScreen);
  885. }
  886. rmoOld.vDeleteRGNOBJ();
  887. rmoDirty.vDeleteRGNOBJ();
  888. rmoRect.vDeleteRGNOBJ();
  889. }
  890. }
  891. EngUnlockSurface(psoShrink);
  892. EngDeleteSurface(hsurfShrink);
  893. }
  894. EngUnlockSurface(psoShadow);
  895. EngDeleteSurface(hsurfShadow);
  896. }
  897. EngDeleteSurface(hsurfScreen);
  898. }
  899. EngUnlockSurface(psoDevice);
  900. }
  901. (*PPFNTABLE(ppan->apfn, DisableSurface))(ppan->dhpdevDevice);
  902. }
  903. return(0);
  904. }
  905. /******************************Public*Routine******************************\
  906. * VOID PanDisableSurface
  907. *
  908. * Free resources allocated by PanEnableSurface. Release the surface.
  909. *
  910. \**************************************************************************/
  911. VOID PanDisableSurface(
  912. DHPDEV dhpdev)
  913. {
  914. PANDEV* ppan;
  915. HSURF hsurfShadow;
  916. HSURF hsurfShrink;
  917. ppan = (PANDEV*) dhpdev;
  918. RGNOBJ roDirty(ppan->prgnDirty);
  919. RGNOBJ roOld(ppan->prgnOld);
  920. RGNOBJ roRect(ppan->prgnRect);
  921. roOld.vDeleteRGNOBJ();
  922. roDirty.vDeleteRGNOBJ();
  923. roRect.vDeleteRGNOBJ();
  924. hsurfShadow = ppan->psoShadow->hsurf;
  925. EngUnlockSurface(ppan->psoShadow);
  926. EngDeleteSurface(hsurfShadow);
  927. if (ppan->psoShrink)
  928. {
  929. hsurfShrink = ppan->psoShrink->hsurf;
  930. EngUnlockSurface(ppan->psoShrink);
  931. EngDeleteSurface(hsurfShrink);
  932. }
  933. EngDeleteSurface(ppan->hsurfScreen);
  934. EngUnlockSurface(ppan->psoDevice);
  935. (*PPFNTABLE(ppan->apfn, DisableSurface))(ppan->dhpdevDevice);
  936. }
  937. /******************************Public*Structure****************************\
  938. * DFVFN gadrvfnPanning[]
  939. *
  940. * Build the driver function table gadrvfn with function index/address
  941. * pairs. This table tells GDI which DDI calls we support, and their
  942. * location (GDI does an indirect call through this table to call us).
  943. *
  944. \**************************************************************************/
  945. DRVFN gadrvfnPanning[] = {
  946. { INDEX_DrvEnablePDEV, (PFN) PanEnablePDEV },
  947. { INDEX_DrvCompletePDEV, (PFN) PanCompletePDEV },
  948. { INDEX_DrvDisablePDEV, (PFN) PanDisablePDEV },
  949. { INDEX_DrvEnableSurface, (PFN) PanEnableSurface },
  950. { INDEX_DrvDisableSurface, (PFN) PanDisableSurface },
  951. { INDEX_DrvDitherColor, (PFN) PanDitherColor },
  952. { INDEX_DrvAssertMode, (PFN) PanAssertMode },
  953. { INDEX_DrvBitBlt, (PFN) PanBitBlt },
  954. { INDEX_DrvTextOut, (PFN) PanTextOut },
  955. { INDEX_DrvStrokePath, (PFN) PanStrokePath },
  956. { INDEX_DrvCopyBits, (PFN) PanCopyBits },
  957. { INDEX_DrvTransparentBlt, (PFN) PanTransparentBlt },
  958. { INDEX_DrvAlphaBlend, (PFN) PanAlphaBlend },
  959. { INDEX_DrvGradientFill, (PFN) PanGradientFill },
  960. { INDEX_DrvStretchBlt, (PFN) PanStretchBlt },
  961. { INDEX_DrvSetPalette, (PFN) PanSetPalette },
  962. { INDEX_DrvMovePointer, (PFN) PanMovePointer },
  963. { INDEX_DrvSynchronize, (PFN) PanSynchronize },
  964. };
  965. ULONG gcdrvfnPanning = sizeof(gadrvfnPanning) / sizeof(DRVFN);
  966. /******************************Public*Routine******************************\
  967. * BOOL PanEnableDriver
  968. *
  969. * Standard driver DrvEnableDriver function
  970. *
  971. \**************************************************************************/
  972. BOOL PanEnableDriver(
  973. ULONG iEngineVersion,
  974. ULONG cj,
  975. DRVENABLEDATA* pded)
  976. {
  977. pded->pdrvfn = gadrvfnPanning;
  978. pded->c = gcdrvfnPanning;
  979. pded->iDriverVersion = DDI_DRIVER_VERSION_NT5;
  980. return(TRUE);
  981. }