Logo Search packages:      
Sourcecode: helix-player version File versions

sm1doc.cpp

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

Generated by  Doxygen 1.6.0   Back to index