|
|
//------------------------------------------------------------------------------
// zorder.cpp
// Copyright (c)1997-1999 Microsoft Corporation, All Rights Reserved
//
// Author
// V-BMohan
//
// History
// 8-15-97 created (ThomasOl)
// 10-31-97 rewritten (V-BMohan)
//
//
//------------------------------------------------------------------------------
#include "stdafx.h"
#include <stdlib.h>
//#include "mfcincl.h"
#include "triedit.h"
#include "document.h"
#include "zorder.h"
#include "dispatch.h"
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::CompareProc
//
// Compare the Z-order of the two items (which must be CZOrder pointers)
// and return:
//
// -1 if the Z-order of item 1 preceeds that of item 2
// 1 if the Z-order of item 1 succeeds or is the same as that of item 2
//
int CTriEditDocument::CompareProc(const void *arg1, const void *arg2) { CZOrder* pcz1 = (CZOrder*)arg1; CZOrder* pcz2 = (CZOrder*)arg2;
_ASSERTE(pcz1 != NULL); _ASSERTE(pcz2 != NULL); if (pcz1->m_zOrder < pcz2->m_zOrder) return -1; else if (pcz1->m_zOrder > pcz2->m_zOrder) return 1;
// if arg1's Z-order is qual to arg2's zorder then return a one
// instead of a zero so that the qsort function treats it as
// arg1's Z-Order > arg2's Z-order and keeps arg1 in top of the
// sort order.
//
// This actually helps us to sort elements in such a way that among
// the elements having the same Z-order the recently created one will be
// in top of the order. This way we make sure that when propagating
// Z-order it doesn't affect the existing Z-order appearance of the
// elements.
return 1; }
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::IsEqualZIndex
//
// Given a sorted array of CZorder objects and the number of elements
// in the array, return TRUE if any two consecutive objects have the
// same Z-order. Return FALSE if this is not the case.
//
BOOL CTriEditDocument::IsEqualZIndex(CZOrder* pczOrder, LONG lIndex) { for (LONG lLoop = 0; lLoop < (lIndex - 1); ++lLoop) { if (pczOrder[lLoop].m_zOrder == pczOrder[lLoop+1].m_zOrder) return TRUE; } return FALSE; }
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::GetZIndex
//
// Fetch the Z-order value from the given HTML element and return
// it under *plZindex. Return S_OK or a Trident error.
//
HRESULT CTriEditDocument::GetZIndex(IHTMLElement* pihtmlElement, LONG* plZindex) { HRESULT hr; IHTMLStyle* pihtmlStyle=NULL; VARIANT var;
_ASSERTE(pihtmlElement); _ASSERTE(plZindex); hr = pihtmlElement->get_style(&pihtmlStyle); _ASSERTE(SUCCEEDED(hr)); _ASSERTE(pihtmlStyle);
if (SUCCEEDED(hr) && pihtmlStyle) { VariantInit(&var); hr = pihtmlStyle->get_zIndex(&var); hr = VariantChangeType(&var, &var, 0, VT_I4);
if (SUCCEEDED(hr)) { *plZindex = var.lVal; } }
SAFERELEASE(pihtmlStyle); return hr; }
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::SetZIndex
//
// Set the Z-order of the given HTML element as indicated. Return S_OK
// or a Trident error.
//
HRESULT CTriEditDocument::SetZIndex(IHTMLElement* pihtmlElement, LONG lZindex) { HRESULT hr; IHTMLStyle* pihtmlStyle=NULL; VARIANT var;
_ASSERTE(pihtmlElement); hr = pihtmlElement->get_style(&pihtmlStyle); _ASSERTE(SUCCEEDED(hr)); _ASSERTE(pihtmlStyle);
if (SUCCEEDED(hr) && pihtmlStyle) { VariantInit(&var); var.vt = VT_I4; var.lVal = lZindex; hr = pihtmlStyle->put_zIndex(var); _ASSERTE(SUCCEEDED(hr)); }
SAFERELEASE(pihtmlStyle); return hr; }
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::AssignZIndex
//
// Set the Z-order of the given HTML element according to the index mode:
//
// SEND_BACKWARD
// SEND_FORWARD
// SEND_TO_BACK
// SEND_TO_FRONT
// SEND_BEHIND_1D
// SEND_FRONT_1D
// MADE_ABSOLUTE
//
// The Z-order of the element's sibling will be adjusted as necessary
// in order to keep them unique. Returns S_OK or a Trident error.
//
HRESULT CTriEditDocument::AssignZIndex(IHTMLElement* pihtmlElement, int nZIndexMode) { HRESULT hr = E_FAIL; IHTMLElementCollection* pihtmlCollection = NULL; IHTMLElement* pihtmlElementTemp = NULL; IHTMLElement* pihtmlElementParent = NULL; LONG iIndex, lLoop; LONG lZindex = 0; LONG lSourceIndexTemp, lSourceIndexElement, lSourceIndexParent; LONG cElements = 0; BOOL f2d = FALSE; BOOL f2dCapable = FALSE; BOOL fZeroIndex = FALSE; BOOL fSorted = FALSE; BOOL fZIndexNegative = FALSE; // FALSE means we need to deal with
// elements having +ve Z-INDEX and
// vice versa.
CZOrder* pczOrder=NULL; _ASSERTE(pihtmlElement);
if ( !pihtmlElement) { return E_FAIL; }
hr = pihtmlElement->get_offsetParent(&pihtmlElementParent);
if (FAILED(hr) || !pihtmlElementParent) { return E_FAIL; }
// we get the source index of the passed element's parent to
// be used in the following for loop to identify the elements
// belonging to this parent.
hr = pihtmlElementParent->get_sourceIndex(&lSourceIndexParent); SAFERELEASE(pihtmlElementParent); _ASSERTE(SUCCEEDED(hr) && (lSourceIndexParent != -1)); if (FAILED(hr) || (lSourceIndexParent == -1)) { return E_FAIL; }
// we get the source index of the element to be used in the
// following for loop to identify the current element in
// the collection.
hr = pihtmlElement->get_sourceIndex(&lSourceIndexElement);
_ASSERTE(SUCCEEDED(hr) && (lSourceIndexElement != -1)); if (FAILED(hr) || (lSourceIndexElement == -1)) { return E_FAIL; }
hr = GetZIndex(pihtmlElement, &lZindex); _ASSERTE(SUCCEEDED(hr));
if (FAILED(hr)) { return E_FAIL; }
if (lZindex < 0) { if (nZIndexMode == SEND_BEHIND_1D) // If Z-order is negative then
// its already behind 1D.
{ // hence return.
return S_OK; } else if(nZIndexMode != SEND_FRONT_1D) { fZIndexNegative = TRUE; // If the passed element has negative
// Z-order and if mode is anything
} // other than send front then we
// need to deal only with negative
// elements.
} else { if (nZIndexMode == SEND_FRONT_1D) // If Z-order is positive then
// its already in front of 1D
{ // hence return.
if (lZindex > 0) return S_OK; } else if(nZIndexMode == SEND_BEHIND_1D) { fZIndexNegative = TRUE; // If the passed element has positive
// Z-order and if mode is send behind
} // then we need to deal only with
// negative elements.
}
hr = GetAllCollection(&pihtmlCollection); _ASSERTE(SUCCEEDED(hr)); _ASSERTE(pihtmlCollection);
if (FAILED(hr) || !pihtmlCollection) // If we dont have a collection
// then exit
{ hr = E_FAIL; goto Cleanup; }
hr = pihtmlCollection->get_length(&cElements); // Get number of elements
// in the collection
_ASSERTE(SUCCEEDED(hr)); _ASSERTE(cElements > 0);
if ( FAILED(hr) || cElements <= 0 ) { hr = E_FAIL; goto Cleanup; }
pczOrder = new CZOrder[cElements]; // Allocate an array of CZOrder
// big enough for all
if (!pczOrder) { hr = E_FAIL; goto Cleanup; }
// Now we collect all elements which are children of the parent of
// the element passed to this function, including the passed element
// itself.
for (lLoop=0, iIndex=0; lLoop < cElements; lLoop++) { hr = GetCollectionElement(pihtmlCollection, lLoop, &pihtmlElementTemp); _ASSERTE(SUCCEEDED(hr)); _ASSERTE(pihtmlElementTemp);
if (FAILED(hr) || !pihtmlElementTemp) { hr = E_FAIL; goto Cleanup; }
hr = Is2DCapable(pihtmlElementTemp, &f2dCapable);
if (FAILED(hr)) goto Cleanup;
if (f2dCapable) { hr = Is2DElement(pihtmlElementTemp, &f2d);
if (FAILED(hr)) goto Cleanup;
if (f2d) // If the element is a 2D element
{ hr = pihtmlElementTemp->get_offsetParent(&pihtmlElementParent); _ASSERTE(SUCCEEDED(hr)); _ASSERTE(pihtmlElementParent);
if (FAILED(hr) || !pihtmlElementParent) goto Cleanup;
hr = pihtmlElementParent->get_sourceIndex(&lSourceIndexTemp); SAFERELEASE(pihtmlElementParent); _ASSERTE(SUCCEEDED(hr) && lSourceIndexElement != -1);
if (FAILED(hr) || (lSourceIndexTemp == -1)) { hr = E_FAIL; goto Cleanup; }
// Is it a child of the same parent as that of the
// parent of the element passed to this function?
if (lSourceIndexTemp == lSourceIndexParent) { hr = GetZIndex(pihtmlElementTemp, &lZindex); _ASSERTE(SUCCEEDED(hr));
if (FAILED(hr)) goto Cleanup;
if (lZindex == 0) { hr = pihtmlElementTemp->get_sourceIndex(&lSourceIndexTemp); if (FAILED(hr) || (lSourceIndexTemp == -1)) { hr = E_FAIL; goto Cleanup; }
// General scenario is that we set fZeroIndex to
// TRUE when we encounter a child with no Z-order
// index.
//
// So that after we have collected all the children
// we could assign Z-order to all the children.
//
// However, when this function is called after
// making a 2D element we need to ensure that we
// don't set fZeroIndex to TRUE when the current
// child is the one which is made absolute, hence
// the following check.
if (!((lSourceIndexTemp == lSourceIndexElement) && (nZIndexMode == MADE_ABSOLUTE))) fZeroIndex = TRUE; } if (fZIndexNegative) { if (lZindex < 0) // Collect only children with
// negative Z-order index.
{ CZOrder z(pihtmlElementTemp, lZindex); pczOrder[iIndex++] = z; } } else { if (lZindex >= 0) // collect only children with
// positive or no Z-order index.
{ CZOrder z(pihtmlElementTemp, lZindex); pczOrder[iIndex++] = z; } }
} }
} SAFERELEASE(pihtmlElementTemp); }
// If we have at least one child with no Z-order index and if we are
// dealing with an element with a positive Z-order index, then we
// assign new Z-order indexes to all the children collected above.
if (fZeroIndex && !fZIndexNegative) { LONG lZOrder = ZINDEX_BASE;
for ( lLoop = 0; lLoop < iIndex; lLoop++, lZOrder++) { if (pczOrder[lLoop].m_zOrder != 0) { // Maintain the existing Z-order index
pczOrder[lLoop].m_zOrder += (iIndex+ZINDEX_BASE); } else { pczOrder[lLoop].m_zOrder += lZOrder; } } if (iIndex > 1) { // Wwe have at least two children; sort by Zorder index,
// and propagate starting from ZINDEX_BASE.
qsort( (LPVOID)pczOrder, iIndex, sizeof(CZOrder), CompareProc); hr = PropagateZIndex(pczOrder, iIndex); _ASSERTE(SUCCEEDED(hr));
if (FAILED(hr)) goto Cleanup; fSorted = TRUE; }
}
// If we have at least two children and not already sorted then sort
// by Z-order index.
if ((iIndex > 1) && !fSorted) qsort( (LPVOID)pczOrder, iIndex, sizeof(CZOrder), CompareProc);
if (IsEqualZIndex(pczOrder, iIndex)) { hr = PropagateZIndex(pczOrder, iIndex); if (FAILED(hr)) goto Cleanup; }
if ((nZIndexMode == MADE_ABSOLUTE) || (nZIndexMode == SEND_TO_FRONT) || (nZIndexMode == SEND_BEHIND_1D)) { LONG lZIndex; LONG lmaxZIndex = pczOrder[iIndex - 1].m_zOrder;
if (fZIndexNegative) { if (iIndex == 0) // If we have no children with negative
// Z-order index.
{ hr = SetZIndex(pihtmlElement, -ZINDEX_BASE); goto Cleanup; } else { // when we are dealing with elements with negative Z-order
// we need to ensure that the maximum Z-order index (to be
// assigned to the current element) can never become
// greater than or equal to 0. If so then propagate
// the Z-order index starting from ZINDEX_BASE.
if ((lmaxZIndex + 1) >=0) { hr = PropagateZIndex(pczOrder, iIndex, fZIndexNegative);
if (FAILED(hr)) goto Cleanup; } lmaxZIndex = pczOrder[iIndex - 1].m_zOrder; } }
if(SUCCEEDED(hr = GetZIndex(pihtmlElement, &lZIndex))) { if(lZIndex != lmaxZIndex) { // The current element is not the top most element
hr = SetZIndex(pihtmlElement, lmaxZIndex+1); _ASSERTE(SUCCEEDED(hr)); } else if(lmaxZIndex == 0) { // if the current element has no Z-order index
hr = SetZIndex(pihtmlElement, ZINDEX_BASE); _ASSERTE(SUCCEEDED(hr)); } } } else if ((nZIndexMode == SEND_BACKWARD) || (nZIndexMode == SEND_FORWARD)) { LONG lPrevOrNextZIndex; LONG lIndexBuf = iIndex;
hr = GetZIndex(pihtmlElement, &lPrevOrNextZIndex); if (FAILED(hr)) goto Cleanup;
if (iIndex == 1) goto Cleanup; while(--iIndex>=0) { if (pczOrder[iIndex].m_zOrder == lPrevOrNextZIndex) { if (nZIndexMode == SEND_BACKWARD) { if ( (iIndex - 1) < 0) // The element already has the lowest Z-order index
// so exit.
goto Cleanup; else iIndex--; } else { if ((iIndex + 1) == lIndexBuf) // The element already has the highest Z-order index
// so exit.
goto Cleanup; else iIndex++; }
hr = SetZIndex(pihtmlElement, pczOrder[iIndex].m_zOrder); _ASSERTE(SUCCEEDED(hr)); if (FAILED(hr)) goto Cleanup; hr = SetZIndex(pczOrder[iIndex].m_pihtmlElement, lPrevOrNextZIndex); _ASSERTE(SUCCEEDED(hr)); if (FAILED(hr)) goto Cleanup;
break; }
}
} else if((nZIndexMode == SEND_TO_BACK) || (nZIndexMode == SEND_FRONT_1D)) { LONG lZIndex; LONG lminZIndex = pczOrder[0].m_zOrder;
if (iIndex == 0) { // We have no children with a positive Z-order index
hr = SetZIndex(pihtmlElement, ZINDEX_BASE); goto Cleanup; }
if (!fZIndexNegative) { // When we are dealing with elements with positive Z-order
// index, we need to ensure that the minimum Z-order index
// (to be assigned to the current element) should never become
// less than or equal to 0. If so then propagate the
// Z-order index starting from ZINDEX_BASE.
if ((lminZIndex - 1) <= 0) { hr = PropagateZIndex(pczOrder, iIndex); if (FAILED(hr)) goto Cleanup; }
lminZIndex = pczOrder[0].m_zOrder; }
if(SUCCEEDED(hr = GetZIndex(pihtmlElement, &lZIndex))) { if(lZIndex != lminZIndex) { // The current element is not the bottom most element
hr = SetZIndex(pihtmlElement, lminZIndex - 1); _ASSERTE(SUCCEEDED(hr)); } } } if (SUCCEEDED(hr)) { RECT rcElement;
if (SUCCEEDED(GetElementPosition(pihtmlElement, &rcElement))) { InflateRect(&rcElement, ELEMENT_GRAB_SIZE, ELEMENT_GRAB_SIZE); if( SUCCEEDED(GetTridentWindow())) { _ASSERTE(m_hwndTrident); InvalidateRect(m_hwndTrident,&rcElement, FALSE); } } } Cleanup:
if (pczOrder) delete [] pczOrder; SAFERELEASE(pihtmlElementTemp); SAFERELEASE(pihtmlElementParent); SAFERELEASE(pihtmlCollection);
return hr; }
///////////////////////////////////////////////////////////////////////////////
//
// CTriEditDocument::PropagateZIndex
//
// Set the Z-order index for each element in the given array. Return S_OK
// or a Trident error.
//
HRESULT CTriEditDocument::PropagateZIndex(CZOrder* pczOrder, LONG lZIndex, BOOL fZIndexNegative) { HRESULT hr = S_OK; // init
LONG lLoop; LONG lZOrder;
// if fZIndexNegative is true means that we have a collection of
// negative ZOrder elements and hence the initial ZOrder needs to
// be ZINDEX_BASE + number of elments in the array.
lZOrder = fZIndexNegative ? -(ZINDEX_BASE+lZIndex) : ZINDEX_BASE;
for ( lLoop = 0; lLoop < lZIndex; lLoop++, lZOrder+=1) { hr = SetZIndex(pczOrder[lLoop].m_pihtmlElement, lZOrder); _ASSERTE(SUCCEEDED(hr)); if (FAILED(hr)) return hr;
pczOrder[lLoop].m_zOrder = lZOrder; }
return hr; }
|