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.

448 lines
16 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. // surface.h : surface management utility classes for vidctl
  3. // Copyright (c) Microsoft Corporation 2000.
  4. #pragma once
  5. #ifndef SURFACE_H
  6. #define SURFACE_H
  7. #include <scalingrect.h>
  8. typedef CComPtr<IOleInPlaceFrame> PQFrame;
  9. typedef CComPtr<IOleInPlaceUIWindow> PQUIWin;
  10. class AspectRatio : public CSize {
  11. public:
  12. AspectRatio(ULONG xi = 0, ULONG yi = 0) : CSize(xi, yi) {
  13. Normalize();
  14. }
  15. AspectRatio(const AspectRatio& ar) : CSize(ar.cx, ar.cy) {}
  16. AspectRatio(const CRect& ri) : CSize(abs(ri.Width()), abs(ri.Height())) {
  17. Normalize();
  18. }
  19. AspectRatio(LPCRECT ri) : CSize(abs(ri->left - ri->right),
  20. abs(ri->top - ri->bottom)) {
  21. Normalize();
  22. }
  23. void Normalize() {
  24. ULONG d = GCD(abs(cx), abs(cy));
  25. if (!d) return;
  26. cx /= d;
  27. cy /= d;
  28. }
  29. // from knuth semi-numerical algorithms p. 321(sort of).
  30. // since >> on signed isn't guaranteed to be arithmetic in C/C++ we've made some modifications
  31. ULONG GCD(ULONG a, ULONG b) const {
  32. ULONG k = 0;
  33. if (!a) return b; // by defn
  34. if (!b) return a;
  35. while ((!(a & 1)) && (!( b & 1))) {
  36. _ASSERT((a > 1) && (b > 1)); // since a,b != 0 and even then they must be > 1
  37. // if a and b are even then gcd(a,b) == 2 * gcd(a/2,b/2), so factor out all the 2s
  38. ++k;
  39. a >>= 1;
  40. b >>= 1;
  41. }
  42. do {
  43. _ASSERT(a && b); // neither can be zero otherwise we'd have returned from the top(1st time)
  44. // or fallen out earlier(subsequent iterations)
  45. _ASSERT((a & 1) || (b & 1)); // at this point either a or b (or both) is odd
  46. if (!(a & 1) || !(b & 1)) { // if one of them is even then factor out the 2s
  47. // since if x is even then gcd(x,y) == gcx(x/2,y)
  48. ULONG t = (a & 1) ? b : a;
  49. do {
  50. _ASSERT(t && (t > 1) && !(t & 1)); // t is even and non-zero(implying t > 1)
  51. t >>= 1;
  52. } while (!(t & 1));
  53. _ASSERT(t && (t & 1)); // t is odd and > 0
  54. // put t back where we got it from
  55. if (a & 1) {
  56. b = t;
  57. } else {
  58. a = t;
  59. }
  60. _ASSERT((a & 1) && (b & 1)); // they're both odd now
  61. }
  62. // replace larger with difference
  63. // gcd(x, y) == gcd(y, x)
  64. // gcd(x,y) == gcd(x - y, y)
  65. if (a > b) {
  66. a = a - b;
  67. } else {
  68. b = b - a;
  69. }
  70. _ASSERT(a | b); // they can't both be 0 or we'd have been done last time through
  71. } while (a && b); // if one of the values is 0 then we're done gcd(x,0) == x
  72. return (a > b ? a : b) << k;
  73. }
  74. AspectRatio& operator=(const AspectRatio& rhs) {
  75. if (&rhs != this) {
  76. cx = rhs.cx;
  77. cy = rhs.cy;
  78. }
  79. Normalize();
  80. return *this;
  81. }
  82. AspectRatio& operator=(const CRect& rhs) {
  83. cx = abs(rhs.Width());
  84. cy = abs(rhs.Height());
  85. Normalize();
  86. return *this;
  87. }
  88. AspectRatio& operator=(const CSize& rhs) {
  89. if (&rhs != this) {
  90. cx = rhs.cx;
  91. cy = rhs.cy;
  92. }
  93. Normalize();
  94. return *this;
  95. }
  96. AspectRatio& operator=(const LPSIZE rhs) {
  97. if (rhs != this) {
  98. cx = rhs->cx;
  99. cy = rhs->cy;
  100. }
  101. Normalize();
  102. return *this;
  103. }
  104. AspectRatio& operator=(LPCRECT rhs) {
  105. cx = abs(rhs->left - rhs->right);
  106. cy = abs(rhs->top - rhs->bottom);
  107. Normalize();
  108. return *this;
  109. }
  110. bool operator==(const AspectRatio& rhs) const {
  111. return cx == rhs.cx && cy == rhs.cy;
  112. }
  113. bool operator==(const CSize& rhs) const {
  114. return cx == rhs.cx && cy == rhs.cy;
  115. }
  116. bool operator!=(const AspectRatio& rhs) const {
  117. return !operator==(rhs);
  118. }
  119. bool operator!() {
  120. return !cx && !cy;
  121. }
  122. ULONG X() const { return cx; }
  123. ULONG Y() const { return cy; }
  124. ULONG X(ULONG xi) {
  125. cx = xi;
  126. Normalize();
  127. return cx;
  128. }
  129. ULONG Y(ULONG yi) {
  130. cy = yi;
  131. Normalize();
  132. return cy;
  133. }
  134. void XY(ULONG xi, ULONG yi) {
  135. cx = xi;
  136. cy = yi;
  137. Normalize();
  138. }
  139. };
  140. class SurfaceState : public CScalingRect {
  141. public:
  142. const static int MIN_RECT_WIDTH = 4;
  143. const static int MIN_RECT_HEIGHT = 3;
  144. SurfaceState(const long l = 0,
  145. const long t = 0,
  146. const long r = 0,
  147. const long b = 0,
  148. const HWND iOwner = INVALID_HWND,
  149. const bool iVis = false,
  150. const bool iAspect = true,
  151. const bool iSource = false) :
  152. CScalingRect(l, t, r, b, iOwner),
  153. m_fVisible(iVis),
  154. m_fForceAspectRatio(iAspect),
  155. m_fForceSourceSize(iSource) {}
  156. SurfaceState(const CRect& iPos,
  157. const HWND iOwner = INVALID_HWND,
  158. const bool iVis = false,
  159. const bool iAspect = true,
  160. const bool iSource = false) :
  161. CScalingRect(iPos, iOwner),
  162. m_fVisible(iVis),
  163. m_fForceAspectRatio(iAspect),
  164. m_fForceSourceSize(iSource) {}
  165. SurfaceState(const CScalingRect& iPos,
  166. const bool iVis = false,
  167. const bool iAspect = true,
  168. const bool iSource = false) :
  169. CScalingRect(iPos),
  170. m_fVisible(iVis),
  171. m_fForceAspectRatio(iAspect),
  172. m_fForceSourceSize(iSource) {}
  173. SurfaceState(const HWND iOwner,
  174. const bool iVis = false,
  175. const bool iAspect = true,
  176. const bool iSource = false) :
  177. CScalingRect(iOwner),
  178. m_fVisible(iVis),
  179. m_fForceAspectRatio(iAspect),
  180. m_fForceSourceSize(iSource) {}
  181. SurfaceState(const PQSiteWindowless& pSite,
  182. const bool iVis = false,
  183. const bool iAspect = true,
  184. const bool iSource = false) :
  185. m_fVisible(iVis),
  186. m_fForceAspectRatio(iAspect),
  187. m_fForceSourceSize(iSource) {
  188. Site(pSite);
  189. }
  190. SurfaceState(const WINDOWPOS *const wp,
  191. const bool iAspect = true,
  192. const bool iSource = false) :
  193. m_fForceAspectRatio(iAspect),
  194. m_fForceSourceSize(iSource) {
  195. ASSERT(!((wp->flags & SWP_SHOWWINDOW) && (wp->flags & SWP_HIDEWINDOW)));
  196. CScalingRect(CPoint(wp->x, wp->y), CSize(wp->cx, wp->cy));
  197. if (wp->flags & SWP_SHOWWINDOW) {
  198. Visible(true);
  199. } else if (wp->flags & SWP_HIDEWINDOW) {
  200. Visible(false);
  201. }
  202. TRACELSM(TRACE_DETAIL, (dbgDump << "SurfaceState::SurfaceState(LPWINDOWPOS) visible = " << m_fVisible), "" );
  203. }
  204. SurfaceState& operator=(const SurfaceState& rhs) {
  205. if (this != &rhs) {
  206. CScalingRect::operator=(rhs);
  207. m_fVisible = rhs.m_fVisible;
  208. m_fForceAspectRatio = rhs.m_fForceAspectRatio;
  209. m_fForceSourceSize = rhs.m_fForceSourceSize;
  210. }
  211. return *this;
  212. }
  213. SurfaceState& operator=(const CScalingRect& rhs) {
  214. if (this != &rhs) {
  215. CScalingRect::operator=(rhs);
  216. }
  217. return *this;
  218. }
  219. SurfaceState& operator=(const CRect& rhs) {
  220. if (this != &rhs) {
  221. CScalingRect::operator=(rhs);
  222. }
  223. return *this;
  224. }
  225. bool operator==(const SurfaceState& rhs) const {
  226. return CRect::operator==(rhs) &&
  227. rhs.m_fVisible == m_fVisible &&
  228. rhs.m_fForceAspectRatio == m_fForceAspectRatio &&
  229. rhs.m_fForceSourceSize == m_fForceSourceSize;
  230. }
  231. bool operator !=(const SurfaceState& rhs) const {
  232. return !operator==(rhs);
  233. }
  234. bool operator==(const CScalingRect& rhs) const {
  235. return CScalingRect::operator==(rhs);
  236. }
  237. bool operator !=(const CScalingRect& rhs) const {
  238. return !operator==(rhs);
  239. }
  240. AspectRatio Aspect() const {
  241. return AspectRatio(*this);
  242. }
  243. bool Round(const AspectRatio& ar) {
  244. bool fChanged = false;
  245. // at some point we probably want to round the current rectangle to the
  246. // nearest rectangle that has the specified aspect ratio
  247. // i.e. minimize total areal change
  248. // if we ever round we should take the monitor size into consideration
  249. // i.e if we decide to round up and we go off the monitor in either direction
  250. // then round down instead.
  251. // for now we're choosing the next size down for ease of coding
  252. // try narrower first
  253. TRACELSM(TRACE_PAINT, (dbgDump << "SurfaceState::Round() ar = " << ar << "this = " << *this), "");
  254. NormalizeRect();
  255. // adjust height and width to nearest multiple of x, y to avoid fractional pixel problems
  256. ASSERT(ar.X() && ar.Y());
  257. if (Width() % ar.X()) {
  258. right -= Width() % ar.X();
  259. TRACELSM(TRACE_PAINT, (dbgDump << "SurfaceState::Round() right adjusted to multiple = " << bottom), "");
  260. fChanged = true;
  261. }
  262. if (Height() % ar.Y()) {
  263. bottom -= Height() % ar.Y();
  264. TRACELSM(TRACE_PAINT, (dbgDump << "SurfaceState::Round() bottom adjusted to multiple = " << bottom), "");
  265. fChanged = true;
  266. }
  267. // force very small rectangles to minimum size;
  268. if (Width() < MIN_RECT_WIDTH) {
  269. right = left + ar.X();
  270. fChanged = true;
  271. TRACELSM(TRACE_PAINT, (dbgDump << "SurfaceState::Round() forcing min width = " << Width()), "");
  272. }
  273. if (Height() < MIN_RECT_HEIGHT) {
  274. bottom = top + ar.Y();
  275. fChanged = true;
  276. TRACELSM(TRACE_PAINT, (dbgDump << "SurfaceState::Round() forcing min height = " << Height()), "");
  277. }
  278. TRACELSM(TRACE_PAINT, (dbgDump << "SurfaceState::Round() this = " << *this), "");
  279. if (AspectRatio(this) != ar) {
  280. TRACELSM(TRACE_PAINT, (dbgDump << "SurfaceState::Round() ar(this) x = " << AspectRatio(this).X()
  281. << " y = " << AspectRatio(this).Y()), "");
  282. TRACELSM(TRACE_PAINT, (dbgDump << "SurfaceState::Round() terms w = " << Width()
  283. << " ratio w = " << ((ar.X() * Height()) / ar.Y())), "");
  284. long delta = Width();
  285. delta -= ((ar.X() * Height()) / ar.Y());
  286. TRACELSM(TRACE_PAINT, (dbgDump << "SurfaceState::Round() delta = " << delta), "");
  287. if (delta > 0) {
  288. // too wide
  289. ASSERT( ((Height() / ar.Y()) * ar.Y()) == Height());
  290. right -= delta / 2; // distribute adjustment evenly on both sides
  291. left += delta / 2; // shift so that adjustment is distributed evenly on both sides
  292. if (delta & 1) {
  293. --right; // if delta is odd distribute the extra on the right
  294. }
  295. TRACELSM(TRACE_PAINT, (dbgDump << "SurfaceState::Round() was too wide, now this = " << *this), "");
  296. } else {
  297. // too tall
  298. delta = Height();
  299. delta -= ((ar.Y() * Width()) / ar.X());
  300. TRACELSM(TRACE_PAINT, (dbgDump << "SurfaceState::Round() too tall, now delta = " << delta), "");
  301. ASSERT(delta > 0);
  302. ASSERT( ((Width() / ar.X()) * ar.X()) == Width());
  303. //bottom = (Width() / ar.X()) * ar.Y() + top;
  304. bottom -= (delta >> 1);
  305. top += (delta >> 1); // apply half of adjustment on each side
  306. if (delta & 1) {
  307. --bottom; // if delta is odd distribute the extra on the bottom
  308. }
  309. TRACELSM(TRACE_PAINT, (dbgDump << "SurfaceState::Round() was too tall, now this = " << *this), "");
  310. }
  311. fChanged = true;
  312. }
  313. TRACELSM(TRACE_PAINT, (dbgDump << "SurfaceState::Round() complete, this = " << *this << " ar.x = " << AspectRatio(this).X() << " ar.y = " << AspectRatio(this).Y()), "");
  314. ASSERT(AspectRatio(this) == ar);
  315. return fChanged;
  316. }
  317. bool IsVisible() const { return m_fVisible; }
  318. void Visible(const bool fVal) {
  319. if (m_fVisible != fVal) {
  320. m_fVisible = fVal;
  321. m_bRequiresSave = true;
  322. }
  323. }
  324. bool ForceAspectRatio() const { return m_fForceAspectRatio; }
  325. void ForceAspectRatio(const bool fVal) {
  326. if (m_fForceAspectRatio != fVal) {
  327. m_fForceAspectRatio = fVal;
  328. m_bRequiresSave = true;
  329. }
  330. }
  331. bool ForceSourceSize() const { return m_fForceSourceSize; }
  332. void ForceSourceSize(const bool fVal) {
  333. if (m_fForceSourceSize != fVal) {
  334. m_fForceSourceSize = fVal;
  335. m_bRequiresSave = true;
  336. }
  337. }
  338. void WindowPos(const WINDOWPOS *const wp) {
  339. ASSERT(!((wp->flags & SWP_SHOWWINDOW) && (wp->flags & SWP_HIDEWINDOW)));
  340. HWND parent = ::GetParent(Owner());
  341. CScalingRect newpos(CPoint(wp->x, wp->y), CSize(wp->cx, wp->cy), parent);
  342. operator=(newpos);
  343. if (wp->flags & SWP_SHOWWINDOW) {
  344. Visible(true);
  345. } else if (wp->flags & SWP_HIDEWINDOW) {
  346. Visible(false);
  347. }
  348. TRACELSM(TRACE_DETAIL, (dbgDump << "SurfaceState::SurfaceState(LPWINDOWPOS) visible = " << m_fVisible), "" );
  349. }
  350. PQSiteWindowless Site() const { return m_pSiteWndless; }
  351. void Site(const PQSiteWindowless& pSite) {
  352. PQFrame pFrame;
  353. PQUIWin pDoc;
  354. // go ahead and reprocess even if site pointer matches existing site because the context may have changed and need
  355. // to be refreshed(for example we've been deactived and are being reactivated in a different size by the same site
  356. #if 0
  357. if (m_pSiteWndless.IsEqualObject(static_cast<IUnknown*>(pSite.p))) {
  358. return;
  359. }
  360. #endif
  361. m_pSiteWndless = static_cast<IUnknown*>(pSite.p); // this forces the correct re-QI since atl improperly casts and overloads its pointer
  362. if (m_pSiteWndless) {
  363. CRect rc;
  364. CRect clip;
  365. OLEINPLACEFRAMEINFO frameInfo;
  366. // for some stupid reason none of these parms can be NULL, even if we don't care about them
  367. HRESULT hr = m_pSiteWndless->GetWindowContext(&pFrame, &pDoc, &rc, &clip, &frameInfo);
  368. if (FAILED(hr)) {
  369. TRACELM(TRACE_ERROR, "SurfaceState::operator=(InPlaceSite*) can't get window context with frame");
  370. THROWCOM(hr);
  371. }
  372. CRect SiteRect;
  373. SiteRect.IntersectRect(&rc, &clip);
  374. HWND hOwner;
  375. // get container window
  376. hr = m_pSiteWndless->GetWindow(&hOwner);
  377. if (FAILED(hr)) {
  378. hr = pDoc->GetWindow(&hOwner);
  379. if (FAILED(hr)) {
  380. TRACELM(TRACE_DETAIL, "SurfaceState::operator=(InPlaceSite*) can't get doc Owner");
  381. hr = pFrame->GetWindow(&hOwner);
  382. if (FAILED(hr)) {
  383. THROWCOM(hr);
  384. }
  385. }
  386. }
  387. ASSERT(::IsWindow(hOwner));
  388. Owner(hOwner);
  389. *this = SiteRect;
  390. TRACELSM(TRACE_PAINT, (dbgDump << "SurfaceState::Site(InPlaceSite*) new rect = " << *this), "");
  391. } else {
  392. *this = CScalingRect(0, 0, 0, 0, INVALID_HWND);
  393. }
  394. return;
  395. }
  396. // translate a point relative to the owner window to a point relative to the rectangle
  397. // for this surface
  398. CPoint XlateOwnerPointToSurfacePoint(CPoint &p) {
  399. TRACELSM(TRACE_PAINT, (dbgDump << "SurfaceState::Xlate p = " << p.x << ", " << p.y), "");
  400. CPoint retp(p);
  401. retp.x -= left;
  402. retp.y -= top;
  403. TRACELSM(TRACE_PAINT, (dbgDump << "SurfaceState::Xlate retp = " << retp.x << ", " << retp.y << " this " << *this), "");
  404. return retp;
  405. }
  406. private:
  407. bool m_fVisible;
  408. bool m_fForceAspectRatio;
  409. bool m_fForceSourceSize;
  410. PQSiteWindowless m_pSiteWndless;
  411. };
  412. #endif
  413. // end of file surface.h