/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: sm1doc.cpp,v 1.3.12.2 2004/07/26 19:52:31 milko Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

#include <stdio.h>
#include <math.h>

#include "hxtypes.h"
#include "hxwintyp.h"
#include "chxxtype.h"
#include "smil1typ.h"   /* renamed for SHAZAM; used to be smiltype.h */
#include "hxcom.h"
#include "hxcomm.h"
#include "ihxpckts.h"
#include "hxfiles.h"
#include "hxcore.h"
#include "hxprefs.h"
#include "hxrendr.h"
#include "hxasm.h"
#include "hxplugn.h"
#include "hxengin.h"
#include "hxcore.h"
#include "hxclsnk.h"
#include "hxwin.h"
#include "hxsite2.h"
#include "hxsrc.h"
#include "hxgroup.h"
#include "hxrendr.h"
#include "hxevent.h"
#include "hxvsurf.h"
#include "hxerror.h"
#include "hxupgrd.h"
#include "hxvsurf.h"
#include "hxhyper.h"
#include "hxxres.h"
#include "hxxrsmg.h"
#include "hxsm2sm.h"

#include "hxxml.h"
#include "hxxmlprs.h"
#include "xmlreslt.h"

#include "hxstack.h"
#include "hxslist.h"
#include "chxpckts.h"
#include "hxstring.h"
#include "hxurl.h"
#include "hxmap.h"
#include "hxstrutl.h"
#include "errdbg.h"
#include "hxordval.h"	// CHXOrderedValues

#if defined(_WINDOWS)
#include "diballoc.h"
#define IDC_HANDCURSOR 102
#elif defined (_MACINTOSH)
#include "hxmm.h"
#include "cresload.h"
extern FSSpec g_DLLFSpec;
#endif

#if defined(_UNIX)  &&  (!defined(_BEOS))  &&  defined(USE_XWINDOWS)
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
/* USE_SHM doesn't work yet */
#ifdef USE_SHM
#undef USE_SHM
#endif /* USE_SHM */
#endif

#include "sm1elem.h"
#include "sm1parse.h"
#include "sm1error.h"
#include "smilres.h"
#include "smlrendr.h" /* for SMIL2+ renderer (CSmilRenderer) */
#include "sm1rendr.h"

#include "sm1doc.h"

#include "debugout.h" // XXXMEH
#include "hxtick.h"   // XXXMEH
#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE
static const char HX_THIS_FILE[] = __FILE__;
#endif

#ifdef _DEBUG
#ifdef _WINDOWS
static const char SMILDEPFILE[] = "\\smildep.txt";
#else
static const char SMILDEPFILE[] = "smildep.txt";
#endif
#endif

#ifdef _WINDOWS
extern HINSTANCE g_hInstance;
#endif

#ifdef _DEBUG
#define MAX_DEBUG_STRING 20000
#define SDEBUG_OUT(x, y)	{						\
			    char* s;					\
			    FILE* f1;					\
			    s = new char[MAX_DEBUG_STRING];					\
			    sprintf y;					\
			    f1 = (x)?(::fopen(x, "a+")):(NULL);			\
			    (f1)?(::fprintf(f1, s), ::fclose(f1)):(0);	\
			    delete[] s; \
		       }
#else
#define SDEBUG_OUT(x, y)
#endif

#define SDEBUG_FILE 0//"e:\\temp\\smilout.txt"

//
// site information - used
// to handle site show/hide
// behavior in seek and hyperlinking
//
struct SMIL1SiteInfo
{
    IHXSite* m_pRendererSite;
    IHXSite* m_pRegionSite;
    HXxSize m_rendererSize;
    UINT16 m_uGroupIndex;
    UINT32 m_ulDelay;
    UINT32 m_ulDuration;
    BOOL m_bRemoveSite;
    BOOL m_bNoRegion;
    CHXString m_regionID;
    IHXRenderer* m_pRenderer;
};

// source information - contained
// in SMIL1PlayToAssoc.m_sourceMap
struct SMIL1SourceInfo
{
    IUnknown* m_pStream;
    IHXRenderer* m_pRenderer;
    CHXString m_tunerName;
    CHXString m_childTunerName;
    CSmil1EventHook* m_pRendererEventHook;
    UINT32 m_ulDuration;
    UINT32 m_ulDelay;
};

//
// struct that associates group,track,and playto property of a stream
//
struct SMIL1PlayToAssoc
{
    UINT16 m_uGroupIndex;
    UINT16 m_uTrackIndex;
    BOOL m_bDurationResolved;
    CHXMapLongToObj m_sourceMap;
    CHXString m_playTo;
    CHXString m_id;
    CHXString m_repeatid;
    CHXString m_tunerName;
    CHXString m_childTunerName;
    CHXString m_regionName;
    UINT32 m_ulDelay;
    UINT32 m_ulDuration;
    BOOL m_bRemoveSite;
    CHXSimpleList* m_pHyperlinks;
    CSmil1EventHook* m_pRendererEventHook;
    CHXSimpleList* m_pSiteInfoList;
    BOOL m_bLiveSource;
};

//
// group information
//
struct SMIL1GroupInfo
{
    int m_nTracks;
    int m_nTracksAdded;
    int m_nTrackDurationsSet;
    UINT32 m_ulDuration;
};

//
// site/z-order info 
//
struct SMIL1ZOrderInfo
{
    IHXSite* m_pSite;
    INT32 m_lZIndex;
};

//
// event source info (endsync in SMIL)
//
struct SMIL1DeferredSourceInfo
{
    UINT32 m_ulDuration;
    UINT32 m_ulDelay;
};

//
// event handler classes
//
class CSmil1LayoutEvent : public CHXBaseCountingObject
{
public:
    CSmil1LayoutEvent		    (UINT16 uGroupIndex,
				    UINT32 ulEventTime);
    virtual ~CSmil1LayoutEvent	    ();

    virtual HX_RESULT handleEvent   () = 0;

    UINT32 m_ulEventTime;
    UINT16 m_uGroupIndex;
};

CSmil1LayoutEvent::CSmil1LayoutEvent(UINT16 uGroupIndex, UINT32 ulEventTime):
    m_uGroupIndex(uGroupIndex),
    m_ulEventTime(ulEventTime)
{
}

CSmil1LayoutEvent::~CSmil1LayoutEvent()
{
}

class CSmil1ShowSiteEvent: public CSmil1LayoutEvent
{
public:
    CSmil1ShowSiteEvent		    (UINT16 uGroupIndex,
				    UINT32 ulEventTime,
				    IHXSite* pSite,
				    IHXSite* pRegionSite,
				    BOOL bShowSite);
    virtual ~CSmil1ShowSiteEvent	    ();

    virtual HX_RESULT handleEvent   ();
    IHXSite* getRegionSite	    () { return m_pRegionSite; }
    IHXSite* getRendererSite	    () { return m_pSite; }
    BOOL showSite   		    () { return m_bShowSite; }

    IHXSite* m_pSite;
    IHXSite* m_pRegionSite;
    BOOL m_bShowSite;
};

CSmil1ShowSiteEvent::CSmil1ShowSiteEvent(UINT16 uGroupIndex,
				      UINT32 ulEventTime,
				      IHXSite* pSite,
				      IHXSite* pRegionSite,
				      BOOL bShowSite):
    CSmil1LayoutEvent(uGroupIndex, ulEventTime),
    m_pSite(pSite),
    m_pRegionSite(pRegionSite),
    m_bShowSite(bShowSite)
{
#if defined(_DEBUG) && defined(XXXMEH_CHECK_FOR_LEAKS)
    char szDbgStr[128]; /* Flawfinder: ignore */
    sprintf(szDbgStr, "CON CSmil1LayoutEvent 0x%08x\n", this); /* Flawfinder: ignore */
    OutputDebugString(szDbgStr);
#endif
    if (m_pSite)
    {
        m_pSite->AddRef();
    }
    if (m_pRegionSite)
    {
        m_pRegionSite->AddRef();
    }
}

CSmil1ShowSiteEvent::~CSmil1ShowSiteEvent()
{
#if defined(_DEBUG) && defined(XXXMEH_CHECK_FOR_LEAKS)
    char szDbgStr[128]; /* Flawfinder: ignore */
    sprintf(szDbgStr, "DES CSmil1LayoutEvent 0x%08x\n", this); /* Flawfinder: ignore */
    OutputDebugString(szDbgStr);
#endif
    HX_RELEASE(m_pSite);
    HX_RELEASE(m_pRegionSite);
}

HX_RESULT
CSmil1ShowSiteEvent::handleEvent()
{
    HX_RESULT rc = HXR_OK;

    IHXSite2* pRegionSite2 = 0;
    IHXSite2* pSite2 = 0;
    
    if (m_pRegionSite)
	m_pRegionSite->QueryInterface(IID_IHXSite2,(void**)&pRegionSite2);
    if (m_pSite)
	m_pSite->QueryInterface(IID_IHXSite2,(void**)&pSite2);
    
    if (m_bShowSite)
    {
	// if showing, then first show the site before the region site
	// to prevent the flash when the region site is shown before the
	// site.
	if (pSite2) pSite2->ShowSite(m_bShowSite);
	if (pRegionSite2) pRegionSite2->ShowSite(m_bShowSite);
    }
    else
    {
	// if hiding, then first hide the region so it's a one-step
	// process visually.
	if (pRegionSite2) pRegionSite2->ShowSite(m_bShowSite);
	if (pSite2) pSite2->ShowSite(m_bShowSite);
    }
    
    if (pRegionSite2) pRegionSite2->Release();
    if (pSite2) pSite2->Release();
    
    return rc;
}

/*
 * CSmil1DocumentRenderer methods
 */

CSmil1DocumentRenderer::CSmil1DocumentRenderer(
    CSmil1Renderer* pParent, IUnknown* pContext):
    m_pParent(pParent),
    m_pSmilParser(0),
    m_ulParseResult(HXR_OK),
    m_lRefCount(0),
    m_pContext(pContext),
    m_pMISUSSite(0),
    m_pRegionMap(0),
    m_pSiteInfoByRendererMap(0),
    m_pSiteWatcherMap(0),
    m_pGroupInfoMap(0),
    m_pGroupMap(0),
    m_pDeferredSourceMap(0),
    m_pRepeatIDMap(0),
    m_pSiteInfoList(0),
    m_uCurrentGroupIndex(-1),
    m_pPlayToAssocList(0),
    m_pZOrderList(0),
    m_pSiteMgr(0),
    m_pScheduler(0),
    m_pEventList(0),
    m_pValues(0),
    m_pFragment(0),
    m_ulCurrentTime(0),
    m_ulEventListPosition(0),
    m_bFirstTimeSync(FALSE),
    m_bSiteChangingSize(FALSE),
    m_bRootLayoutWidthSet(FALSE),
    m_bRootLayoutHeightSet(FALSE),
    m_ulRootLayoutHeight(0),
    m_ulRootLayoutWidth(0),
    m_ulNoRootLayoutHeight(0),
    m_ulNoRootLayoutWidth(0),
    m_ulRootLayoutBGColor(0),
    m_bSettingFragment(FALSE),
    m_bInHyperlink(FALSE),
    m_pStatusMessage(0),
    m_bStatusMessageSet(FALSE),
#ifdef _WINDOWS
    m_hPreHyperlinkCursor(0),
    m_hHyperlinkCursor(0),
    m_bNeedToSetHyperlinkCursor(FALSE),
#endif
#ifdef _MACINTOSH
    m_hHyperlinkCursor(0),
    m_bResetCursor(FALSE),
#endif
#if defined(_UNIX)  &&  (!defined(_BEOS))  &&  defined(USE_XWINDOWS)
    m_hHyperlinkCursor(0),
    m_hCurrentCursor(0),
    m_pDisplay(0),
    m_Window(0),
    m_pPixmapDisplay(NULL),
    m_pVisualInfo(NULL),
#endif
    m_bSiteLayoutComplete(FALSE),
    m_nFragmentTracks(0),
    m_bShowDependencies(FALSE),
    m_dResizeXScale(1.0),
    m_dResizeYScale(1.0)
    , m_ulGroupIndex(0)
    , m_ulTrackIndex(0)
    , m_uGroupIndexWithin(0)
    , m_bSitesDetached(FALSE)
    , m_bInRAM20(FALSE)
    , m_bLastGroupInRAM20(FALSE)
    , m_ulPersistentComponentDelay(0)
    , m_ulPersistentComponentID(0)
    , m_uPersistentGroupID(0)
    , m_uPersistentTrackID(0)
    , m_elementWithinTag(WithinUnknown)
    , m_pPersistentProperties(NULL)
    , m_pPersistentParentRenderer(NULL)
    , m_bCloseCalled(FALSE)
    , m_pProcessElementCallback(NULL)
    , m_ulPktnum(0)
    , m_usOldXPos(0)
    , m_usOldYPos(0)
{
#if defined(_DEBUG) && defined(XXXMEH_CHECK_FOR_LEAKS)
    char szDbgStr[128]; /* Flawfinder: ignore */
    sprintf(szDbgStr, "CON CSmil1DocumentRenderer 0x%08x\n", this); /* Flawfinder: ignore */
    OutputDebugString(szDbgStr);
#endif

    HX_ASSERT( m_pContext );
    if(m_pContext)
    {
	m_pContext->AddRef();
	
	HX_VERIFY(HXR_OK == m_pContext->
		  QueryInterface(IID_IHXSiteManager,(void**)&m_pSiteMgr));
	
	HX_VERIFY(HXR_OK == m_pContext->
		  QueryInterface(IID_IHXScheduler, (void**)&m_pScheduler));
	
	if (HXR_OK != m_pContext->QueryInterface(IID_IHXStatusMessage,
						 (void**)&m_pStatusMessage))
	{
	    // not an error, just a feature waiting to happen...
	    m_pStatusMessage = NULL;
	}
    }

#ifdef _WINDOWS
    m_hHyperlinkCursor = LoadCursor(g_hInstance,
        MAKEINTRESOURCE(IDC_HANDCURSOR));
#endif
#ifdef _MACINTOSH
    const short HAND_CURSOR  = 1313;
    m_pResourceLoader = CResourceLoader::CreateInstance(g_DLLFSpec);
    m_hHyperlinkCursor = (CursHandle)m_pResourceLoader->LoadResource('CURS', HAND_CURSOR);
#endif
    
#ifdef _DEBUG
    IHXPreferences* pPrefs = NULL;
    // get "showdependencies" preference
    //IHXPreferences* pPrefs = 0;
    if(HXR_OK == m_pContext->QueryInterface(
       IID_IHXPreferences, (void**)&pPrefs))
    {
	IHXBuffer* pBuf = 0;
	if(HXR_OK == pPrefs->ReadPref("showdependencies", pBuf))
	{
	    m_bShowDependencies = (BOOL)atol((const char*)pBuf->GetBuffer());
	    HX_RELEASE(pBuf);
	}
	pPrefs->Release();
    }
    if(m_bShowDependencies)
    {
	// mark file boundary
	FILE* fp = fopen(SMILDEPFILE, "a");
	if(fp)
	{
    	    fprintf(fp, "===========================\n");
	    fclose(fp);
	}
    }
#endif
}

CSmil1DocumentRenderer::~CSmil1DocumentRenderer()
{
#if defined(_DEBUG) && defined(XXXMEH_CHECK_FOR_LEAKS)
    char szDbgStr[128]; /* Flawfinder: ignore */
    sprintf(szDbgStr, "DES CSmil1DocumentRenderer 0x%08x\n", this); /* Flawfinder: ignore */
    OutputDebugString(szDbgStr);
#endif
    HX_RELEASE(m_pSiteMgr);

#if defined(_UNIX)  &&  (!defined(_BEOS))  &&  defined(USE_XWINDOWS)
    CHXMapPtrToPtr::Iterator i = m_siteToXDataMap.Begin();
    for(; i != m_siteToXDataMap.End(); ++i)
    {
        XData* xData = (XData*)(*i);
	delete xData;
    }

    if (m_pVisualInfo)
    {
	XFree(m_pVisualInfo);
	m_pVisualInfo = NULL;
    }

    if (m_pDisplay && m_hHyperlinkCursor)
    {
	XFreeCursor(m_pDisplay, m_hHyperlinkCursor);
	m_hHyperlinkCursor = 0;
    }
#endif    
#if defined(_MACINTOSH)
    if (m_hHyperlinkCursor)
    {
    	m_pResourceLoader->UnloadResource((Handle)m_hHyperlinkCursor);
    	m_hHyperlinkCursor = NULL;
    	
    	HX_RELEASE(m_pResourceLoader);
    }

    if (m_bResetCursor)
    {
	::InitCursor();
    }
#endif
}

/*
 * IUnknown methods
 */
STDMETHODIMP
CSmil1DocumentRenderer::QueryInterface(REFIID riid, void** ppvObj)
{
    if(IsEqualIID(riid, IID_IUnknown))
    {
	AddRef();
	*ppvObj = this;
	return HXR_OK;
    }
    else if(IsEqualIID(riid, IID_IHXValues))
    {
	AddRef();
	*ppvObj = (IHXValues*)this;
	return HXR_OK;
    }
    else if(IsEqualIID(riid, IID_IHXSiteUser))
    {
	AddRef();
	*ppvObj = (IHXSiteUser*)this;
	return HXR_OK;
    }
    else if(IsEqualIID(riid, IID_IHXRendererAdviseSink))
    {
	AddRef();
	*ppvObj = (IHXRendererAdviseSink*)this;
	return HXR_OK;
    }
    else if(IsEqualIID(riid, IID_IHXGroupSink))
    {
	AddRef();
	*ppvObj = (IHXGroupSink*)this;
	return HXR_OK;
    }
    *ppvObj = NULL;
    return HXR_NOINTERFACE;
}

STDMETHODIMP_(ULONG32)
CSmil1DocumentRenderer::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

STDMETHODIMP_(ULONG32)
CSmil1DocumentRenderer::Release()
{
    if(InterlockedDecrement(&m_lRefCount) > 0)
    {
	return m_lRefCount;
    }

    delete this;
    return 0;
}

HX_RESULT
CSmil1DocumentRenderer::close(CSmil1Renderer* pParent)
{
    if (m_pProcessElementCallback)
    {
	if (m_pScheduler && m_pProcessElementCallback->m_bIsCallbackPending)
	{
    	    m_pProcessElementCallback->m_bIsCallbackPending = FALSE;
	    m_pScheduler->Remove(m_pProcessElementCallback->m_PendingHandle);
	    m_pProcessElementCallback->m_PendingHandle = 0;
	}
	HX_RELEASE(m_pProcessElementCallback);
    }

    IUnknown* pThisUnk = 0;
    if(HXR_OK == QueryInterface(IID_IUnknown, (void**)&pThisUnk))
    {
	pParent->HandleRemoveLayoutSiteGroup(pThisUnk);
	pThisUnk->Release();
    }

    if(m_pEventList)
    {
	CHXSimpleList::Iterator i = m_pEventList->Begin();
	for(; i != m_pEventList->End(); ++i)
	{
	    CSmil1LayoutEvent* pEvent = (CSmil1LayoutEvent*)(*i);
	    delete pEvent;
	}
    }
    HX_DELETE(m_pEventList);

    removeAllPlayToAssoc();

    if (m_bSitesDetached)
    {
        if(m_pRegionMap)
        {
	    CHXMapStringToOb::Iterator i = m_pRegionMap->Begin();
	    for(; i != m_pRegionMap->End(); ++i)
	    {
	        CSmil1BasicRegion* pRegion = (CSmil1BasicRegion*)(*i);
	        delete pRegion;
	    }
        }
        HX_DELETE(m_pRegionMap);
    }

    if(m_pGroupInfoMap)
    {
	CHXMapLongToObj::Iterator i = m_pGroupInfoMap->Begin();
	for(; i != m_pGroupInfoMap->End(); ++i)
	{
	    SMIL1GroupInfo* pGroupInfo = (SMIL1GroupInfo*)(*i);
	    delete pGroupInfo;
	}
    }
    HX_DELETE(m_pGroupInfoMap);

    if(m_pDeferredSourceMap)
    {
	CHXMapStringToOb::Iterator i = m_pDeferredSourceMap->Begin();
	for(; i != m_pDeferredSourceMap->End(); ++i)
	{
	    SMIL1DeferredSourceInfo* pInfo = (SMIL1DeferredSourceInfo*)(*i);
	    delete pInfo;
	}
    }
    HX_DELETE(m_pDeferredSourceMap);

    HX_DELETE(m_pRepeatIDMap);

    if (m_bSitesDetached)
    {
        if(m_pSiteInfoList)
        {
	    CHXSimpleList::Iterator i = m_pSiteInfoList->Begin();
	    for(; i != m_pSiteInfoList->End(); ++i)
	    {
	        SMIL1SiteInfo* pSiteInfo = (SMIL1SiteInfo*)(*i);
	        delete pSiteInfo;
	    }
        }
        HX_DELETE(m_pSiteInfoList);
    }

    if(m_pStatusMessage)
    {
	m_pStatusMessage->SetStatus(NULL);
    }
    HX_RELEASE(m_pStatusMessage);

    if (m_bSitesDetached)
    {
        HX_DELETE(m_pSiteInfoByRendererMap);
    }

    if (m_bSitesDetached)
    {
        if(m_pSiteWatcherMap)
        {
	    CHXMapPtrToPtr::Iterator i= m_pSiteWatcherMap->Begin();
	    for(; i != m_pSiteWatcherMap->End(); ++i)
	    {
	        CSmil1SiteWatcher* pSiteWatcher = (CSmil1SiteWatcher*)(*i);
	        pSiteWatcher->Release();
	    }
	    HX_DELETE(m_pSiteWatcherMap);
        }
    }

    HX_RELEASE(m_pValues);
    HX_DELETE(m_pSmilParser);
    HX_VECTOR_DELETE(m_pFragment);
    HX_RELEASE(m_pScheduler);
    HX_RELEASE(m_pContext);

#ifdef _MACINTOSH
    if (m_bResetCursor)
    {
	m_bResetCursor = FALSE;
	::InitCursor();
    }
#endif

    m_bCloseCalled = TRUE;

    return HXR_OK;
}

HX_RESULT
CSmil1DocumentRenderer::onHeader(IHXValues* pHeader)
{
    m_pValues = new CHXHeader;
    m_pValues->AddRef();
    m_pRegionMap = new CHXMapStringToOb;
    m_pSiteInfoByRendererMap = new CHXMapPtrToPtr;
 
    if (m_pPersistentParentRenderer &&
	HXR_OK == m_pPersistentParentRenderer->GetElementProperties(m_uPersistentGroupID,
								    m_uPersistentTrackID,
								    m_pPersistentProperties))
    {
	m_pPersistentProperties->GetPropertyULONG32("ElementWithinTag", (UINT32&)m_elementWithinTag);
    }
    
    IHXBuffer* pBuffer = 0;
    IHXCommonClassFactory* pFactory = m_pParent->getFactory();
    if(HXR_OK == pFactory->CreateInstance(CLSID_IHXBuffer,
	(void**)&pBuffer))
    {
	pBuffer->Set((const BYTE*)"TopLevelSite", strlen("TopLevelSite")+1);
	SetPropertyCString("name", pBuffer);
	SetPropertyULONG32("GroupIndex", m_uPersistentGroupID);
	SetPropertyULONG32("TrackIndex", m_uPersistentTrackID);
	pBuffer->Release();
    }

    m_pSmilParser = new CSmil1Parser(m_pContext);
    m_pSmilParser->init();
    m_pSmilParser->InitPersistent(m_ulPersistentComponentID, m_elementWithinTag);

    return HXR_OK;
}

HX_RESULT
CSmil1DocumentRenderer::getErrorInfo(REF(UINT32) ulLineNumber,
				    REF(UINT32) ulColumnNumber,
				    REF(IHXBuffer*) pErrorText)
{
    ulLineNumber = m_pSmilParser->m_ulErrorLineNumber;
    ulColumnNumber = m_pSmilParser->m_ulErrorColumnNumber;
    pErrorText = m_pSmilParser->m_pErrorText;
    if(pErrorText)
    {
	pErrorText->AddRef();
    }

    return HXR_OK;
}

HX_RESULT
CSmil1DocumentRenderer::onPacket(IHXBuffer* pBuffer, BOOL bIsLast)
{
    HX_RESULT rc = HXR_OK;

    BOOL bDumpToFile = FALSE;
    getBooleanPreference(m_pContext,
                         "NonObviousKeyNameVer1",
                         bDumpToFile);
    BOOL bShowPacketBoundaries = FALSE;
    getBooleanPreference(m_pContext,
                         "NonObviousKeyNameVer1Option1",
                         bShowPacketBoundaries);
    if (bDumpToFile)
    {
#ifdef _WINDOWS
        const char* pszFile = "c:\\smil1dump.txt";
#else
        const char* pszFile = "smil1dump.txt";
#endif
        FILE* pFoo = fopen(pszFile, m_ulPktnum > 0L ? "a" : "w");
        if (pFoo)
        {
            char* pBuf = (char*) pBuffer->GetBuffer();
            if(pBuf && strlen(pBuf) > 0)
            {
                if (bShowPacketBoundaries)
                {
                    fprintf(pFoo, "[[[packet # %lu]]]:{{{", m_ulPktnum);
                }
                fwrite(pBuf, 1, pBuffer->GetSize(), pFoo);
                if (bShowPacketBoundaries)
                {
                    fprintf(pFoo, "}}}\n");
                }
            }
            else
            {
                if (bShowPacketBoundaries)
                {
                    fprintf(pFoo, "\n[[[Packet %lu empty in onPacket()]]]\n",
                            m_ulPktnum);
                }
            }
        }
        fclose(pFoo);
        if (bIsLast)
            m_ulPktnum = 0L;
        else
            m_ulPktnum++;
    }
    rc = m_pSmilParser->parse(pBuffer, bIsLast);

    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::setDocument(const char* pFragment)
{
    HX_RESULT rc = m_pSmilParser->createElements();
    if(HXR_OK == rc)
    {
	rc = handleElements();
	IHXPlayer* pPlayer = m_pParent->getPlayer();
	IHXGroupManager* pMgr = 0;

	if(HXR_OK == pPlayer->QueryInterface(IID_IHXGroupManager, (void**)&pMgr))
	{
	    if(pFragment)
	    {
		m_pFragment = new_string(pFragment);
		m_bSettingFragment = TRUE;
    	    	m_nFragmentTracks = 0;
		UINT16 uFragmentGroup = 
		    m_pSmilParser->getFragmentGroup(m_pFragment);
		pMgr->SetCurrentGroup(uFragmentGroup);
	    }
	    // /Adding the "else" around this fixes PR 75814; without this,
	    // the code was ignoring the uFragmentGroup set already, above,
	    // and thus "foo.smil#fragmentInHighGroup" links stopped working
	    // in the RealOne Player:
	    else
	    {
		if (m_pParent->m_bUseNestedMeta && !m_bLastGroupInRAM20 && m_uCurrentGroupIndex == -1)
		{
		    pMgr->GetCurrentGroup((UINT16&)m_uCurrentGroupIndex);
		}
		else
		{
		    pMgr->SetCurrentGroup(0);
		}
	    }
	    pMgr->Release();
	}
    }

    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::handleElements()
{
    HX_RESULT rc = HXR_OK;

    if(m_pSmilParser)
    {
	//if(m_ulParseResult != HXR_STREAM_DONE)
	//{
	    while(HXR_OK == rc)
	    {
		rc = m_pSmilParser->handleNextElement(this);
	    }
	    m_ulParseResult = rc;
	//}
    }

    return HXR_OK;
}

HX_RESULT
CSmil1DocumentRenderer::parseDimension(const char* pDimensionString,
				      REF(UINT32) ulValue,
				      REF(BOOL) bIsPercent)
{
    HX_RESULT rc = HXR_OK;

    if(!pDimensionString || strlen(pDimensionString) == 0)
    {
	ulValue = 0L;
	//[SMIL 1.0 compliance] Helps fix PR 16542.  The caller of this
	// function should look at this return value to determine whether
	// or not the string was empty (and thus 0 is returned in ulValue) or
	// whether "0" or "0%" IS the string (and thus 0 is returned in
	// ulValue along with HXR_OK):
	rc = HXR_FAIL;
    }
    else
    {
	char* pEndPtr = 0;
	ulValue = (UINT32)strtod(pDimensionString, &pEndPtr);
	if(pEndPtr && strcmp(pEndPtr, "%") == 0)
	{
	    bIsPercent = TRUE;
	}
	else
	{
	    bIsPercent = FALSE;
	}
    }
    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::regionToRect(CSmil1Region* pElement, 
    HXxRect* pRect, BOOL& bWidthUnspecified, BOOL& bHeightUnspecified)
{
    HX_RESULT rc = HXR_OK;

    bWidthUnspecified = bHeightUnspecified = FALSE;

    UINT32 ulTop = 0;
    UINT32 ulLeft = 0;
    UINT32 ulWidth = 0;
    UINT32 ulHeight = 0;
    BOOL bTopIsPercent = FALSE;
    BOOL bLeftIsPercent = FALSE;
    BOOL bWidthIsPercent = FALSE;
    BOOL bHeightIsPercent = FALSE;

    parseDimension(pElement->m_left, ulLeft, bLeftIsPercent);
    parseDimension(pElement->m_top, ulTop, bTopIsPercent);
    HX_RESULT rsltW =
	    parseDimension(pElement->m_width, ulWidth, bWidthIsPercent);
    HX_RESULT rsltH =
	    parseDimension(pElement->m_height, ulHeight, bHeightIsPercent);

    /* check for valid region constraints */
    BOOL bRegionError = FALSE;
    char errorBuf[256]; /* Flawfinder: ignore */
    //[SMIL 1.0 compliance] helps fix PR 24630; separate width & height logic
    if((!m_bRootLayoutWidthSet && 
	    (bLeftIsPercent  ||  bWidthIsPercent))  ||
	    (!m_bRootLayoutHeightSet && 
	    (bTopIsPercent  ||  bHeightIsPercent)) )
    {
	//XXXE: needs err msg: "Region can't use % without root-layout"
	rc = HXR_FAIL;
	SafeSprintf(errorBuf, 256, "region %s",
	    (const char*)pElement->m_pNode->m_id);
	CSmil1SMILSyntaxErrorHandler errHandler(m_pContext);
	errHandler.ReportError(SMILErrorBadAttribute, errorBuf, 0);
	return rc;
    }

    if(m_bRootLayoutWidthSet)
    {
	if(bLeftIsPercent)
	{
	    ulLeft = (UINT32)(((float)ulLeft/100.0) * m_ulRootLayoutWidth);
	}
	if(bWidthIsPercent)
	{
	    ulWidth = (UINT32)(((float)ulWidth/100.0) * m_ulRootLayoutWidth);
	}
    }
    if(m_bRootLayoutHeightSet)
    {
	if(bTopIsPercent)
	{
	    ulTop = (UINT32)(((float)ulTop/100.0) * m_ulRootLayoutHeight);
	}
	if(bHeightIsPercent)
	{
	    ulHeight = (UINT32)(((float)ulHeight/100.0) * m_ulRootLayoutHeight);
	}
    }

    if(m_ulNoRootLayoutHeight < (ulTop + ulHeight))
    {
	m_ulNoRootLayoutHeight = ulTop + ulHeight;
    }
    if(m_ulNoRootLayoutWidth < (ulLeft + ulWidth))
    {
	m_ulNoRootLayoutWidth =  ulLeft + ulWidth;
    }

    //[SMIL 1.0 compliance] Helps fix PR 16542:
    if(m_pSmilParser)
    {
	//If we're in full-compliance mode and someone enters a
	// width="0" or width="0%", we should leave it as 0.  We
	// know that they omitted width or height (which is returned as 0
	// from parseDimension), if the return value is HXR_FAIL:
	if (!ulWidth  &&  HXR_FAIL == rsltW)
	{
	    bWidthUnspecified = TRUE;
	}
	if (!ulHeight  &&  HXR_FAIL == rsltH)
	{
	    bHeightUnspecified = TRUE;
	}
    }

    pRect->left = ulLeft;
    pRect->top = ulTop;
    pRect->right = ulLeft + ulWidth;
    pRect->bottom = ulTop + ulHeight;

    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::handleRegion(CSmil1Region* pElement)
{
    HX_RESULT rc = HXR_OK;

    HXxRect rect;
    rect.left = 0;
    rect.right = 0;
    rect.top = 0;
    rect.bottom = 0;

    BOOL bWidthUnspecified, bHeightUnspecified;

    if(HXR_OK != regionToRect(pElement, &rect,
	    //[SMIL 1.0 compliance] Helps fix PR 16542; these are passed
	    // by reference and set to TRUE if width or height (respectively)
	    // is not explicitly set:
	    bWidthUnspecified, bHeightUnspecified))
    {
	rc = HXR_FAIL;
    }
    else
    {
	CSmil1BasicRegion* pRegion = new CSmil1BasicRegion(pElement->m_pNode->m_id, rect, 
	    pElement->m_zIndex, pElement->m_fit, pElement->m_ulBgColor,
	    pElement->m_bBgColorSet, FALSE,
	    bWidthUnspecified, bHeightUnspecified);
	(*m_pRegionMap)[(const char*)pElement->m_pNode->m_id] = pRegion;
    }
    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::handleRootLayout(CSmil1RootLayout* pElement)
{
    HX_RESULT rc = HXR_OK;

    m_bRootLayoutWidthSet = !pElement->m_bWidthUnspecified;
    m_bRootLayoutHeightSet = !pElement->m_bHeightUnspecified;
    m_ulRootLayoutHeight = pElement->m_ulHeight;
    m_ulRootLayoutWidth = pElement->m_ulWidth;
    m_ulRootLayoutBGColor = pElement->m_ulBgColor;

    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::handleAddGroup(CSmil1AddGroup* pElement)
{
    HX_RESULT	rc = HXR_OK;

    if (m_bInRAM20 && !m_bLastGroupInRAM20 && m_ulGroupIndex)
    {
	return rc;
    }

    if(!m_pGroupMap)
    {
	m_pGroupMap = new CHXMapLongToObj;
    }

    IHXPlayer* pPlayer = m_pParent->getPlayer();
    IHXGroupManager* pMgr = 0;
    if(HXR_OK == pPlayer->QueryInterface(IID_IHXGroupManager, (void**)&pMgr))
    {
	IHXGroup* pGroup = NULL;
	IHXGroup2* pGroup2 = NULL;

	if (m_pParent->m_bUseNestedMeta && 0 == m_ulGroupIndex)
	{
	    if (m_bLastGroupInRAM20)
	    {
		rc = pMgr->CreateGroup(pGroup);
	    }
	    else
	    {
		HX_ASSERT(pMgr->GetGroupCount());
		rc = pMgr->GetCurrentGroup(m_uGroupIndexWithin);
		rc = pMgr->GetGroup(m_uGroupIndexWithin, pGroup);
	    }
	}
	else
	{
	    rc = pMgr->CreateGroup(pGroup);
	}

	if(HXR_OK == rc)	
	    // release pGroup when m_pGroupMap is destructed
	{
	    CHXHeader* pGroupValues = new CHXHeader;
	    pGroupValues->AddRef();

	    if(pElement->m_ulDuration != (UINT32)-1)
	    {
		pGroupValues->SetPropertyULONG32("duration", pElement->m_ulDuration);
	    }

	    pGroupValues->SetPropertyULONG32("total_tracks", pElement->m_nTotalTracks);
	    pGroupValues->SetPropertyULONG32("initial_tracks", pElement->m_nInitTracks);	   
	    pGroupValues->SetPropertyULONG32("PersistentComponentID", m_ulPersistentComponentID);
	    
	    if (m_bLastGroupInRAM20)
	    {
		pGroupValues->SetPropertyULONG32("LastGroupInRAM20", 1);
	    }

	    // copy all the node values to group values
	    IHXValues* pValues = pElement->m_pValues;
	    if(pValues)
	    {
		IHXBuffer* pBuf = NULL;
		const char* pName = NULL;
		HX_RESULT res = 
		    pValues->GetFirstPropertyCString(pName, pBuf);
		while(HXR_OK == res)
		{
		    pGroupValues->SetPropertyCString(pName, pBuf);

		    HX_RELEASE(pBuf);
		    res = pValues->GetNextPropertyCString(pName, pBuf);
		}
	    }

	    pGroup->SetGroupProperties(pGroupValues);

	    if (HXR_OK == pGroup->QueryInterface(IID_IHXGroup2, (void**)&pGroup2))
	    {
		pGroup2->SetPersistentComponentProperties(m_ulPersistentComponentID,
							  pGroupValues);
	    }
	    HX_RELEASE(pGroup2);
	    HX_RELEASE(pGroupValues);

	    if (m_pParent->m_bUseNestedMeta && 0 == m_ulGroupIndex)
	    {
		if (m_bLastGroupInRAM20)
		{
		    pMgr->AddGroup(pGroup);
		}
		else
		{
		    GroupAdded(m_uGroupIndexWithin, pGroup);
		}
	    }
	    else
	    {
		pMgr->AddGroup(pGroup);
	    }	    

	    m_ulTrackIndex = 0;
	    m_ulGroupIndex++;

	    (*m_pGroupMap)[pElement->m_nGroup] = pGroup;
	}
    }
    HX_RELEASE(pMgr);

    return rc;
}

void
CSmil1DocumentRenderer::setProperty(IHXValues* pValues, 
    const char* pName, const char* pValue)
{
    IHXBuffer* pBuf = 0;
    IHXCommonClassFactory* pFactory = m_pParent->getFactory();
    if(HXR_OK == pFactory->CreateInstance(CLSID_IHXBuffer,
    	    (void**)&pBuf))
    {
	pBuf->Set((BYTE*)pValue, strlen(pValue)+1);
	pValues->SetPropertyCString(pName, pBuf);
	pBuf->Release();
    }
}

HX_RESULT
CSmil1DocumentRenderer::convertURL(const char* pURL, CHXString& newURL)
{
    CHXURL urlObj(pURL);
    IHXValues* pHeader = urlObj.GetProperties();
    IHXBuffer* pBuffer = NULL;

    if(!pHeader)
    {
	return HXR_FAIL;
    }

    if(HXR_OK == pHeader->GetPropertyBuffer(PROPERTY_SCHEME, pBuffer))
    {
	// fully qualified URL
	newURL = pURL;
	HX_RELEASE(pBuffer);
    }
    else
    {
	// relative URL
	// if it starts with '/', make it relative to the root of 
	// the URL prefix

	if(*pURL == '/')
	{
	    newURL = m_pParent->getURLRoot() + pURL;
	}
	else if (strnicmp(pURL, URL_COMMAND, sizeof(URL_COMMAND) - 1) == 0)
	{
	    newURL = pURL;
	}
	else
	{
	    newURL = m_pParent->getURLPrefix() + pURL;
	}
    }

    HX_RELEASE(pHeader);
    return HXR_OK;
}

HX_RESULT
CSmil1DocumentRenderer::handleSource(CSmil1Source* pElement)
{
    HX_RESULT rc = HXR_OK;

    CHXString urlString;
    convertURL(pElement->m_src, urlString);

    if (!m_pRepeatIDMap)
    {
	m_pRepeatIDMap = new CHXMapStringToOb;
    }

    IHXGroup* pGroup = 0;
    if(m_pGroupMap && 
       m_pGroupMap->Lookup(pElement->m_pNode->m_nGroup, (void*&)pGroup))
    {
	IHXCommonClassFactory* pFactory = m_pParent->getFactory();
	IHXValues* pValues = 0;
	if(HXR_OK == pFactory->CreateInstance(CLSID_IHXValues,
		(void**)&pValues))
	{
	    pValues->SetPropertyULONG32("PersistentComponentID", m_ulPersistentComponentID);	   

	    setProperty(pValues, "url", urlString);
	    setProperty(pValues, "id", pElement->m_pNode->m_id);
	    setProperty(pValues, "repeatid", pElement->m_pNode->m_repeatid);
	    setProperty(pValues, "playto", pElement->m_region);
	    if(pElement->m_region.GetLength() > 0)
	    {
		// save original region name in track values
		setProperty(pValues, "region", pElement->m_region);
	    }
	    setProperty(pValues, "fill", pElement->m_fill);
	    setProperty(pValues, "track-hint", pElement->m_pNode->m_trackHint);

	    UINT32 ulDelay = 0;
	    if(pElement->m_ulDelay != (UINT32)-1)
	    {
		//if(pElement->m_ulBeginOffset != (UINT32)-1)
		//{
		//    pValues->SetPropertyULONG32("delay", pElement->m_ulDelay +
		//			    pElement->m_ulBeginOffset);
		//}
		//else
		//{
		    ulDelay = pElement->m_ulDelay + m_ulPersistentComponentDelay;
		//}
	    }
	    else
	    {
		ulDelay = m_ulPersistentComponentDelay;
	    }

	    if (ulDelay)
	    {
		pValues->SetPropertyULONG32("delay", ulDelay);
	    }

	    if(pElement->m_ulDuration != (UINT32)-1)
	    {
		pValues->SetPropertyULONG32("duration", pElement->m_ulDuration);
	    }
	    if(pElement->m_ulMaxDuration != (UINT32)-1)
	    {
		pValues->SetPropertyULONG32("maxduration", pElement->m_ulMaxDuration);
	    }
	    if(pElement->m_ulClipBegin != (UINT32)-1)
	    {
		pValues->SetPropertyULONG32("start", pElement->m_ulClipBegin);
	    }
	    if(pElement->m_ulClipEnd != (UINT32)-1)
	    {
		pValues->SetPropertyULONG32("end", pElement->m_ulClipEnd);
	    }

	    if (pElement->m_pNode->m_repeatTag !=
		RepeatUnknown)
	    {
		pValues->SetPropertyULONG32("repeatTag", pElement->m_pNode->m_repeatTag);
	    }

	    if (pElement->m_bIndefiniteDuration)
	    {
		pValues->SetPropertyULONG32("indefiniteduration", TRUE);
	    }
	    
	    // add arbitrary name-value pairs to track
	    if(pElement->m_pNode->m_pValues)
	    {
		IHXValues* pSrcValues = pElement->m_pNode->m_pValues;
		const char* pName = 0;
		IHXBuffer* pValue = 0;

		HX_RESULT rCode = pSrcValues->GetFirstPropertyCString(
		    pName, pValue);
		while(HXR_OK == rCode)
		{
		    // skip the values we already have or have overridden...
		    if((strcasecmp(pName, "url") != 0) &&
		       (strcasecmp(pName, "id") != 0) &&
		       (strcasecmp(pName, "playto") != 0) &&
		       (strcasecmp(pName, "fill") != 0))
		    {
			setProperty(pValues, pName, 
			    (const char*)pValue->GetBuffer());
		    }
		    HX_RELEASE(pValue);
		    rCode = pSrcValues->GetNextPropertyCString(
			pName, pValue);
		}
		HX_RELEASE(pValue);
	    }

#ifdef _DEBUG
	    // just resolve this puppy at the outset and send 
	    // to an output file
	    if(m_bShowDependencies)
	    {
		FILE* fp = fopen(SMILDEPFILE, "a");
		if(fp)
		{
		    fprintf(fp, "src %s url %s group %d delay %ld\n",
			(const char*)pElement->m_pNode->m_id, 
			(const char*)urlString,
			pElement->m_pNode->m_nGroup,
			(pElement->m_ulBeginOffset != (UINT32)-1) ?
			    pElement->m_ulDelay + pElement->m_ulBeginOffset :
			    pElement->m_ulDelay);
		    fclose(fp);
		}

		// determine duration resolution
		// NOTE - this will give lame results 
		// for values that exceed ulNominalDuration
		const UINT32 ulNominalDuration = 60000; // 1 min nominal
		UINT32 ulDuration = ulNominalDuration;

		if(pElement->m_ulClipEnd != (UINT32)-1)
		{
		    ulDuration = pElement->m_ulClipEnd;
		}
		if(pElement->m_ulDuration != (UINT32)-1)
		{
		    ulDuration = pElement->m_ulDuration;
		}
		if(pElement->m_ulBeginOffset != (UINT32)-1)
		{
		    ulDuration += pElement->m_ulBeginOffset;
		}
		if(pElement->m_ulEndOffset != (UINT32)-1)
		{
		    ulDuration -= pElement->m_ulEndOffset;
		}
		if(pElement->m_ulClipBegin != (UINT32)-1)
		{
		    ulDuration -= pElement->m_ulClipBegin;
		}

		m_pSmilParser->durationResolved(pElement->m_pNode->m_id, ulDuration);
	    }
	    else
	    {
#if defined(PRE_SHAZAM_SMIL_1_0_CODE)
		IHXGroup* pTempGroup = NULL;
		if (m_pRepeatIDMap->Lookup(pElement->m_pNode->m_repeatid, (void*&)pTempGroup))
		{
		    IHXGroup2* pTempGroup2 = NULL;

		    if (HXR_OK == pTempGroup->QueryInterface(IID_IHXGroup2, (void**)&pTempGroup2))
		    {
			pTempGroup2->AddRepeatTrack(pValues);
		    }
		    HX_RELEASE(pTempGroup2);
		}
		else
#else
		// /The following was added for SHAZAM since
		// IHXGroup2's AddRepeatTrack() has been deprecated
		// in favor of calling IHXTrack's AddTrack():
		BOOL bRepeatTrackHandled = FALSE;
		SMIL1PlayToAssoc*    pPlayToAssoc = NULL;
 		if(m_pPlayToAssocList)
		{
		    CHXSimpleList::Iterator i = m_pPlayToAssocList->Begin();
		    for ( ;i!=m_pPlayToAssocList->End()  &&  !bRepeatTrackHandled; ++i)
		    {
			SMIL1PlayToAssoc* pThisAssoc = (SMIL1PlayToAssoc*)(*i);
			if (pThisAssoc->m_repeatid ==
				pElement->m_pNode->m_repeatid)
			{
			    IHXGroup2* pGroup2 = NULL;
			    IHXTrack*	pHXTrack = NULL;

			    if (HXR_OK == pGroup->QueryInterface(IID_IHXGroup2,
				    (void**)&pGroup2))
			    {
				if (HXR_OK == pGroup2->GetIHXTrack(
					pThisAssoc->m_uTrackIndex, pHXTrack)  &&
					pHXTrack)
				{
				    pHXTrack->AddRepeat(pValues);
				    bRepeatTrackHandled = TRUE;
				}
				HX_RELEASE(pHXTrack);
			    }
			    HX_RELEASE(pGroup2);
			}
		    }
		}
		if (!bRepeatTrackHandled)
#endif
		{
		    (*m_pRepeatIDMap)[pElement->m_pNode->m_repeatid] = pGroup;
		    pGroup->AddTrack(pValues);
		}
	    }
#else
#if defined(PRE_SHAZAM_SMIL_1_0_CODE)
	    IHXGroup* pTempGroup = NULL;
	    if (m_pRepeatIDMap->Lookup(pElement->m_pNode->m_repeatid, (void*&)pTempGroup))
	    {
		IHXGroup2* pTempGroup2 = NULL;

		if (HXR_OK == pTempGroup->QueryInterface(IID_IHXGroup2, (void**)&pTempGroup2))
		{
		    pTempGroup2->AddRepeat(pValues);
		}
		HX_RELEASE(pTempGroup2);
	    }
	    else
#else
	    // /The following was added for SHAZAM since
	    // IHXGroup2's AddRepeatTrack() has been deprecated
	    // in favor of calling IHXTrack's AddTrack():
	    BOOL bRepeatTrackHandled = FALSE;
	    SMIL1PlayToAssoc*    pPlayToAssoc = NULL;
 	    if(m_pPlayToAssocList)
	    {
		CHXSimpleList::Iterator i = m_pPlayToAssocList->Begin();
		for ( ;i!=m_pPlayToAssocList->End()  &&  !bRepeatTrackHandled; ++i)
		{
		    SMIL1PlayToAssoc* pThisAssoc = (SMIL1PlayToAssoc*)(*i);
		    if (pThisAssoc->m_repeatid ==
			    pElement->m_pNode->m_repeatid)
		    {
			IHXGroup2* pGroup2 = NULL;
			IHXTrack*	pHXTrack = NULL;

			if (HXR_OK == pGroup->QueryInterface(IID_IHXGroup2,
				(void**)&pGroup2))
			{
			    if (HXR_OK == pGroup2->GetIHXTrack(
				    pThisAssoc->m_uTrackIndex, pHXTrack)  &&
				    pHXTrack)
			    {
				pHXTrack->AddRepeat(pValues);
				bRepeatTrackHandled = TRUE;
			    }
			    HX_RELEASE(pHXTrack);
			}
			HX_RELEASE(pGroup2);
		    }
		}
	    }
	    if (!bRepeatTrackHandled)
#endif
	    {
		(*m_pRepeatIDMap)[pElement->m_pNode->m_repeatid] = pGroup;
		pGroup->AddTrack(pValues);
	    }
#endif
	    pValues->Release();
	}
    }

    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::handleSourceUpdate(CSmil1SourceUpdate* pElement)
{
    HX_RESULT rc = HXR_OK;

    const char* pID = (const char*)pElement->m_srcID;

    // determine whether this source has been initialized yet...
    SMIL1PlayToAssoc* pPlayToAssoc = 0;
    if(m_pPlayToAssocList)
    {
	CHXSimpleList::Iterator i;
	for(i=m_pPlayToAssocList->Begin();i!=m_pPlayToAssocList->End();++i)
	{
	    SMIL1PlayToAssoc* pThisAssoc = (SMIL1PlayToAssoc*)(*i);
	    if(pThisAssoc->m_id == pID)
	    {
		pPlayToAssoc = pThisAssoc;
		break;
	    }
	}
    }
    if(pPlayToAssoc &&
	pPlayToAssoc->m_sourceMap.GetCount() > 0)
    {
        CSmil1Element* pThisElement = 
	    m_pSmilParser->findElement(pID);
	if(pThisElement->m_ulBeginOffset != (UINT32)-1)
	{
	    if(pElement->m_ulUpdatedDuration > pThisElement->m_ulBeginOffset)
	    {
		updateStreamTiming(pID, pElement->m_ulUpdatedDuration -
		    pThisElement->m_ulBeginOffset);
	    }
	    else
	    {
		updateStreamTiming(pID, 0);
	    }
	}
	else
	{
	    updateStreamTiming(pID, pElement->m_ulUpdatedDuration);
	}
    }
    else
    {
	// stick it into the deferred map,
	// it will be handled in RendererInitialized()
	if(!m_pDeferredSourceMap)
	{
	    m_pDeferredSourceMap = new CHXMapStringToOb;
	}
	
	SMIL1DeferredSourceInfo* pInfo = new SMIL1DeferredSourceInfo;
	pInfo->m_ulDuration = pElement->m_ulUpdatedDuration;
	pInfo->m_ulDelay = 0;
	// /Fixes mem leak when pID is already in the map:
	SMIL1DeferredSourceInfo* pTmpInfo;
	if (m_pDeferredSourceMap->Lookup(pID, (void*&)pTmpInfo))
	{
	    HX_DELETE(pTmpInfo);
	}
	(*m_pDeferredSourceMap)[pID] = pInfo;
    }

    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::handleEndLayout(CSmil1EndLayout* pElement)
{
    return setupRootLayout();
}

HX_RESULT CSmil1DocumentRenderer::setupRootLayout()
{
    HX_RESULT rc = HXR_OK;

    IUnknown* pThisUnk = 0;
    if(HXR_OK == QueryInterface(IID_IUnknown, (void**)&pThisUnk))
    {
	m_pParent->HandleAddLayoutSiteGroup(pThisUnk);
	pThisUnk->Release();
	m_bSiteLayoutComplete = TRUE;
    }
    createRegionSites();

    // force initial redraw
    HXxSize siteWinSize;
    if (m_pMISUSSite)
    {
	m_pMISUSSite->GetSize(siteWinSize);
	CHXxRect updateRect(0, 0, siteWinSize.cx, siteWinSize.cy);
	m_pMISUSSite->DamageRect(updateRect);
#ifndef  _WIN32
	m_pMISUSSite->ForceRedraw();
#endif
    }

    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::handleMeta(CSmil1Meta* pElement)
{
    HX_RESULT rc = HXR_OK;

    IHXPlayer* pPlayer = m_pParent->getPlayer();
    IHXGroupManager* pMgr = NULL;
    IHXValues* pValues = NULL;

    if(pElement->m_name.GetLength() > 0)
    {
	if(HXR_OK == pPlayer->QueryInterface(IID_IHXGroupManager, (void**)&pMgr))
	{
	    pValues = pMgr->GetPresentationProperties();
	    if(!pValues)
	    {
		pValues = new CHXOrderedValues;
		pValues->AddRef();
		pMgr->SetPresentationProperties(pValues);
	    }

	    IHXBuffer* pBuf = new CHXBuffer;
	    pBuf->AddRef();
	    pBuf->Set((BYTE*)(const char*)pElement->m_content,
		pElement->m_content.GetLength()+1);
	    pValues->SetPropertyCString((const char*)pElement->m_name,
		pBuf);
	    pBuf->Release();
	    pValues->Release();
	    pMgr->Release();
	}
    }

    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::handleRendererPreFetch(CSmil1RendererPreFetch *pRend)
{
    HX_RESULT rc = HXR_OK;
    const char* pMimeType = (const char*)pRend->m_mimeType;

    IHXRendererUpgrade* pUpgrade = 0;

    if(m_pContext)
    {
	IHXSystemRequired* pISystemRequired = NULL;
	m_pContext->QueryInterface(IID_IHXSystemRequired, 
	    (void**)&pISystemRequired);
	
	CHXBuffer* pBuffer = new CHXBuffer;
	pBuffer->AddRef();
	pBuffer->Set((BYTE*)pMimeType, strlen(pMimeType)+1);
	if (pISystemRequired)
	{
	    IHXUpgradeCollection* pUpgradeCollection = NULL;
	    IHXPlayer* pPlayer = m_pParent->getPlayer();	    
	    if(pPlayer)
		pPlayer->QueryInterface(IID_IHXUpgradeCollection, (void**)&pUpgradeCollection);

	    if(pUpgradeCollection)
	    {
		pUpgradeCollection->Add(eUT_Required, pBuffer, 0, 0);
		// HasFeatures() calls removes all existing features from pUpgradeCollection.
		pISystemRequired->HasFeatures(pUpgradeCollection);
	    }
	    HX_RELEASE(pUpgradeCollection);
	    HX_RELEASE(pISystemRequired);
	}

	HX_RELEASE(pBuffer);
    }

    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::insertEvent(CSmil1ShowSiteEvent* pEvent)
{
    if(!m_pEventList)
    {
	m_pEventList = new CHXSimpleList;
    }

    LISTPOSITION lPos = m_pEventList->GetHeadPosition();
    LISTPOSITION lPrev = lPos;

    BOOL bInserted = FALSE;
    while(lPos)
    {
	CSmil1ShowSiteEvent* pThisEvent = 
	    (CSmil1ShowSiteEvent*)m_pEventList->GetNext(lPos);

	if(pThisEvent->m_ulEventTime == pEvent->m_ulEventTime &&
	    pThisEvent->getRegionSite() == pEvent->getRegionSite())
	{
	    if(pEvent->showSite())
	    {
		if(!lPos)
		{
		    m_pEventList->AddTail(pEvent);
		    bInserted = TRUE;
		    break;
		}

		// find position of last 'hide' event at this time
		while(lPos &&
		    pThisEvent->m_ulEventTime == pEvent->m_ulEventTime &&
		    pThisEvent->getRegionSite() == pEvent->getRegionSite() &&
		    !pThisEvent->showSite())
		{
		    lPrev = lPos;
		    pThisEvent = (CSmil1ShowSiteEvent*)m_pEventList->GetNext(lPos);
		}
	    }

	    m_pEventList->InsertBefore(lPrev, pEvent);
	    bInserted = TRUE;
	    break;
	}
	else if(pThisEvent->m_ulEventTime > pEvent->m_ulEventTime)
	{
	    m_pEventList->InsertBefore(lPrev, pEvent);
	    bInserted = TRUE;
	    break;
	}
	lPrev = lPos;
    }
    if(!bInserted)
    {
	// not inserted, stick it on the end of the list
	m_pEventList->AddTail(pEvent);
    }

    // set list position member
    m_ulEventListPosition = m_pEventList->GetHeadPosition();

    return HXR_OK;
}

CSmil1ShowSiteEvent* 
CSmil1DocumentRenderer::getShowHideEvent(IHXSite*  pRegionSite,
					 IHXSite*  pRendererSite,
                                         BOOL	    bShowEvent)
{
    CSmil1ShowSiteEvent* pRet = NULL;

    if (m_pEventList && pRegionSite)
    {
        LISTPOSITION pos = m_pEventList->GetHeadPosition();
        while (pos)
        {
            CSmil1ShowSiteEvent* pEvent = (CSmil1ShowSiteEvent*) m_pEventList->GetNext(pos);
            if (pEvent)
            {
                if (pEvent->showSite() == bShowEvent	    &&
		    pEvent->getRegionSite() == pRegionSite  &&
		    pEvent->getRendererSite() == pRendererSite)
                {
                    pRet = pEvent;
                    break;
                }
            }
        }
    }

    return pRet;
}

HX_RESULT
CSmil1DocumentRenderer::insertSiteInfo(void* pVoidInfo)
{
    if(!m_pSiteInfoList)
    {
	m_pSiteInfoList = new CHXSimpleList;
    }

    SMIL1SiteInfo* pInfo = (SMIL1SiteInfo*)pVoidInfo;

    LISTPOSITION lPos = m_pSiteInfoList->GetHeadPosition();
    LISTPOSITION lPrev = lPos;

    BOOL bInserted = FALSE;
    while(lPos)
    {
	SMIL1SiteInfo* pThisInfo = 
	    (SMIL1SiteInfo*)m_pSiteInfoList->GetNext(lPos);

	if(pThisInfo->m_ulDelay > pInfo->m_ulDelay)
	{
	    m_pSiteInfoList->InsertBefore(lPrev, pInfo);
	    bInserted = TRUE;
	    break;
	}
	lPrev = lPos;
    }
    if(!bInserted)
    {
	// not inserted, stick it on the end of the list
	m_pSiteInfoList->AddTail(pInfo);
    }

    return HXR_OK;
}


void
CSmil1DocumentRenderer::resizeSite(IHXSite* pSite,
				  double dXScale,
				  double dYScale)
{
    if (!pSite)
    {
	return;
    }

    HXxSize oldChildSize;
    HXxPoint oldChildPosition;
    pSite->GetSize(oldChildSize);
    pSite->GetPosition(oldChildPosition);
    HXxSize newChildSize;
    HXxPoint newChildPosition;
    newChildSize.cx = (INT32)(dXScale * (double)(oldChildSize.cx) + 0.5);
    newChildSize.cy = (INT32)(dYScale * (double)(oldChildSize.cy) + 0.5);
    newChildPosition.x = (INT32)(dXScale*(double)(oldChildPosition.x) + 0.5);
    newChildPosition.y = (INT32)(dYScale*(double)(oldChildPosition.y) + 0.5);

    CSmil1SiteWatcher* pSiteWatcher = NULL;
    if(m_pSiteWatcherMap && m_pSiteWatcherMap->Lookup(pSite, (void*&)pSiteWatcher))
    {
	pSiteWatcher->SiteChangingSize(TRUE);
//        char szDbgStr[128];
//        DEBUGPRINTF(szDbgStr, "(%ld,%ld) ", newChildSize.cx, newChildSize.cy);
	pSite->SetSize(newChildSize);
	pSiteWatcher->SiteChangingSize(FALSE);
    }
    else
    {
//        char szDbgStr[128];
//        DEBUGPRINTF(szDbgStr, "(%ld,%ld) ", newChildSize.cx, newChildSize.cy);
	pSite->SetSize(newChildSize);
    }
//    char szDbgStr[128];
//    DEBUGPRINTF(szDbgStr, "repos to (%ld,%ld)\n", newChildPosition.x, newChildPosition.y);
    pSite->SetPosition(newChildPosition);

    CHXxRect updateRect(0, 0, newChildSize.cx, newChildSize.cy);
    pSite->DamageRect(updateRect);
#ifndef  _WIN32
    pSite->ForceRedraw();
#endif
}

void CSmil1DocumentRenderer::resizeRegionSiteAbs(CSmil1BasicRegion* pRegion,
                                                double            dXAbsScale,
                                                double            dYAbsScale)
{
    if (pRegion && pRegion->m_pSite)
    {
        HXxSize  cSize = {0, 0};
        HXxPoint cPos  = {0, 0};
        cPos.x         = (INT32) floor(dXAbsScale * ((double) pRegion->m_originalRect.left) + 0.5);
        cPos.y         = (INT32) floor(dYAbsScale * ((double) pRegion->m_originalRect.top)  + 0.5);
        cSize.cx       = (INT32) floor(dXAbsScale * ((double) HXxRECT_WIDTH(pRegion->m_originalRect)) + 0.5);
        cSize.cy       = (INT32) floor(dYAbsScale * ((double) HXxRECT_HEIGHT(pRegion->m_originalRect)) + 0.5);

        CSmil1SiteWatcher* pSiteWatcher = NULL;
        if(m_pSiteWatcherMap && m_pSiteWatcherMap->Lookup(pRegion->m_pSite, (void*&)pSiteWatcher))
        {
	    pSiteWatcher->SiteChangingSize(TRUE);
//            char szDbgStr[128];
//            DEBUGPRINTF(szDbgStr, "(%ld,%ld) ", cSize.cx, cSize.cy);
	    pRegion->m_pSite->SetSize(cSize);
	    pSiteWatcher->SiteChangingSize(FALSE);
        }
        else
        {
//            char szDbgStr[128];
//            DEBUGPRINTF(szDbgStr, "(%ld,%ld) ", cSize.cx, cSize.cy);
	    pRegion->m_pSite->SetSize(cSize);
        }
//        char szDbgStr[128];
//        DEBUGPRINTF(szDbgStr, "repos to (%ld,%ld)\n", cPos.x, cPos.y);
        pRegion->m_pSite->SetPosition(cPos);

        pRegion->m_rect.left   = cPos.x;
        pRegion->m_rect.top    = cPos.y;
        pRegion->m_rect.right  = cPos.x + cSize.cx;
        pRegion->m_rect.bottom = cPos.y + cSize.cy;

        CHXxRect updateRect(0, 0, cSize.cx, cSize.cy);
        pRegion->m_pSite->DamageRect(updateRect);
#ifndef  _WIN32
        pRegion->m_pSite->ForceRedraw();
#endif
    }
}

void
CSmil1DocumentRenderer::resizeSite(HXxSize newSize)
{
    double dXScale = 1.0;
    double dYScale = 1.0;

    if(newSize.cx       > 0 &&
       newSize.cy       > 0 &&
       m_topSiteSize.cx > 0 &&
       m_topSiteSize.cy > 0)
    {
	dXScale = (double)newSize.cx / (double)m_topSiteSize.cx;
	dYScale = (double)newSize.cy / (double)m_topSiteSize.cy;
    }

    double dXAbsScale = 1.0;
    double dYAbsScale = 1.0;
    if (m_topSiteOriginalSize.cx > 0 &&
        m_topSiteOriginalSize.cy > 0)
    {
        dXAbsScale = (double) newSize.cx / (double) m_topSiteOriginalSize.cx;
        dYAbsScale = (double) newSize.cy / (double) m_topSiteOriginalSize.cy;
    }

    m_topSiteSize.cx = newSize.cx;
    m_topSiteSize.cy = newSize.cy;

    BOOL bSetOriginalSize = FALSE;
    if(m_topSiteSize.cx == m_topSiteOriginalSize.cx &&
	m_topSiteSize.cy == m_topSiteOriginalSize.cy)
    {
	bSetOriginalSize = TRUE;
	m_dResizeXScale = 1.0;
	m_dResizeYScale = 1.0;
    }
    else
    {
	m_dResizeXScale = dXScale;
	m_dResizeYScale = dYScale;
    }

    if(m_pRegionMap)
    {
	// scale regions
	CHXMapStringToOb::Iterator i = m_pRegionMap->Begin();
	for(; i != m_pRegionMap->End(); ++i)
	{
            BOOL bAbs = FALSE;
	    CSmil1BasicRegion* pRegion = (CSmil1BasicRegion*)(*i);
            if ((m_bRootLayoutWidthSet || m_ulNoRootLayoutWidth) &&
                (m_bRootLayoutHeightSet || m_ulNoRootLayoutHeight) &&
                !pRegion->m_bWidthUnspecified &&
                !pRegion->m_bHeightUnspecified)
            {
                bAbs = TRUE;
//                char szDbgStr[128];
//                DEBUGPRINTF(szDbgStr, "region %s abs resizing to ", (const char*) pRegion->m_region);
                resizeRegionSiteAbs(pRegion, dXAbsScale, dYAbsScale);
            }
            else
            {
//                char szDbgStr[128];
//                DEBUGPRINTF(szDbgStr, "region %s resizing to ", (const char*) pRegion->m_region);
                resizeSite(pRegion->m_pSite, dXScale, dYScale);
            }

	    SMIL1PlayToAssoc* pAssoc = getPlayToAssoc(pRegion->m_region);

	    if(bSetOriginalSize)
	    {
		pRegion->m_rect = pRegion->m_originalRect;

		//Helps fix PR 11265:
		pRegion->m_mediaSize.cx = pRegion->m_originalMediaSize.cx;
		pRegion->m_mediaSize.cy = pRegion->m_originalMediaSize.cy;

		if(pAssoc && pAssoc->m_pHyperlinks)
		{
		    CHXSimpleList::Iterator i = pAssoc->m_pHyperlinks->Begin();
		    for(; i != pAssoc->m_pHyperlinks->End(); ++i)
		    {
			CSmil1AAnchorElement* pAnchor = 
			    (CSmil1AAnchorElement*)(*i);
			pAnchor->rescale(0.0, 0.0, TRUE);   // set to original coords
		    }
		}
	    }
	    else
            {
                if (!bAbs)
                {
		    // Fix for PR 17415
		    // dXScale & dYScale are reletive to the current size, 
		    UINT32 ulNewLeft = (INT32)(dXScale * 
		        (double)(pRegion->m_rect.left) + 0.5);
		    UINT32 ulNewTop = (INT32)(dYScale * 
		        (double)(pRegion->m_rect.top) + 0.5);
		    UINT32 ulNewWidth = (INT32)(dXScale * 
         	        (double)(pRegion->m_rect.right -
		        pRegion->m_rect.left) + 0.5);
		    UINT32 ulNewHeight = (INT32)(dYScale * 
		        (double)(pRegion->m_rect.bottom -
		        pRegion->m_rect.top) + 0.5);
		    pRegion->m_rect.left = ulNewLeft;
		    pRegion->m_rect.top = ulNewTop;
		    pRegion->m_rect.right = ulNewLeft + ulNewWidth;
		    pRegion->m_rect.bottom = ulNewTop + ulNewHeight;

		    //Fixes PR 11265:
		    pRegion->m_mediaSize.cx = ulNewWidth;
		    pRegion->m_mediaSize.cy = ulNewHeight;
                }

		if(pAssoc && pAssoc->m_pHyperlinks)
		{
		    CHXSimpleList::Iterator i = pAssoc->m_pHyperlinks->Begin();
		    for(; i != pAssoc->m_pHyperlinks->End(); ++i)
		    {
			CSmil1AAnchorElement* pAnchor = 
			    (CSmil1AAnchorElement*)(*i);
			pAnchor->rescale(dXScale, dYScale, FALSE);
		    }
		}
	    }
	}
    }

    if(m_pSiteInfoList)
    {
	// scale current renderer sites
	CHXSimpleList::Iterator i = m_pSiteInfoList->Begin();
	for(; i != m_pSiteInfoList->End(); ++i)
	{
	    SMIL1SiteInfo* pSiteInfo = (SMIL1SiteInfo*)(*i);
//            char szDbgStr[128];
//            DEBUGPRINTF(szDbgStr, "media in region %s resizing to ",
//                        (const char*) pSiteInfo->m_regionID);
            // See if we can look up a region
            CSmil1BasicRegion* pReg = getRegion((const char*) pSiteInfo->m_regionID);
            if (pReg)
            {
                // Compute the media layout at original scale
                HXxSize cOrigRegSize = {0, 0};
                cOrigRegSize.cx      = HXxRECT_WIDTH(pReg->m_originalRect);
                cOrigRegSize.cy      = HXxRECT_HEIGHT(pReg->m_originalRect);
                HXxSize cFitSize     = pReg->m_originalMediaSize;
                computeMediaFitSize(cOrigRegSize, pReg->m_originalMediaSize,
                                    pReg->m_fit, cFitSize);
                // Now scale the original media size
                HXxSize cScaledFitSize = {0, 0};
                cScaledFitSize.cx = (INT32) ((double) cFitSize.cx * dXAbsScale + 0.5);
                cScaledFitSize.cy = (INT32) ((double) cFitSize.cy * dYAbsScale + 0.5);
                // Get the site watcher
                CSmil1SiteWatcher* pSW = NULL;
                if(m_pSiteWatcherMap)
                {
                    void* pVoid = NULL;
                    if (m_pSiteWatcherMap->Lookup(pSiteInfo->m_pRendererSite, pVoid))
                    {
                        pSW = (CSmil1SiteWatcher*) pVoid;
                    }
                }
                // Set the "disable" flag in the site watcher
                if (pSW) pSW->SiteChangingSize(TRUE);
                // Set the size
//                DEBUGPRINTF(szDbgStr, "(%ld,%ld)\n", cScaledFitSize.cx, cScaledFitSize.cy);
                if(pSiteInfo && pSiteInfo->m_pRendererSite)
                      pSiteInfo->m_pRendererSite->SetSize(cScaledFitSize);
                
                // Clear the "disable" flag in the site watcher
                if (pSW) pSW->SiteChangingSize(FALSE);
            }
            else
            {
                // Do what we normally do
                resizeSite(pSiteInfo->m_pRendererSite, dXScale, dYScale);
            }
	}
    }
}

HX_RESULT
CSmil1DocumentRenderer::onTimeSync(UINT32 ulTimeValue)
{
//    char szDbgStr[128];
//    DEBUGPRINTF(szDbgStr, "onTimeSync(%lu)\n", ulTimeValue);
    HX_RESULT rc = HXR_OK;
    m_ulCurrentTime = ulTimeValue;

    if(!m_bFirstTimeSync)
    {
	// draw background and regions
	m_bFirstTimeSync = TRUE;

	// now I should force a background redraw...
	if(m_pMISUSSite)
	{
	    HXxSize siteWinSize;
	    m_pMISUSSite->GetSize(siteWinSize);
	    CHXxRect updateRect(0, 0, siteWinSize.cx, siteWinSize.cy);
	    m_pMISUSSite->DamageRect(updateRect);
	    m_pMISUSSite->ForceRedraw();


	    if(m_pRegionMap)
	    {
		CHXMapStringToOb::Iterator i = m_pRegionMap->Begin();
		for(; i != m_pRegionMap->End(); ++i)
		{
		    CSmil1BasicRegion* pRegion = (CSmil1BasicRegion*)(*i);
		    if(pRegion->m_pSite)
		    {
			pRegion->m_pSite->GetSize(siteWinSize);
			CHXxRect siteRect(0, 0, siteWinSize.cx, siteWinSize.cy);
			pRegion->m_pSite->DamageRect(siteRect);
			pRegion->m_pSite->ForceRedraw();
		    }
		}
	    }
	}
    }

    rc = flushAllEvents( ulTimeValue, TRUE );
    return rc;
}

void
CSmil1DocumentRenderer::RemoveEvents(UINT32 ulGroupIndex, IHXSite* pSite)
{
    // handle all events up to time ulFlushToTime + ulGranularity
    HX_RESULT rc = HXR_OK;

    if(m_pEventList)
    {
	LISTPOSITION lPos = m_pEventList->GetHeadPosition();
	while(lPos && m_pEventList->GetCount())
	{
	    // handle all events at or before ulTimeValue
	    CSmil1ShowSiteEvent* pEvent = (CSmil1ShowSiteEvent*)m_pEventList->GetAt(lPos);
	    if(pEvent->m_uGroupIndex == ulGroupIndex &&
	       pEvent->getRendererSite() == pSite)
	    {
		HX_DELETE(pEvent);
		lPos = m_pEventList->RemoveAt(lPos);
	    }
	    else
	    {
		m_pEventList->GetNext(lPos);
	    }
	}

	// set list position member
	m_ulEventListPosition = m_pEventList->GetHeadPosition();
    }

    return;
}

HX_RESULT CSmil1DocumentRenderer::flushAllEvents( UINT32 ulFlushToTime, BOOL bBreak)
{
    // handle all events up to time ulFlushToTime + ulGranularity
    HX_RESULT rc = HXR_OK;

    if(m_pEventList && m_pEventList->GetCount() > 0)
    {
	//LISTPOSITION lPos = m_pEventList->GetHeadPosition();
	while(m_ulEventListPosition)
	{
	    // handle events which have eventTime<=ulFlushToTime+ulGranularity
	    CSmil1LayoutEvent* pEvent
		= (CSmil1LayoutEvent*) m_pEventList->GetAt(m_ulEventListPosition);
//{FILE* f1 = ::fopen("c:\\temp\\out.txt", "a+"); ::fprintf(f1, "Flush Events pEvent=%lu\n", pEvent);::fclose(f1);}
	    
#ifdef _MACINTOSH
	    // XXXBobClark:
	    // On the Mac side, our site's ShowSite implementation
	    // draws synchronously: right then. On Windows, it draws
	    // asynchronously by setting up a callback. The upshot is
	    // that on Windows you can get away with a ShowSite(TRUE)
	    // followed immediately by a ShowSite(FALSE), because the
	    // actual screen won't get updated while the site is
	    // briefly visible. But on the Mac it will show a visible
	    // flicker. So the interim workaround here is to check the
	    // events we're flushing; if we're showing a site that will
	    // be hidden by the time the flush is done (or vice versa),
	    // we ignore that event.
	    LISTPOSITION tempPos = m_ulEventListPosition;
	    BOOL bCurrentEventCancelledOutByFutureEvent = FALSE;
	    CSmil1ShowSiteEvent* pCurrentEvent = (CSmil1ShowSiteEvent*)pEvent;
	    m_pEventList->GetNext(tempPos); // to start with the next position...
	    while (tempPos)
	    {
		CSmil1ShowSiteEvent* pFutureEvent = (CSmil1ShowSiteEvent*)m_pEventList->GetAt(tempPos);
		if ( !pFutureEvent
		     || pFutureEvent->m_ulEventTime > ulFlushToTime)
		{
		    break;
		}
		
		if ( pFutureEvent && pCurrentEvent
			&& pCurrentEvent->m_pSite == pFutureEvent->m_pSite
			&& pCurrentEvent->m_pRegionSite == pFutureEvent->m_pRegionSite
			&& pCurrentEvent->m_bShowSite != pFutureEvent->m_bShowSite )
		{
		    bCurrentEventCancelledOutByFutureEvent = TRUE;
		    break;
		}
		
		m_pEventList->GetNext(tempPos);
	    }
#endif
	    // no need of granularity since the core will
	    // ensure we call OnTimeSync at the end of its duration
	    if (pEvent &&
		pEvent->m_ulEventTime <= ulFlushToTime)
	    {
#ifdef _MACINTOSH
	      if (!bCurrentEventCancelledOutByFutureEvent)
#endif
		rc = pEvent->handleEvent();
		//lPos = m_pEventList->RemoveAt(lPos);
	    }
	    else if( bBreak )
	    {
		break;
	    }

	    m_pEventList->GetNext(m_ulEventListPosition);
	}
    }

    return rc;
}


BOOL
CSmil1DocumentRenderer::IsFullScreen()
{
    BOOL bRet = FALSE;

    if (m_pMISUSSite)
    {
	IHXSiteFullScreen* pFull = NULL;
	m_pMISUSSite->QueryInterface(IID_IHXSiteFullScreen, (void**) &pFull);
	if (pFull)
	{
	    bRet = pFull->IsFullScreen();
	}
	HX_RELEASE(pFull);
    }

    return bRet;
}

void CSmil1DocumentRenderer::computeMediaFitSize(HXxSize      cRegSize,
                                                 HXxSize      cMedSize,
                                                 const char*  pszFitAttr,
                                                 REF(HXxSize) rcFitSize)
{
    UINT32 ulFit = 0; // 0=hidden, 1=fill, 2=meet, 3=slice, 4=scroll
    if (pszFitAttr)
    {
        if (!strcmp(pszFitAttr, "hidden"))
        {
            ulFit = 0;
        }
        else if (!strcmp(pszFitAttr, "fill"))
        {
            ulFit = 1;
        }
        else if (!strcmp(pszFitAttr, "meet"))
        {
            ulFit = 2;
        }
        else if (!strcmp(pszFitAttr, "slice"))
        {
            ulFit = 3;
        }
        else if (!strcmp(pszFitAttr, "scroll"))
        {
            ulFit = 4;
        }
    }
    switch (ulFit)
    {
        case 0:
            {
                // fit="hidden"
                rcFitSize = cMedSize;
            }
            break;
        case 1:
            {
                // fit="fill"
                rcFitSize = cRegSize;
            }
            break;
        case 2:
            {
                // fit="meet"
                double dMedAspectRatio = 1.0;
                if(cMedSize.cx != 0 && cMedSize.cy != 0)
                {
                    dMedAspectRatio = (double) cMedSize.cx / (double) cMedSize.cy;
                }
                INT32 lTryHeight = (INT32)((double) cRegSize.cx / dMedAspectRatio + 0.5);
                if(lTryHeight > cRegSize.cy)
                {
                    rcFitSize.cx = (INT32) ((double) cRegSize.cy * dMedAspectRatio + 0.5);
                    rcFitSize.cy = cRegSize.cy;
                }
                else
                {
                    rcFitSize.cx = cRegSize.cx;
                    rcFitSize.cy = lTryHeight;
                }
            }
            break;
        case 3:
            {
                // fit="slice"
                double dMedAspectRatio  = 1.0;
                if(cMedSize.cx != 0 && cMedSize.cy != 0)
                {
                    dMedAspectRatio = (double) cMedSize.cx / (double) cMedSize.cy;
                }
                double dRegAspectRatio = 1.0;
                if (cRegSize.cx != 0 && cRegSize.cy != 0)
                {
                    dRegAspectRatio = (double) cRegSize.cx / (double) cRegSize.cy;
                }
                // fit to greater of region height or width
                if(dRegAspectRatio > dMedAspectRatio)
                {
                    rcFitSize.cx = cRegSize.cx;
                    rcFitSize.cy = (INT32)((double) cRegSize.cx / dMedAspectRatio + 0.5);
                }
                else
                {
                    rcFitSize.cx = (INT32)((double) cRegSize.cy * dMedAspectRatio + 0.5);
                    rcFitSize.cy = cRegSize.cy;
                }
            }
            break;
        case 4:
            {
                // fit="scroll"
                rcFitSize = cMedSize;
            }
            break;
    }
}

HX_RESULT CSmil1DocumentRenderer::getPreference(IUnknown*        pContext,
                                                const char*      pszKey,
                                                REF(IHXBuffer*) rpValue)
{
    HX_RESULT retVal = HXR_FAIL;

    if (pContext && pszKey)
    {
        IHXPreferences* pPreferences = NULL;
        retVal = pContext->QueryInterface(IID_IHXPreferences,
                                          (void**) &pPreferences);
        if (SUCCEEDED(retVal))
        {
            IHXBuffer* pBuf = NULL;
            retVal = pPreferences->ReadPref(pszKey, pBuf);
            if (SUCCEEDED(retVal))
            {
                HX_RELEASE(rpValue);
                rpValue = pBuf;
                rpValue->AddRef();
            }
            HX_RELEASE(pBuf);

        }
        HX_RELEASE(pPreferences);
    }

    return retVal;
}

HX_RESULT CSmil1DocumentRenderer::getBooleanPreference(IUnknown*   pContext,
                                                       const char* pszKey,
                                                       REF(BOOL)   rbValue)
{
    HX_RESULT retVal = HXR_FAIL;

    if (pContext && pszKey)
    {
        IHXBuffer* pBuf = NULL;
        retVal = getPreference(pContext, pszKey, pBuf);
        if (SUCCEEDED(retVal))
        {
            INT32 lValue = ::atoi((const char*) pBuf->GetBuffer());
            if (lValue == 1)
            {
                rbValue = TRUE;
            }
        }
        HX_RELEASE(pBuf);
    }

    return retVal;
}

HX_RESULT
CSmil1DocumentRenderer::onPreSeek(UINT32 ulOldTime, UINT32 ulNewTime)
{
    HX_RESULT rc = HXR_OK;

//{FILE* f1 = ::fopen("c:\\temp\\out.txt", "a+"); ::fprintf(f1, "onPreSeek\n");::fclose(f1);}

    if(m_pSiteInfoList)
    {
	// hide all regions/sites in current group
	CHXSimpleList::Iterator i = m_pSiteInfoList->Begin();
	for(; i != m_pSiteInfoList->End(); ++i)
	{
	    SMIL1SiteInfo* pSiteInfo = (SMIL1SiteInfo*)(*i);
	    if(pSiteInfo->m_uGroupIndex == m_uCurrentGroupIndex)
	    {
		IHXSite* pRegionSite = NULL;
		CSmil1BasicRegion* pRegion = getRegion(pSiteInfo->m_regionID);
		if(!pRegion->m_bBgColorSet)
		{
		    pRegionSite = pSiteInfo->m_pRegionSite;
		}
		showSite(pSiteInfo->m_pRendererSite, FALSE);
		showSite(pRegionSite, FALSE);
	    }
	}

	// show/hide sites up to ulNewTime

	// events at the same time for the same region
	// are ordererd 'hide' first, then 'show' so
	// a hide doesn't override a show.
	m_ulEventListPosition = m_pEventList->GetHeadPosition();
	flushAllEvents( ulNewTime, TRUE );
    }
    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::endStream()
{
    flushAllEvents();    // flush all remaining events

    if(m_pGroupMap)
    {
	CHXMapLongToObj::Iterator i;
	for(i=m_pGroupMap->Begin();i!=m_pGroupMap->End();++i)
	{
	    IHXGroup* pGroup = (IHXGroup*)(*i);
	    pGroup->Release();
	}
	HX_DELETE(m_pGroupMap);
    }

    HX_RELEASE(m_pPersistentProperties);
    HX_RELEASE(m_pPersistentParentRenderer);

    return HXR_OK;
}

CSmil1BasicRegion*
CSmil1DocumentRenderer::getRegion(const char* pID)
{
    CSmil1BasicRegion* pRegion = 0;
    if(m_pRegionMap)
    {
	m_pRegionMap->Lookup(pID, (void*&)pRegion);
    }
    return pRegion;
}

void
CSmil1DocumentRenderer::setTopLevelSiteSize()
{
    HXxRect outerRect;
    
    outerRect.left	= 0;
    outerRect.right	= 0;
    outerRect.bottom	= 0;
    outerRect.top	= 0;

    if(m_bRootLayoutWidthSet)
    {
	outerRect.left = 0;
	outerRect.right = m_ulRootLayoutWidth;
    }
    else
    {
	outerRect.left = 0;
	outerRect.right = m_ulNoRootLayoutWidth;
    }
    if(m_bRootLayoutHeightSet)
    {
	outerRect.top = 0;
	outerRect.bottom = m_ulRootLayoutHeight;
    }
    else
    {
	outerRect.top = 0;
	outerRect.bottom = m_ulNoRootLayoutHeight;
    }

    HXxSize size;
    size.cx = HXxRECT_WIDTH(outerRect);
    size.cy = HXxRECT_HEIGHT(outerRect);

    m_topSiteSize.cx = HXxRECT_WIDTH(outerRect);
    m_topSiteSize.cy = HXxRECT_HEIGHT(outerRect);
    m_topSiteOriginalSize.cx = m_topSiteSize.cx;
    m_topSiteOriginalSize.cy = m_topSiteSize.cy;

    if(m_topSiteSize.cx > 0 && m_topSiteSize.cy > 0)
    {
	m_pMISUSSite->SetSize(m_topSiteSize);
        m_pMISUSSite->GetSize(m_topSiteSize);
    }
}

HX_RESULT
CSmil1DocumentRenderer::createRegionSites()
{
    // these sites and site users will be deleted
    // in the CSmil1BasicRegion destructor
    if(m_pMISUSSite && m_pRegionMap)
    {
	CHXMapStringToOb::Iterator i = m_pRegionMap->Begin();
	for(; i != m_pRegionMap->End(); ++i)
	{
	    CSmil1BasicRegion* pRegion = (CSmil1BasicRegion*)(*i);
	    m_pMISUSSite->CreateChild(pRegion->m_pSite);

	    // set region size and position
	    HXxPoint point;
	    HXxSize size;
	    point.x = pRegion->m_rect.left;
	    point.y = pRegion->m_rect.top;
	    pRegion->m_pSite->SetPosition(point);
	    size.cx = HXxRECT_WIDTH(pRegion->m_rect);
	    size.cy = HXxRECT_HEIGHT(pRegion->m_rect);
	    pRegion->m_pSite->SetSize(size);

	    pRegion->m_pSiteUser = new CSmil1SiteUser(this, pRegion->m_ulBgColor);
	    pRegion->m_pSiteUser->AddRef();
	    pRegion->m_pSite->AttachUser(pRegion->m_pSiteUser);

	    if(!pRegion->m_bBgColorSet)
	    {
		showSite(pRegion->m_pSite, FALSE);
	    }
	}
    }
    return HXR_OK;
}

/*
 * IHXSiteUser methods
 */

STDMETHODIMP
CSmil1DocumentRenderer::AttachSite(IHXSite* /*IN*/ pSite)
{
    HX_RESULT rc = HXR_OK;

    if (m_pMISUSSite)
    {
	return rc;
    }
    m_pMISUSSite = pSite;
    m_pMISUSSite->AddRef();

    IHXCommonClassFactory* pFactory = m_pParent->getFactory();

    setTopLevelSiteSize();

    IHXSite2* pSite2 = NULL;
    if(HXR_OK == m_pMISUSSite->QueryInterface(IID_IHXSite2, (void**)&pSite2))
    {
	pSite2->AddPassiveSiteWatcher(this);
	pSite2->Release();
    }
    return rc;
}

STDMETHODIMP
CSmil1DocumentRenderer::DetachSite()
{
    // XXX HP keep the m_pSiteInfoByRendererMap object
    // which will be delete in close()
    if(m_pSiteInfoByRendererMap)
    {
	CHXMapPtrToPtr::Iterator i = m_pSiteInfoByRendererMap->Begin();
	for (;i!=m_pSiteInfoByRendererMap->End();++i)
	{
	    SMIL1SiteInfo* pSiteInfo = (SMIL1SiteInfo*)(*i);
	    m_pSiteMgr->RemoveSite(pSiteInfo->m_pRendererSite);
	    CSmil1BasicRegion* pRegion = getRegion(pSiteInfo->m_regionID);
	    if(pRegion &&
		pRegion->m_pSite)
	    {
		pRegion->m_pSite->DestroyChild(pSiteInfo->m_pRendererSite);
	    }
	    pSiteInfo->m_pRendererSite->DetachWatcher();
	    HX_RELEASE(pSiteInfo->m_pRendererSite);
	}
	m_pSiteInfoByRendererMap->RemoveAll();	
        if (m_bCloseCalled)
        {
            HX_DELETE(m_pSiteInfoByRendererMap);
        }
    }

    if(m_pRegionMap)
    {
	CHXMapStringToOb::Iterator i = m_pRegionMap->Begin();
	for(; i != m_pRegionMap->End(); ++i)
	{
	    CSmil1BasicRegion* pRegion = (CSmil1BasicRegion*)(*i);
	    if(pRegion->m_pSite)
	    {
		m_pMISUSSite->DestroyChild(pRegion->m_pSite);
                // Detach the site user
                pRegion->m_pSite->DetachUser();
                // Release our ref on the site user
                HX_RELEASE(pRegion->m_pSiteUser);
	    }
	    HX_RELEASE(pRegion->m_pSite);
            if (m_bCloseCalled)
            {
                HX_DELETE(pRegion);
            }
	}
        if (m_bCloseCalled)
        {
            m_pRegionMap->RemoveAll();
            HX_DELETE(m_pRegionMap);
        }
    }

    if(m_pSiteWatcherMap)
    {
	CHXMapPtrToPtr::Iterator i= m_pSiteWatcherMap->Begin();
	for(; i != m_pSiteWatcherMap->End(); ++i)
	{
	    CSmil1SiteWatcher* pSiteWatcher = (CSmil1SiteWatcher*)(*i);
	    pSiteWatcher->Release();
	}
	HX_DELETE(m_pSiteWatcherMap);
    }

    IHXSite2* pSite2 = NULL;
    if(m_pMISUSSite &&
	HXR_OK == m_pMISUSSite->QueryInterface(IID_IHXSite2, (void**)&pSite2))
    {
	pSite2->RemovePassiveSiteWatcher(this);
	pSite2->Release();
    }

    HX_RELEASE(m_pMISUSSite);

#ifdef _MACINTOSH
    if (m_bResetCursor)
    {
	m_bResetCursor = FALSE;
	::InitCursor();
    }
#endif

    m_bSitesDetached = TRUE;

    if (m_bCloseCalled)
    {
        if(m_pSiteInfoList)
        {
	    CHXSimpleList::Iterator i = m_pSiteInfoList->Begin();
	    for(; i != m_pSiteInfoList->End(); ++i)
	    {
	        SMIL1SiteInfo* pSiteInfo = (SMIL1SiteInfo*)(*i);
	        delete pSiteInfo;
	    }
        }
        HX_DELETE(m_pSiteInfoList);
    }

    return HXR_OK;
}

HX_RESULT
CSmil1DocumentRenderer::HandleSurfaceUpdate(HXxEvent* pEvent,
					   IHXSite* pSite,
					   HXxColor ulBGColor)
{
    HX_RESULT rc = HXR_OK;

    HXxColor ulInitialBGColor = 0;  // paint black until first timestamp is received
    if(pSite)
    {
	draw(pEvent, pSite, 
	    m_bFirstTimeSync ?
		ulBGColor: ulInitialBGColor);
    }

    return rc;
}


STDMETHODIMP
CSmil1DocumentRenderer::HandleEvent(HXxEvent* /*IN*/ pEvent)
{
    pEvent->handled = FALSE;
    pEvent->result  = 0;

    switch (pEvent->event)
    {
	case HX_SURFACE_UPDATE:
	{
	    if(HXR_OK == HandleSurfaceUpdate(pEvent, m_pMISUSSite,
		(m_bRootLayoutWidthSet  ||  m_bRootLayoutHeightSet) ?
		    m_ulRootLayoutBGColor: 0))
	    {
		pEvent->handled = TRUE;
	    }
	}

#if defined(_UNIX)  &&  (!defined(_BEOS))  &&  defined(USE_XWINDOWS)
	    //
	    // Create a "hand" cursor for hyperlinks
	    //
	    {
		//
		// free previously allocated cursor
		//
		if (m_pDisplay && m_hHyperlinkCursor)
		{
		    XFreeCursor(m_pDisplay, m_hHyperlinkCursor);
		    m_hHyperlinkCursor = 0;
		}

		// 
		// get new display/window parameters and 
		// allocate a new cursor
		//
		HXxWindow *pWnd = (HXxWindow*)pEvent->param2;
		m_pDisplay = (Display*)pWnd->display;
		m_Window = (Window)pWnd->window;
		if (m_pDisplay)
		    m_hHyperlinkCursor = XCreateFontCursor(m_pDisplay, XC_hand2);
	    }	    
#endif

	break;
    }

    return HXR_OK;
}

/*
 *	IHXPassiveSiteWatcher methods
 */
STDMETHODIMP
CSmil1DocumentRenderer::PositionChanged (HXxPoint* /*IN*/ pPoint)
{
    return HXR_OK; // PNR_NOIMPL???
}

STDMETHODIMP
CSmil1DocumentRenderer::SizeChanged (HXxSize* /*IN*/ pSize)
{
//    char szDbgStr[128];
//    DEBUGPRINTF(szDbgStr, "SizeChanged(%ld,%ld) m_topSiteSize=(%ld,%ld) m_ulCurrentTime=%lu t=%lu\n",
//                pSize->cx, pSize->cy, m_topSiteSize.cx, m_topSiteSize.cy,
//                m_ulCurrentTime, HX_GET_BETTERTICKCOUNT());
    // check for resize of top level site, we must have
    // a "site" and not already be resizing!
    if(m_pMISUSSite && !m_bSiteChangingSize)
    {
        if (pSize->cx != m_topSiteSize.cx ||
            pSize->cy != m_topSiteSize.cy)
        {
	    m_bSiteChangingSize = TRUE;
	    resizeSite(*pSize);
	    CHXxRect updateRect(0, 0, pSize->cx, pSize->cy);
	    m_pMISUSSite->DamageRect(updateRect);
#ifndef  _WIN32
	    m_pMISUSSite->ForceRedraw();
#endif
	    m_bSiteChangingSize = FALSE;
        }
    }

    return HXR_OK;
}

#ifdef _MACINTOSH
UINT16	Convert8BitTo16Bit(UINT8 x)
{
    float factor=((float)x)/255;
    long returnValue=(factor*65535);
    
    return returnValue;
}

void ConvertCOLORTYPEtoRGBColor(RGBColor& rgbColor, HXxColor colorVal)
{
    char*	x=(char*)&colorVal;
    
    rgbColor.red   =(short)Convert8BitTo16Bit(x[1]);
    rgbColor.green =(short)Convert8BitTo16Bit(x[2]);
    rgbColor.blue  =(short)Convert8BitTo16Bit(x[3]);
    
}
#endif

#if defined(_UNIX)  &&  (!defined(_BEOS))  &&  defined(USE_XWINDOWS)
void  CSmil1DocumentRenderer::ConvertPNxColorToXColor(HXxColor hxxColor, XColor& xcolor)
{
    // assume starting with a new XColor
    memset(&xcolor, 0, sizeof(XColor));

    // separate r,g and b
    UINT16 t;
    t = (hxxColor & 0x00ff0000) >> 16;
    xcolor.red   = t << 8;
    
    t = (hxxColor & 0x0000ff00) >> 8;
    xcolor.green = t << 8;
    
    t = (hxxColor & 0x000000ff);
    xcolor.blue  = t << 8;
    
    //color.pixel = n;
    xcolor.flags = DoRed | DoGreen | DoBlue;
}
#endif

BOOL
CSmil1DocumentRenderer::draw(HXxEvent* pEvent, IHXSite* pSite, 
			    HXxColor ulBgColor)
{
    if(pEvent &&
       pEvent->event == HX_SURFACE_UPDATE && 
       pEvent->result == HXR_OK)
    {
        // Set up color
        UINT32 ulColor = ulBgColor;
        // Set up bitmap info header
        HXBitmapInfoHeader cHeader;
        cHeader.biSize          = 40;
        cHeader.biWidth         = 1;
        cHeader.biHeight        = 1;
        cHeader.biPlanes        = 1;
        cHeader.biBitCount      = 32;
        cHeader.biCompression   = (ulBgColor & 0xFF000000 ? HX_ARGB : HX_RGB);
        cHeader.biSizeImage     = 0;
        cHeader.biXPelsPerMeter = 0;
        cHeader.biYPelsPerMeter = 0;
        cHeader.biClrUsed       = 0;
        cHeader.biClrImportant  = 0;
        cHeader.rcolor          = 0;
        cHeader.gcolor          = 0;
        cHeader.bcolor          = 0;
        // Set up src rect
        HXxRect cSrcRect = {0, 0, 1, 1};
        // Set up dst rect
        HXxSize cSize = {0, 0};
        pSite->GetSize(cSize);
        HXxRect cDstRect = {0, 0, cSize.cx, cSize.cy};
        // Do the blt
        IHXVideoSurface* pSurf = (IHXVideoSurface*) pEvent->param1;
        if(pSurf)
        {
            pSurf->AddRef();
            pEvent->result = pSurf->Blt((BYTE*) &ulColor,
                                        &cHeader,
                                        cDstRect,
                                        cSrcRect);
            pSurf->Release();
        }
    }
    return TRUE;
}

STDMETHODIMP_(BOOL)
CSmil1DocumentRenderer::NeedsWindowedSites()
{
    return FALSE;
}


/*
 * IHXRendererAdviseSink methods
 */

STDMETHODIMP
CSmil1DocumentRenderer::TrackDurationSet(UINT32 ulGroupIndex,
					UINT32 ulTrackIndex,
					UINT32 ulDuration,
					UINT32 ulDelay,
					BOOL bLiveSource)
{
    HX_RESULT rc = HXR_FAILED;
    SMIL1PlayToAssoc* pPlayToAssoc = NULL;

#if defined(HELIX_FEATURE_SMIL2)
    if (m_pParent->isHigherVersionSmilStreamFromOldSMIL1FF())
    {
	HX_ASSERT(m_pParent->m_pNextGenSmilRenderer);
	if (m_pParent->m_pNextGenSmilRenderer)
	{
	    rc = m_pParent->m_pNextGenSmilRenderer->SmilDocTrackDurationSet(
		    ulGroupIndex, ulTrackIndex, ulDuration, ulDelay,
		    bLiveSource);
	    goto cleanup;
	}
    }
#endif /* defined(HELIX_FEATURE_SMIL2). */

    pPlayToAssoc = getPlayToAssoc((UINT16)ulGroupIndex,
						   (UINT16)ulTrackIndex);

    if(pPlayToAssoc && !pPlayToAssoc->m_bDurationResolved)
    {
	pPlayToAssoc->m_bDurationResolved = TRUE;
	pPlayToAssoc->m_ulDelay = ulDelay;
	pPlayToAssoc->m_ulDuration = ulDuration - ulDelay;
	if(bLiveSource &&
	    pPlayToAssoc->m_ulDuration == 0)
	{
	    // don't resolve duration
	}
	else
	{
    	    m_pSmilParser->durationResolved(pPlayToAssoc->m_id,
		    pPlayToAssoc->m_ulDuration);
	}
	handleElements();

	SMIL1GroupInfo* pGroupInfo = 0;
	if(m_pGroupInfoMap->Lookup(ulGroupIndex, (void*&)pGroupInfo))
	{
	    pGroupInfo->m_nTrackDurationsSet++;
	    if (pGroupInfo->m_nTrackDurationsSet == pGroupInfo->m_nTracks)
	    {
		PersistentDurationSet(ulDuration,
				      m_ulPersistentComponentDelay,
				      bLiveSource);
	    }
	}
	return HXR_OK;
    }

#if defined(HELIX_FEATURE_SMIL2)
cleanup:
#endif /* defined(HELIX_FEATURE_SMIL2). */
    return rc;
}

STDMETHODIMP
CSmil1DocumentRenderer::RepeatedTrackDurationSet(const char*  pID,
						UINT32 ulDuration,					
						BOOL   bIsLive)
{
    HX_RESULT rc = HXR_OK;

#if defined(HELIX_FEATURE_SMIL2)
    if (m_pParent->isHigherVersionSmilStreamFromOldSMIL1FF())
    {
	HX_ASSERT(m_pParent->m_pNextGenSmilRenderer);
	if (m_pParent->m_pNextGenSmilRenderer)
	{
	    rc = m_pParent->m_pNextGenSmilRenderer->SmilDocRepeatedTrackDurationSet(
		    pID, ulDuration, bIsLive);
	    goto cleanup;
	}
    }
#endif /* defined(HELIX_FEATURE_SMIL2). */

    if(!bIsLive)
    {
	m_pSmilParser->durationResolved(pID,
					ulDuration);

	handleElements();
    }

#if defined(HELIX_FEATURE_SMIL2)
cleanup:
#endif /* defined(HELIX_FEATURE_SMIL2). */
    return rc;
}

// /For SHAZAM:
// /POST-RP8REV release IHXRendererAdviseSink method:
STDMETHODIMP
CSmil1DocumentRenderer::TrackUpdated(UINT32 ulGroupIndex,
				    UINT32 ulTrackIndex,
				    IHXValues* pValues)
{
    HX_RESULT	rc = HXR_OK;
    UINT16	uNewTrackIndex = 0;

    SMIL1PlayToAssoc* pPlayToAssoc = NULL;

#if defined(HELIX_FEATURE_SMIL2)
    if (m_pParent->isHigherVersionSmilStreamFromOldSMIL1FF())
    {
	HX_ASSERT(m_pParent->m_pNextGenSmilRenderer);
	if (m_pParent->m_pNextGenSmilRenderer)
	{
	    rc = m_pParent->m_pNextGenSmilRenderer->SmilDocTrackUpdated(
		    ulGroupIndex, ulTrackIndex, pValues);
	    goto cleanup;
	}
    }
#endif /* defined(HELIX_FEATURE_SMIL2). */

    pPlayToAssoc = getPlayToAssoc((UINT16)ulGroupIndex,
						   (UINT16)ulTrackIndex);

    if (!pPlayToAssoc)
    {
	rc = HXR_UNEXPECTED;
	goto cleanup;
    }

    if (HXR_OK == pValues->GetPropertyULONG32("TrackIndex", (UINT32&)uNewTrackIndex))
    {
	pPlayToAssoc->m_uTrackIndex = uNewTrackIndex;
    }

cleanup:

    return rc;
}


HX_RESULT
CSmil1DocumentRenderer::addShowEvents(const char* pRegionName,
				     IHXSite* pSite)
{
    HX_RESULT rc = HXR_OK;

    SMIL1PlayToAssoc* pPlayToAssoc = getPlayToAssoc(pRegionName);
    if(pPlayToAssoc)
    {
	showSite(pSite, FALSE);

	// show site after m_ulDelay
	CSmil1ShowSiteEvent* pShowEvent = 
	    new CSmil1ShowSiteEvent(pPlayToAssoc->m_uGroupIndex,
		pPlayToAssoc->m_ulDelay, pSite, 
		NULL, TRUE);
	insertEvent(pShowEvent);

	// hide site after m_ulDuration if it isn't live
	if(pPlayToAssoc->m_bRemoveSite &&
	   !pPlayToAssoc->m_bLiveSource)
	{
	    CSmil1ShowSiteEvent* pHideEvent = 
		new CSmil1ShowSiteEvent(pPlayToAssoc->m_uGroupIndex,
		pPlayToAssoc->m_ulDuration + pPlayToAssoc->m_ulDelay, 
		pSite, NULL, FALSE);
	    insertEvent(pHideEvent);
	}
    }

    return rc;
}

STDMETHODIMP
CSmil1DocumentRenderer::RendererInitialized(IHXRenderer* pRenderer, 
    IUnknown* pStream, IHXValues* pInfo)
{
    HX_RESULT	rc = HXR_OK;

    BOOL bIsWindowed = FALSE;
    BOOL bHandleElement = FALSE;

    HX_DISPLAY_TYPE ulFlags;
    IHXBuffer* pBuf = 0;

    SMIL1PlayToAssoc* pPlayToAssoc = NULL;

    UINT32 ulGroupIndex = 0;
    UINT32 ulTrackIndex = 0;
    UINT32 ulDelay = 0;
    UINT32 ulDuration = 0;
    UINT32 ulLiveSource = 0;

    UINT16 uStreamNumber = 0;
    IHXStream* pStr = 0;

#if defined(HELIX_FEATURE_SMIL2)
    if (m_pParent->isHigherVersionSmilStreamFromOldSMIL1FF())
    {
	HX_ASSERT(m_pParent->m_pNextGenSmilRenderer);
	if (m_pParent->m_pNextGenSmilRenderer)
	{
	    rc = m_pParent->m_pNextGenSmilRenderer->SmilDocRendererInitialized(
		    pRenderer, pStream, pInfo);
	    goto cleanup;
	}
    }
#endif /* defined(HELIX_FEATURE_SMIL2). */

    if(HXR_OK == pRenderer->GetDisplayType(ulFlags, pBuf))
    {
        if (HX_DISPLAY_WINDOW == (HX_DISPLAY_WINDOW & ulFlags))
	{
	    bIsWindowed = TRUE;
	}
	HX_RELEASE(pBuf);
    }

    pInfo->GetPropertyULONG32("GroupIndex", ulGroupIndex);
    pInfo->GetPropertyULONG32("TrackIndex", ulTrackIndex);
    pInfo->GetPropertyULONG32("Delay", ulDelay);
    // "duration" is really the end time in the current group
    pInfo->GetPropertyULONG32("Duration", ulDuration);  
    pInfo->GetPropertyULONG32("LiveSource", ulLiveSource);

    if(HXR_OK == pStream->QueryInterface(IID_IHXStream,
	    (void**)&pStr))
    {
	uStreamNumber = pStr->GetStreamNumber();
	HX_RELEASE(pStr);
    }

    if(bIsWindowed)
    {
	IHXLayoutStream* pLayoutStream = 0;
	if(HXR_OK == pStream->QueryInterface(IID_IHXLayoutStream, 
		    (void**)&pLayoutStream))
	{
	    BOOL bNoRegion = TRUE;

	    pPlayToAssoc = getPlayToAssoc((UINT16)ulGroupIndex, 
		(UINT16)ulTrackIndex);
	    if(pPlayToAssoc)
	    {
		CHXSimpleList*	pRendererList = NULL;
		SMIL1SourceInfo* pSourceInfo = NULL;
		const char* pPlayTo = pPlayToAssoc->m_playTo;

		// re-create layout/region/renderer sites if
		// sites have been detached upon playlist navigation
		if (m_bSitesDetached)
		{
		    m_bSitesDetached = FALSE;
		    HX_RESULT rc = setupRootLayout();
		    HX_ASSERT(HXR_OK == rc);
		}

		// see if we need to layout this renderer...
		CSmil1BasicRegion* pRegion = getRegion(pPlayTo);
		if(pRegion)
		{
		    bNoRegion = FALSE;
		}
		else
		{
		    // phony one up
		    HXxRect rect;
		    rect.left = 0;
		    rect.top = 0;
		    rect.right = 0;
		    rect.bottom = 0;
		    
		    pRegion = new CSmil1BasicRegion(pPlayTo, rect, 0, "hidden", 0, 
			FALSE, TRUE,
			//Default to TRUE for width unspecified and
			// height unspecified:
			TRUE, TRUE);
		    (*m_pRegionMap)[pPlayTo] = pRegion;
		}

		pSourceInfo = new SMIL1SourceInfo;
		pSourceInfo->m_pStream = pStream;
		if(pSourceInfo->m_pStream)
		{
		    pSourceInfo->m_pStream->AddRef();
		}
		pSourceInfo->m_pRenderer = pRenderer;
		if(pSourceInfo->m_pRenderer)
		{
		    pSourceInfo->m_pRenderer->AddRef();
		}
		
		pSourceInfo->m_ulDelay = ulDelay;
		pSourceInfo->m_ulDuration = ulDuration - ulDelay;

		char cTemp[20]; /* Flawfinder: ignore */
		::sprintf(cTemp,"%#010lx",(ULONG32)(void*)pSourceInfo); /* Flawfinder: ignore */
		pSourceInfo->m_tunerName   = (const char*) cTemp;
		::sprintf(cTemp,"%#010lx",(ULONG32)(void*)pSourceInfo+1); /* Flawfinder: ignore */
		pSourceInfo->m_childTunerName = (const char*)cTemp;

		const char* pChildTuner = pSourceInfo->m_childTunerName;

		// get to the site manager and set an event hook
		IHXEventHookMgr* pHookMgr = NULL;
		if(HXR_OK ==
		    m_pSiteMgr->QueryInterface(IID_IHXEventHookMgr, 
					    (void**)&pHookMgr))
		{
		    CSmil1EventHook* pChildEventHook = NULL;

		    // create event hook for playto
		    pChildEventHook = new CSmil1EventHook(
			this, pPlayTo, pChildTuner, bNoRegion);
		    pChildEventHook->AddRef();

		    pHookMgr->AddHook(pChildEventHook,
			pChildTuner, 0);

		    pSourceInfo->m_pRendererEventHook = pChildEventHook;

		    pHookMgr->Release();
		}
		else
		{
		    pSourceInfo->m_pRendererEventHook = NULL;
		}

		if (NULL == pPlayToAssoc->m_sourceMap[uStreamNumber])
		{
		    pPlayToAssoc->m_sourceMap[uStreamNumber] = new CHXSimpleList();

		    pPlayToAssoc->m_tunerName = pSourceInfo->m_tunerName;
		    pPlayToAssoc->m_childTunerName = pSourceInfo->m_childTunerName;
		    pPlayToAssoc->m_ulDelay = pSourceInfo->m_ulDelay;
		    pPlayToAssoc->m_ulDuration = pSourceInfo->m_ulDuration;
		    pPlayToAssoc->m_bLiveSource = ulLiveSource ? TRUE : FALSE;
		    pPlayToAssoc->m_pRendererEventHook = pSourceInfo->m_pRendererEventHook;

		    // add hyperlinks
		    CSmil1Element* pElement = m_pSmilParser->findElement(
			pPlayToAssoc->m_id);
		    if(pElement && pElement->m_pHyperlinks)
		    {
			CHXSimpleList::Iterator i = 
				pElement->m_pHyperlinks->Begin();
			for(; i != pElement->m_pHyperlinks->End(); ++i)
			{
			    CSmil1AAnchorElement* pAnchor = 
				(CSmil1AAnchorElement*)(*i);
			    //[SMIL 1.0 Compliance] Fixes PR 26473:
			    // We want to add in LIFO fashion so inner
			    // (nested) anchors will be found first in
			    // CSmil1DocumentRenderer::findHyperlinkElement(),
			    // below.  In other words, we're giving an
			    // effective higher link "z-order" to the
			    // decendants of other links.  This used to
			    // call AddTail():
			    pPlayToAssoc->m_pHyperlinks->AddHead(pAnchor);
                            // If the TLC starts off in double-size or non-original
                            // size, then these anchors can get added AFTER the
                            // SizeChanged call. Therefore, we need to check
                            // here whether or not they need to be scaled.
                            if ((m_topSiteSize.cx != m_topSiteOriginalSize.cx ||
                                 m_topSiteSize.cy != m_topSiteOriginalSize.cy) &&
                                 m_topSiteOriginalSize.cx != 0                 &&
                                 m_topSiteOriginalSize.cy != 0)
                            {
                                // We are getting added when TLC is already scaled,
                                // so we need to scale this anchor right off the bat
                                //
                                // Compute the absolute scale
                                double dScaleX = (double) m_topSiteSize.cx / (double) m_topSiteOriginalSize.cx;
                                double dScaleY = (double) m_topSiteSize.cy / (double) m_topSiteOriginalSize.cy;
                                // Scale the anchor
                                pAnchor->rescaleAbsolute(dScaleX, dScaleY);
                            }
			}
		    }

		    bHandleElement = TRUE;
		}

		pRendererList = (CHXSimpleList*) pPlayToAssoc->m_sourceMap[uStreamNumber];
		pRendererList->AddTail(pSourceInfo);

		IHXValues* pValues = 0;
		IHXBuffer* pPlayToBuffer = 0;
		IHXBuffer* pRegionName = 0;
		IHXCommonClassFactory* pFactory = m_pParent->getFactory();
		if ((HXR_OK == pFactory->CreateInstance(CLSID_IHXValues, (void**)&pValues)) &&
		    (HXR_OK == pFactory->CreateInstance(CLSID_IHXBuffer, (void**)&pPlayToBuffer)) &&
		    (HXR_OK == pFactory->CreateInstance(CLSID_IHXBuffer, (void**)&pRegionName)))
		{		    
		    pPlayToBuffer->Set((BYTE*)pChildTuner, strlen(pChildTuner)+1);
		    pValues->SetPropertyCString("playto", pPlayToBuffer);
		    HX_RELEASE(pPlayToBuffer);

		    if(pPlayToAssoc->m_regionName.GetLength() > 0)
		    {
			const char* pName = pPlayToAssoc->m_regionName;
			pRegionName->Set((BYTE*)pName, strlen(pName)+1);
			pValues->SetPropertyCString("region", pRegionName);
		    }
		    HX_RELEASE(pRegionName);

		    pLayoutStream->SetProperties(pValues);
		    pValues->Release();
		}

		if(!pRegion->m_bImplicitRegion)
		{
		    addSiteForRenderer(pPlayToAssoc, pSourceInfo, pRenderer, bNoRegion);
		}
	    }
	}
	setZOrder();
	HX_RELEASE(pLayoutStream);
    }
    else    // non-windowed renderer
    {
	pPlayToAssoc = getPlayToAssoc((UINT16)ulGroupIndex, 
	    (UINT16)ulTrackIndex);
	if(pPlayToAssoc)
	{
	    SMIL1SourceInfo* pSourceInfo = NULL;
	    CHXSimpleList* pRendererList = NULL;

	    if (NULL == pPlayToAssoc->m_sourceMap[uStreamNumber])
	    {
		pPlayToAssoc->m_sourceMap[uStreamNumber] = new CHXSimpleList();
		pPlayToAssoc->m_ulDuration = ulDuration - ulDelay;

		bHandleElement = TRUE;
	    }
	    
	    pSourceInfo = new SMIL1SourceInfo;

	    pSourceInfo->m_pStream = pStream;
	    if(pSourceInfo->m_pStream)
	    {
		pSourceInfo->m_pStream->AddRef();
	    }
	    pSourceInfo->m_pRenderer = pRenderer;
	    if(pSourceInfo->m_pRenderer)
	    {
		pSourceInfo->m_pRenderer->AddRef();
	    }

	    pSourceInfo->m_pRendererEventHook = NULL;
	    pSourceInfo->m_ulDelay = ulDelay;
	    pSourceInfo->m_ulDuration = ulDuration = ulDelay;
    
	    pRendererList = (CHXSimpleList*) pPlayToAssoc->m_sourceMap[uStreamNumber];
	    pRendererList->AddTail(pSourceInfo);
	}
    }

    // update the stream timing if it's been called in handleSourceUpdate()
    if(m_pDeferredSourceMap)
    {
	SMIL1DeferredSourceInfo* pDeferredInfo = NULL;
	const char* pDeferredID = (const char*)pPlayToAssoc->m_id;
	if(m_pDeferredSourceMap->Lookup(pDeferredID,
	    (void*&)pDeferredInfo))
	{
	    CSmil1Element* pThisElement = 
		m_pSmilParser->findElement(pDeferredID);
	    if(pThisElement &&
		pThisElement->m_ulBeginOffset != (UINT32)-1)
	    {
		if(pDeferredInfo->m_ulDuration > pThisElement->m_ulBeginOffset)
		{
		    updateStreamTiming(pDeferredID, 
			pDeferredInfo->m_ulDuration -
			pThisElement->m_ulBeginOffset);
		}
		else
		{
		    updateStreamTiming(pDeferredID, 0);
		}
	    }
	    else
	    {
		updateStreamTiming(pDeferredID, pDeferredInfo->m_ulDuration);
	    }
	}
    }

    if (bHandleElement)
    {
	handleElements();
    }

#if defined(HELIX_FEATURE_SMIL2)
cleanup:
#endif /* defined(HELIX_FEATURE_SMIL2). */
    return rc;
}

#if defined(_UNIX)  &&  (!defined(_BEOS))  &&  defined(USE_XWINDOWS)
XData*  CSmil1DocumentRenderer::InitXVisualSupport(IHXSite* pSite, HXxWindow* pWnd)
{
    // create new XData object
    XData* pxData = new XData();

    // use the pointer to the X display and window
    // conveniently given us by CHXSiteWindowed::HandleEvent
    m_pPixmapDisplay = (Display*) pWnd->display;
    Window window = (Window) pWnd->window; 

    // save ptr to display in XData object also...
    pxData->m_Display = m_pPixmapDisplay;

    // get visual & set depth
    XWindowAttributes attr;
    XGetWindowAttributes(m_pPixmapDisplay, window, &attr);

    // get visual info & depth 
    XVisualInfo visInfoMask;
    memset(&visInfoMask, 0, sizeof(XVisualInfo));
    visInfoMask.visualid = attr.visual->visualid;

    if (m_pVisualInfo)
    {
	XFree(m_pVisualInfo);
	m_pVisualInfo = NULL;
    }

    int nv;
    m_pVisualInfo  = XGetVisualInfo(m_pPixmapDisplay, VisualIDMask, &visInfoMask, &nv);

    UINT32 nDepth = 32;
    nDepth = (UINT32) m_pVisualInfo->depth;

    // Get Colormap
    pxData->m_colormap = attr.colormap;

    // get bits per pixel information for the best depth we can display
    ULONG32 bitsPerPixel = 32;
    int i, n;
    XPixmapFormatValues *pixmap_formats = XListPixmapFormats(m_pPixmapDisplay, &n);
    if (pixmap_formats) 
    {
	for (i = 0; i < n; i++)
	{
	    if (pixmap_formats[i].depth == nDepth)
	    {
	        bitsPerPixel = pixmap_formats[i].bits_per_pixel;
	    }
	 }
    }
    XFree(pixmap_formats);

    // get site size
    HXxSize siteWinSize;
    pSite->GetSize(siteWinSize);

    pxData->m_backgroundBitmapInfoHeader.biSize = sizeof(HXBitmapInfoHeader);  

    pxData->m_backgroundBitmapInfoHeader.biWidth = siteWinSize.cx;
    pxData->m_backgroundBitmapInfoHeader.biHeight = siteWinSize.cy;
    pxData->m_backgroundBitmapInfoHeader.biPlanes = 1; // just seems to be the convention  
    pxData->m_backgroundBitmapInfoHeader.biBitCount = bitsPerPixel;
    HX_ASSERT(pxData->m_backgroundBitmapInfoHeader.biBitCount % 8 == 0);

    // BI_RGB just seems to be the convention 
    switch (pxData->m_backgroundBitmapInfoHeader.biBitCount) 
    {
	case 8:
	case 24:
	case 32:
	    pxData->m_backgroundBitmapInfoHeader.biCompression = BI_RGB;
	    break;
	case 16:
	    pxData->m_backgroundBitmapInfoHeader.biCompression = HXCOLOR_RGB565_ID;
	    break;
	default:
	    HX_ASSERT(FALSE);
    }

    pxData->m_backgroundBitmapInfoHeader.biSizeImage = //size of image (bytes):
		pxData->m_backgroundBitmapInfoHeader.biWidth * pxData->m_backgroundBitmapInfoHeader.biHeight *  
		pxData->m_backgroundBitmapInfoHeader.biBitCount;
    pxData->m_backgroundBitmapInfoHeader.biXPelsPerMeter = 0;   
    pxData->m_backgroundBitmapInfoHeader.biYPelsPerMeter = 0;   
    pxData->m_backgroundBitmapInfoHeader.biClrUsed = 0;  
    pxData->m_backgroundBitmapInfoHeader.biClrImportant = 0;  
    pxData->m_backgroundBitmapInfoHeader.rcolor = m_pVisualInfo->red_mask; 
    pxData->m_backgroundBitmapInfoHeader.gcolor = m_pVisualInfo->green_mask;   
    pxData->m_backgroundBitmapInfoHeader.bcolor = m_pVisualInfo->blue_mask; 

    pxData->m_Pixmap = XCreatePixmap(m_pPixmapDisplay, 
			     window,
			     pxData->m_backgroundBitmapInfoHeader.biWidth, 
			     pxData->m_backgroundBitmapInfoHeader.biHeight, 
			     nDepth);
    return pxData;
}
#endif

STDMETHODIMP
CSmil1DocumentRenderer::RendererClosed(IHXRenderer* pRenderer, 
				    IHXValues* pInfo)
{
    HX_RESULT rc = HXR_OK;

    UINT32 ulGroupIndex = 0;
    UINT32 ulTrackIndex = 0;
    UINT32 ulStreamNumber = 0;    
    CHXSimpleList* pRendererList = NULL;
    SMIL1PlayToAssoc* pPlayToAssoc = NULL;
    SMIL1SiteInfo* pSiteInfo = NULL;

#if defined(HELIX_FEATURE_SMIL2)
    if (m_pParent->isHigherVersionSmilStreamFromOldSMIL1FF())
    {
	HX_ASSERT(m_pParent->m_pNextGenSmilRenderer);
	if (m_pParent->m_pNextGenSmilRenderer)
	{
	    rc = m_pParent->m_pNextGenSmilRenderer->SmilDocRendererClosed(
		    pRenderer, pInfo);
	    goto cleanup;
	}
    }
#endif /* defined(HELIX_FEATURE_SMIL2). */

    pInfo->GetPropertyULONG32("GroupIndex", ulGroupIndex);
    pInfo->GetPropertyULONG32("TrackIndex", ulTrackIndex);
    pInfo->GetPropertyULONG32("StreamNumber", ulStreamNumber);

    if (m_pPlayToAssocList)
    {
	pPlayToAssoc = getPlayToAssoc((UINT16)ulGroupIndex, 
				      (UINT16)ulTrackIndex);

	if (pPlayToAssoc)
	{
	    pPlayToAssoc->m_sourceMap.Lookup(ulStreamNumber, (void*&) pRendererList);
	}
    }

    if (m_pSiteInfoByRendererMap && 
	m_pSiteInfoByRendererMap->Lookup(pRenderer, (void*&) pSiteInfo))
    {
	RemoveEvents(ulGroupIndex, pSiteInfo->m_pRendererSite);

	CSmil1BasicRegion* pRegion = getRegion(pSiteInfo->m_regionID);

	showSite(pSiteInfo->m_pRendererSite, FALSE);

	// we only want to hide the region if there is no more 
	// renderer site shares the same region	
	if (!pRendererList || pRendererList->GetCount() == 1)
	{
	    IHXSite* pRegionSite = NULL;
	    if (!pRegion->m_bBgColorSet)
	    {
		pRegionSite = pSiteInfo->m_pRegionSite;
	    }    
	    showSite(pRegionSite, FALSE);
	}

	if (pSiteInfo->m_pRendererSite)
	{
	    m_pSiteMgr->RemoveSite(pSiteInfo->m_pRendererSite);
	    pSiteInfo->m_pRendererSite->DetachWatcher();
	    
	    if(pRegion && pRegion->m_pSite)
	    {
		pRegion->m_pSite->DestroyChild(pSiteInfo->m_pRendererSite);
	    }
	}
	HX_RELEASE(pSiteInfo->m_pRendererSite);
	m_pSiteInfoByRendererMap->RemoveKey((void*)pRenderer);

	if(m_pSiteInfoList)
	{
	    // remove pSiteInfo from list
	    LISTPOSITION pos = m_pSiteInfoList->GetHeadPosition();
	    while(pos)
	    {
		SMIL1SiteInfo* pThisSiteInfo = (SMIL1SiteInfo*)
		    m_pSiteInfoList->GetAt(pos);
		if(pThisSiteInfo == pSiteInfo)
		{
		    delete pThisSiteInfo;
		    m_pSiteInfoList->RemoveAt(pos);

		    break;
		}
		m_pSiteInfoList->GetNext(pos);
	    }
	}
    }

    if (pPlayToAssoc)
    {
	LISTPOSITION    pos;
	SMIL1SourceInfo* pSMIL1SourceInfo = NULL;

	if (pRendererList)
	{
	    CHXSimpleList::Iterator  i = pRendererList->Begin();

	    for (; i != pRendererList->End(); ++i)
	    {
		pSMIL1SourceInfo = (SMIL1SourceInfo*) (*i);
	
		if (pSMIL1SourceInfo->m_pRenderer == pRenderer)
		{
		    pos = pRendererList->Find(pSMIL1SourceInfo);
		    pRendererList->RemoveAt(pos);	  
	
		    if (pSMIL1SourceInfo->m_pRendererEventHook)
		    {
			// get to the site manager and set an event hook
			IHXEventHookMgr* pHookMgr = NULL;
			if(HXR_OK == m_pSiteMgr->QueryInterface(IID_IHXEventHookMgr, 
								(void**)&pHookMgr))
			{
			    pHookMgr->RemoveHook(pSMIL1SourceInfo->m_pRendererEventHook, 
						 pSMIL1SourceInfo->m_pRendererEventHook->m_pChannelName, 0);	
			}
			pHookMgr->Release();
		    }
		    
		    HX_RELEASE(pSMIL1SourceInfo->m_pRendererEventHook);
		    HX_RELEASE(pSMIL1SourceInfo->m_pStream);
		    HX_RELEASE(pSMIL1SourceInfo->m_pRenderer);

		    HX_DELETE(pSMIL1SourceInfo);
		    break;
		}
	    }

	    if (pRendererList->GetCount())
	    {
		pSMIL1SourceInfo = (SMIL1SourceInfo*)pRendererList->GetHead();
	    
		pPlayToAssoc->m_tunerName = pSMIL1SourceInfo->m_tunerName;
		pPlayToAssoc->m_childTunerName = pSMIL1SourceInfo->m_childTunerName;
		pPlayToAssoc->m_ulDelay = pSMIL1SourceInfo->m_ulDelay;
		pPlayToAssoc->m_ulDuration = pSMIL1SourceInfo->m_ulDuration;
		pPlayToAssoc->m_pRendererEventHook = pSMIL1SourceInfo->m_pRendererEventHook;
	    }
	}

	if (pPlayToAssoc->m_pSiteInfoList->GetCount() > 0 &&
	    pSiteInfo)
	{
	    pos = pPlayToAssoc->m_pSiteInfoList->Find(pSiteInfo);
	    pPlayToAssoc->m_pSiteInfoList->RemoveAt(pos);
	}
    }

#if defined(HELIX_FEATURE_SMIL2)
cleanup:
#endif /* defined(HELIX_FEATURE_SMIL2). */
    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::addSiteForRenderer(SMIL1PlayToAssoc* pPlayToAssoc,
					  SMIL1SourceInfo* pSMIL1SourceInfo,
					  IHXRenderer* pRenderer,
					  BOOL bNoRegion)
{
    IHXSite* pRendererSite = 0;

    if(!m_pMISUSSite)
    {
	return HXR_UNEXPECTED;
    }

    CSmil1BasicRegion* pRegion = getRegion(pPlayToAssoc->m_playTo);
    HX_ASSERT(pRegion);
    HX_ASSERT(pRegion->m_pSite);

    // now create a child of the parent site
    // to hook to the renderer
    pRegion->m_pSite->CreateChild(pRendererSite);
    HX_ASSERT(pRendererSite);

#ifdef _DEBUGBAB
    char debugStr[256]; /* Flawfinder: ignore */
    sprintf(debugStr, "region %s z-index %ld site: %p renderer site %p\n", /* Flawfinder: ignore */
	(const char*)pPlayToAssoc->m_playTo,
	pRegion->m_lZIndex,
	pRegion->m_pSite,
	pRendererSite);
    OutputDebugString(debugStr);
#endif
    CSmil1SiteWatcher* pRendererWatch = new CSmil1SiteWatcher(
	this, pPlayToAssoc->m_playTo, TRUE);
    pRendererWatch->AddRef();
    pRendererSite->AttachWatcher(pRendererWatch);

    // map renderer site to the renderer
    if(!m_pSiteWatcherMap)
    {
	m_pSiteWatcherMap = new CHXMapPtrToPtr;
    }
    (*m_pSiteWatcherMap)[pRendererSite] = pRendererWatch;

    IHXValues* pRendererSiteProps = NULL;
    if (HXR_OK == pRendererSite->QueryInterface
			    (IID_IHXValues,
			     (void**)&pRendererSiteProps))
    {
	CHXBuffer* pTunerValue = new CHXBuffer;
	pTunerValue->AddRef();
	pTunerValue->Set((UCHAR*)(const char*) pSMIL1SourceInfo->m_childTunerName,
		    strlen(pSMIL1SourceInfo->m_childTunerName)+1);
	pRendererSiteProps->SetPropertyCString("channel", pTunerValue);
	pTunerValue->Release();
	pRendererSiteProps->Release();
    }

    // This site needs to be added to the Site Manager!!!
    m_pSiteMgr->AddSite(pRendererSite);

    // hide the site initially
    IHXSite* pRegionSite = NULL;
    if(!pRegion->m_bBgColorSet)
    {
	pRegionSite = pRegion->m_pSite;
    }

    if(pSMIL1SourceInfo->m_ulDelay > 0)
    {
	// show site after m_ulDelay
	showSite(pRendererSite, FALSE);
    }
    else
    {
	// show it now, don't wait for first time sync
	showSite(pRegionSite, TRUE);
	showSite(pRendererSite, TRUE);
    }
    // in any case, stick the event on the list...
    CSmil1ShowSiteEvent* pShowEvent = 
	new CSmil1ShowSiteEvent(pPlayToAssoc->m_uGroupIndex,
	    pSMIL1SourceInfo->m_ulDelay, pRendererSite, 
	    pRegionSite, TRUE);
    insertEvent(pShowEvent);

    // hide site after m_ulDuration if it isn't live
    if(pPlayToAssoc->m_bRemoveSite &&
       !pPlayToAssoc->m_bLiveSource)
    {
	CSmil1ShowSiteEvent* pHideEvent = 
	    new CSmil1ShowSiteEvent(pPlayToAssoc->m_uGroupIndex,
	    pSMIL1SourceInfo->m_ulDuration + pSMIL1SourceInfo->m_ulDelay, 
	    pRendererSite, pRegionSite, FALSE);
	insertEvent(pHideEvent);
    }

    SMIL1SiteInfo* pSiteInfo = new SMIL1SiteInfo;
    pSiteInfo->m_pRendererSite = pRendererSite;
    pSiteInfo->m_pRegionSite = pRegionSite;
    pSiteInfo->m_uGroupIndex = pPlayToAssoc->m_uGroupIndex;
    pSiteInfo->m_ulDelay = pSMIL1SourceInfo->m_ulDelay;
    pSiteInfo->m_ulDuration = pSMIL1SourceInfo->m_ulDuration + 
			      pSMIL1SourceInfo->m_ulDelay;
    pSiteInfo->m_bRemoveSite = pPlayToAssoc->m_bRemoveSite;
    pSiteInfo->m_bNoRegion = bNoRegion;
    pSiteInfo->m_regionID = pPlayToAssoc->m_playTo;
    pSiteInfo->m_pRenderer = pRenderer;

    pPlayToAssoc->m_pSiteInfoList->AddTail(pSiteInfo);

    insertSiteInfo(pSiteInfo);

    m_pSiteInfoByRendererMap->SetAt(pRenderer, 
	pSiteInfo);

    return HXR_OK;
}

void
CSmil1DocumentRenderer::insertZOrder(IHXSite* pSite, INT32 lZOrder)
{
    if(!m_pZOrderList)
    {
	m_pZOrderList = new CHXSimpleList;
    }

    SMIL1ZOrderInfo* pInfo = new SMIL1ZOrderInfo;
    pInfo->m_pSite = pSite;
    pInfo->m_lZIndex = lZOrder;

    LISTPOSITION lPos = m_pZOrderList->GetHeadPosition();
    LISTPOSITION lPrev = lPos;

    BOOL bInserted = FALSE;
    while(lPos)
    {
	SMIL1ZOrderInfo* pThisInfo = (SMIL1ZOrderInfo*)m_pZOrderList->GetNext(lPos);
	if(pThisInfo->m_lZIndex > lZOrder)
	{
	    m_pZOrderList->InsertBefore(lPrev, pInfo);
	    bInserted = TRUE;
	    break;
	}
	lPrev = lPos;
    }
    if(!bInserted)
    {
	// not inserted, stick it on the end of the list
	m_pZOrderList->AddTail(pInfo);
    }
}

/*
 * setZOrder - run through all the channels
 * and set the Z ordering for each
 */
void
CSmil1DocumentRenderer::setZOrder()
{
    if(!m_pRegionMap)
    {
	return;
    }

    CHXMapStringToOb::Iterator i = m_pRegionMap->Begin();
    for(; i != m_pRegionMap->End(); ++i)
    {
	CSmil1BasicRegion* pRegion = (CSmil1BasicRegion*)(*i);

	HXxWindow* pWindow = NULL;
	IHXSiteWindowed* pSiteWindowed = NULL;
	if(pRegion->m_pSite &&
	    HXR_OK == pRegion->m_pSite->QueryInterface(
	    IID_IHXSiteWindowed, (void**)&pSiteWindowed))

	{
	    pWindow = pSiteWindowed->GetWindow();
	    if (!pWindow || !pWindow->window)
	    {
		IHXSite2* pSite2 = 0;
		if(HXR_OK == pRegion->m_pSite->QueryInterface(
		    IID_IHXSite2, (void**)&pSite2))
		{
		    pSite2->SetZOrder(pRegion->m_lZIndex);
		    pSite2->Release();
		}
	    }
	    else
	    {
		insertZOrder(pRegion->m_pSite, pRegion->m_lZIndex);
	    }

	    pSiteWindowed->Release();
	}
	else
	{
	    insertZOrder(pRegion->m_pSite, pRegion->m_lZIndex);
	}
    }

    if(m_pZOrderList)
    {
	INT32 idx = 0;
	LISTPOSITION lPos = m_pZOrderList->GetHeadPosition();
	while(lPos)
	{
	    SMIL1ZOrderInfo* pInfo = 
		(SMIL1ZOrderInfo*)m_pZOrderList->GetAt(lPos);
	    IHXSite2* pSite2 = 0;
	    if(pInfo->m_pSite &&
		HXR_OK == pInfo->m_pSite->QueryInterface(IID_IHXSite2, 
		(void**)&pSite2))
	    {
#ifdef _DEBUGBAB
		char debugStr[256]; /* Flawfinder: ignore */
		sprintf(debugStr, "SMILDocRenderer:: site %p set z-order %ld\n", pInfo->m_pSite, idx); /* Flawfinder: ignore */
		OutputDebugString(debugStr);
#endif
		pSite2->SetZOrder(idx);
		pSite2->Release();
	    }
	    idx++;
	    delete pInfo;
	    lPos = m_pZOrderList->RemoveAt(lPos);
	}
	HX_DELETE(m_pZOrderList);
    }
}

/*
 * IHXGroupSink methods
 */

STDMETHODIMP
CSmil1DocumentRenderer::GroupAdded(UINT16	uGroupIndex,
				IHXGroup*	pGroup)
{
    HX_RESULT rc = HXR_OK;

    SMIL1GroupInfo* pGroupInfo = 0;

#if defined(HELIX_FEATURE_SMIL2)
    if (m_pParent->isHigherVersionSmilStreamFromOldSMIL1FF())
    {
	HX_ASSERT(m_pParent->m_pNextGenSmilRenderer);
	if (m_pParent->m_pNextGenSmilRenderer)
	{
	    rc = m_pParent->m_pNextGenSmilRenderer->SmilDocGroupAdded(
		    uGroupIndex, pGroup);
	    goto cleanup;
	}
    }
#endif /* defined(HELIX_FEATURE_SMIL2). */

    if(!m_pGroupInfoMap)
    {
	m_pGroupInfoMap = new CHXMapLongToObj;
    }

    // save group info
    if(!m_pGroupInfoMap->Lookup(uGroupIndex, (void*&)pGroupInfo))
    {
	IHXPlayer* pPlayer = m_pParent->getPlayer();
	IHXGroupManager* pMgr = 0;
	UINT32 ulTotalTracks = 0;

	if(HXR_OK == pPlayer->QueryInterface(IID_IHXGroupManager, 
	    (void**)&pMgr))
	{
	    IHXGroup* pGroup = NULL;
	    IHXGroup2* pGroup2 = NULL;
	    if (HXR_OK == pMgr->GetGroup(uGroupIndex, pGroup) &&
		HXR_OK == pGroup->QueryInterface(IID_IHXGroup2, (void**)&pGroup2))
	    {
		IHXValues* pGroupProperties = NULL;

		pGroup2->GetPersistentComponentProperties(m_ulPersistentComponentID,
							  pGroupProperties);
		if(pGroupProperties)
		{
		    pGroupProperties->GetPropertyULONG32("total_tracks", 
			ulTotalTracks);
		}
		HX_RELEASE(pGroupProperties);
	    }
	    HX_RELEASE(pGroup2);
	    HX_RELEASE(pGroup);
	}
	HX_RELEASE(pMgr);
	
	pGroupInfo = new SMIL1GroupInfo;
	pGroupInfo->m_nTracks = (int)ulTotalTracks;
	pGroupInfo->m_nTracksAdded = 0;
	pGroupInfo->m_nTrackDurationsSet = 0;
	pGroupInfo->m_ulDuration = 0;
	(*m_pGroupInfoMap)[uGroupIndex] = pGroupInfo;
    }
    else
    {
	pGroupInfo->m_nTracksAdded++;
    }

#if defined(HELIX_FEATURE_SMIL2)
cleanup:
#endif /* defined(HELIX_FEATURE_SMIL2). */
    return rc;
}

STDMETHODIMP
CSmil1DocumentRenderer::GroupRemoved(UINT16	uGroupIndex,
				 IHXGroup*	pGroup)
{
    HX_RESULT rc = HXR_OK;

#if defined(HELIX_FEATURE_SMIL2)
    if (m_pParent->isHigherVersionSmilStreamFromOldSMIL1FF())
    {
	HX_ASSERT(m_pParent->m_pNextGenSmilRenderer);
	if (m_pParent->m_pNextGenSmilRenderer)
	{
	    rc = m_pParent->m_pNextGenSmilRenderer->SmilDocGroupRemoved(
		    uGroupIndex, pGroup);
	    goto cleanup;
	}
    }
#endif /* defined(HELIX_FEATURE_SMIL2). */

#if defined(HELIX_FEATURE_SMIL2)
cleanup:
#endif /* defined(HELIX_FEATURE_SMIL2). */
    return rc;
}


STDMETHODIMP
CSmil1DocumentRenderer::AllGroupsRemoved()
{
    HX_RESULT rc = HXR_NOTIMPL;

#if defined(HELIX_FEATURE_SMIL2)
    if (m_pParent->isHigherVersionSmilStreamFromOldSMIL1FF())
    {
	HX_ASSERT(m_pParent->m_pNextGenSmilRenderer);
	if (m_pParent->m_pNextGenSmilRenderer)
	{
	    rc = m_pParent->m_pNextGenSmilRenderer->SmilDocAllGroupsRemoved();
	    goto cleanup;
	}
    }
#endif /* defined(HELIX_FEATURE_SMIL2). */

#if defined(HELIX_FEATURE_SMIL2)
cleanup:
#endif /* defined(HELIX_FEATURE_SMIL2). */
    return rc;
}


STDMETHODIMP
CSmil1DocumentRenderer::TrackAdded(UINT16	uGroupIndex,
			       UINT16		uTrackIndex,
			       IHXValues*	pTrack)
{
    HX_RESULT rc = HXR_OK;
#if defined(HELIX_FEATURE_SMIL2)
    if (m_pParent->isHigherVersionSmilStreamFromOldSMIL1FF())
    {
	HX_ASSERT(m_pParent->m_pNextGenSmilRenderer);
	if (m_pParent->m_pNextGenSmilRenderer)
	{
	    rc = m_pParent->m_pNextGenSmilRenderer->SmilDocTrackAdded(
		    uGroupIndex, uTrackIndex, pTrack);
	    goto cleanup;
	}
    }
#endif /* defined(HELIX_FEATURE_SMIL2). */

    if(pTrack)
    {
	IHXBuffer* pBuf = 0;
	const char* pID = 0;
	const char* pRegionName = 0;
	UINT32 ulDelay = 0;

	const char* pRepeatID = 0; // /For SHAZAM.

	if(HXR_OK == pTrack->GetPropertyCString("id", pBuf))
	{
	    pID = (const char*)pBuf->GetBuffer();
	    pBuf->Release();
	}

	// /For SHAZAM:
	if(HXR_OK == pTrack->GetPropertyCString("repeatid", pBuf))
	{
	    pRepeatID = (const char*)pBuf->GetBuffer();
	    pBuf->Release();
	}

	if(HXR_OK == pTrack->GetPropertyCString("region", pBuf))
	{
	    pRegionName = (const char*)pBuf->GetBuffer();
	    pBuf->Release();
	}

	if(HXR_OK == pTrack->GetPropertyCString("playto", pBuf))
	{
	    const char* pPlayTo = (const char*)pBuf->GetBuffer();
	    setPlayToAssoc(uGroupIndex, uTrackIndex, pID, pRepeatID,
		    pPlayTo, pRegionName);
	    pBuf->Release();
	}
	else	// non-windowed renderer
	{
	    setPlayToAssoc(uGroupIndex, uTrackIndex, pID, pRepeatID,
		    0, pRegionName);
	}

	SMIL1PlayToAssoc* pAssoc = getPlayToAssoc(uGroupIndex, uTrackIndex);

	if(pAssoc)
	{
	    if(HXR_OK == pTrack->GetPropertyCString("fill", pBuf))
	    {
		const char* pFill = (const char*)pBuf->GetBuffer();
		if(strcmp(pFill, "freeze") == 0)    // default is 'remove'
		{
		    pAssoc->m_bRemoveSite = FALSE;
		}
		pBuf->Release();
	    }
	}

	SMIL1GroupInfo* pGroupInfo = 0;
	if(m_pGroupInfoMap->Lookup(uGroupIndex, (void*&)pGroupInfo))
	{
	    pGroupInfo->m_nTracksAdded++;
	}
    }

#if defined(HELIX_FEATURE_SMIL2)
cleanup:
#endif /* defined(HELIX_FEATURE_SMIL2). */
    return rc;
}

STDMETHODIMP
CSmil1DocumentRenderer::TrackRemoved(UINT16	uGroupIndex,
				 UINT16		uTrackIndex,
				 IHXValues*	pTrack)
{
    HX_RESULT rc = HXR_NOTIMPL;
#if defined(HELIX_FEATURE_SMIL2)
    if (m_pParent->isHigherVersionSmilStreamFromOldSMIL1FF())
    {
	HX_ASSERT(m_pParent->m_pNextGenSmilRenderer);
	if (m_pParent->m_pNextGenSmilRenderer)
	{
	    rc = m_pParent->m_pNextGenSmilRenderer->SmilDocTrackRemoved(
		    uGroupIndex, uTrackIndex, pTrack);
	    goto cleanup;
	}
    }
#endif /* defined(HELIX_FEATURE_SMIL2). */

#if defined(HELIX_FEATURE_SMIL2)
cleanup:
#endif /* defined(HELIX_FEATURE_SMIL2). */
    return rc;
}

STDMETHODIMP
CSmil1DocumentRenderer::TrackStarted(UINT16	uGroupIndex,
				 UINT16		uTrackIndex,
				 IHXValues*	pTrack)
{
    HX_RESULT rc = HXR_NOTIMPL;
#if defined(HELIX_FEATURE_SMIL2)
    if (m_pParent->isHigherVersionSmilStreamFromOldSMIL1FF())
    {
	HX_ASSERT(m_pParent->m_pNextGenSmilRenderer);
	if (m_pParent->m_pNextGenSmilRenderer)
	{
	    rc = m_pParent->m_pNextGenSmilRenderer->SmilDocTrackStarted(
		    uGroupIndex, uTrackIndex, pTrack);
	    goto cleanup;
	}
    }
#endif /* defined(HELIX_FEATURE_SMIL2). */

    if(m_bSettingFragment)
    {
	// find out if all tracks for this group have been
	// added, then go ahead and seek
	UINT16 uFragmentGroup = m_pSmilParser->getFragmentGroup(m_pFragment);
	if(uFragmentGroup == uGroupIndex)
	{
	    SMIL1GroupInfo* pGroupInfo = 0;

	    m_nFragmentTracks++;
	    if(m_pGroupInfoMap->Lookup(uFragmentGroup, (void*&)pGroupInfo))
	    {
		if(pGroupInfo->m_nTracks == m_nFragmentTracks)
		{
		    IHXPlayer* pPlayer = m_pParent->getPlayer();

		    BOOL bFragFoundAndResolved = TRUE;
		    UINT32 ulFragmentOffset = 
			m_pSmilParser->getFragmentOffset(m_pFragment,
			bFragFoundAndResolved /*<--Passed by reference.*/);
		    //If getFragmentOffset() found the fragment and it had
		    // a resolved begin time (plus offset) of zero,
		    // we used to not seek to 0 even though that's a valid
		    // value.
		    // (Note: this problem was found while fixing PR 22655.)
		    if(bFragFoundAndResolved)
		    {
			pPlayer->Seek(ulFragmentOffset);
		    }
		    m_bSettingFragment = FALSE;
		}
	    }
	}
    }

#if defined(HELIX_FEATURE_SMIL2)
cleanup:
#endif /* defined(HELIX_FEATURE_SMIL2). */
    return rc;
}

STDMETHODIMP
CSmil1DocumentRenderer::TrackStopped(UINT16	uGroupIndex,
				 UINT16		uTrackIndex,
				 IHXValues*	pTrack)
{
    HX_RESULT rc = HXR_NOTIMPL;
#if defined(HELIX_FEATURE_SMIL2)
    if (m_pParent->isHigherVersionSmilStreamFromOldSMIL1FF())
    {
	HX_ASSERT(m_pParent->m_pNextGenSmilRenderer);
	if (m_pParent->m_pNextGenSmilRenderer)
	{
	    rc = m_pParent->m_pNextGenSmilRenderer->SmilDocTrackStopped(
		    uGroupIndex, uTrackIndex, pTrack);
	    goto cleanup;
	}
    }
#endif /* defined(HELIX_FEATURE_SMIL2). */

#if defined(HELIX_FEATURE_SMIL2)
cleanup:
#endif /* defined(HELIX_FEATURE_SMIL2). */
    return rc;
}

STDMETHODIMP
CSmil1DocumentRenderer::CurrentGroupSet(UINT16	uGroupIndex,
				    IHXGroup*	pGroup)
{
    HX_RESULT rc = HXR_OK;
    INT16   uPrevGroupIndex = m_uCurrentGroupIndex;

#if defined(HELIX_FEATURE_SMIL2)
    if (m_pParent->isHigherVersionSmilStreamFromOldSMIL1FF())
    {
	HX_ASSERT(m_pParent->m_pNextGenSmilRenderer);
	if (m_pParent->m_pNextGenSmilRenderer)
	{
	    rc = m_pParent->m_pNextGenSmilRenderer->SmilDocCurrentGroupSet(
		    uGroupIndex, pGroup);
	    goto cleanup;
	}
    }
#endif /* defined(HELIX_FEATURE_SMIL2). */

    m_uCurrentGroupIndex = (INT16)uGroupIndex;
    m_ulCurrentTime = 0;

    if(uPrevGroupIndex != -1)
    {
	m_pSmilParser->resetTimeline();

	removeGroupEvents(uPrevGroupIndex);
	
	removeGroupsPlayToAssoc(uPrevGroupIndex);
	
	m_ulEventListPosition = 0;

	if(m_pStatusMessage)
	{
	    m_pStatusMessage->SetStatus(NULL);
	}

	// hide any "transparent" sites
	if(m_pRegionMap)
	{
	    CHXMapStringToOb::Iterator i = m_pRegionMap->Begin();
	    for(; i != m_pRegionMap->End(); ++i)
	    {
		CSmil1BasicRegion* pRegion = (CSmil1BasicRegion*)(*i);
		if(!pRegion->m_bBgColorSet)
		{
		    showSite(pRegion->m_pSite, FALSE);
		}
	    }
	}
    }
    
#if defined(HELIX_FEATURE_SMIL2)
cleanup:
#endif /* defined(HELIX_FEATURE_SMIL2). */
    return rc;
}

void
CSmil1DocumentRenderer::removeGroupEvents(UINT16 uGroupIndex)
{
    if(m_pEventList)
    {
	LISTPOSITION lPos = m_pEventList->GetHeadPosition();
	while(lPos)
	{
	    // handle all events at or before ulTimeValue
	    CSmil1LayoutEvent* pEvent = (CSmil1LayoutEvent*)m_pEventList->GetAt(lPos);
	    if(pEvent->m_uGroupIndex == uGroupIndex)
	    {
		delete pEvent;
		lPos = m_pEventList->RemoveAt(lPos);
	    }
	}
    }
}

SMIL1PlayToAssoc*
CSmil1DocumentRenderer::getPlayToAssoc(UINT16 uGroupIndex, UINT16 uTrackIndex)
{
    SMIL1PlayToAssoc* pPlayToAssoc = 0;
    if(m_pPlayToAssocList)
    {
	CHXSimpleList::Iterator i;
	for(i=m_pPlayToAssocList->Begin();i!=m_pPlayToAssocList->End();++i)
	{
	    SMIL1PlayToAssoc* pThisAssoc = (SMIL1PlayToAssoc*)(*i);
	    if((pThisAssoc->m_uGroupIndex == uGroupIndex) &&
	       (pThisAssoc->m_uTrackIndex == uTrackIndex))
	    {
		pPlayToAssoc = pThisAssoc;
		break;
	    }
	}
    }
    return pPlayToAssoc;
}

SMIL1PlayToAssoc*
CSmil1DocumentRenderer::getPlayToAssoc(const char* pPlayTo)
{
    SMIL1PlayToAssoc* pPlayToAssoc = 0;
    if(m_pPlayToAssocList)
    {
	CHXSimpleList::Iterator i;
	for(i=m_pPlayToAssocList->Begin();i!=m_pPlayToAssocList->End();++i)
	{
	    SMIL1PlayToAssoc* pThisAssoc = (SMIL1PlayToAssoc*)(*i);
	    if(pThisAssoc->m_playTo == pPlayTo)
	    {
		pPlayToAssoc = pThisAssoc;
		break;
	    }
	}
    }
    return pPlayToAssoc;
}

void
CSmil1DocumentRenderer::setPlayToAssoc(UINT16 uGroupIndex, UINT16 uTrackIndex, 
				    const char* pID,
				    const char* pRepeatID, // /For SHAZAM
				    const char* pPlayTo,
				    const char* pRegionName)
{
    SMIL1PlayToAssoc* pPlayToAssoc = getPlayToAssoc(uGroupIndex, uTrackIndex);
    if(!pPlayToAssoc)
    {
	pPlayToAssoc		    = new SMIL1PlayToAssoc;
	pPlayToAssoc->m_uGroupIndex = uGroupIndex;
	pPlayToAssoc->m_uTrackIndex = uTrackIndex;
	pPlayToAssoc->m_id	    = pID;
	pPlayToAssoc->m_repeatid    = pRepeatID;
	pPlayToAssoc->m_playTo	    = pPlayTo;
	pPlayToAssoc->m_ulDelay	    = 0;
	pPlayToAssoc->m_ulDuration  = 0;
	pPlayToAssoc->m_bDurationResolved = FALSE;
	pPlayToAssoc->m_bRemoveSite = TRUE;	// default is remove
	pPlayToAssoc->m_pHyperlinks = new CHXSimpleList;
	pPlayToAssoc->m_pRendererEventHook  = NULL;
	pPlayToAssoc->m_pSiteInfoList	    = new CHXSimpleList;
	if(pRegionName)
	{
	    pPlayToAssoc->m_regionName  = pRegionName;
	}

	char cTemp[20]; /* Flawfinder: ignore */
	::sprintf(cTemp,"%#010lx",(ULONG32)(void*)pPlayToAssoc); /* Flawfinder: ignore */
	pPlayToAssoc->m_tunerName   = (const char*) cTemp;
	::sprintf(cTemp,"%#010lx",(ULONG32)(void*)pPlayToAssoc+1); /* Flawfinder: ignore */
	pPlayToAssoc->m_childTunerName = (const char*)cTemp;

	// see if the pPlayTo points to a valid CSmil1BasicRegion
	BOOL bNoRegion = TRUE;
	if(pPlayTo)
	{
	    CSmil1BasicRegion* pRegion = getRegion(pPlayTo);
	    if(pRegion)
	    {
		bNoRegion = FALSE;
	    }
	}

	if(bNoRegion)
	{
	    // region name is tuner name if it's anonymous
	    pPlayToAssoc->m_playTo = pPlayToAssoc->m_childTunerName;
	}
	else
	{
	    pPlayToAssoc->m_playTo = pPlayTo;
	}

	if(!m_pPlayToAssocList)
	{
	    m_pPlayToAssocList = new CHXSimpleList;
	}
	m_pPlayToAssocList->AddTail(pPlayToAssoc);
    }
}

void 
CSmil1DocumentRenderer::removeSourcemap(SMIL1PlayToAssoc* pPlayToAssoc)
{
    // get to the site manager and remove event hook
    IHXEventHookMgr* pHookMgr = NULL;
    m_pSiteMgr->QueryInterface(IID_IHXEventHookMgr, (void**)&pHookMgr);

    CHXMapLongToObj::Iterator j = pPlayToAssoc->m_sourceMap.Begin();
    for(; j != pPlayToAssoc->m_sourceMap.End(); ++j)
    {
	CHXSimpleList* pRendererList = (CHXSimpleList*)(*j);

	CHXSimpleList::Iterator k = pRendererList->Begin();
	for (; k != pRendererList->End(); ++k)
	{
	    SMIL1SourceInfo* pSMIL1SourceInfo = (SMIL1SourceInfo*)(*k);

	    if (pSMIL1SourceInfo->m_pRendererEventHook && pHookMgr)	    
	    {
		pHookMgr->RemoveHook(pSMIL1SourceInfo->m_pRendererEventHook, 
				     pSMIL1SourceInfo->m_pRendererEventHook->m_pChannelName, 0);
	    }

	    HX_RELEASE(pSMIL1SourceInfo->m_pRendererEventHook);
	    HX_RELEASE(pSMIL1SourceInfo->m_pStream);
	    HX_RELEASE(pSMIL1SourceInfo->m_pRenderer);
	
	    HX_DELETE(pSMIL1SourceInfo);
	}
	HX_DELETE(pRendererList);
    }
    pPlayToAssoc->m_sourceMap.RemoveAll();
    HX_RELEASE(pHookMgr);
}

void
CSmil1DocumentRenderer::removeAllPlayToAssoc()
{
    if(m_pPlayToAssocList)
    {
	CHXSimpleList::Iterator i = m_pPlayToAssocList->Begin();
	for(; i != m_pPlayToAssocList->End(); ++i)
	{
	    SMIL1PlayToAssoc* pPlayToAssoc = (SMIL1PlayToAssoc*)(*i);
	    
	    HX_DELETE(pPlayToAssoc->m_pHyperlinks);
	    
	    removeSourcemap(pPlayToAssoc);

	    if (pPlayToAssoc->m_pSiteInfoList)
	    {
		pPlayToAssoc->m_pSiteInfoList->RemoveAll();
		HX_DELETE(pPlayToAssoc->m_pSiteInfoList);
	    }
	    
	    HX_DELETE(pPlayToAssoc);
	}
    }
    HX_DELETE(m_pPlayToAssocList);
}

void
CSmil1DocumentRenderer::removeGroupsPlayToAssoc(UINT16	uGroupIndex)
{
    if(m_pPlayToAssocList)
    {
	CHXSimpleList::Iterator i = m_pPlayToAssocList->Begin();
	for(; i != m_pPlayToAssocList->End(); ++i)
	{
	    SMIL1PlayToAssoc* pPlayToAssoc = (SMIL1PlayToAssoc*)(*i);
	    
	    /*
	    if the PlayToAssoc has the same group number as the group index,
	    then remove it.
	    */
	    
	    if ( pPlayToAssoc->m_uGroupIndex == uGroupIndex )
	    {
		removeSourcemap(pPlayToAssoc);

		if (pPlayToAssoc->m_pSiteInfoList)
		{
		    pPlayToAssoc->m_pSiteInfoList->RemoveAll();
		}
		
		break;
	    }	    
	}
    }
}

void
CSmil1DocumentRenderer::showSite(IHXSite* pSite, BOOL bShow)
{
    if(pSite)
    {
	IHXSite2* pSite2 = 0;
	if(HXR_OK == pSite->QueryInterface(IID_IHXSite2,
	    (void**)&pSite2))
	{
	    pSite2->ShowSite(bShow);
	    pSite2->Release();
	}
    }
}

CSmil1AAnchorElement*
CSmil1DocumentRenderer::findHyperlinkElement(const char* pID,
    UINT16 uXPos, UINT16 uYPos)
{
    // This code is not needed with new windowless site impl. of fullscreen 
    if (IsFullScreen())
    {
	IHXSiteWindowless* pSiteWndless = NULL;
	if (m_pMISUSSite)
	{
	    m_pMISUSSite->QueryInterface(IID_IHXSiteWindowless, (void**) &pSiteWndless);
	}

	// need to do this conversion only for the OLD site implementation
	if (m_pMISUSSite && pSiteWndless == NULL)
	{
	    // If we are at full screen, then we need to scale the x and y
	    // mouse locations down to the original size, since for full
	    // screen we do not get a resizeSite.
	    //
            // Get the current size
	    HXxSize cCurSize;
	    m_pMISUSSite->GetSize(cCurSize);
            // Scale it down
	    if (cCurSize.cx)
	    {
		uXPos = (UINT16) (uXPos * m_topSiteOriginalSize.cx / cCurSize.cx);
	    }
	    if (cCurSize.cy)
	    {
		uYPos = (UINT16) (uYPos * m_topSiteOriginalSize.cy / cCurSize.cy);
	    }
	}
	
	HX_RELEASE(pSiteWndless);
    }

    CHXSimpleList::Iterator i = m_pPlayToAssocList->Begin();
    for(; i != m_pPlayToAssocList->End(); ++i)
    {
	SMIL1PlayToAssoc* pAssoc = (SMIL1PlayToAssoc*)(*i);
	if(strcmp((const char*)pAssoc->m_playTo, pID) == 0 &&
	   pAssoc->m_uGroupIndex == m_uCurrentGroupIndex &&
	   pAssoc->m_pHyperlinks)
	{
	    if(pAssoc->m_ulDelay == (UINT32)-1)
	    {
		// not resolved yet
		return NULL;
	    }

	    // see if this site is current (visible) now;
	    // if it isn't then no hyperlinks can be active
	    // on that site.
	    if (pAssoc->m_pSiteInfoList)
	    {
		CHXSimpleList::Iterator j = pAssoc->m_pSiteInfoList->Begin();

		for (; j != pAssoc->m_pSiteInfoList->End(); ++j)
		{
		    BOOL bCurrentSite = TRUE;	// if no site info, then
						// the site is always current
		    SMIL1SiteInfo* pSiteInfo = (SMIL1SiteInfo*)(*j);

		    if(pSiteInfo->m_bRemoveSite)
		    {
			// /Fix for PR 34836:
			// live sources that have 0 dur, which means they play
			// forever, should have MAX_ULONG32, not 0, used as
			// their dur when calculating whether or not they're
			// visible at the current time:
			ULONG32 ulDur = pAssoc->m_ulDuration;
			if (pAssoc->m_bLiveSource  &&  0 == ulDur)
			{
			    ulDur = (ULONG32)(-1);
			}
			bCurrentSite = m_ulCurrentTime >= pSiteInfo->m_ulDelay &&
				       m_ulCurrentTime <= pSiteInfo->m_ulDelay + 
				       ulDur;
		    }
		    else
		    {
			bCurrentSite = m_ulCurrentTime >= pSiteInfo->m_ulDelay;
		    }
	    
		    if(bCurrentSite)
		    {
			UINT32 ulRelativeTime = m_ulCurrentTime - pAssoc->m_ulDelay;

			CHXSimpleList::Iterator j = pAssoc->m_pHyperlinks->Begin();
			for(; j != pAssoc->m_pHyperlinks->End(); ++j)
			{
			    CSmil1AAnchorElement* pAnchor = (CSmil1AAnchorElement*)(*j);

			    CSmil1BasicRegion* pRegion =
				getRegion(pAssoc->m_playTo);
			    if(pRegion)
			    {
				HXxRect mediaRect;
				mediaRect.left = 0;
				mediaRect.top = 0;
				if(pRegion->m_bMediaSizeSet)
				{
				    mediaRect.right = pRegion->m_mediaSize.cx;
				    mediaRect.bottom = pRegion->m_mediaSize.cy;
				}
				else
				{
				    mediaRect.right = pRegion->m_rect.right;
				    mediaRect.bottom = pRegion->m_rect.bottom;
				}
				if(pAnchor->isCurrentLink(ulRelativeTime, uXPos, uYPos,
				    mediaRect))
				{
				    //Now, we have to see if this points to a
				    // fragment in the current SMIL presentation and,
				    // if so, make sure that the begin time of the
				    // associated element has been resolved.  If not,
				    // we need to ignore the hyperlink for now:
				    const char* pFragment =
                                        pAnchor->m_href.GetBuffer(2);
				    HX_ASSERT(pFragment);
				    //Only do the following if this is a fragment:
				    if(pFragment && '#' == *pFragment)
				    {
					BOOL bFragFoundAndResolved = TRUE;
					UINT32 ulFragmentOffset = 
						m_pSmilParser->getFragmentOffset(
						&(pFragment[1]),
						/* This is passed by reference: */
						bFragFoundAndResolved); 
					//Fixes PR 22655:
					//Ignore if not found or not yet resolved:
					if(!bFragFoundAndResolved)
					{
					    // begin time not resolved yet
					    return NULL;
					}
				    }
				    return pAnchor;
				}
			    }
			}
		    }
		}
	    }
	}
    }
    return NULL;
}

HX_RESULT
CSmil1DocumentRenderer::handleMouseMove(void* pWindow,
				const char* pID,
				UINT16 uXPos, UINT16 uYPos)
{
    // since IHXStatusMessage::SetStatus() effectively
    // results in a mouse move (and I don't want to loop
    // forever) don't do anything if this mouse move event
    // has the same xy as the previous mouse move event

    if(uXPos == m_usOldXPos &&
	uYPos == m_usOldYPos)
    {
	return HXR_OK;
    }

    m_usOldXPos = uXPos;
    m_usOldYPos = uYPos;

    HX_RESULT rc = HXR_FAIL;

#if defined(_WINDOWS)
    HCURSOR hCurrentCursor = GetCursor();
#endif

    CSmil1AAnchorElement* pAnchor = findHyperlinkElement(pID,
	uXPos, uYPos);
    if(pAnchor)
    {
#if defined(_WINDOWS)
	if(hCurrentCursor != m_hHyperlinkCursor)
	{
	    m_bNeedToSetHyperlinkCursor = TRUE;
	}
#elif defined(_MACINTOSH)
        if (m_hHyperlinkCursor)
        {
	    m_bResetCursor = TRUE;
	    ::SetCursor(*m_hHyperlinkCursor);
        }
#endif
#if defined(_UNIX)  &&  (!defined(_BEOS))  &&  defined(USE_XWINDOWS)
	if (m_pDisplay && m_Window && m_hHyperlinkCursor && m_hCurrentCursor != m_hHyperlinkCursor)
	{
	    XDefineCursor(m_pDisplay, m_Window, m_hHyperlinkCursor);
	    m_hCurrentCursor = m_hHyperlinkCursor;
	}
#endif

	if (m_pStatusMessage)
	{
	    m_pStatusMessage->SetStatus (pAnchor->m_href);
	    m_bStatusMessageSet = TRUE;
	}
	rc = HXR_OK;	// handled
    }
    else
    {
#if defined(_WINDOWS)
	if(hCurrentCursor == m_hHyperlinkCursor)
	{
	    //We need to change it back -- we just moved off of a hyperlink:
	    m_bNeedToSetHyperlinkCursor = FALSE;
	}
#elif defined(_MACINTOSH)
	if (m_bResetCursor)
	{
	    m_bResetCursor = FALSE;
	    InitCursor();
	}
#elif defined(_UNIX)  &&  (!defined(_BEOS))  &&  defined(USE_XWINDOWS)
	if (m_pDisplay && m_Window && m_hCurrentCursor == m_hHyperlinkCursor)
	{
	    XUndefineCursor(m_pDisplay, m_Window);
	    m_hCurrentCursor = 0;
	}
#endif
	if (m_pStatusMessage &&
	    m_bStatusMessageSet)
	{
	    m_pStatusMessage->SetStatus(NULL);
	    m_bStatusMessageSet = FALSE;
	}
    }

    return rc;
}

BOOL
CSmil1DocumentRenderer::handleSetCursor()
{
    BOOL rc = FALSE;

#ifdef _WINDOWS
    if(m_bNeedToSetHyperlinkCursor)
    {
	// We don't want to overwrite our pre hyperlink cursor
	HCURSOR hTemp = SetCursor(m_hHyperlinkCursor);
	if (hTemp != m_hHyperlinkCursor)
	{
	    m_hPreHyperlinkCursor = hTemp;
		
	}
	rc = TRUE;
    }
    else if (m_hPreHyperlinkCursor)
    {
	SetCursor(m_hPreHyperlinkCursor);
	m_hPreHyperlinkCursor = NULL;
	rc = TRUE;
    }
#endif

    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::handleLButtonUp(const char* pID,
    UINT16 uXPos, UINT16 uYPos)
{
#if defined(_UNIX)  &&  (!defined(_BEOS))  &&  defined(USE_XWINDOWS)
//Clear the previously set cursors before leaving this window
    if(m_Window)
        XUndefineCursor(m_pDisplay, m_Window);
#endif

    HX_RESULT rc = HXR_FAIL;

    CSmil1AAnchorElement* pAnchor = findHyperlinkElement(pID,
	uXPos, uYPos);
    if(pAnchor && pAnchor->m_href.GetLength() > 0)
    {
	if(m_pParent)
	{
	    IHXPlayer* pPlayer = m_pParent->getPlayer();
	    if(pPlayer)
	    {
		const char* pTarget = "_player";

		// if show is 'new' or 'pause', spawn a browser
		if(pAnchor->m_show == "new" ||
		   pAnchor->m_show == "pause")
		{
		    pTarget = 0;
		}

		if(pAnchor->m_href[0] == '#')
		{
		    if (!m_pProcessElementCallback)
		    {
			m_pProcessElementCallback = new ProcessElementCallback();
			m_pProcessElementCallback->m_pOwner = this;
			m_pProcessElementCallback->AddRef();
		    }

		    if (m_pScheduler && !m_pProcessElementCallback->m_bIsCallbackPending)
		    {
			m_pProcessElementCallback->m_elementID = pAnchor->m_href.Mid(1);
			m_pProcessElementCallback->m_bIsCallbackPending = TRUE;
			m_pProcessElementCallback->m_PendingHandle = m_pScheduler->RelativeEnter(m_pProcessElementCallback, 0);
		    }	
		    else
		    {
			HX_ASSERT(FALSE);
		    }
		}
		else
		{
		    if(pAnchor->m_show == "pause")
		    {
			pPlayer->Pause();
		    }

		    IHXHyperNavigate* pHyper = 0;
		    if(HXR_OK == pPlayer->QueryInterface(IID_IHXHyperNavigate,
			(void**)&pHyper))
		    {
			CHXString urlString;
			convertURL(pAnchor->m_href, urlString);
			pHyper->GoToURL(urlString, pTarget);
			pHyper->Release();
		    }
		}
	    }
	    rc = HXR_OK;
	}
    }
    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::detachSite(IHXSite* pSite)
{
    HX_RESULT rc = HXR_OK;

    // remove site from site info list

    LISTPOSITION pos = m_pSiteInfoList->GetHeadPosition();
    while(pos)
    {
	SMIL1SiteInfo* pSiteInfo = 
	    (SMIL1SiteInfo*)m_pSiteInfoList->GetAt(pos);
	if(pSiteInfo->m_pRendererSite == pSite)
	{
	    CSmil1BasicRegion* pRegion = getRegion(pSiteInfo->m_regionID);
	    if(pRegion)
	    {
		pRegion->m_pSite->DestroyChild(pSite);
	    }
	    m_pSiteInfoList->RemoveAt(pos);

	    // at this time go through the PlayToAssocList list and
	    // change any that reference the soon to be removed 
	    // site info.

	    if (m_pPlayToAssocList)
	    {
		CHXSimpleList::Iterator i = m_pPlayToAssocList->Begin();
		for (; i!=m_pPlayToAssocList->End(); ++i)
		{
		    SMIL1PlayToAssoc* pPlayToAssoc = (SMIL1PlayToAssoc*)(*i);
		    
		    LISTPOSITION pos = pPlayToAssoc->m_pSiteInfoList->Find(pSiteInfo);
		    pPlayToAssoc->m_pSiteInfoList->RemoveAt(pos);
		}
	    }
	    
	    HX_DELETE(pSiteInfo);
	    break;
	}
	m_pSiteInfoList->GetNext(pos);
    }

    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::updateStreamTiming(const char* pElementID,
					  UINT32 ulDuration)
{
    HX_RESULT rc = HXR_OK;

    CSmil1Element* pElement = m_pSmilParser->findElement(pElementID);

    if(pElement)
    {
	// find the SMIL1PlayToAssoc associated with this element ID
	SMIL1PlayToAssoc* pPlayToAssoc = NULL;
	if(m_pPlayToAssocList)
	{
	    CHXSimpleList::Iterator i = m_pPlayToAssocList->Begin();
	    for (; i!=m_pPlayToAssocList->End(); ++i)
	    {
		SMIL1PlayToAssoc* pThisAssoc = (SMIL1PlayToAssoc*)(*i);
		if(pThisAssoc->m_id == (const char*)pElement->m_pNode->m_id)
		{
		    pPlayToAssoc = pThisAssoc;
		    break;
		}
	    }
	}
	if(pPlayToAssoc && 
	   pPlayToAssoc->m_sourceMap.GetCount() > 0)
	{
	    pPlayToAssoc->m_ulDuration = ulDuration;
	    CHXMapLongToObj::Iterator j = pPlayToAssoc->m_sourceMap.Begin();
	
	    CHXSimpleList* pRendererInfoList = (CHXSimpleList*)(*j);
	    SMIL1SourceInfo* pSourceInfo = (SMIL1SourceInfo*)pRendererInfoList->GetHead();
	    IHXLayoutStream* pLayoutStream = NULL;
	    if(HXR_OK == 
		pSourceInfo->m_pStream->QueryInterface(IID_IHXLayoutStream, 
						    (void**)&pLayoutStream))
	    {
		IHXValues* pStreamProps = NULL;
		if(HXR_OK == pLayoutStream->GetProperties(pStreamProps))
		{
		    pStreamProps->SetPropertyULONG32("duration", ulDuration);
		    pLayoutStream->SetProperties(pStreamProps);
		    pStreamProps->Release();

		    // XXX HP THIS IS NO-OP!!
		    // update delay for subsequent elements
		    //updateStreamDelay(pPlayToAssoc->m_uGroupIndex,
		    //		      pPlayToAssoc->m_ulDelay);
		}
		pLayoutStream->Release();
	    }
	    updateSiteEvents(pPlayToAssoc->m_uGroupIndex);
	}
    }

    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::updateStreamDelay(UINT16 uGroupIndex,
					 UINT32 ulInitialDelay)
{
    HX_RESULT rc = HXR_OK;

    if(m_pPlayToAssocList)
    {
	CHXSimpleList::Iterator i = m_pPlayToAssocList->Begin();
	for (; i!=m_pPlayToAssocList->End(); ++i)
	{
	    SMIL1PlayToAssoc* pPlayToAssoc = (SMIL1PlayToAssoc*)(*i);
	    if(pPlayToAssoc->m_uGroupIndex == uGroupIndex &&
		pPlayToAssoc->m_ulDelay > ulInitialDelay)
	    {
		UINT32 ulNewDelay = pPlayToAssoc->m_ulDelay;
		pPlayToAssoc->m_ulDelay = ulNewDelay;
		if(pPlayToAssoc->m_sourceMap.GetCount() > 0)
		{
		    CHXMapLongToObj::Iterator j = pPlayToAssoc->m_sourceMap.Begin();

		    CHXSimpleList* pRendererList = (CHXSimpleList*)(*j);

		    CHXSimpleList::Iterator k = pRendererList->Begin();
		    for (; k != pRendererList->End(); ++k)
		    {
			SMIL1SourceInfo* pSMIL1SourceInfo = (SMIL1SourceInfo*)(*k);
			IHXLayoutStream* pLayoutStream = NULL;
			if(HXR_OK == 
			    pSMIL1SourceInfo->m_pStream->QueryInterface(
			    IID_IHXLayoutStream,
			    (void**)&pLayoutStream))
			{
			    IHXValues* pStreamProps = NULL;
			    if(HXR_OK == pLayoutStream->GetProperties(
				pStreamProps))
			    {
				pStreamProps->SetPropertyULONG32("delay", 
				    pPlayToAssoc->m_ulDelay);
				pLayoutStream->SetProperties(pStreamProps);
				pStreamProps->Release();
			    }
			    pLayoutStream->Release();
			}
		    }
		}
	    }
	}
    }
    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::updateSiteEvents(UINT16 uGroupIndex)
{
    HX_RESULT rc = HXR_OK;

    if(m_pPlayToAssocList)
    {
	// blow away current events
	removeGroupEvents(uGroupIndex);

	CHXSimpleList::Iterator i = m_pPlayToAssocList->Begin();
	for (; i!=m_pPlayToAssocList->End(); ++i)
	{
	    SMIL1PlayToAssoc* pPlayToAssoc = (SMIL1PlayToAssoc*)(*i);
	    if(pPlayToAssoc->m_uGroupIndex == uGroupIndex &&
		pPlayToAssoc->m_pSiteInfoList)
	    {
		CHXSimpleList::Iterator j = pPlayToAssoc->m_pSiteInfoList->Begin();
		for (; j != pPlayToAssoc->m_pSiteInfoList->End(); ++j)
		{
		    SMIL1SiteInfo* pSiteInfo = (SMIL1SiteInfo*)(*j);
		
		    IHXSite* pRegionSite = NULL;
		    CSmil1BasicRegion* pRegion = getRegion(pSiteInfo->m_regionID);
		    if(pRegion && !pRegion->m_bBgColorSet)
		    {
			pRegionSite = pRegion->m_pSite;
		    }

		    pSiteInfo->m_ulDelay = pPlayToAssoc->m_ulDelay;
		    pSiteInfo->m_ulDuration = pPlayToAssoc->m_ulDuration;

		    if(pSiteInfo->m_ulDelay > m_ulCurrentTime)
		    {
			// hide site and schedule show and hide events
			showSite(pSiteInfo->m_pRendererSite, FALSE);
			showSite(pRegionSite, FALSE);
			CSmil1ShowSiteEvent* pShowEvent =
			    new CSmil1ShowSiteEvent(uGroupIndex,
				pSiteInfo->m_ulDelay, pSiteInfo->m_pRendererSite, 
				pRegionSite, TRUE);
			insertEvent(pShowEvent);

			if(pSiteInfo->m_bRemoveSite)
			{
			    CSmil1ShowSiteEvent* pHideEvent =
				new CSmil1ShowSiteEvent(uGroupIndex,
				    pSiteInfo->m_ulDuration + pSiteInfo->m_ulDelay, 
				    pSiteInfo->m_pRendererSite, 
				    pRegionSite, FALSE);
			    insertEvent(pHideEvent);
			}
		    }
		    else if((pSiteInfo->m_ulDelay + pSiteInfo->m_ulDuration)
			    < m_ulCurrentTime)
		    {
			// XXX HP THIS SHOULD NEVER HAPPEN!!
			HX_ASSERT(FALSE);
			// after this site should be hidden
			if(pSiteInfo->m_bRemoveSite)
			{
			    showSite(pSiteInfo->m_pRendererSite, FALSE);
			    showSite(pRegionSite, FALSE);
			}
		    }
		    else
		    {
			// schedule both show and hide events
			// so onPreSeek will get all necessary
			// events

			CSmil1ShowSiteEvent* pShowEvent =
			    new CSmil1ShowSiteEvent(uGroupIndex,
				pSiteInfo->m_ulDelay, pSiteInfo->m_pRendererSite, 
				pRegionSite, TRUE);
			insertEvent(pShowEvent);

			if(pSiteInfo->m_bRemoveSite)
			{
			    CSmil1ShowSiteEvent* pHideEvent =
				new CSmil1ShowSiteEvent(uGroupIndex,
				    pSiteInfo->m_ulDuration + pSiteInfo->m_ulDelay, 
				    pSiteInfo->m_pRendererSite, 
				    pRegionSite, FALSE);
			    insertEvent(pHideEvent);
			}
		    }
		}
	    }
	}
    }
    return rc;
}
					 

HX_RESULT
CSmil1DocumentRenderer::seekTo(const char* pElementID)
{
    HX_RESULT rc = HXR_OK;

    CSmil1Element* pElement = m_pSmilParser->findElement(pElementID);

    if(pElement)
    {
	HX_VECTOR_DELETE(m_pFragment);
	m_pFragment = new_string(pElementID);

	IHXPlayer* pPlayer = m_pParent->getPlayer();
	IHXGroupManager* pMgr = 0;

	if(HXR_OK == pPlayer->QueryInterface(IID_IHXGroupManager, (void**)&pMgr))
	{
	    UINT16 uFragmentGroup = m_pSmilParser->getFragmentGroup(m_pFragment);
	    if(uFragmentGroup != m_uCurrentGroupIndex)
	    {
		m_bSettingFragment = TRUE;
    		m_nFragmentTracks = 0;
		pMgr->SetCurrentGroup(uFragmentGroup);
	    }
	    else
	    {
		BOOL bFragFoundAndResolved =TRUE;
		UINT32 ulFragmentOffset = 
		    m_pSmilParser->getFragmentOffset(m_pFragment,
			    /* This is passed by reference: */
			    bFragFoundAndResolved); 
		//If getFragmentOffset() failed to find the fragment or
		// found it but it did not yet have a resolved begin time,
		// we used to seek to 0 (the returned value), but now we
		// just don't do a seek:
		// (Note: this problem was found while fixing PR 22655.)
		if(bFragFoundAndResolved)
		{
		    pPlayer->Seek(ulFragmentOffset);
		    pPlayer->Begin();
		}
	    }
	    pMgr->Release();
	}
    }
    else
    {
	rc = HXR_FAIL;
    }
    return rc;
}

void
CSmil1DocumentRenderer::resizeRegion(const char* pRegionName,
				    HXxSize* pNewSize)
{
    CSmil1BasicRegion* pRegion = getRegion(pRegionName);
    if(pRegion)
    {
	pRegion->m_rect.right = pRegion->m_rect.left + pNewSize->cx;
	pRegion->m_rect.bottom = pRegion->m_rect.top + pNewSize->cy;
    }
}

void
CSmil1DocumentRenderer::repositionRegion(const char* pRegionName,
				      HXxPoint* pNewPosition)
{
    CSmil1BasicRegion* pRegion = getRegion(pRegionName);
    if(pRegion)
    {
	HXxSize size;
	size.cx = HXxRECT_WIDTH(pRegion->m_rect);
	size.cy = HXxRECT_HEIGHT(pRegion->m_rect);

	pRegion->m_rect.left = pNewPosition->x;
	pRegion->m_rect.top = pNewPosition->y;
	pRegion->m_rect.right = pRegion->m_rect.left + size.cx;
	pRegion->m_rect.bottom = pRegion->m_rect.top + size.cy;
    }
}

/*
 * IHXValues methods
 */

STDMETHODIMP
CSmil1DocumentRenderer::GetPropertyULONG32	     (
	    const char*          pPropertyName,
	    REF(ULONG32)         uPropertyValue)
{
    return m_pValues->GetPropertyULONG32(pPropertyName, uPropertyValue);
}

STDMETHODIMP
CSmil1DocumentRenderer::GetPropertyCString	    (
		const char*         pPropertyName,
		REF(IHXBuffer*)    pPropertyValue)
{
    return m_pValues->GetPropertyCString(pPropertyName, pPropertyValue);
}

STDMETHODIMP
CSmil1DocumentRenderer::SetPropertyULONG32	     (
		const char*          pPropertyName,
		ULONG32              uPropertyValue)
{
    return m_pValues->SetPropertyULONG32(pPropertyName, uPropertyValue);
}

STDMETHODIMP
CSmil1DocumentRenderer::GetFirstPropertyULONG32   (
		REF(const char*)     pPropertyName,
		REF(ULONG32)         uPropertyValue)
{	
    return m_pValues->GetFirstPropertyULONG32(pPropertyName, uPropertyValue);
}

STDMETHODIMP
CSmil1DocumentRenderer::GetNextPropertyULONG32   (
		REF(const char*)    pPropertyName,
		REF(ULONG32)        uPropertyValue)
{	
    return m_pValues->GetNextPropertyULONG32(pPropertyName, uPropertyValue);
}

STDMETHODIMP
CSmil1DocumentRenderer::SetPropertyBuffer	    (
		const char*         pPropertyName,
		IHXBuffer*         pPropertyValue)
{
    return m_pValues->SetPropertyBuffer(pPropertyName, pPropertyValue);
}

STDMETHODIMP
CSmil1DocumentRenderer::GetPropertyBuffer	    (
		const char*         pPropertyName,
		REF(IHXBuffer*)    pPropertyValue)
{
    return m_pValues->GetPropertyBuffer(pPropertyName, pPropertyValue);
}

STDMETHODIMP
CSmil1DocumentRenderer::GetFirstPropertyBuffer   (
		REF(const char*)    pPropertyName,
		REF(IHXBuffer*)    pPropertyValue)
{	
    return m_pValues->GetFirstPropertyBuffer(pPropertyName, pPropertyValue);
}

STDMETHODIMP
CSmil1DocumentRenderer::GetNextPropertyBuffer    (
		REF(const char*)    pPropertyName,
		REF(IHXBuffer*)    pPropertyValue)
{	
    return m_pValues->GetNextPropertyBuffer(pPropertyName, pPropertyValue);
}

STDMETHODIMP
CSmil1DocumentRenderer::SetPropertyCString	    (
		const char*         pPropertyName,
		IHXBuffer*         pPropertyValue)
{
    return m_pValues->SetPropertyCString(pPropertyName, pPropertyValue);
}

STDMETHODIMP
CSmil1DocumentRenderer::GetFirstPropertyCString   (
		REF(const char*)    pPropertyName,
		REF(IHXBuffer*)    pPropertyValue)
{	
    return m_pValues->GetFirstPropertyCString(pPropertyName, pPropertyValue);
}

STDMETHODIMP
CSmil1DocumentRenderer::GetNextPropertyCString    (
		REF(const char*)    pPropertyName,
		REF(IHXBuffer*)    pPropertyValue)
{	
    return m_pValues->GetNextPropertyCString(pPropertyName, pPropertyValue);
}

HX_RESULT
CSmil1DocumentRenderer::GetElementProperties(UINT16		uGroupID, 
					    UINT16		uTrackID, 
					    REF(IHXValues*)	pProperties)
{
    HX_RESULT		rc = HXR_OK;
    ElementWithinTag	elementWithinTag = WithinUnknown;

    SMIL1PlayToAssoc* pPlayToAssoc = getPlayToAssoc(uGroupID,
						   uTrackID);

    if(pPlayToAssoc)
    {
	elementWithinTag = m_pSmilParser->GetElementWithin(pPlayToAssoc->m_id);
    }
    pProperties = new CHXHeader();
    pProperties->AddRef();

    pProperties->SetPropertyULONG32("ElementWithinTag", elementWithinTag);

    return rc;
}

HX_RESULT		 
CSmil1DocumentRenderer::GetElementStatus(UINT16		    uGroupID,
				         UINT16		    uTrackID,
				         UINT32		    ulCurrentTime,
				         REF(IHXValues*)   pStatus)
{
    HX_RESULT		    rc = HXR_OK;
    CHXSimpleList*	    pSiteInfoList = NULL;
    CSmil1Element*	    pElement = NULL;
    CSmil1ShowSiteEvent*    pCurHideEvent = NULL;
    SMIL1PlayToAssoc*	    pPlayToAssoc = getPlayToAssoc(uGroupID, uTrackID);

    pStatus = NULL;

    if (pPlayToAssoc && pPlayToAssoc->m_pSiteInfoList)
    {
	pSiteInfoList = pPlayToAssoc->m_pSiteInfoList;
	
        LISTPOSITION pos = pSiteInfoList->GetHeadPosition();
        while (pos)
        {
            SMIL1SiteInfo* pSiteInfo = (SMIL1SiteInfo*)pSiteInfoList->GetNext(pos);
            if (pSiteInfo)
            {
		pCurHideEvent = getShowHideEvent(pSiteInfo->m_pRegionSite,
						 pSiteInfo->m_pRendererSite,
                                                 FALSE);

		if (pCurHideEvent && pCurHideEvent->m_ulEventTime > ulCurrentTime)
		{
		    pStatus = new CHXHeader();
		    pStatus->AddRef();

		    pStatus->SetPropertyULONG32("Show", 1);
		    break;
		}
	    }
	}
    }

    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::AttachElementLayout(UINT16	    uGroupID,
					    UINT16	    uTrackID,
					    IHXRenderer*   pRenderer,
					    IHXStream*	    pStream,
					    IHXValues*	    pProps)
{
    HX_RESULT		rc = HXR_OK;    
    UINT32		ulDelay = 0;
    UINT32		ulDuration = 0;
    IHXLayoutStream*	pLayoutStream = NULL;
    CSmil1BasicRegion*	pRegion = NULL;
    CHXSimpleList*	pRendererList = NULL;
    SMIL1SourceInfo*	pSourceInfo = NULL;
    SMIL1PlayToAssoc*	pPlayToAssoc = NULL;

    // setup the Root layout if it has not
    // this could happen when the child SMIL gets initialized 
    // ahead of its parent when switching groups
    if (m_bSitesDetached)
    {
	m_bSitesDetached = FALSE;
	rc = setupRootLayout();
	HX_ASSERT(HXR_OK == rc);
    }

    pPlayToAssoc = getPlayToAssoc(uGroupID, uTrackID);
    HX_ASSERT(pPlayToAssoc);

    pRegion = getRegion(pPlayToAssoc->m_playTo);    
    if (!pRegion)
    {
	// phony one up
	HXxRect rect = {0, 0, 0, 0};
	pRegion = new CSmil1BasicRegion(pPlayToAssoc->m_playTo, rect, 0, "hidden", 0, 
	    FALSE, TRUE,
	    //Default to TRUE for width unspecified and
	    // height unspecified:
	    TRUE, TRUE);
	(*m_pRegionMap)[pPlayToAssoc->m_playTo] = pRegion;
    }

    if (pStream && pProps)
    {
	pSourceInfo = new SMIL1SourceInfo;
	pSourceInfo->m_pStream = pStream;
	if(pSourceInfo->m_pStream)
	{
	    pSourceInfo->m_pStream->AddRef();
	}
	pSourceInfo->m_pRenderer = pRenderer;
	if(pSourceInfo->m_pRenderer)
	{
	    pSourceInfo->m_pRenderer->AddRef();
	}
    
	pProps->GetPropertyULONG32("Delay", ulDelay);
	pProps->GetPropertyULONG32("Duration", ulDuration);

	pSourceInfo->m_ulDelay = ulDelay;
	pSourceInfo->m_ulDuration = ulDuration - ulDelay;

	pRendererList = (CHXSimpleList*) pPlayToAssoc->m_sourceMap[0];
	pRendererList->AddTail(pSourceInfo);
    }
    else
    {
	pRendererList = (CHXSimpleList*)pPlayToAssoc->m_sourceMap[0];
	HX_ASSERT(pRendererList->GetCount() == 1);

	pSourceInfo = (SMIL1SourceInfo*)pRendererList->GetHead();
    }

    char cTemp[20]; /* Flawfinder: ignore */
    ::sprintf(cTemp,"%#010lx",(ULONG32)(void*)pRenderer); /* Flawfinder: ignore */
    pSourceInfo->m_tunerName   = (const char*) cTemp;
    ::sprintf(cTemp,"%#010lx",(ULONG32)(void*)pRenderer+1); /* Flawfinder: ignore */
    pSourceInfo->m_childTunerName = (const char*)cTemp;

    const char* pChildTuner = pSourceInfo->m_childTunerName;

    // get to the site manager and set an event hook
    IHXEventHookMgr* pHookMgr = NULL;
    if(HXR_OK ==
	m_pSiteMgr->QueryInterface(IID_IHXEventHookMgr, 
				(void**)&pHookMgr))
    {
	CSmil1EventHook* pChildEventHook = NULL;

	// create event hook for playto
	pChildEventHook = new CSmil1EventHook(this,
					     pPlayToAssoc->m_playTo, pChildTuner, FALSE);

	pChildEventHook->AddRef();

	pHookMgr->AddHook(pChildEventHook, pChildTuner, 0);

	pSourceInfo->m_pRendererEventHook = pChildEventHook;

	pHookMgr->Release();
    }
    else
    {
	pSourceInfo->m_pRendererEventHook = NULL;
    }

    pPlayToAssoc->m_tunerName = pSourceInfo->m_tunerName;
    pPlayToAssoc->m_childTunerName = pSourceInfo->m_childTunerName;
    pPlayToAssoc->m_pRendererEventHook = pSourceInfo->m_pRendererEventHook;

    // add hyperlinks
    CSmil1Element* pElement = m_pSmilParser->findElement(pPlayToAssoc->m_id);
    if(pElement && pElement->m_pHyperlinks)
    {
	CHXSimpleList::Iterator i = 
		pElement->m_pHyperlinks->Begin();
	for(; i != pElement->m_pHyperlinks->End(); ++i)
	{
	    CSmil1AAnchorElement* pAnchor = 
		(CSmil1AAnchorElement*)(*i);
	    //[SMIL 1.0 Compliance] Fixes PR 26473:
	    // We want to add in LIFO fashion so inner
	    // (nested) anchors will be found first in
	    // CSmilDocumentRenderer::findHyperlinkElement(),
	    // below.  In other words, we're giving an
	    // effective higher link "z-order" to the
	    // decendants of other links.  This used to
	    // call AddTail():
	    pPlayToAssoc->m_pHyperlinks->AddHead(pAnchor);
	}
    }

    IHXValues* pValues = 0;
    IHXBuffer* pPlayToBuffer = 0;
    IHXBuffer* pRegionName = 0;
    IHXCommonClassFactory* pFactory = m_pParent->getFactory();
    if ((HXR_OK == pFactory->CreateInstance(CLSID_IHXValues, (void**)&pValues)) &&
	(HXR_OK == pFactory->CreateInstance(CLSID_IHXBuffer, (void**)&pPlayToBuffer)) &&
	(HXR_OK == pFactory->CreateInstance(CLSID_IHXBuffer, (void**)&pRegionName)))
    {		    
	pPlayToBuffer->Set((BYTE*)pChildTuner, strlen(pChildTuner)+1);
	pValues->SetPropertyCString("playto", pPlayToBuffer);

	if(pPlayToAssoc->m_regionName.GetLength() > 0)
	{
	    const char* pName = pPlayToAssoc->m_regionName;
	    pRegionName->Set((BYTE*)pName, strlen(pName)+1);
	    pValues->SetPropertyCString("region", pRegionName);
	}
    }
    HX_RELEASE(pPlayToBuffer);
    HX_RELEASE(pRegionName);

    if (pStream &&
	HXR_OK == pStream->QueryInterface(IID_IHXLayoutStream, (void**)&pLayoutStream))
    {
	pLayoutStream->SetProperties(pValues);
    }
    HX_RELEASE(pLayoutStream);

    if(!pRegion->m_bImplicitRegion)
    {
	addSiteForRenderer(pPlayToAssoc, pSourceInfo, pRenderer, FALSE);
    
	if (!pStream)
	{
	    m_pParent->HandleAttachElementLayout((IUnknown*)pRenderer, pValues);
	}
    }
    HX_RELEASE(pValues);

    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::DetachElementLayout(IUnknown* pLSG)
{
    HX_RESULT	rc = HXR_OK;
    return rc;
}

HX_RESULT
CSmil1DocumentRenderer::InitPersistent(UINT32			ulPersistentComponentID,
				      UINT16			uPersistentGroupID,
				      UINT16			uPersistentTrackID,
				      IHXPersistentRenderer*	pPersistentParent)
{
    m_ulPersistentComponentID = ulPersistentComponentID;
    m_uPersistentGroupID = uPersistentGroupID;
    m_uPersistentTrackID = uPersistentTrackID;

    m_pPersistentParentRenderer = pPersistentParent;
    HX_ADDREF(m_pPersistentParentRenderer);

    return HXR_OK;
}

BOOL 
CSmil1DocumentRenderer::IsNestedMetaSupported(UINT16& uSupportedType)
{
    BOOL	    bResult = TRUE;    
    UINT32	    ulParentPersistentVersion = 0;
    UINT32	    ulParentPersistentMajorVersion = 0;
    UINT32	    ulParentPersistentType = PersistentUnknown;
    IHXValues*	    pProperties = NULL;

    uSupportedType = 0;

    if (!m_pPersistentParentRenderer)
    {
	return bResult;
    }

    if (HXR_OK == m_pPersistentParentRenderer->GetPersistentProperties(pProperties))
    {
	pProperties->GetPropertyULONG32("PersistentType", ulParentPersistentType);
	pProperties->GetPropertyULONG32("PersistentVersion", ulParentPersistentVersion);

	ulParentPersistentMajorVersion = HX_GET_MAJOR_VERSION(ulParentPersistentVersion);

	switch (ulParentPersistentType)
	{
	case PersistentUnknown:
	    bResult = FALSE;
	    break;
	case PersistentRAM:
	    // RP8 SS3 - limited SMIL in RAM support
	    if (ulParentPersistentMajorVersion == 2)
	    {
		m_bInRAM20 = TRUE;
		uSupportedType = 1;
	    }
	    // otherwise - fully nested meta support even though
	    // the parent RAM is 1.0
	    else
	    {
		uSupportedType = 2;
	    }
	    break;
	case PersistentSMIL:
	    if (ulParentPersistentMajorVersion == 1)
	    {
		bResult = FALSE;
	    }
	    else
	    {
		uSupportedType = 2;
	    }
	    break;
	default:
	    break;
	}
    }
    HX_RELEASE(pProperties);
    
    return bResult;
}

void
CSmil1DocumentRenderer::PersistentDurationSet(UINT32 ulDuration, 
					     UINT32 ulDelay, 
					     BOOL bIsLive)
{
    IHXRendererAdviseSink* pRendererAdviseSink = NULL;

    if (m_pPersistentParentRenderer &&
	HXR_OK == m_pPersistentParentRenderer->QueryInterface(IID_IHXRendererAdviseSink, (void**)&pRendererAdviseSink))
    {
	pRendererAdviseSink->TrackDurationSet(m_uPersistentGroupID,
					      m_uPersistentTrackID,
					      ulDuration,
					      ulDelay,
					      bIsLive);
    }
    HX_RELEASE(pRendererAdviseSink);

    return;
}

/*
 * CSmil1SiteWatcher methods
 */

CSmil1SiteWatcher::CSmil1SiteWatcher(CSmil1DocumentRenderer* 
    pDoc, const char* pID, BOOL bIsChildSite):
    m_pDoc(pDoc),
    m_lRefCount(0),
    m_id(pID),
    m_bIsChildSite(bIsChildSite),
    m_pSite(0),
    m_bChangingSize(FALSE),
    m_bFirstSetSize(TRUE)
{
#if defined(_DEBUG) && defined(XXXMEH_CHECK_FOR_LEAKS)
    char szDbgStr[128]; /* Flawfinder: ignore */
    sprintf(szDbgStr, "CON CSmil1SiteWatcher 0x%08x\n", this); /* Flawfinder: ignore */
    OutputDebugString(szDbgStr);
#endif
    if(m_pDoc)
    {
	m_pDoc->AddRef();
    }
}

CSmil1SiteWatcher::~CSmil1SiteWatcher()
{
#if defined(_DEBUG) && defined(XXXMEH_CHECK_FOR_LEAKS)
    char szDbgStr[128]; /* Flawfinder: ignore */
    sprintf(szDbgStr, "DES CSmil1SiteWatcher 0x%08x\n", this); /* Flawfinder: ignore */
    OutputDebugString(szDbgStr);
#endif
    close();
}

HX_RESULT
CSmil1SiteWatcher::close()
{
    HX_RELEASE(m_pDoc);
    HX_RELEASE(m_pSite);

    return HXR_OK;
}

/*
 * IUnknown methods
 */
STDMETHODIMP
CSmil1SiteWatcher::QueryInterface(REFIID riid, void** ppvObj)
{
    if(IsEqualIID(riid, IID_IUnknown))
    {
	AddRef();
	*ppvObj = this;
	return HXR_OK;
    }
    else if(IsEqualIID(riid, IID_IHXSiteWatcher))
    {
	AddRef();
	*ppvObj = (IHXSiteWatcher*)this;
	return HXR_OK;
    }
    *ppvObj = NULL;
    return HXR_NOINTERFACE;
}

STDMETHODIMP_(ULONG32)
CSmil1SiteWatcher::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

STDMETHODIMP_(ULONG32)
CSmil1SiteWatcher::Release()
{
    if(InterlockedDecrement(&m_lRefCount) > 0)
    {
	return m_lRefCount;
    }

    delete this;
    return 0;
}

/*
 * IHXSiteWatcher methods
 */

STDMETHODIMP
CSmil1SiteWatcher::AttachSite(IHXSite* pSite)
{
    m_pSite = pSite;
    if(m_pSite)
    {
	m_pSite->AddRef();
    }

    return HXR_OK;
}

STDMETHODIMP
CSmil1SiteWatcher::DetachSite()
{
    HX_RELEASE(m_pSite);

    return HXR_OK;
}

STDMETHODIMP
CSmil1SiteWatcher::ChangingPosition(HXxPoint oldPos, REF(HXxPoint) newPos)
{
    return HXR_OK;
}

STDMETHODIMP
CSmil1SiteWatcher::ChangingSize(HXxSize oldSize, REF(HXxSize) newSize)
{
    if(m_bChangingSize ||
	(newSize.cx == 0 &&
	 newSize.cy == 0))
    {
	return HXR_OK;	// don't change size
    }

    CSmil1BasicRegion* pRegion = m_pDoc->getRegion(m_id);
    if(pRegion)
    {
	BOOL bResizeRegion = FALSE;

	if(m_bIsChildSite)
	{
	    INT32 lRegionWidth = HXxRECT_WIDTH(pRegion->m_rect);
	    INT32 lRegionHeight = HXxRECT_HEIGHT(pRegion->m_rect);
	    double xScaleFactor = 1.; 
	    double yScaleFactor = 1.; 
	    if (m_pDoc->m_topSiteOriginalSize.cx)
	    {
		xScaleFactor = (double) m_pDoc->m_topSiteSize.cx/(double) m_pDoc->m_topSiteOriginalSize.cx;
	    }
	    if (m_pDoc->m_topSiteOriginalSize.cy)
	    {
		yScaleFactor = (double) m_pDoc->m_topSiteSize.cy/(double) m_pDoc->m_topSiteOriginalSize.cy;
	    }

	    if(m_bFirstSetSize)
	    {
                // Clear the flag
                m_bFirstSetSize = FALSE;

		pRegion->m_originalMediaSize.cx = newSize.cx;
		pRegion->m_originalMediaSize.cy = newSize.cy;

		if(pRegion->m_rect.right == pRegion->m_rect.left  &&
			//[SMIL 1.0 Compliance] Helps fix PR 16542;
			// only do the following if width="0" or "0%"
			// was not explicitly requested.  The fix for
			// PR 16542 is to treat unspecified dimension values
			// as such and not treat them as 0 (which is a valid
			// value and should not be treated as an unspecified
			// value).
			pRegion->m_bWidthUnspecified)
		{
		    //[SMIL 1.0 compliance] Fixes PR 26038 (horizontal part
		    // of the bug): don't reset the right value to the width
		    // when the right value may include an offset as well.
		    // Set the right value to the new width **plus the left
		    // value**, i.e., no longer assume the left is zero:
		    pRegion->m_rect.right =
			    pRegion->m_rect.left + newSize.cx;
		    pRegion->m_originalRect.right =
			    pRegion->m_rect.left + newSize.cx;
		    lRegionWidth = newSize.cx;
		    //[SMIL 1.0 compliance] more of PR 26038 fix: make sure
		    // to account for left offset in overall layout as well
		    // since the width of the layout includes the offset since
		    // it is a bounding box of all regions:
		    if(m_pDoc->m_ulNoRootLayoutWidth <
			    (UINT32)(pRegion->m_rect.right) )
		    {
			//Only include this region if it is visible:
			if (pRegion->m_rect.right > 0L)
			{
			    m_pDoc->m_ulNoRootLayoutWidth =
				    pRegion->m_rect.right;
			}
		    }
		    //[SMIL 1.0 compliance] Fixes PR 27184:
		    // Always resize region if no size was explicitly
		    // specified for it (not just when the above if () is
		    // entered) otherwise it won't show up:
		    bResizeRegion = TRUE;
		}

		if(pRegion->m_rect.bottom == pRegion->m_rect.top  &&
			//[SMIL 1.0 Compliance] Helps fix PR 16542;
			// only do the following if height="0" or "0%"
			// was not explicitly requested.  The fix for
			// PR 16542 is to treat unspecified dimension values
			// as such and not treat them as 0 (which is a valid
			// value and should not be treated as an unspecified
			// value).
			pRegion->m_bHeightUnspecified)
		{
		    //[SMIL 1.0 compliance] Fixes PR 26038 (vertical part
		    // of the bug): don't reset the bottom value to the
		    // height when the bottom value may include an offset as
		    // well.  Set the bottom value to the new height **plus
		    // the top value**, i.e., no longer assume the top is
		    // zero:
		    pRegion->m_rect.bottom =
			    pRegion->m_rect.top + newSize.cy;
		    pRegion->m_originalRect.bottom =
			    pRegion->m_rect.top + newSize.cy;
		    lRegionHeight = newSize.cy;
		    //[SMIL 1.0 compliance] more of PR 26038 fix: make sure
		    // to account for left offset in overall layout as well
		    // since the width of the layout includes the offset since
		    // it is a bounding box of all regions:
		    if(m_pDoc->m_ulNoRootLayoutHeight <
			    (UINT32)(pRegion->m_rect.bottom) )
		    {
			//Only include this region if it is visible:
			if (pRegion->m_rect.bottom > 0L)
			{
			    m_pDoc->m_ulNoRootLayoutHeight =
				    pRegion->m_rect.bottom;
			}
		    }
		    //[SMIL 1.0 compliance] Fixes PR 27184:
		    // Always resize region if no size was explicitly
		    // specified for it (not just when the above if () is
		    // entered) otherwise it won't show up:
		    bResizeRegion = TRUE;
		}

		pRegion->m_bMediaSizeSet = TRUE;
	    }
	    // check for fit, rescale if necessary
	    if(pRegion->m_fit == "fill")
	    {
		newSize.cx = lRegionWidth;
		newSize.cy = lRegionHeight;
	    }
	    else if(pRegion->m_fit == "meet")
	    {
		// preserve aspect ratio, don't clip
		double dAspectRatio = 0.0;
		if(pRegion->m_originalMediaSize.cy)
		{
		    dAspectRatio = (double)pRegion->m_originalMediaSize.cx /
				    (double)pRegion->m_originalMediaSize.cy;
		}
		// first try to meet region width
		if(dAspectRatio > 0.0)
		{
		    INT32 lTryHeight = (INT32)((double)lRegionWidth / dAspectRatio + 0.5);
		    if(lTryHeight > lRegionHeight)
		    {
			newSize.cx = (INT32)((double)lRegionHeight * dAspectRatio + 0.5);
			newSize.cy = lRegionHeight;
		    }
		    else
		    {
			newSize.cx = lRegionWidth;
			newSize.cy = lTryHeight;
		    }
		}
	    }
	    else if(pRegion->m_fit == "slice")
	    {
		// preserve aspect ratio, OK to clip
		double dAspectRatio = 0.0;
		double dRegionAspectRatio = 0.0;
		if(pRegion->m_originalMediaSize.cy && 
		    pRegion->m_originalMediaSize.cx &&
		    lRegionHeight)
		{
		    dAspectRatio = (double)pRegion->m_originalMediaSize.cx /
				    (double)pRegion->m_originalMediaSize.cy;
		    dRegionAspectRatio = (double)lRegionWidth/(double)lRegionHeight;
		}
		// fit to greater of region height or width
		if(dAspectRatio > 0.0)
		{
		    if(dRegionAspectRatio > dAspectRatio)
		    {
			// the region has a greater aspect ratio than the 
			// media.  Therefore we want to scale the media's
			// height, and set its width = the region's width...
			newSize.cx = lRegionWidth;
			// /First half of Fix for PR 35268: we want to scale
			// the media's height based on the region's width,
			// not on its height:
			newSize.cy = (INT32)((double)lRegionWidth /
			    dAspectRatio + 0.5);
		    }
		    else
		    {
			// set the height = regionHeight && scale the width
			newSize.cy = lRegionHeight;
			// /Other half of Fix for PR 35268: we want to scale
			// the media's width based on the region's height,
			// not on its width:
			newSize.cx = (INT32)((double)lRegionHeight *
			    dAspectRatio + 0.5);
		    }
		}
	    }
	    else if(pRegion->m_fit == "scroll")
	    {
		// keep intrinsic size, draw scroll bars (some day!)
		newSize.cx = (INT32)((double)pRegion->m_originalMediaSize.cx *
		    xScaleFactor + 0.5);
		newSize.cy = (INT32)((double)pRegion->m_originalMediaSize.cy *
		    yScaleFactor + 0.5);

 		IHXValues* pValues = NULL;
 		if ( m_pSite->QueryInterface( IID_IHXValues, (void**) &pValues ) == HXR_OK )
 		{
 		    pValues->SetPropertyULONG32("ScrollingSite", 1);
 		}
	    }
	    else if(pRegion->m_fit == "hidden")
	    {
		// keep intrinsic size
		newSize.cx = (INT32)((double)pRegion->m_originalMediaSize.cx *
		    xScaleFactor + 0.5);
		newSize.cy = (INT32)((double)pRegion->m_originalMediaSize.cy *
		    yScaleFactor + 0.5);
	    }
	    pRegion->m_mediaSize.cx = newSize.cx;
	    pRegion->m_mediaSize.cy = newSize.cy;
	}
	else if(!m_pDoc->m_bSiteChangingSize)
	{
	    newSize.cx = HXxRECT_WIDTH(pRegion->m_rect);
	    newSize.cy = HXxRECT_HEIGHT(pRegion->m_rect);
	}

	if(bResizeRegion)
	{
	    HXxSize size;
	    size.cx = HXxRECT_WIDTH(pRegion->m_rect);
	    size.cy = HXxRECT_HEIGHT(pRegion->m_rect);
	    pRegion->m_pSite->SetSize(size);
            if (!m_pDoc->isRootLayoutWidthSet() ||
                !m_pDoc->isRootLayoutHeightSet())
            {
                m_pDoc->setTopLevelSiteSize();
            }
	}
    }
//    char szDbgStr[128];
//    DEBUGPRINTF(szDbgStr, "\tmedia in region %s: ChangingSize((%ld,%ld),(%ld,%ld))\n",
//                (const char*) m_id,
//                oldSize.cx, oldSize.cy, newSize.cx, newSize.cy);
    return HXR_OK;
}

/*
 * CSmil1EventHook methods
 */

CSmil1EventHook::CSmil1EventHook(CSmil1DocumentRenderer* pDoc,
			       const char* pRegionName,
			       const char* pChannelName,
			       BOOL bNoRegion):
    m_lRefCount(0),
    m_pDoc(pDoc),
    m_pRegionName(NULL),
    m_pChannelName(NULL),
    m_bNoRegion(bNoRegion),
    m_pSite(NULL),
    m_pSiteWatcher(NULL)
{
#if defined(_DEBUG) && defined(XXXMEH_CHECK_FOR_LEAKS)
    char szDbgStr[128]; /* Flawfinder: ignore */
    sprintf(szDbgStr, "CON CSmil1EventHook 0x%08x\n", this); /* Flawfinder: ignore */
    OutputDebugString(szDbgStr);
#endif
    HX_ASSERT(m_pDoc);
    HX_ASSERT(pRegionName);
    HX_ASSERT(pChannelName);

    m_pDoc->AddRef();
    m_pRegionName = new_string(pRegionName);
    m_pChannelName = new_string(pChannelName);
}

CSmil1EventHook::~CSmil1EventHook()
{
#if defined(_DEBUG) && defined(XXXMEH_CHECK_FOR_LEAKS)
    char szDbgStr[128]; /* Flawfinder: ignore */
    sprintf(szDbgStr, "DES CSmil1EventHook 0x%08x\n", this); /* Flawfinder: ignore */
    OutputDebugString(szDbgStr);
#endif
    m_pDoc->Release();
    delete[] m_pRegionName;
    delete[] m_pChannelName;
}

/*
 * IUnknown methods
 */
STDMETHODIMP
CSmil1EventHook::QueryInterface(REFIID riid, void** ppvObj)
{
    if(IsEqualIID(riid, IID_IUnknown))
    {
	AddRef();
	*ppvObj = this;
	return HXR_OK;
    }
    else if(IsEqualIID(riid, IID_IHXEventHook))
    {
	AddRef();
	*ppvObj = (IHXEventHook*)this;
	return HXR_OK;
    }
    *ppvObj = NULL;
    return HXR_NOINTERFACE;
}

STDMETHODIMP_(ULONG32)
CSmil1EventHook::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

STDMETHODIMP_(ULONG32)
CSmil1EventHook::Release()
{
    if(InterlockedDecrement(&m_lRefCount) > 0)
    {
	return m_lRefCount;
    }

    delete this;
    return 0;
}

STDMETHODIMP
CSmil1EventHook::HandleEvent(IHXSite* pSite, HXxEvent* pEvent)
{
    HX_RESULT rc = HXR_OK;

    if(m_pSite == pSite)
    {
	switch(pEvent->event)
	{
	    case HX_MOUSE_MOVE:
	    case HX_MOUSE_ENTER:
	    case HX_MOUSE_LEAVE:
	    {
		HXxPoint* mousePt = (HXxPoint*) pEvent->param1;
		if(HXR_OK == m_pDoc->handleMouseMove(
			    pEvent->window,
			    m_pRegionName,
			    (INT16)mousePt->x,
			    (INT16)mousePt->y))
		{
		    pEvent->handled = TRUE;
		}
	    }
	    break;

	    case HX_PRIMARY_BUTTON_UP:
	    {
		HXxPoint* mousePt = (HXxPoint*) pEvent->param1;
		if(HXR_OK == m_pDoc->handleLButtonUp(
				m_pRegionName,
				(INT16)mousePt->x,
				(INT16)mousePt->y))
		{
		    pEvent->handled = TRUE;
		}
	    }
	    break;

#ifdef _WINDOWS
	    case WM_SETCURSOR:
	    {
		pEvent->handled = m_pDoc->handleSetCursor();
	    }
	    break;
#endif  
	    default:
		break;
	}
    }

    return rc;
}

STDMETHODIMP
CSmil1EventHook::SiteAdded(IHXSite* pSite)
{
    HX_RESULT rc = HXR_OK;

    HX_ASSERT(pSite);
    m_pSite = pSite;
    m_pSite->AddRef();

    // add a passive site watcher to get
    // size and position updates
    m_pSiteWatcher =
	new CSmil1PassiveSiteWatcher(m_pDoc, m_pRegionName);
    m_pSiteWatcher->AddRef();
    
    IHXSite2* pSite2 = NULL;
    if(HXR_OK == m_pSite->QueryInterface(IID_IHXSite2, (void**)&pSite2))
    {
	pSite2->AddPassiveSiteWatcher(m_pSiteWatcher);
	pSite2->Release();
    }

    if(m_bNoRegion)
    {
	m_pDoc->addShowEvents(m_pRegionName, m_pSite);
    }

    return rc;
}

STDMETHODIMP
CSmil1EventHook::SiteRemoved(IHXSite* pSite)
{
    HX_RESULT rc = HXR_OK;

    HX_ASSERT(m_pSite == pSite);

    IHXSite2* pSite2 = NULL;
    if(m_pSite &&
	HXR_OK == m_pSite->QueryInterface(IID_IHXSite2, (void**)&pSite2))
    {
	pSite2->RemovePassiveSiteWatcher(m_pSiteWatcher);
	pSite2->Release();
    }

    HX_RELEASE(m_pSite);
    HX_RELEASE(m_pSiteWatcher);

    return rc;
}

/*
 * CSmil1PassiveSiteWatcher methods
 */

CSmil1PassiveSiteWatcher::CSmil1PassiveSiteWatcher(CSmil1DocumentRenderer* pDoc,
						 const char* pRegionName):
    m_lRefCount(0),
    m_pDoc(pDoc),
    m_pRegionName(NULL)
{
#if defined(_DEBUG) && defined(XXXMEH_CHECK_FOR_LEAKS)
    char szDbgStr[128]; /* Flawfinder: ignore */
    sprintf(szDbgStr, "CON CSmil1EventHook 0x%08x\n", this); /* Flawfinder: ignore */
    OutputDebugString(szDbgStr);
#endif
    HX_ASSERT(m_pDoc);
    HX_ASSERT(pRegionName);
    m_pDoc->AddRef();
    m_pRegionName = new_string(pRegionName); 
}

CSmil1PassiveSiteWatcher::~CSmil1PassiveSiteWatcher()
{
#if defined(_DEBUG) && defined(XXXMEH_CHECK_FOR_LEAKS)
    char szDbgStr[128]; /* Flawfinder: ignore */
    sprintf(szDbgStr, "DES CSmil1EventHook 0x%08x\n", this); /* Flawfinder: ignore */
    OutputDebugString(szDbgStr);
#endif
    HX_RELEASE(m_pDoc);
    delete[] m_pRegionName;
}


/*
 * IUnknown methods
 */
STDMETHODIMP
CSmil1PassiveSiteWatcher::QueryInterface(REFIID riid, void** ppvObj)
{
    if(IsEqualIID(riid, IID_IUnknown))
    {
	AddRef();
	*ppvObj = this;
	return HXR_OK;
    }
    else if(IsEqualIID(riid, IID_IHXPassiveSiteWatcher))
    {
	AddRef();
	*ppvObj = (IHXSiteWatcher*)this;
	return HXR_OK;
    }
    *ppvObj = NULL;
    return HXR_NOINTERFACE;
}

STDMETHODIMP_(ULONG32)
CSmil1PassiveSiteWatcher::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

STDMETHODIMP_(ULONG32)
CSmil1PassiveSiteWatcher::Release()
{
    if(InterlockedDecrement(&m_lRefCount) > 0)
    {
	return m_lRefCount;
    }

    delete this;
    return 0;
}


STDMETHODIMP
CSmil1PassiveSiteWatcher::PositionChanged(HXxPoint* pPoint)
{
    // The passive watcher is only attached to renderer
    // sites, therefore we really don't want to resize
    // the region, the regions are scaled and sized 
    // already.
    //m_pDoc->repositionRegion(m_pRegionName, pPoint);
    return HXR_OK;
}

STDMETHODIMP
CSmil1PassiveSiteWatcher::SizeChanged(HXxSize* pSize)
{
    // The passive watcher is only attached to renderer
    // sites, therefore we really don't want to resize
    // the region, the regions are scaled and sized 
    // already.
    //m_pDoc->resizeRegion(m_pRegionName, pSize);
    return HXR_OK;
}

/*
 * CSmil1SiteUser methods
 */

CSmil1SiteUser::CSmil1SiteUser(CSmil1DocumentRenderer* pDoc,
			     HXxColor ulBGColor):
    m_lRefCount(0),
    m_pDoc(pDoc),
    m_ulBGColor(ulBGColor),
    m_pSite(NULL)
{
#if defined(_DEBUG) && defined(XXXMEH_CHECK_FOR_LEAKS)
    char szDbgStr[128]; /* Flawfinder: ignore */
    sprintf(szDbgStr, "CON CSmil1SiteUser 0x%08x\n", this); /* Flawfinder: ignore */
    OutputDebugString(szDbgStr);
#endif
    HX_ASSERT(m_pDoc);
    m_pDoc->AddRef();
}

CSmil1SiteUser::~CSmil1SiteUser()
{
#if defined(_DEBUG) && defined(XXXMEH_CHECK_FOR_LEAKS)
    char szDbgStr[128]; /* Flawfinder: ignore */
    sprintf(szDbgStr, "DES CSmil1SiteUser 0x%08x\n", this); /* Flawfinder: ignore */
    OutputDebugString(szDbgStr);
#endif
    HX_RELEASE(m_pSite);
    HX_RELEASE(m_pDoc);
}


/*
 * IUnknown methods
 */
STDMETHODIMP
CSmil1SiteUser::QueryInterface(REFIID riid, void** ppvObj)
{
    if(IsEqualIID(riid, IID_IUnknown))
    {
	AddRef();
	*ppvObj = this;
	return HXR_OK;
    }
    else if(IsEqualIID(riid, IID_IHXSiteUser))
    {
	AddRef();
	*ppvObj = (IHXSiteUser*)this;
	return HXR_OK;
    }
    *ppvObj = NULL;
    return HXR_NOINTERFACE;
}

STDMETHODIMP_(ULONG32)
CSmil1SiteUser::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

STDMETHODIMP_(ULONG32)
CSmil1SiteUser::Release()
{
    if(InterlockedDecrement(&m_lRefCount) > 0)
    {
	return m_lRefCount;
    }

    delete this;
    return 0;
}

/*
 * IHXSiteUser methods
 */

STDMETHODIMP
CSmil1SiteUser::AttachSite(IHXSite* /*IN*/ pSite)
{
    HX_RESULT rc = HXR_OK;

    if (m_pSite)
    {
	return rc;
    }
    m_pSite = pSite;
    m_pSite->AddRef();

    return rc;
}

STDMETHODIMP
CSmil1SiteUser::DetachSite()
{
    HX_RELEASE(m_pSite);
    return HXR_OK;
}

STDMETHODIMP_(BOOL)
CSmil1SiteUser::NeedsWindowedSites()
{
    return FALSE;
}

STDMETHODIMP
CSmil1SiteUser::HandleEvent(HXxEvent* /*IN*/ pEvent)
{
    HX_RESULT rc = HXR_OK;
    pEvent->handled = FALSE;
    pEvent->result  = 0;

    switch (pEvent->event)
    {
	case HX_SURFACE_UPDATE:
	{
	    if(HXR_OK ==
		m_pDoc->HandleSurfaceUpdate(pEvent, m_pSite, m_ulBGColor))
	    {
		pEvent->handled = TRUE;
	    }
	}
	break;
    }
    return HXR_OK;
}


/*
 * CSmil1BasicRegion methods
 */
CSmil1BasicRegion::CSmil1BasicRegion(const char* pName,
    HXxRect rect, INT32 lZIndex, const char* pFit,
    HXxColor ulBgColor, BOOL bBgColorSet, BOOL bImplicitRegion,
    //[SMIL 1.0 Compliance] Helps fix PR 16542:
    BOOL bWidthUnspecified, BOOL bHeightUnspecified):
    m_region(pName),
    m_rect(rect),
    m_originalRect(rect),
    m_pSite(NULL),
    m_pSiteUser(NULL),
    m_lZIndex(lZIndex),
    m_fit(pFit),
    m_ulBgColor(ulBgColor),
    m_bBgColorSet(bBgColorSet),
    m_bMediaSizeSet(FALSE),
    m_bImplicitRegion(bImplicitRegion)
    //[SMIL 1.0 Compliance] These helps fix PR 16542:
    , m_bWidthUnspecified(bWidthUnspecified)
    , m_bHeightUnspecified(bHeightUnspecified)
{
#if defined(_DEBUG) && defined(XXXMEH_CHECK_FOR_LEAKS)
    char szDbgStr[128]; /* Flawfinder: ignore */
    sprintf(szDbgStr, "CON CSmil1BasicRegion 0x%08x\n", this); /* Flawfinder: ignore */
    OutputDebugString(szDbgStr);
#endif
}

CSmil1BasicRegion::~CSmil1BasicRegion()
{
#if defined(_DEBUG) && defined(XXXMEH_CHECK_FOR_LEAKS)
    char szDbgStr[128]; /* Flawfinder: ignore */
    sprintf(szDbgStr, "DES CSmil1BasicRegion 0x%08x\n", this); /* Flawfinder: ignore */
    OutputDebugString(szDbgStr);
#endif
    if(m_pSite)
    {
	m_pSite->DetachUser();
    }
    HX_RELEASE(m_pSiteUser);
    HX_RELEASE(m_pSite);
}

// ProcessElementCallback
ProcessElementCallback::ProcessElementCallback() :
     m_lRefCount(0)
    ,m_pOwner(0)
    ,m_PendingHandle(0)
    ,m_bIsCallbackPending(FALSE)
{
}

ProcessElementCallback::~ProcessElementCallback()
{
}

/*
 * IUnknown methods
 */

/////////////////////////////////////////////////////////////////////////
//      Method:
//              IUnknown::QueryInterface
//      Purpose:
//              Implement this to export the interfaces supported by your
//              object.
//
STDMETHODIMP ProcessElementCallback::QueryInterface(REFIID riid, void** ppvObj)
{
    if (IsEqualIID(riid, IID_IHXCallback))
    {
	AddRef();
	*ppvObj = (IHXCallback*)this;
	return HXR_OK;
    }
    else if (IsEqualIID(riid, IID_IUnknown))
    {
	AddRef();
	*ppvObj = this;
	return HXR_OK;
    }

    *ppvObj = NULL;
    return HXR_NOINTERFACE;
}

/////////////////////////////////////////////////////////////////////////
//      Method:
//              IUnknown::AddRef
//      Purpose:
//              Everyone usually implements this the same... feel free to use
//              this implementation.
//
STDMETHODIMP_(ULONG32) ProcessElementCallback::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

/////////////////////////////////////////////////////////////////////////
//      Method:
//              IUnknown::Release
//      Purpose:
//              Everyone usually implements this the same... feel free to use
//              this implementation.
//
STDMETHODIMP_(ULONG32) ProcessElementCallback::Release()
{
    if (InterlockedDecrement(&m_lRefCount) > 0)
    {
	return m_lRefCount;
    }

    delete this;
    return 0;
}


/*
 *      IHXCallback methods
 */
STDMETHODIMP ProcessElementCallback::Func(void)
{
    m_PendingHandle = 0;
    m_bIsCallbackPending = FALSE;

    if (m_pOwner && !m_elementID.IsEmpty())
    {
	m_pOwner->seekTo(m_elementID);
    }
    m_elementID.Empty();

    return HXR_OK;
}
