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.

666 lines
20 KiB

  1. //------------------------------------------------------------------------------
  2. // zorder.cpp
  3. // Copyright (c)1997-1999 Microsoft Corporation, All Rights Reserved
  4. //
  5. // Author
  6. // V-BMohan
  7. //
  8. // History
  9. // 8-15-97 created (ThomasOl)
  10. // 10-31-97 rewritten (V-BMohan)
  11. //
  12. //
  13. //------------------------------------------------------------------------------
  14. #include "stdafx.h"
  15. #include <stdlib.h>
  16. //#include "mfcincl.h"
  17. #include "triedit.h"
  18. #include "document.h"
  19. #include "zorder.h"
  20. #include "dispatch.h"
  21. ///////////////////////////////////////////////////////////////////////////////
  22. //
  23. // CTriEditDocument::CompareProc
  24. //
  25. // Compare the Z-order of the two items (which must be CZOrder pointers)
  26. // and return:
  27. //
  28. // -1 if the Z-order of item 1 preceeds that of item 2
  29. // 1 if the Z-order of item 1 succeeds or is the same as that of item 2
  30. //
  31. int CTriEditDocument::CompareProc(const void *arg1, const void *arg2)
  32. {
  33. CZOrder* pcz1 = (CZOrder*)arg1;
  34. CZOrder* pcz2 = (CZOrder*)arg2;
  35. _ASSERTE(pcz1 != NULL);
  36. _ASSERTE(pcz2 != NULL);
  37. if (pcz1->m_zOrder < pcz2->m_zOrder)
  38. return -1;
  39. else
  40. if (pcz1->m_zOrder > pcz2->m_zOrder)
  41. return 1;
  42. // if arg1's Z-order is qual to arg2's zorder then return a one
  43. // instead of a zero so that the qsort function treats it as
  44. // arg1's Z-Order > arg2's Z-order and keeps arg1 in top of the
  45. // sort order.
  46. //
  47. // This actually helps us to sort elements in such a way that among
  48. // the elements having the same Z-order the recently created one will be
  49. // in top of the order. This way we make sure that when propagating
  50. // Z-order it doesn't affect the existing Z-order appearance of the
  51. // elements.
  52. return 1;
  53. }
  54. ///////////////////////////////////////////////////////////////////////////////
  55. //
  56. // CTriEditDocument::IsEqualZIndex
  57. //
  58. // Given a sorted array of CZorder objects and the number of elements
  59. // in the array, return TRUE if any two consecutive objects have the
  60. // same Z-order. Return FALSE if this is not the case.
  61. //
  62. BOOL CTriEditDocument::IsEqualZIndex(CZOrder* pczOrder, LONG lIndex)
  63. {
  64. for (LONG lLoop = 0; lLoop < (lIndex - 1); ++lLoop)
  65. {
  66. if (pczOrder[lLoop].m_zOrder == pczOrder[lLoop+1].m_zOrder)
  67. return TRUE;
  68. }
  69. return FALSE;
  70. }
  71. ///////////////////////////////////////////////////////////////////////////////
  72. //
  73. // CTriEditDocument::GetZIndex
  74. //
  75. // Fetch the Z-order value from the given HTML element and return
  76. // it under *plZindex. Return S_OK or a Trident error.
  77. //
  78. HRESULT CTriEditDocument::GetZIndex(IHTMLElement* pihtmlElement, LONG* plZindex)
  79. {
  80. HRESULT hr;
  81. IHTMLStyle* pihtmlStyle=NULL;
  82. VARIANT var;
  83. _ASSERTE(pihtmlElement);
  84. _ASSERTE(plZindex);
  85. hr = pihtmlElement->get_style(&pihtmlStyle);
  86. _ASSERTE(SUCCEEDED(hr));
  87. _ASSERTE(pihtmlStyle);
  88. if (SUCCEEDED(hr) && pihtmlStyle)
  89. {
  90. VariantInit(&var);
  91. hr = pihtmlStyle->get_zIndex(&var);
  92. hr = VariantChangeType(&var, &var, 0, VT_I4);
  93. if (SUCCEEDED(hr))
  94. {
  95. *plZindex = var.lVal;
  96. }
  97. }
  98. SAFERELEASE(pihtmlStyle);
  99. return hr;
  100. }
  101. ///////////////////////////////////////////////////////////////////////////////
  102. //
  103. // CTriEditDocument::SetZIndex
  104. //
  105. // Set the Z-order of the given HTML element as indicated. Return S_OK
  106. // or a Trident error.
  107. //
  108. HRESULT CTriEditDocument::SetZIndex(IHTMLElement* pihtmlElement, LONG lZindex)
  109. {
  110. HRESULT hr;
  111. IHTMLStyle* pihtmlStyle=NULL;
  112. VARIANT var;
  113. _ASSERTE(pihtmlElement);
  114. hr = pihtmlElement->get_style(&pihtmlStyle);
  115. _ASSERTE(SUCCEEDED(hr));
  116. _ASSERTE(pihtmlStyle);
  117. if (SUCCEEDED(hr) && pihtmlStyle)
  118. {
  119. VariantInit(&var);
  120. var.vt = VT_I4;
  121. var.lVal = lZindex;
  122. hr = pihtmlStyle->put_zIndex(var);
  123. _ASSERTE(SUCCEEDED(hr));
  124. }
  125. SAFERELEASE(pihtmlStyle);
  126. return hr;
  127. }
  128. ///////////////////////////////////////////////////////////////////////////////
  129. //
  130. // CTriEditDocument::AssignZIndex
  131. //
  132. // Set the Z-order of the given HTML element according to the index mode:
  133. //
  134. // SEND_BACKWARD
  135. // SEND_FORWARD
  136. // SEND_TO_BACK
  137. // SEND_TO_FRONT
  138. // SEND_BEHIND_1D
  139. // SEND_FRONT_1D
  140. // MADE_ABSOLUTE
  141. //
  142. // The Z-order of the element's sibling will be adjusted as necessary
  143. // in order to keep them unique. Returns S_OK or a Trident error.
  144. //
  145. HRESULT CTriEditDocument::AssignZIndex(IHTMLElement* pihtmlElement, int nZIndexMode)
  146. {
  147. HRESULT hr = E_FAIL;
  148. IHTMLElementCollection* pihtmlCollection = NULL;
  149. IHTMLElement* pihtmlElementTemp = NULL;
  150. IHTMLElement* pihtmlElementParent = NULL;
  151. LONG iIndex, lLoop;
  152. LONG lZindex = 0;
  153. LONG lSourceIndexTemp, lSourceIndexElement, lSourceIndexParent;
  154. LONG cElements = 0;
  155. BOOL f2d = FALSE;
  156. BOOL f2dCapable = FALSE;
  157. BOOL fZeroIndex = FALSE;
  158. BOOL fSorted = FALSE;
  159. BOOL fZIndexNegative = FALSE; // FALSE means we need to deal with
  160. // elements having +ve Z-INDEX and
  161. // vice versa.
  162. CZOrder* pczOrder=NULL;
  163. _ASSERTE(pihtmlElement);
  164. if ( !pihtmlElement)
  165. {
  166. return E_FAIL;
  167. }
  168. hr = pihtmlElement->get_offsetParent(&pihtmlElementParent);
  169. if (FAILED(hr) || !pihtmlElementParent)
  170. {
  171. return E_FAIL;
  172. }
  173. // we get the source index of the passed element's parent to
  174. // be used in the following for loop to identify the elements
  175. // belonging to this parent.
  176. hr = pihtmlElementParent->get_sourceIndex(&lSourceIndexParent);
  177. SAFERELEASE(pihtmlElementParent);
  178. _ASSERTE(SUCCEEDED(hr) && (lSourceIndexParent != -1));
  179. if (FAILED(hr) || (lSourceIndexParent == -1))
  180. {
  181. return E_FAIL;
  182. }
  183. // we get the source index of the element to be used in the
  184. // following for loop to identify the current element in
  185. // the collection.
  186. hr = pihtmlElement->get_sourceIndex(&lSourceIndexElement);
  187. _ASSERTE(SUCCEEDED(hr) && (lSourceIndexElement != -1));
  188. if (FAILED(hr) || (lSourceIndexElement == -1))
  189. {
  190. return E_FAIL;
  191. }
  192. hr = GetZIndex(pihtmlElement, &lZindex);
  193. _ASSERTE(SUCCEEDED(hr));
  194. if (FAILED(hr))
  195. {
  196. return E_FAIL;
  197. }
  198. if (lZindex < 0)
  199. {
  200. if (nZIndexMode == SEND_BEHIND_1D) // If Z-order is negative then
  201. // its already behind 1D.
  202. { // hence return.
  203. return S_OK;
  204. }
  205. else if(nZIndexMode != SEND_FRONT_1D)
  206. {
  207. fZIndexNegative = TRUE; // If the passed element has negative
  208. // Z-order and if mode is anything
  209. } // other than send front then we
  210. // need to deal only with negative
  211. // elements.
  212. }
  213. else
  214. {
  215. if (nZIndexMode == SEND_FRONT_1D) // If Z-order is positive then
  216. // its already in front of 1D
  217. { // hence return.
  218. if (lZindex > 0)
  219. return S_OK;
  220. }
  221. else if(nZIndexMode == SEND_BEHIND_1D)
  222. {
  223. fZIndexNegative = TRUE; // If the passed element has positive
  224. // Z-order and if mode is send behind
  225. } // then we need to deal only with
  226. // negative elements.
  227. }
  228. hr = GetAllCollection(&pihtmlCollection);
  229. _ASSERTE(SUCCEEDED(hr));
  230. _ASSERTE(pihtmlCollection);
  231. if (FAILED(hr) || !pihtmlCollection) // If we dont have a collection
  232. // then exit
  233. {
  234. hr = E_FAIL;
  235. goto Cleanup;
  236. }
  237. hr = pihtmlCollection->get_length(&cElements); // Get number of elements
  238. // in the collection
  239. _ASSERTE(SUCCEEDED(hr));
  240. _ASSERTE(cElements > 0);
  241. if ( FAILED(hr) || cElements <= 0 )
  242. {
  243. hr = E_FAIL;
  244. goto Cleanup;
  245. }
  246. pczOrder = new CZOrder[cElements]; // Allocate an array of CZOrder
  247. // big enough for all
  248. if (!pczOrder)
  249. {
  250. hr = E_FAIL;
  251. goto Cleanup;
  252. }
  253. // Now we collect all elements which are children of the parent of
  254. // the element passed to this function, including the passed element
  255. // itself.
  256. for (lLoop=0, iIndex=0; lLoop < cElements; lLoop++)
  257. {
  258. hr = GetCollectionElement(pihtmlCollection, lLoop, &pihtmlElementTemp);
  259. _ASSERTE(SUCCEEDED(hr));
  260. _ASSERTE(pihtmlElementTemp);
  261. if (FAILED(hr) || !pihtmlElementTemp)
  262. {
  263. hr = E_FAIL;
  264. goto Cleanup;
  265. }
  266. hr = Is2DCapable(pihtmlElementTemp, &f2dCapable);
  267. if (FAILED(hr))
  268. goto Cleanup;
  269. if (f2dCapable)
  270. {
  271. hr = Is2DElement(pihtmlElementTemp, &f2d);
  272. if (FAILED(hr))
  273. goto Cleanup;
  274. if (f2d) // If the element is a 2D element
  275. {
  276. hr = pihtmlElementTemp->get_offsetParent(&pihtmlElementParent);
  277. _ASSERTE(SUCCEEDED(hr));
  278. _ASSERTE(pihtmlElementParent);
  279. if (FAILED(hr) || !pihtmlElementParent)
  280. goto Cleanup;
  281. hr = pihtmlElementParent->get_sourceIndex(&lSourceIndexTemp);
  282. SAFERELEASE(pihtmlElementParent);
  283. _ASSERTE(SUCCEEDED(hr) && lSourceIndexElement != -1);
  284. if (FAILED(hr) || (lSourceIndexTemp == -1))
  285. {
  286. hr = E_FAIL;
  287. goto Cleanup;
  288. }
  289. // Is it a child of the same parent as that of the
  290. // parent of the element passed to this function?
  291. if (lSourceIndexTemp == lSourceIndexParent)
  292. {
  293. hr = GetZIndex(pihtmlElementTemp, &lZindex);
  294. _ASSERTE(SUCCEEDED(hr));
  295. if (FAILED(hr))
  296. goto Cleanup;
  297. if (lZindex == 0)
  298. {
  299. hr = pihtmlElementTemp->get_sourceIndex(&lSourceIndexTemp);
  300. if (FAILED(hr) || (lSourceIndexTemp == -1))
  301. {
  302. hr = E_FAIL;
  303. goto Cleanup;
  304. }
  305. // General scenario is that we set fZeroIndex to
  306. // TRUE when we encounter a child with no Z-order
  307. // index.
  308. //
  309. // So that after we have collected all the children
  310. // we could assign Z-order to all the children.
  311. //
  312. // However, when this function is called after
  313. // making a 2D element we need to ensure that we
  314. // don't set fZeroIndex to TRUE when the current
  315. // child is the one which is made absolute, hence
  316. // the following check.
  317. if (!((lSourceIndexTemp == lSourceIndexElement) &&
  318. (nZIndexMode == MADE_ABSOLUTE)))
  319. fZeroIndex = TRUE;
  320. }
  321. if (fZIndexNegative)
  322. {
  323. if (lZindex < 0) // Collect only children with
  324. // negative Z-order index.
  325. {
  326. CZOrder z(pihtmlElementTemp, lZindex);
  327. pczOrder[iIndex++] = z;
  328. }
  329. }
  330. else
  331. {
  332. if (lZindex >= 0) // collect only children with
  333. // positive or no Z-order index.
  334. {
  335. CZOrder z(pihtmlElementTemp, lZindex);
  336. pczOrder[iIndex++] = z;
  337. }
  338. }
  339. }
  340. }
  341. }
  342. SAFERELEASE(pihtmlElementTemp);
  343. }
  344. // If we have at least one child with no Z-order index and if we are
  345. // dealing with an element with a positive Z-order index, then we
  346. // assign new Z-order indexes to all the children collected above.
  347. if (fZeroIndex && !fZIndexNegative)
  348. {
  349. LONG lZOrder = ZINDEX_BASE;
  350. for ( lLoop = 0; lLoop < iIndex; lLoop++, lZOrder++)
  351. {
  352. if (pczOrder[lLoop].m_zOrder != 0)
  353. {
  354. // Maintain the existing Z-order index
  355. pczOrder[lLoop].m_zOrder += (iIndex+ZINDEX_BASE);
  356. }
  357. else
  358. {
  359. pczOrder[lLoop].m_zOrder += lZOrder;
  360. }
  361. }
  362. if (iIndex > 1)
  363. {
  364. // Wwe have at least two children; sort by Zorder index,
  365. // and propagate starting from ZINDEX_BASE.
  366. qsort( (LPVOID)pczOrder, iIndex, sizeof(CZOrder), CompareProc);
  367. hr = PropagateZIndex(pczOrder, iIndex);
  368. _ASSERTE(SUCCEEDED(hr));
  369. if (FAILED(hr))
  370. goto Cleanup;
  371. fSorted = TRUE;
  372. }
  373. }
  374. // If we have at least two children and not already sorted then sort
  375. // by Z-order index.
  376. if ((iIndex > 1) && !fSorted)
  377. qsort( (LPVOID)pczOrder, iIndex, sizeof(CZOrder), CompareProc);
  378. if (IsEqualZIndex(pczOrder, iIndex))
  379. {
  380. hr = PropagateZIndex(pczOrder, iIndex);
  381. if (FAILED(hr))
  382. goto Cleanup;
  383. }
  384. if ((nZIndexMode == MADE_ABSOLUTE) ||
  385. (nZIndexMode == SEND_TO_FRONT) ||
  386. (nZIndexMode == SEND_BEHIND_1D))
  387. {
  388. LONG lZIndex;
  389. LONG lmaxZIndex = pczOrder[iIndex - 1].m_zOrder;
  390. if (fZIndexNegative)
  391. {
  392. if (iIndex == 0) // If we have no children with negative
  393. // Z-order index.
  394. {
  395. hr = SetZIndex(pihtmlElement, -ZINDEX_BASE);
  396. goto Cleanup;
  397. }
  398. else
  399. {
  400. // when we are dealing with elements with negative Z-order
  401. // we need to ensure that the maximum Z-order index (to be
  402. // assigned to the current element) can never become
  403. // greater than or equal to 0. If so then propagate
  404. // the Z-order index starting from ZINDEX_BASE.
  405. if ((lmaxZIndex + 1) >=0)
  406. {
  407. hr = PropagateZIndex(pczOrder, iIndex, fZIndexNegative);
  408. if (FAILED(hr))
  409. goto Cleanup;
  410. }
  411. lmaxZIndex = pczOrder[iIndex - 1].m_zOrder;
  412. }
  413. }
  414. if(SUCCEEDED(hr = GetZIndex(pihtmlElement, &lZIndex)))
  415. {
  416. if(lZIndex != lmaxZIndex)
  417. {
  418. // The current element is not the top most element
  419. hr = SetZIndex(pihtmlElement, lmaxZIndex+1);
  420. _ASSERTE(SUCCEEDED(hr));
  421. }
  422. else if(lmaxZIndex == 0)
  423. {
  424. // if the current element has no Z-order index
  425. hr = SetZIndex(pihtmlElement, ZINDEX_BASE);
  426. _ASSERTE(SUCCEEDED(hr));
  427. }
  428. }
  429. }
  430. else if ((nZIndexMode == SEND_BACKWARD) || (nZIndexMode == SEND_FORWARD))
  431. {
  432. LONG lPrevOrNextZIndex;
  433. LONG lIndexBuf = iIndex;
  434. hr = GetZIndex(pihtmlElement, &lPrevOrNextZIndex);
  435. if (FAILED(hr))
  436. goto Cleanup;
  437. if (iIndex == 1)
  438. goto Cleanup;
  439. while(--iIndex>=0)
  440. {
  441. if (pczOrder[iIndex].m_zOrder == lPrevOrNextZIndex)
  442. {
  443. if (nZIndexMode == SEND_BACKWARD)
  444. {
  445. if ( (iIndex - 1) < 0)
  446. // The element already has the lowest Z-order index
  447. // so exit.
  448. goto Cleanup;
  449. else
  450. iIndex--;
  451. }
  452. else
  453. {
  454. if ((iIndex + 1) == lIndexBuf)
  455. // The element already has the highest Z-order index
  456. // so exit.
  457. goto Cleanup;
  458. else
  459. iIndex++;
  460. }
  461. hr = SetZIndex(pihtmlElement, pczOrder[iIndex].m_zOrder);
  462. _ASSERTE(SUCCEEDED(hr));
  463. if (FAILED(hr))
  464. goto Cleanup;
  465. hr = SetZIndex(pczOrder[iIndex].m_pihtmlElement, lPrevOrNextZIndex);
  466. _ASSERTE(SUCCEEDED(hr));
  467. if (FAILED(hr))
  468. goto Cleanup;
  469. break;
  470. }
  471. }
  472. }
  473. else if((nZIndexMode == SEND_TO_BACK) || (nZIndexMode == SEND_FRONT_1D))
  474. {
  475. LONG lZIndex;
  476. LONG lminZIndex = pczOrder[0].m_zOrder;
  477. if (iIndex == 0)
  478. {
  479. // We have no children with a positive Z-order index
  480. hr = SetZIndex(pihtmlElement, ZINDEX_BASE);
  481. goto Cleanup;
  482. }
  483. if (!fZIndexNegative)
  484. {
  485. // When we are dealing with elements with positive Z-order
  486. // index, we need to ensure that the minimum Z-order index
  487. // (to be assigned to the current element) should never become
  488. // less than or equal to 0. If so then propagate the
  489. // Z-order index starting from ZINDEX_BASE.
  490. if ((lminZIndex - 1) <= 0)
  491. {
  492. hr = PropagateZIndex(pczOrder, iIndex);
  493. if (FAILED(hr))
  494. goto Cleanup;
  495. }
  496. lminZIndex = pczOrder[0].m_zOrder;
  497. }
  498. if(SUCCEEDED(hr = GetZIndex(pihtmlElement, &lZIndex)))
  499. {
  500. if(lZIndex != lminZIndex)
  501. {
  502. // The current element is not the bottom most element
  503. hr = SetZIndex(pihtmlElement, lminZIndex - 1);
  504. _ASSERTE(SUCCEEDED(hr));
  505. }
  506. }
  507. }
  508. if (SUCCEEDED(hr))
  509. {
  510. RECT rcElement;
  511. if (SUCCEEDED(GetElementPosition(pihtmlElement, &rcElement)))
  512. {
  513. InflateRect(&rcElement, ELEMENT_GRAB_SIZE, ELEMENT_GRAB_SIZE);
  514. if( SUCCEEDED(GetTridentWindow()))
  515. {
  516. _ASSERTE(m_hwndTrident);
  517. InvalidateRect(m_hwndTrident,&rcElement, FALSE);
  518. }
  519. }
  520. }
  521. Cleanup:
  522. if (pczOrder)
  523. delete [] pczOrder;
  524. SAFERELEASE(pihtmlElementTemp);
  525. SAFERELEASE(pihtmlElementParent);
  526. SAFERELEASE(pihtmlCollection);
  527. return hr;
  528. }
  529. ///////////////////////////////////////////////////////////////////////////////
  530. //
  531. // CTriEditDocument::PropagateZIndex
  532. //
  533. // Set the Z-order index for each element in the given array. Return S_OK
  534. // or a Trident error.
  535. //
  536. HRESULT CTriEditDocument::PropagateZIndex(CZOrder* pczOrder, LONG lZIndex, BOOL fZIndexNegative)
  537. {
  538. HRESULT hr = S_OK; // init
  539. LONG lLoop;
  540. LONG lZOrder;
  541. // if fZIndexNegative is true means that we have a collection of
  542. // negative ZOrder elements and hence the initial ZOrder needs to
  543. // be ZINDEX_BASE + number of elments in the array.
  544. lZOrder = fZIndexNegative ? -(ZINDEX_BASE+lZIndex) : ZINDEX_BASE;
  545. for ( lLoop = 0; lLoop < lZIndex; lLoop++, lZOrder+=1)
  546. {
  547. hr = SetZIndex(pczOrder[lLoop].m_pihtmlElement, lZOrder);
  548. _ASSERTE(SUCCEEDED(hr));
  549. if (FAILED(hr))
  550. return hr;
  551. pczOrder[lLoop].m_zOrder = lZOrder;
  552. }
  553. return hr;
  554. }