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

//------------------------------------------------------------------------------
// 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;
}