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.

303 lines
9.4 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. *
  8. *
  9. * Abstract:
  10. *
  11. *
  12. *
  13. * Notes:
  14. *
  15. *
  16. *
  17. * Created:
  18. *
  19. * //1999 agodfrey
  20. *
  21. \**************************************************************************/
  22. #include "precomp.hpp"
  23. DpDriver::DpDriver()
  24. {
  25. Internal = new DpDriverInternal;
  26. Device = NULL;
  27. }
  28. DpDriver::~DpDriver()
  29. {
  30. delete Internal;
  31. SetValid(FALSE); // so we don't use a deleted object
  32. }
  33. // If we let the clipping region height get too large, then GDI will allocate
  34. // tons of memory when we select the clip path in.
  35. #define GDI_MAX_REGION_HEIGHT_FOR_GDI 65536
  36. // Returns TRUE if we succeed in setting the clipping using
  37. // path clipping.
  38. static BOOL
  39. SetupPathClipping(
  40. HDC hdc,
  41. const DpContext * context,
  42. BOOL doSaveDC,
  43. const GpRect * drawBounds
  44. )
  45. {
  46. // We can use the actual clip path to set up the clipping
  47. // under the following circumstances:
  48. // 1) the application clipping has only one path
  49. // 2) the container clip is simple (a single rect)
  50. // which either fully encompasses the application clipping
  51. // or else the application clipping is also a single rect
  52. // and the intersection of the 2 rects can be used.
  53. // We could expand this criteria to include more cases, but for
  54. // now, this is sufficient.
  55. const GpRegion * appClip = &(context->AppClip);
  56. const DpRegion * containerClip = &(context->ContainerClip);
  57. if (appClip->IsOnePath() && containerClip->IsSimple())
  58. {
  59. // ContainerClip is a single rect
  60. // It may be inifinte, but it shouldn't be empty at this point.
  61. GpRect pathRect;
  62. GpRect containerBounds;
  63. GpRect appBounds;
  64. GpMatrix identityMatrix;
  65. containerClip->GetBounds(&containerBounds);
  66. appClip->GetBounds(&identityMatrix, &appBounds);
  67. if (appClip->IsRect())
  68. {
  69. GpRect::IntersectRect(pathRect, appBounds, containerBounds);
  70. if (doSaveDC)
  71. {
  72. ::SaveDC(hdc);
  73. }
  74. // Use IntersectClipRect (not BeginPath, Rectangle, EndPath),
  75. // because mf3216.dll assumes that
  76. // path clipping means do XOR, black, XOR technique, and
  77. // we don't want that if we are playing a metafile into
  78. // another metafile.
  79. ::IntersectClipRect(hdc,
  80. pathRect.GetLeft(),
  81. pathRect.GetTop(),
  82. pathRect.GetRight(),
  83. pathRect.GetBottom());
  84. return TRUE;
  85. }
  86. else // use the AppClip as the clip path
  87. {
  88. ConvertPathToGdi gdiPath(appClip->GetPath(), &identityMatrix, ForFill);
  89. if (gdiPath.IsValid())
  90. {
  91. if (doSaveDC)
  92. {
  93. ::SaveDC(hdc);
  94. }
  95. gdiPath.AndClip(hdc);
  96. if ((appBounds.GetLeft() < containerBounds.GetLeft()) ||
  97. (appBounds.GetRight() > containerBounds.GetRight()) ||
  98. (appBounds.GetTop() < containerBounds.GetTop()) ||
  99. (appBounds.GetBottom() > containerBounds.GetBottom()))
  100. {
  101. ::IntersectClipRect(hdc,
  102. containerBounds.GetLeft(),
  103. containerBounds.GetTop(),
  104. containerBounds.GetRight(),
  105. containerBounds.GetBottom());
  106. }
  107. return TRUE;
  108. }
  109. }
  110. }
  111. else
  112. {
  113. const DpClipRegion * clipRegion = &(context->VisibleClip);
  114. DpClipRegion intersectClip(drawBounds);
  115. GpRect clipBounds;
  116. if (intersectClip.IsValid())
  117. {
  118. clipRegion->GetBounds(&clipBounds);
  119. // GDI doesn't handle large clip regions very well -- it uses
  120. // the height of the region to decide how much memory to allocate,
  121. // so can end up allocating huge amounts of memory. An example
  122. // of this is to take an infinite region and exclude a rect from
  123. // it and then clip to that region. To solve this problem,
  124. // intersect the clip region with the drawBounds (which are hopefully
  125. // a reasonable size).
  126. if (clipBounds.Height >= GDI_MAX_REGION_HEIGHT_FOR_GDI)
  127. {
  128. intersectClip.And(clipRegion);
  129. if (intersectClip.IsValid())
  130. {
  131. clipRegion = &intersectClip;
  132. }
  133. }
  134. GpPath path(clipRegion);
  135. if (path.IsValid())
  136. {
  137. GpMatrix identityMatrix;
  138. ConvertPathToGdi gdiPath(&path, &identityMatrix, ForFill);
  139. if (gdiPath.IsValid())
  140. {
  141. if (doSaveDC)
  142. {
  143. ::SaveDC(hdc);
  144. }
  145. gdiPath.AndClip(hdc);
  146. return TRUE;
  147. }
  148. }
  149. }
  150. }
  151. return FALSE;
  152. }
  153. /**************************************************************************\
  154. *
  155. * Function Description:
  156. *
  157. * Set up the clipping in the HDC for the GDI primitive
  158. *
  159. * Arguments:
  160. *
  161. * [IN] hdc - The device to set the clipping in
  162. * [IN] clipRegion - The region to clip to
  163. * [IN] drawBounds - The bounds of the object being drawn
  164. * [OUT] isClip - Whether or not we are clipping the object
  165. *
  166. * Return Value:
  167. *
  168. * N/A
  169. *
  170. * Created:
  171. *
  172. * 9/15/1999 DCurtis
  173. *
  174. \**************************************************************************/
  175. VOID
  176. DpDriver::SetupClipping(
  177. HDC hdc,
  178. DpContext * context,
  179. const GpRect * drawBounds,
  180. BOOL & isClip,
  181. BOOL & usePathClipping,
  182. BOOL forceClipping
  183. )
  184. {
  185. // VisibleClip is the combination of the AppClip and the ContainerClip.
  186. // The ContainerClip is always intersected with the WindowClip.
  187. DpClipRegion * clipRegion = &(context->VisibleClip);
  188. // We set wantPathClipping to be what the user wants to do. This way
  189. // when we return usePathClipping is true only if we did indeed setup a
  190. // path clipping
  191. BOOL wantPathClipping = usePathClipping;
  192. usePathClipping = FALSE;
  193. isClip = FALSE;
  194. if (forceClipping ||
  195. (clipRegion->GetRectVisibility(
  196. drawBounds->X, drawBounds->Y,
  197. drawBounds->GetRight(),
  198. drawBounds->GetBottom()) != DpRegion::TotallyVisible))
  199. {
  200. if (clipRegion->IsSimple())
  201. {
  202. isClip = TRUE;
  203. GpRect clipRect;
  204. clipRegion->GetBounds(&clipRect);
  205. ::SaveDC(hdc);
  206. // If we have an infinite region don't intersect
  207. if (!clipRegion->IsInfinite())
  208. {
  209. ::IntersectClipRect(hdc, clipRect.X, clipRect.Y,
  210. clipRect.GetRight(), clipRect.GetBottom());
  211. }
  212. return;
  213. }
  214. // I'm assuming that by now we've already decided that the
  215. // drawBounds is at least partially visible. Otherwise, we're
  216. // going to a lot of trouble here for nothing.
  217. // When writing a metafile, we always want to use path clipping
  218. // so that the clipping scales properly when being played back.
  219. if (wantPathClipping)
  220. {
  221. if (SetupPathClipping(hdc, context, TRUE, drawBounds))
  222. {
  223. isClip = TRUE;
  224. usePathClipping = TRUE;
  225. return;
  226. }
  227. }
  228. // Either we're not supposed to use path clipping, or else
  229. // path clipping failed for some reason, so use the region
  230. // to clip.
  231. // Since this might get saved out to a metafile, we need
  232. // to Save the DC, and restore it once the clipping is back
  233. // so that we don't overwrite the application's clipping
  234. HRGN hRgn = clipRegion->GetHRgn();
  235. if (hRgn != (HRGN)0)
  236. {
  237. ::SaveDC(hdc);
  238. ::ExtSelectClipRgn(hdc, hRgn, RGN_AND);
  239. ::DeleteObject(hRgn);
  240. isClip = TRUE;
  241. }
  242. }
  243. }
  244. /**************************************************************************\
  245. *
  246. * Function Description:
  247. *
  248. * Restore the clipping state in the HDC
  249. *
  250. * Arguments:
  251. *
  252. * [IN] hdc - The device to set the clipping in
  253. * [IN] isClip - If clipping was turned on or not
  254. *
  255. * Return Value:
  256. *
  257. * N/A
  258. *
  259. * Created:
  260. *
  261. * 9/15/1999 DCurtis
  262. *
  263. \**************************************************************************/
  264. VOID
  265. DpDriver::RestoreClipping(
  266. HDC hdc,
  267. BOOL isClip,
  268. BOOL usePathClipping
  269. )
  270. {
  271. if (isClip)
  272. {
  273. // Restore the DC in both cases for PathClipping or
  274. // for region clipping
  275. ::RestoreDC(hdc, -1);
  276. }
  277. }