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

smltime.cpp

/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: smltime.cpp,v 1.3.4.2 2004/07/13 23:02:47 ehodge 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 ***** */

// system
#include <time.h>
// include
#include "hxtypes.h"
#include "hxwintyp.h"
#include "hxcom.h"
#include "hxxml.h"
#include "smiltype.h"
// pncont
#include "hxslist.h"
#include "hxmap.h"
// pnmisc
#include "hxwinver.h"
// rnxmllib
#include "hxxmlprs.h"
// rmasmil
#include "smlelem.h"
#include "smlparse.h"
#include "smltime.h"
#include "smlprstime.h"
// pndebug
#include "debugout.h"
#include "hxassert.h"
#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE           
static const char HX_THIS_FILE[] = __FILE__;
#endif

// /#define XXXEH_DEBUGOUT_ADDDURATION
#if defined(XXXEH_DEBUGOUT_ADDDURATION)
#define ADDDURATION_DEBUGOUT_STR_NEW_FILE   "w"
#define ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE   "a+"
static BOOL bFirstTimeAddDurDebugout = TRUE;
#endif

/*
 * CSmilTimelineElementManager methods
 */

CSmilTimelineElementManager::CSmilTimelineElementManager():
    m_pElementMap(NULL),
    m_pNotifierMap(NULL)
{
}

CSmilTimelineElementManager::~CSmilTimelineElementManager()
{
    HX_DELETE(m_pElementMap);
    if(m_pNotifierMap)
    {
      CHXMapStringToOb::Iterator i = m_pNotifierMap->Begin();
      for(; i != m_pNotifierMap->End(); ++i)
      {
          CHXSimpleList* pList = (CHXSimpleList*)(*i);
          delete pList;
      }
      HX_DELETE(m_pNotifierMap);
    }
}

void
CSmilTimelineElementManager::addTimelineElement(CSmilTimelineElement* pElement)
{
    if(!m_pElementMap)
    {
      m_pElementMap = new CHXMapStringToOb;
    }
    (*m_pElementMap)[pElement->m_pID] = pElement;
}

CSmilTimelineElement*
CSmilTimelineElementManager::getTimelineElement(const char* pID)
{
    CSmilTimelineElement* pElement = NULL;
    if(m_pElementMap)
    {
      m_pElementMap->Lookup(pID, (void*&)pElement);
    }
    return pElement;
}

void
CSmilTimelineElementManager::addNotification(const char* pID,
                                   CSmilTimelineElement* pElement)
{
    if(!m_pNotifierMap)
    {
      m_pNotifierMap = new CHXMapStringToOb;
    }

    CHXSimpleList* pNotifyList = NULL;
    if(!m_pNotifierMap->Lookup(pID, (void*&)pNotifyList))
    {
      pNotifyList = new CHXSimpleList;
      (*m_pNotifierMap)[pID] = pNotifyList;
    }
    pNotifyList->AddTail(pElement);
}

void
CSmilTimelineElementManager::notify(const char* pID)
{
    CHXSimpleList* pNotifyList = NULL;
    if(m_pNotifierMap)
    {
      if(m_pNotifierMap->Lookup(pID, (void*&)pNotifyList))
      {
          CSmilTimelineElement* pDependentElement = NULL;
          if(m_pElementMap->Lookup(pID, (void*&)pDependentElement))
          {
            CHXSimpleList::Iterator i = pNotifyList->Begin();
            for(; i != pNotifyList->End(); ++i)
            {
                CSmilTimelineElement* pElement = 
                  (CSmilTimelineElement*)(*i);
                pElement->elementResolved(pDependentElement);
            }
          }
      }
    }
}

void
CSmilTimelineElementManager::resetTimeline()
{
    if(m_pElementMap)
    {
      CHXMapStringToOb::Iterator i = m_pElementMap->Begin();
      for(; i != m_pElementMap->End(); ++i)
      {
          CSmilTimelineElement* pElement = 
            (CSmilTimelineElement*)(*i);
          pElement->reset();
      }
    }
}     
/*
 * CSmilTimelineElement methods
 */

CSmilTimelineElement::CSmilTimelineElement(CSmilElement* pSourceElement,
                                 CSmilParser* pParser):
    m_pSourceElement(pSourceElement),
    m_pParser(pParser),
    m_bDurationSet(FALSE),
    m_bMaxDurationSet(FALSE),
    m_bDelaySet(FALSE),
    m_bDontResetDuration(FALSE),
    m_bNonEventDelaySet(FALSE),
    m_ulNonEventDelay((UINT32)-1),
    m_bDelayEvent(FALSE),
    m_bDurationEvent(FALSE),
    m_pChildDurAddedMap(NULL),
    m_bHasChildWithScheduledBegin(FALSE),
    m_bInElementResolved(FALSE),
    m_pParent(NULL),
    m_pChildren(NULL),
    m_pDependent(NULL)
{
    m_pID = new char[pSourceElement->m_pNode->m_id.GetLength() + 1];
    strcpy(m_pID, (const char*)m_pSourceElement->m_pNode->m_id); /* Flawfinder: ignore */

    //[SMIL 1.0 Compliance] Helps fix PR 26471:
    // /XXXEH- TODO: this is probably one of the places where
    // endsync="media" is handled.  We probably don't want to do the
    // following if() statement if endsync is NOT media on the parent
    // of an anchor|area element:
    if (SMILAnchor != m_pSourceElement->m_pNode->m_tag  &&
          SMILArea != m_pSourceElement->m_pNode->m_tag)
    {
      m_pParser->m_pTimelineElementManager->addTimelineElement(this);
    }

    if(pSourceElement->m_nBeginEventSourceTag == SMILEventSourceBegin ||
      pSourceElement->m_nBeginEventSourceTag == SMILEventSourceEnd ||
      pSourceElement->m_nBeginEventSourceTag == SMILEventSourceClock)
    {
      m_pParser->m_pTimelineElementManager->addNotification(pSourceElement->m_BeginEventSourceID,
          this);
      // /If we've already got a resolved begin, then we don't want to claim
      // that we're awaiting this sync-arc begin (as can happen if
      // begin="0s; x.begin+4s")
      if (!pSourceElement->m_bBeginOffsetSet)
      {
          m_bDelayEvent = TRUE;
      }
    }

    if(pSourceElement->m_nEndEventSourceTag == SMILEventSourceBegin ||
      pSourceElement->m_nEndEventSourceTag == SMILEventSourceEnd ||
      pSourceElement->m_nEndEventSourceTag == SMILEventSourceClock)
    {
      m_pParser->m_pTimelineElementManager->addNotification(pSourceElement->m_EndEventSourceID,
          this);
      // /If we've already got a resolved end, then we don't want to claim
      // that we're awaiting this sync-arc end (as can happen if
      // end="10s; x.begin+14s")
      if (!pSourceElement->m_bEndOffsetSet)
      {
          m_bDurationEvent = TRUE;
      }
    }

    if(pSourceElement->m_nEndsyncEventSourceTag == SMILEventSourceID)
    {
      m_pParser->m_pTimelineElementManager->addNotification(pSourceElement->m_EndsyncEventSourceID,
          this);
      m_bDurationEvent = TRUE;
    }

    m_pChildDurAddedMap = new CHXMapStringToOb();

    // /XXXEH- TODO: make sure this is what we want to do:
    // /Get next resolved time, if any.  If none are found in a non-empty
    // begin-time list, then treat this as a delayed event:
    if (NULL != pSourceElement->m_pBeginTimeList  &&
          !pSourceElement->m_pBeginTimeList->IsEmpty())
    {
      SmilTimeValue* pNextResolvedTimeValue = NULL;

      HX_RESULT rettimeval = HXR_OK;
      rettimeval = pSourceElement->getNextResolvedTimeValue(
            pNextResolvedTimeValue,
            // /XXXEH- TODO: make sure we don't want to input cur time here;
            // is it possible that we'd get here after time 0 in the parent
            // timeline???  I don't think so...:
            SMILTIME_NEGATIVE_INFINITY,
            SMILTIME_NEGATIVE_INFINITY,
            SmilBeginTimeList,
            /* Don't need list of resolved times:*/ NULL);
      if (!SUCCEEDED(rettimeval)  ||  NULL == pNextResolvedTimeValue)
      {
          // /Has no resolved time yet so must be awaiting an event:
          m_bDelayEvent = TRUE;
      }
    }
}

CSmilTimelineElement::~CSmilTimelineElement()
{
    delete m_pChildren;
    delete[] m_pID;
    HX_DELETE(m_pChildDurAddedMap);
}

void
CSmilTimelineElement::reset()
{
    m_bDelaySet = FALSE;
    m_bNonEventDelaySet = FALSE;
    m_ulNonEventDelay = (UINT32)-1;
    m_bDurationSet = FALSE;
    m_bMaxDurationSet = FALSE;
    // /XXXEH- do we really want to do this? Find a way to test this:
#if defined(XXXEH_NEEDS_TESTING)
    HX_DELETE(m_pChildDurAddedMap); // /start fresh
#endif
}

void
CSmilTimelineElement::prepForRestart()
{
    m_bDelaySet = FALSE;
    m_bNonEventDelaySet = FALSE;
    m_ulNonEventDelay = (UINT32)-1;

#if XXXEH_OLD_WAY_THAT_DIDNT_LET_SETDURATION_TAKE_CARE_OF_NEW_DUR
    if (((UINT32)-1) != m_pSourceElement->m_ulOriginalDuration)
    {
      resetDuration(m_pSourceElement->m_ulOriginalDuration);
    }
    // /Note: leave m_bDurationSet & m_bMaxDurationSet alone for restart
#else
    //...But if we're restarting, our duration may be different and this
    // gets handled in CSmilTimelineElement::setDuration():
    m_bDurationSet = FALSE;
    // /Fixes PR 54704: if we don't reset this in concert with resetting
    // m_bDurationSet, above, then ancestorEventsAreResolved() will fail
    // when a re-insertTimelineElement() call on this occurs:
    m_bDurationEvent = FALSE;
#endif

}


void 
CSmilTimelineElement::setDelay(UINT32 ulDelay, BOOL bSetByParent)
{
    ULONG32 ulPreviouslySetDelay = m_pSourceElement->m_ulDelay;
    ULONG32 ulPreviouslySetPureDuration = m_pSourceElement->getPureDuration();

#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION)
    {
      FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout?
            ADDDURATION_DEBUGOUT_STR_NEW_FILE :
            ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE );
      ::fprintf(f1, "CSmilTimelineElement{%s}::setDelay(delay=%lu, "
            "bSetByParent=%sE), prior delay=%lu, m_bDelaySet=%sE\n",
            (const char*)m_pID, ulDelay,
            bSetByParent?"TRU":"FALS",
            ulPreviouslySetDelay,
            m_bDelaySet?"TRU":"FALS");
      ::fclose(f1);
      bFirstTimeAddDurDebugout = FALSE;
    }
#endif

    if(!m_bDelaySet)
    {
      // /For PR 59584: if we're just resolving this to let the
      // group duration "resolve" to unresolved, don't count begin:
      if(WAY_IN_THE_FUTURE <= ulDelay)
      {
          HX_ASSERT(WAY_IN_THE_FUTURE >= ulDelay);
      }
      else if(!m_bDelayEvent)
      {
          BOOL bDelayClippedDueToNegOffset = FALSE;
          if(m_pSourceElement->m_bBeginOffsetSet)
          {
            m_pSourceElement->m_ulDelay = ulDelay;

            // /Handle all cases so that we don't overflow:
            UINT32 ulPosOffset = m_pSourceElement->m_lBeginOffset > 0?
                  m_pSourceElement->m_lBeginOffset : 0;
            UINT32 ulNegOffset = m_pSourceElement->m_lBeginOffset < 0?
                  (UINT32)(-m_pSourceElement->m_lBeginOffset) : 0;
            UINT32 ulClippedAmt = 0;

            if (ulNegOffset > 0)
            {
                m_pSourceElement->m_bNegBeginOffsetAlreadyUsed =
                      TRUE;
            }

            m_pSourceElement->m_ulDelay += ulPosOffset;
            if (m_pSourceElement->m_ulDelay >= ulNegOffset)
            {
                m_pSourceElement->m_ulDelay -= ulNegOffset;
            }
            else
            {
                // /If set by parent, then we want to use the entire
                // negative offset FROM OUR PARENT's BEGIN which already
                // has the delay in it, so <par begin="2s"><ref begin=
                // "-3s" ...> would begin the ref at 2s w/3s clip-begin:
                ulClippedAmt = bSetByParent? ulNegOffset : ulNegOffset -
                      m_pSourceElement->m_ulDelay;
                // /If clip-begin is invalid, set it otherwise add to it:
                m_pSourceElement->m_ulClipBegin = ((UINT32)-1 ==
                      m_pSourceElement->m_ulAuthoredClipBegin?
                      ulClippedAmt : ulClippedAmt +
                      m_pSourceElement->m_ulAuthoredClipBegin);
                if ((UINT32)-1 != m_pSourceElement->m_ulDuration)
                {
                  if (m_pSourceElement->m_ulDuration > ulClippedAmt)
                  {
                      m_pSourceElement->m_ulDuration -= ulClippedAmt;
                  }
                  // /else duration is negative; it can't ever play.
                  else
                  {
                      m_pSourceElement->m_ulDuration = 0;
                  }
                }
            }
          }
          // /Fixes most of PR64499: when restarting the parent of a
          // long-sync-arc-begun element, the begin should still be based on
          // the long sync-arc's global time:
          else if ((UINT32)-1 != m_pSourceElement->m_ulLongSyncArcBeginInGroupTime
                &&  m_pSourceElement->m_bIsRestarting)
          {
            SMILNode* pSyncNode = !m_pParser? NULL :
                   m_pParser->getSyncAncestor(m_pSourceElement->m_pNode);
            HX_ASSERT(pSyncNode  &&  pSyncNode->m_pElement);
            if (pSyncNode  &&  pSyncNode->m_pElement->m_bIsRestarting)
            {           
                m_pSourceElement->m_ulDelay =
                      m_pSourceElement->m_ulLongSyncArcBeginInGroupTime;
            }
          }
          // /Else we've established that the beginOffset is not set, so
          // just use the delay:
          else
          {
            m_pSourceElement->m_ulDelay = ulDelay;

            // /Fixes PR 71386 and PR 77406: event-based begins with sync-
            // arc ends (that are already resolved, here) should not
            // include the delay twice; use the *end* not the *duration*:
            if (m_pSourceElement->m_bEndOffsetSet  &&
                  // /Fixes PR 8XYXZ (broken by original PR 71386 fix);
                  // If being set by parent, we don't need to do anything
                  // because delay is parent delay, not explicitly-set
                  // begin val:
                  !bSetByParent)
            {
                // /If dur was explicitly authored along with end, use the
                // min(end, dur+delay):
                if (WAY_IN_THE_FUTURE ==
                      m_pSourceElement->m_ulAuthoredDur  ||
                      (UINT32)-1 == m_pSourceElement->m_ulAuthoredDur  ||
                      // /Fixes PR 71386 Part 3 = version where element
                      // has end="x.end" AND has dur="z"; if z+delay >
                      // x.end, ignore dur:
                      (m_pSourceElement->m_ulAuthoredDur +
                      m_pSourceElement->m_ulDelay >
                      m_pSourceElement->m_lEndOffset))
                {
                  if (m_pSourceElement->m_lEndOffset > 0  &&
                        (ULONG32)m_pSourceElement->m_lEndOffset >=
                        m_pSourceElement->m_ulDelay)
                  {
                      m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase =
                            FALSE;
                      m_pSourceElement->m_ulDuration =
                            m_pSourceElement->m_lEndOffset -
                            m_pSourceElement->m_ulDelay;
                  }
                  else
                  {
                      HX_ASSERT(0  &&  "pleaseContact_ehodge!");
                      m_pSourceElement->m_ulDuration = 0;
                  }
                }
            }
          }
          m_bDelaySet = TRUE;
          if (HXR_OK == m_pParser->adjustForNegativeOffset(m_pID))
          {
            m_pParser->insertTimelineElement(m_pID, 
                m_pSourceElement->m_ulDelay);
          }
            // XXXMEH - animation can be children of media elements, so when
            // a media element gets its delay set, then we need to
            // set the delay of any children
          if(m_pChildren)
          {
                LISTPOSITION pos = m_pChildren->GetHeadPosition();
                while (pos)
                {
                    CSmilTimelineElement* pChildElement =
                        (CSmilTimelineElement*) m_pChildren->GetNext(pos);
                    if (pChildElement)
                    {
                        pChildElement->setDelay(m_pSourceElement->m_ulDelay, TRUE);
                    }

                }
          }
      }
    }
    else
    {
      HX_ASSERT(WAY_IN_THE_FUTURE > ulDelay); // /PR 59584-related check.

      if(m_pSourceElement->m_bBeginOffsetSet)
      {
          m_pSourceElement->m_ulDelay = (
            ((INT32)ulDelay+m_pSourceElement->m_lBeginOffset > 0) ?
            (UINT32)((INT32)ulDelay+m_pSourceElement->m_lBeginOffset):0);
      }
      else
      {
          // /There are two cases where we might arrive here with
          // ulDelay not equalling ulPreviouslySetDelay; one is when the
          // original delay is based on a sync-arc to an element that never
          // gets added to the timeline, and the other is when the original
          // delay is based on a long sync-arc.  The following allows both
          // to work; we don't want to use the new delay if the orig one
          // was greater than the new one, otherwise we'll play it too soon
          // and that happens in SMIL2 Timing interop case 1.15:
          if (!bSetByParent  ||  ulDelay > ulPreviouslySetDelay)
          {
            m_pSourceElement->m_ulDelay = ulDelay;
          }
      }

      // /If we've got a long sync-arc begin delay that is earlier (and
      // also resolved earlier) than our parent's begin delay, then we want
      // to do a clip-begin of the difference, e.g,:
      //   <par begin="3s">
      //     <video begin="someElementBeginningAtTimeZero.begin" .../> ...
      // so the video element should begin at 3s and clip the 1st 3s of it.
      if (bSetByParent  &&
            ulPreviouslySetDelay < m_pSourceElement->m_ulDelay)
      {
          LONG32 lDiff = m_pSourceElement->m_ulDelay -ulPreviouslySetDelay;
          HX_ASSERT(lDiff >= 0);
          ULONG32 ulDiff = (ULONG32)lDiff;
          // /If clip-begin is invalid, set it otherwise add to it:
          m_pSourceElement->m_ulClipBegin = ((UINT32)-1 ==
                m_pSourceElement->m_ulAuthoredClipBegin?
                ulDiff : ulDiff+m_pSourceElement->m_ulAuthoredClipBegin);
          if ((UINT32)-1 != m_pSourceElement->m_ulDuration)
          {
            if (m_pSourceElement->m_ulDuration > ulDiff)
            {
                m_pSourceElement->m_ulDuration -= ulDiff;
            }
            else
            {
                m_pSourceElement->m_ulDuration = 0;
            }

            if (m_pSourceElement->m_pNode)
            {
                m_pParser->resetTimelineElementDuration(
                      (const char*)m_pSourceElement->m_pNode->m_id,
                      m_pSourceElement->getPureDuration(),
                      ulPreviouslySetPureDuration);
                m_pParser->m_pTimelineElementManager->notify(
                      (const char*)m_pSourceElement->m_pNode->m_id);
            }
          }
      }
      // /More for PR 50411: if it wasn't inserted yet, do so:
      // /(Also helps fix other long-sync-arc bugs like PR 64498 & PR 64499):
      if (m_pSourceElement->m_bAwaitingSyncAncestorBeginNotification)
      {
          HX_ASSERT(!m_pSourceElement->m_bInsertedIntoTimeline);
          m_pParser->insertTimelineElement(m_pID,
                m_pSourceElement->m_ulDelay);
          m_pSourceElement->m_bAwaitingSyncAncestorBeginNotification =
                FALSE;
      }
    }

    // /This helps fix PR 50588 (and other sync-arc-to-x's-begin-where-x-has-
    // resolved-delay-but-not-resolved-duration bugs); notify sync-arc
    // dependents if our delay (or duration) was set or changed:
    if (ulPreviouslySetDelay != m_pSourceElement->m_ulDelay  ||
          ulPreviouslySetPureDuration != m_pSourceElement->getPureDuration())
    {
      m_pParser->m_pTimelineElementManager->notify(m_pID);
    }
}

void 
CSmilTimelineElement::setDuration(UINT32 ulDuration, BOOL bSetFromParent,
                          BOOL bDurationExtendingDueToPause)
{
#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION)
    {
      FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout?
            ADDDURATION_DEBUGOUT_STR_NEW_FILE :
            ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE );
      ::fprintf(f1, "CSmilTimelineElement{%s}::setDuration(ulDuration=%lu, "
            "bSetFromParent=%sE) m_pSourceElement->m_ulDelay=%lu, m_bDelaySet=%s\n",
            (const char*)m_pID, ulDuration,
            bSetFromParent?"TRU":"FALS", m_pSourceElement->m_ulDelay,
            m_bDelaySet?"TRUE":"FALSE-#############!!! DUDE!");
      ::fclose(f1);
      bFirstTimeAddDurDebugout = FALSE;
    }
#endif

    BOOL bTrackStartsTooLateSoTrackRemoved = FALSE;

    ULONG32 ulPriorPureDuration = m_pSourceElement->getPureDuration();

    if(bSetFromParent)
    {
      BOOL bOKToOverrideDuration = FALSE;
      if ((UINT32)-1 == m_pSourceElement->m_ulAuthoredDur)
      {
          if (!m_pSourceElement->m_bHasExplicitEnd  ||  !m_bDurationSet)
          {
            bOKToOverrideDuration = TRUE;
          }
      }
      else if (m_pSourceElement->m_ulAuthoredDur == WAY_IN_THE_FUTURE  &&
            m_pSourceElement->m_bHasExplicitEnd  &&  m_bDurationSet  &&
            // /Fixes PR 50676 part 5: if m_bDurationSet but duration was
            // not set to anything but unresolved, then we do want to
            // override the unresolved value; this continues to let the
            // fix work from 5/9/2001's addition of this else-if:
            m_pSourceElement->m_ulDuration != WAY_IN_THE_FUTURE)
      {
          bOKToOverrideDuration = FALSE;
      }
      else if (m_pSourceElement->m_ulAuthoredDur >= ulDuration  &&
          ((UINT32)-1 == m_pSourceElement->m_ulMaxActiveDur  ||
          m_pSourceElement->m_ulMaxActiveDur >= ulDuration) )
      {
          // /XXXEH- I need to find content that has this feature;
          // I'm pretty sure I want to add m_ulBeginOffsetFromSyncBase to
          // m_ulAuthoredDur when comparing with ulDuration, above, since
          // ulDuration is in syncbase time coordinate system:
          HX_ASSERT((!m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase  ||
                (m_pSourceElement->m_ulBeginOffsetFromSyncBase +
                m_pSourceElement->m_ulAuthoredDur >= ulDuration) )  &&
                "contact ehodge to fix");
          bOKToOverrideDuration = TRUE;
      }

      // /If begin="5s" and end|dur|max are explicitly set, don't override
      // the duration (interop #1.1: BeginEndEvents_Case1.smi):
      // /XXXEH- make sure delay is accounted for (if "ulDuration" is
      // really delay+dur):
      if (bOKToOverrideDuration)
      {
          // /Fixes BUG-20001116_parDurExtended_due_to_syncArc_delay.smi:
          ULONG32 ulRevisedDur = ulDuration;

          BOOL bOkToSetDuration = TRUE;

          BOOL bOKToResetDurationIncludesDelayVar = TRUE;

          BOOL bRevisedDurDoesNotIncludeDelayBeyondSyncbase = FALSE;

          // /Note: when we say "parent" in this function, we really
          // mean sync ancestor (e.g., par when switch is our parent and
          // par is parent of switch).

          ULONG32 ulSyncBaseDelay = (UINT32)-1;
          SMILNode* pSyncNode = !m_pParser? NULL :
               m_pParser->getSyncAncestor(m_pSourceElement->m_pNode);
          HX_ASSERT(pSyncNode  &&  pSyncNode->m_pElement);
          if (pSyncNode  &&  pSyncNode->m_pElement)
          {
            ulSyncBaseDelay = pSyncNode->m_pElement->m_ulDelay;
            // /XXXEH- in PR 59584 (which works OK with code as-is),
            // syncNode is a Seq but prior sibling should really be
            // treated as the "sync base", not the seq.  There are 3
            // other places in this file where this code is needed,
            // but need content that's broken by this before I fix it: PR 6XXX5:
            if (pSyncNode->m_tag == SMILSeq)
            {
                ulSyncBaseDelay = m_pParser->
                      getSyncBaseTimeInGroupTimeCoords(
                      m_pSourceElement->m_pNode);
            }
          }

          // /We need to make sure that our begin+duration does not exceed
          // our parent's end; the ulDuration begin passed in is our
          // syncBase-imposed duration that already includes our syncBase's
          // delay but does not take into account our begin offset or
          // delay relative to our syncBase's begin.  To adjust for this,
          // set the new duration to ulDuration minus (beginOffset set?
          // beginOffset : (delay-parentDelay):  Note that we can have a
          // delay that is due to a sync-arc and not due to our syncBase's
          // delay and thus we may not have a beginOffset set but we still
          // may begin later than our syncBase:
          if (m_pSourceElement->m_bBeginOffsetSet)
          {
            // /Include this code because it fixes
            // <par dur="5s" begin="1s"><ref begin="2s"/></par>
            // as in BUG-20001116_parDurExtended_due_to_syncArc_delay.smi
            // (which broke again due to fix for PR 53514, below, I think):
            if (m_pSourceElement->m_lBeginOffset > 0)
            {
                ulRevisedDur=((ULONG32)m_pSourceElement->m_lBeginOffset>=
                      ulRevisedDur)? 0 : (ulRevisedDur -
                      (ULONG32)m_pSourceElement->m_lBeginOffset);
                bRevisedDurDoesNotIncludeDelayBeyondSyncbase = TRUE;


                // /Fixes PR 58568: if revised dur is 0 or negative
                // (ULONG32 floor of 0 prevents it from being negative),
                // then we need to remove the track if it's been added
                // already, otherwise it'll play in spite of it's
                // parent ending before that time:
                if (0 == ulRevisedDur)
                {
                  if (m_pSourceElement->m_pHandler  &&
                        m_pSourceElement->m_bInsertedIntoTimeline)
                  {
                      // /The following signals subsequent timeline
                      // adjustments to ignore this element in parent
                      // duration computations:
                      m_pSourceElement->m_bCurEndClippedByParent = TRUE;
                      HX_RESULT retval2 = m_pSourceElement->m_pHandler->
                            handleTrackRemoval((const char*)m_pID,
                            (INT32)m_pSourceElement->m_pNode->m_nGroup);
                      if (HXR_OK == retval2)
                      {
                        // /XXXEH- verify in SMIL 2.0 spec how to
                        // handle syncArcs to element that's beyond
                        // its syncBase and thus won't start:
                        // /Fixes case where element has sync arc
                        // to this end time and we need to notify it
                        // that we've ended early:
                        m_pParser->m_pTimelineElementManager->notify((const char*)m_pID);
                        bTrackStartsTooLateSoTrackRemoved = TRUE;
                        goto cleanup;
                      }
                  }
                  
                }
            }
          }
          else // /No begin offset, so use delay minus syncBase delay:
          {
            if (pSyncNode  &&  pSyncNode->m_pElement)
            {
                if ((UINT32)-1 != ulSyncBaseDelay  &&
                      (UINT32)-1 != m_pSourceElement->m_ulDelay )
                {
                  HX_ASSERT(m_pSourceElement->m_ulDelay >=
                        ulSyncBaseDelay);
                  if (m_pSourceElement->m_ulDelay > ulSyncBaseDelay  ||
                        // /Helps fix PR 66391: if delays are equal &
                        // revisedDur=0, then remove this track:
                        (0 == ulRevisedDur  &&
                        m_pSourceElement->m_ulDelay == ulSyncBaseDelay))
                  {
                      ULONG32 ulEffectiveBeginOffset =
                            m_pSourceElement->m_ulDelay -
                            ulSyncBaseDelay;
                      ulRevisedDur =
                            ulRevisedDur>ulEffectiveBeginOffset?
                            ulRevisedDur-ulEffectiveBeginOffset : 0;
                      bRevisedDurDoesNotIncludeDelayBeyondSyncbase = TRUE;

                      bOKToResetDurationIncludesDelayVar = FALSE;
                      // /Be sure to update the begin offset relative
                      // to the parent:  Helps fix
                      // "...20001116_parDurExtended_due_to_syncArc..."
                      m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase =
                            TRUE;
                      m_pSourceElement->m_ulBeginOffsetFromSyncBase =
                            ulEffectiveBeginOffset;
                      // /Fixes part of PR 50684: if revised dur is 0
                      // or negative (ULONG32 floor of 0 prevents it
                      // from being negative), then we need to remove
                      // the track if it's been added already:
                      if (0 == ulRevisedDur  &&
                            m_pSourceElement->m_pHandler  &&
                            m_pSourceElement->m_bInsertedIntoTimeline)
                      {
                        m_pSourceElement->m_bCurEndClippedByParent = TRUE;
                        HX_RESULT retval2 = m_pSourceElement->m_pHandler->
                              handleTrackRemoval((const char*)m_pID,
                              (INT32)m_pSourceElement->m_pNode->m_nGroup);
                        if (HXR_OK == retval2)
                        {
                            // /Fixes case where element has sync arc
                            // to this end time and we need to notify it
                            // that we've ended early:
                            m_pParser->m_pTimelineElementManager->notify((const char*)m_pID);
                            bTrackStartsTooLateSoTrackRemoved = TRUE;
                            goto cleanup;
                        }
                      }
                  }
                        
                }
                else if ((UINT32)-1 == ulSyncBaseDelay)
                {
                  // /Fixes case where par parent child of excl was
                  // allowing child to begin even though par has no
                  // explicit resolved begin and thus shouldn't begin:
                  bOkToSetDuration = FALSE;
                }
            }
          }

          if (bOkToSetDuration  &&  ((UINT32)-1 ==
                m_pSourceElement->m_ulDuration  ||
                m_pSourceElement->m_ulDuration < ulRevisedDur) )
          {
            HX_ASSERT(m_pSourceElement->m_ulDuration == m_pSourceElement->getPureDuration());
            // /Adding this if() fixes PR 53514; parent explicit dur was
            // being forced on this child even if child has a shorter
            // intrinsic duration (which isn't known yet).  We need to
            // hold off setting the duration and rather set the max
            // duration:
            setMaxDuration(ulRevisedDur);
          }
          else if (bOkToSetDuration)
          {
            m_bDurationSet = m_bDontResetDuration = TRUE;

            if (m_pSourceElement->m_ulDuration != ulRevisedDur)
            {
                // /Parent-imposed duration always is relative to parent
                // begin, so duration thus includes delay offset from
                // parent.  Don't set flag unless offset>0, for
                // consistency:
                if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase  &&
                      m_pSourceElement->m_ulBeginOffsetFromSyncBase > 0)
                {
                  m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase = TRUE;
                }
                if (bRevisedDurDoesNotIncludeDelayBeyondSyncbase)
                {
                  m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase = FALSE;
                }

                // /Adding this if() conditional around the call to
                // "resetTimelineElement...()" makes PR55885 happen only
                // after the first time it's played.  If you don't close
                // the player and then restart the clip, sometimes 55885
                // bug still appears; need to debug with core folks to
                // see why this happens.
                // /NOTE: Adding the following conditional *does* 100% fix
                // "BUG-20010613-clickAllFourAndRestartOfGreenCauses..."
                // "...ExtensionOfTimelinePastParEnd.smil":
                if ((UINT32)-1 != m_pSourceElement->m_ulDelay)
                {
                  m_pParser->resetTimelineElementDuration(m_pID,
                        // /Using the revised dur here helps fix
                        // PR 59223, PR 50684, & PR 56795 (and
                        // probably a lot of others):
                        ulRevisedDur, ulPriorPureDuration);
                }
            }
          }
      }
      // /Fixes bug where par with a synchbase end (e.g., end="foo.begin")
      // was being ignored completely because its children were never
      // being added to the timeline:
      if (!m_pSourceElement->m_bInsertedIntoTimeline)
      {
          if (HXR_OK == m_pParser->adjustForNegativeOffset(m_pID))
          {
            // /Helps fix timing interop cases in the 11.2-11.9 range:
            if ((UINT32)-1 != m_pSourceElement->m_ulDelay)
            {
                m_pParser->insertTimelineElement(m_pID, 
                      m_pSourceElement->m_ulDelay);
            }
          }
      }
    }
    else // /Else this duration is not being set by parent:
    {
      if(!m_bDurationSet  ||
            // /Helps fix PR 86107; if pause is extending duration, we're
            // only here to notify our dependents and ancestor excl so it
            // can potentially update its duration so subSEQuent clips can
            // adjust their delays outward before getting scheduled w/core:
            bDurationExtendingDueToPause)
      {
          LONG32 lDelayFromParentBegin = 0;
          HX_ASSERT((!m_pSourceElement->m_bBeginOffsetSet  ||
                m_pSourceElement->m_lBeginOffset>=0  ||
                m_pSourceElement->m_bNegBeginOffsetAlreadyUsed)  &&
                "ehodge_please_help_me_find_content_that_trips_this");
          if (m_pSourceElement->m_bBeginOffsetSet  &&
                // /Don't adjust if already adjusted for neg offset:
                !m_pSourceElement->m_bNegBeginOffsetAlreadyUsed)
          {
            lDelayFromParentBegin = m_pSourceElement->m_lBeginOffset;
          }
          // /Handle case where element began based on event or late-
          // resolving time, in which case we want to treat the diff
          // between when it resolved and what its sync-parent begin
          // is as if it were a m_lBeginOffset:
          else if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase)
          {
            lDelayFromParentBegin = (LONG32)
                  m_pSourceElement->m_ulBeginOffsetFromSyncBase;
          }
          if (lDelayFromParentBegin>0  &&
                // /1st part of fix for interop case 1.15 where begin and
                // end are explicitly set to same val so dur should be 0:
                ulDuration != 0)
          {
            m_pSourceElement->m_ulDuration = (
                ((INT32)ulDuration + lDelayFromParentBegin >0) ?
                (UINT32)(
                (INT32)ulDuration + lDelayFromParentBegin) : 0);

            // /NOTE: m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase
            // is TRUE in PR 79699 (occasionally) but it plays as expected so
            // I removed the HX_ASSERT() on !(..->m_bDurationIncludesDelay...)].
// /XXXEH- 20020625: maybe don't do above adding of delay, and then set this to FALSE?:
            m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase = TRUE;
            // /If duration is unresolved or indefinite, don't include
            // delay from parent so parent duration doesn't get extended
            // beyond WAY_IN_THE_FUTURE:
            if (WAY_IN_THE_FUTURE == ulDuration)
            {
                m_pSourceElement->m_ulDuration = WAY_IN_THE_FUTURE;
            }
          }
          else
          {
            lDelayFromParentBegin = 0; // /In case it was negative.
            m_pSourceElement->m_ulDuration = ulDuration;
            // /If end==begin, we need to NOT play the clip but we do
            // need to fire a beginEvent and endEvent for it.  However,
            // if end < begin, we don't fire these events (as in
            // SMIL 2.0 Interop Timing case 1.16):
            BOOL bEndBeforeBegin =
                  m_pSourceElement->m_bBeginOffsetSet  &&
                  m_pSourceElement->m_bEndOffsetSet  &&
                  m_pSourceElement->m_lBeginOffset >
                  m_pSourceElement->m_lEndOffset;
            if (0 == m_pSourceElement->m_ulDuration  &&
                  !bEndBeforeBegin  &&  m_pSourceElement->m_pNode)
            {
                // /Raise a beginEvent but don't play the thing (as in
                // SMIL 2.0 Interop Timing case 1.15):
                HX_RESULT rslt = HXR_OK;
                rslt = m_pParser->tryToResolveBeginEndEvents(
                      "beginEvent",
                      (const char*)m_pSourceElement->m_pNode->m_id,
                      m_pSourceElement->m_ulDelay);
                rslt = m_pParser->tryToResolveBeginEndEvents(
                      "endEvent",
                      (const char*)m_pSourceElement->m_pNode->m_id,
                      m_pSourceElement->m_ulDelay);
            }
          }
          m_bDurationSet = TRUE;

          HX_ASSERT(m_pSourceElement->m_ulDuration>0  &&
                "timing#1.15: child's dur (=0) not added to parent; refix!");
          if(m_pParent  &&
                // /Timing interop case 1.15 2nd part of fix:
                m_pSourceElement->m_ulDuration>0)
          {
            m_pParent->addDuration(m_pSourceElement->m_ulDuration,
                  m_pSourceElement->m_ulDelay,
                  (UINT32)lDelayFromParentBegin, m_pID);
            m_pSourceElement->m_bAddDurationAlreadyDone = TRUE;
          }
          // /Only do this if we're really setting the original duration
          // (and not updating duration due to predicted pause extension):
          if (!bDurationExtendingDueToPause)
          {
            // /this keeps track of dur="x" or implicit source dur, in
            // case this element restarts after playing at least once:
            m_pSourceElement->m_ulOriginalDuration =
                  m_pSourceElement->getPureDuration();
            HX_ASSERT(ulDuration == m_pSourceElement->getPureDuration()  ||
                  m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase);
          }
      }
      else if(!m_bDontResetDuration)
      {
          m_pSourceElement->m_ulDuration = ulDuration;
          m_pParser->resetTimelineElementDuration(m_pID,
                m_pSourceElement->getPureDuration(),
                ulPriorPureDuration);
          // /this keeps track of dur="x" or implicit source dur, in
          // case this element restarts after playing at least once:
          m_pSourceElement->m_ulOriginalDuration =
                m_pSourceElement->getPureDuration();
          HX_ASSERT(ulDuration == m_pSourceElement->getPureDuration()  ||
                m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase);
      }
      // /Adding the following else-if fixes PR 52110: if parent explicit
      // dur sets this's duration but this never got added to parent (via
      // addDuration()), then all subSEQuent tracks won't ever get resolved
      // begins:
      else if(!m_pSourceElement->m_bAddDurationAlreadyDone)
      {
          HX_ASSERT(m_bDurationSet); // /Here because this was already set.
          HX_ASSERT(m_bDelaySet  &&  (UINT32)-1 != m_pSourceElement->m_ulDelay);
          HX_ASSERT(m_pSourceElement->m_ulDuration>0  &&
                "child's dur (=0) not added to parent; refix!");
          if(m_pParent  &&  m_pSourceElement->m_ulDuration>0)
          {
            ULONG32 ulDelayFromSyncBaseBegin = 0;
            if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase)
            {
                ulDelayFromSyncBaseBegin =
                      m_pSourceElement->m_ulBeginOffsetFromSyncBase;
            }
            m_pParent->addDuration(m_pSourceElement->m_ulDuration, 
                  m_pSourceElement->m_ulDelay,
                  ulDelayFromSyncBaseBegin, m_pID);
            m_pSourceElement->m_bAddDurationAlreadyDone = TRUE;
          }
      }

      // /If "dur" attribute value or intrinsic dur is less than the
      // min attribute value or greater than the max attribute value,
      // then we need to use min or max attribute's value as the duration:
      if (!m_bDontResetDuration  &&
            (m_pSourceElement->m_bUseMediaDurForMinDur  ||
            m_pSourceElement->m_bUseMediaDurForMaxDur  ||
            m_pSourceElement->m_ulMinActiveDur > 0  ||
            m_pSourceElement->m_ulMaxActiveDur != ((UINT32)-1) ) )
      {
          BOOL bDoUpdate = FALSE;
          LONG32 lBeginOffset = 0;
          if (m_pSourceElement->m_bBeginOffsetSet)
          {
            lBeginOffset = m_pSourceElement->m_lBeginOffset;
          }
          // /First, check if m_pSourceElement->m_bUseMediaDurForMinDur
          // is TRUE.  If so, we want to use the max of ulDuration
          // (media's intrinsic dur) and any explicitly-set dur (via
          // dur="..." {or end="..."[-begin=".."]}:
          if (m_pSourceElement->m_bUseMediaDurForMinDur)
          {
            if (((UINT32)-1) != m_pSourceElement->m_ulAuthoredDur)
            {
                HX_ASSERT(0 == m_pSourceElement->m_ulMinActiveDur);
                // /Use authored dur if it's greater than intrinsic
                // duration OR if max<min (since max<min negates both
                // properties):
                if (m_pSourceElement->m_ulAuthoredDur > ulDuration  ||
                      (((UINT32)-1) !=
                      m_pSourceElement->m_ulMaxActiveDur  &&
                      m_pSourceElement->m_ulMaxActiveDur < ulDuration))
                {
                  m_pSourceElement->m_ulDuration =
                        m_pSourceElement->m_ulAuthoredDur;
                  bDoUpdate = TRUE;
                }
            }
          }
          // /Next, check if m_pSourceElement->m_bUseMediaDurForMaxDur
          // is TRUE.  If so, we want to use the min of ulDuration
          // (media's intrinsic dur) and any explicitly-set dur (via
          // dur="..." or {end="..."[-begin=".."]}:
          else if (m_pSourceElement->m_bUseMediaDurForMaxDur)
          {
            if (((UINT32)-1) != m_pSourceElement->m_ulAuthoredDur)
            {
                HX_ASSERT(((UINT32)-1) ==
                      m_pSourceElement->m_ulMaxActiveDur);
                // /Use authored dur if it's less than intrinsic
                // duration OR if min>max (since min>max negates both
                // properties):
                if (m_pSourceElement->m_ulAuthoredDur < ulDuration  ||
                      (0 != m_pSourceElement->m_ulMinActiveDur  &&
                      m_pSourceElement->m_ulMinActiveDur > ulDuration))
                {
                  m_pSourceElement->m_ulDuration =
                        m_pSourceElement->m_ulAuthoredDur;
                  bDoUpdate = TRUE;
                }
            }
          }
          // /If no "dur" or "end" was specified, use the greater of the
          // media's intrinsic dur and its min without exceeding its max,
          // if any:
          else if(((UINT32)-1) == m_pSourceElement->m_ulAuthoredDur)
          {
            if (m_pSourceElement->m_ulMinActiveDur!=0  &&
                  m_pSourceElement->m_ulDuration <
                  m_pSourceElement->m_ulMinActiveDur)
            {
                m_pSourceElement->m_ulDuration =
                      m_pSourceElement->m_ulMinActiveDur;
                bDoUpdate = TRUE;
            }
            if (((UINT32)-1) != m_pSourceElement->m_ulMaxActiveDur  &&
                  m_pSourceElement->m_ulDuration >
                  m_pSourceElement->m_ulMaxActiveDur)
            {
                m_pSourceElement->m_ulDuration =
                      m_pSourceElement->m_ulMaxActiveDur;
                bDoUpdate = TRUE;
            }
          }
          // /If the duration is less than the specified min, use
          // the min (and we already know that the min < max, so we don't
          // need to look at the max, if any):
          else if (m_pSourceElement->m_ulDuration <
                  m_pSourceElement->m_ulMinActiveDur)
          {
            m_pSourceElement->m_ulDuration =
                  m_pSourceElement->m_ulMinActiveDur;
            bDoUpdate = TRUE;
          }
          // /If the duration authored is greater than the specified max,
          // use the max (and we already know that the min < max, so we
          // don't need to look at the min, if any):
          else if (m_pSourceElement->m_ulDuration >
                  m_pSourceElement->m_ulMaxActiveDur)
          {
            m_pSourceElement->m_ulDuration =
                  m_pSourceElement->m_ulMaxActiveDur;
            bDoUpdate = TRUE;
          }
          else // /use authored duration:
          {
            m_pSourceElement->m_ulDuration =
                  m_pSourceElement->m_ulAuthoredDur;
            bDoUpdate = TRUE;
          }

          if (bDoUpdate)
          {
            LONG32 lDiff =
                  (LONG32)m_pSourceElement->m_ulDuration +
                  lBeginOffset;
            m_pSourceElement->m_ulDuration = lDiff>0?
                  lDiff : 0;

            m_pParser->resetTimelineElementDuration(m_pID,
                  m_pSourceElement->getPureDuration(),
                  ulPriorPureDuration);
            // /This keeps track of first-play dur, in case this
            // element restarts during or after playing at least
            // once:
            m_pSourceElement->m_ulOriginalDuration =
                  m_pSourceElement->getPureDuration();
            HX_ASSERT(ulDuration == m_pSourceElement->getPureDuration()  ||
                  m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase);
          }
      }
    }

cleanup:

    if (m_pDependent  &&  ((UINT32)-1 != m_pSourceElement->m_ulDelay))
    {
      HX_ASSERT(WAY_IN_THE_FUTURE >= m_pSourceElement->m_ulDuration +
              m_pSourceElement->m_ulDelay); // 59584(media version) & 50848 
    }

    if(m_pDependent  &&
          // /Helps fix PR 66391: If we removed this track because it fell
          // completely outside its parent's time bounds, then we shouldn't
          // update our dependent, but rather allow further processing of the
          // parent seq's setDuration() to remove it's track:
          !bTrackStartsTooLateSoTrackRemoved  &&
          // /Helps fix some timing interop cases in the 11.2-11.9 range:
          ((UINT32)-1 != m_pSourceElement->m_ulDelay)  &&
          // /Helps fix case where as-yet-unresolved end of seq child should
          // *not* be used to resolve next sibling's begin: (PR 50848)
          WAY_IN_THE_FUTURE > m_pSourceElement->m_ulDuration +
          m_pSourceElement->m_ulDelay) // /+delay for PR 59584-related bug.
    {
      //Removed the addition of m_pSourceElement->m_ulDelay from the
      // source's duration because the source's duration already includes
      // its delay; we don't want to count the delay twice. Fixes PR 13983:
      // /*XXXEH- UNFIXES 13983 by adding back in the ...m_ulDelay addition;
      // the full fix for 13983 requires keeping track of begin=... delay
      // (as opposed to seq-related delay) and then subtracting that begin
      // delay from the m_ulDelay below:
      adjustDependentDuration(m_pDependent);
      // /XXXEH- TODO: figure out if we need to claim this is being set by
      // "parent" (which is really time base) so clip-begin-like action can
      // occur; I don't think so, however:

      // /XXXEH- I think this fixes PR 13983 without breaking other stuff,
      // but need to make sure:
      // /Don't propagate delay of sourceElement (PR 13983) in case its
      // duration already includes its begin offset:
      ULONG32 ulDelayOfSourceElem = m_pSourceElement->m_ulDelay +
            m_pSourceElement->m_ulDuration;
      if (m_pSourceElement->m_bBeginOffsetSet  &&
            m_pSourceElement->m_lBeginOffset > 0)
      {
          ulDelayOfSourceElem =
                ((INT32)ulDelayOfSourceElem >
                m_pSourceElement->m_lBeginOffset ?
                ulDelayOfSourceElem - m_pSourceElement->m_lBeginOffset :
                0);

#if defined(XXXEH_DEBUG)
          HX_ASSERT(!m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase  &&
                "ehodge: don't count delay twice!");
#endif
          if (m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
          {
            HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase <=
                  m_pSourceElement->m_lBeginOffset); // /PR 6XXXX.
          }
      }
      // /If this is a repeat element and the first iteration element
      // was clipped due to a negative begin offset, we want to use the
      // full duration for this clip:
      if (m_pDependent->m_pSourceElement->m_pNode->m_repeatTag ==
            RepeatReplica  &&  m_pSourceElement->m_lBeginOffset < 0)
      {
          ULONG32 ulRepeatIterationFullDur =
                m_pSourceElement->m_ulOriginalDuration -
                m_pSourceElement->m_lBeginOffset;
          if ((UINT32)-1 != m_pSourceElement->m_ulOriginalDuration)
          {
            m_pDependent->m_pSourceElement->m_ulDuration =
                  ulRepeatIterationFullDur;
          }
      }

      if (WAY_IN_THE_FUTURE < ulDelayOfSourceElem)
      {
          HX_ASSERT(WAY_IN_THE_FUTURE == ulDelayOfSourceElem  &&  "PR 59584");
          ulDelayOfSourceElem = WAY_IN_THE_FUTURE; // /For PR 59584.
      }

      m_pDependent->setDelay(ulDelayOfSourceElem, FALSE);
    }

    m_pParser->m_pTimelineElementManager->notify(m_pID);
}

void
CSmilTimelineElement::setMaxDuration(UINT32 ulMaxDuration)
{
    m_bMaxDurationSet = TRUE;
    m_pSourceElement->m_ulMaxDuration = ulMaxDuration;
}

void 
CSmilTimelineElement::adjustDependentDuration(CSmilTimelineElement* pDependent)
{
    if (m_pParent)
    {
      m_pParent->adjustDependentDuration(m_pDependent);
    }
}

void 
CSmilTimelineElement::resetDelay(UINT32 ulDelay)
{
    INT32   lAdjustedDelay = 0;

    UINT32 ulPriorDelay = m_pSourceElement->m_ulDelay;

    if(m_pSourceElement->m_bBeginOffsetSet)
    {
      lAdjustedDelay = (INT32)ulDelay + m_pSourceElement->m_lBeginOffset;
      m_pSourceElement->m_ulDelay = lAdjustedDelay > 0?lAdjustedDelay:0;
    }
    else
    {
      m_pSourceElement->m_ulDelay = ulDelay;
    }
    
    if (m_pDependent && m_bDurationSet)
    {
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
      ULONG32 ulTotalDelay = 0;
        if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase  &&
            m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
      {
          HX_ASSERT(0  &&  "ehodge: CHANGE NOT TESTED!");
      }

      if (HXR_OK !=
            m_pSourceElement->getCurrentScheduledStopTime(ulTotalDelay))
      {
          goto doneSettingDependent;
      }
#else
      ULONG32 ulTotalDelay = m_pSourceElement->m_ulDelay +
            m_pSourceElement->m_ulDuration;
      // /Helps fix PR 6XXXX(media version): if delay is already packed
      // into the duration, then don't count it twice (as can happen in
      // <seq><ref begin="1s" .../><ref begin="1s" .../>...):
      if (m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
      {
          HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1);
/*OK[]*/        if (m_pSourceElement->m_ulBeginOffsetFromSyncBase !=(UINT32)-1)
          {
            HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                  ulTotalDelay);
            if (m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                  ulTotalDelay)
            {
                ulTotalDelay -=
                      m_pSourceElement->m_ulBeginOffsetFromSyncBase;
            }
          }
      }
#endif

      if (WAY_IN_THE_FUTURE < ulTotalDelay)
      {
          HX_ASSERT(WAY_IN_THE_FUTURE == ulTotalDelay  &&  "PR 59584");
          ulTotalDelay = WAY_IN_THE_FUTURE; // /For PR 59584.
      }
 
#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION) 
{ 
    FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout? 
          ADDDURATION_DEBUGOUT_STR_NEW_FILE : 
          ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE ); 
    ::fprintf(f1, "\n\t%s:CSmilTimelineElement::resetDelay(%lu):from %lu to %lu;" 
          "\tresetting dependent (%s)'s delay to %lu\n", (const char*)m_pID, 
          ulDelay, ulPriorDelay, m_pSourceElement->m_ulDelay, 
          (const char*)m_pDependent->m_pID, ulTotalDelay); 
    ::fclose(f1); 
    bFirstTimeAddDurDebugout = FALSE; 
} 
#endif
 
      m_pDependent->resetDelay(ulTotalDelay);
    }
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
doneSettingDependent:
#endif

    if (m_pSourceElement->m_bRendererInitialized)
    {
      m_pParser->resetTimelineElementDelay(m_pID, m_pSourceElement->m_ulDelay,
            ulPriorDelay);
    }

    // /(Added while fixing PR 59851) Let others know our begin time changed:
    m_pParser->m_pTimelineElementManager->notify(m_pID);
}

void 
CSmilTimelineElement::resetDuration(UINT32 ulDuration)
{
    INT32 lAdjustedDuration = 0;

    UINT32 ulPriorPureDuration = m_pSourceElement->getPureDuration();
    
    if(m_pSourceElement->m_bBeginOffsetSet)
    {
      if (!m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
      {
          m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase =
                TRUE; // /=TRUE,not ULONG32. Helps fix PR 68190.
      }
      lAdjustedDuration = (INT32)ulDuration + m_pSourceElement->m_lBeginOffset;
      m_pSourceElement->m_ulDuration = lAdjustedDuration > 0?lAdjustedDuration:0; 
    }
    else
    {
      m_pSourceElement->m_ulDuration = ulDuration;
    }

    if(m_pParent)
    {
      // /Added surrounding if() to prevent adjusting dur of parent when
      // parent has clearly imposed its dur on *this (helps fix PR 58568)
      if (!m_pSourceElement->m_bCurEndClippedByParent)
      {
          m_pParent->adjustDuration();
      }
    }

    if(m_pDependent)
    {
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
      ULONG32 ulTotalDelay = 0;
        if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase  &&
            m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
      {
          HX_ASSERT(0  &&  "ehodge: CHANGE NOT TESTED!");
      }

      if (HXR_OK !=
            m_pSourceElement->getCurrentScheduledStopTime(ulTotalDelay))
      {
          goto doneSettingDependent;
      }
#else
      ULONG32 ulTotalDelay = m_pSourceElement->m_ulDelay +
            m_pSourceElement->m_ulDuration;
      // /Helps fix PR 6XXXX(media version): if delay is already packed
      // into the duration, then don't count it twice (as can happen in
      // <seq><ref begin="1s" .../><ref begin="1s" .../>...):
      if (m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
      {
          HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1);
/*OK[]*/        if (m_pSourceElement->m_ulBeginOffsetFromSyncBase !=(UINT32)-1)
          {
            HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                  ulTotalDelay);
            if (m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                  ulTotalDelay)
            {
                ulTotalDelay -=
                      m_pSourceElement->m_ulBeginOffsetFromSyncBase;
            }
          }
      }
#endif

      if (WAY_IN_THE_FUTURE < ulTotalDelay)
      {
          HX_ASSERT(WAY_IN_THE_FUTURE == ulTotalDelay  &&  "PR 59584");
          ulTotalDelay = WAY_IN_THE_FUTURE; // /For PR 59584.
      }
 
#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION) 
{ 
    FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout? 
          ADDDURATION_DEBUGOUT_STR_NEW_FILE : 
          ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE ); 
    ::fprintf(f1, "\n\t%s:CSmilTimelineElement::resetDuration(%lu):from %lu to %lu;"
          "\tresetting dependent (%s)'s delay to %lu\n", (const char*)m_pID,
          ulPriorPureDuration, ulDuration, m_pSourceElement->m_ulDuration,
          (const char*)m_pDependent->m_pID, ulTotalDelay);
    ::fclose(f1); 
    bFirstTimeAddDurDebugout = FALSE; 
} 
#endif 
 
      // /Helps fix PR 66391; if parent clipped our duration to 0, don't
      // update dependent; that'll be handled in parent seq's setDuration():
      if (0 != ulDuration  &&  !m_pSourceElement->m_bCurEndClippedByParent)
      {
          m_pDependent->resetDelay(ulTotalDelay);
      }
    }
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
doneSettingDependent:
#endif

    m_pParser->m_pTimelineElementManager->notify(m_pID);
}

void 
CSmilTimelineElement::adjustDuration()
{
    // no-op
    return;
}

HX_RESULT
CSmilTimelineElement::handlePrefetchFinished(UINT32 ulTimeFinished)
{
    HX_RESULT pnr = HXR_FAILED;
    if ((UINT32)-1 != ulTimeFinished)
    {
      if (m_pSourceElement  &&  (UINT32)-1==m_pSourceElement->m_ulDuration)
      {
          if (m_bDelaySet)
          {
            if (ulTimeFinished > m_pSourceElement->m_ulDelay)
            {
                ulTimeFinished -= m_pSourceElement->m_ulDelay;
            }
            else
            {
                ulTimeFinished = 0;
            }
          }
          
          pnr = HXR_OK;
          setDuration(ulTimeFinished, FALSE);
      }
    }
    return pnr;
}


void
// /XXXEH- TODO: [20010411] we need to get more information about *what* just
// got resolved so we don't re-resolve the m_pSourceElement on something
// that it already has resolved.  For instance, if the duration of
// pEventElement changed, we only want to resolve or re-resolve
// m_pSourceElement's begin and/or end time that are based on the *end* of
// the event element, and leave be its sync-arcs that are based on the
// *begin* of the event element.
// /XXXEH- TODO: [20010411] Don't set m_bBeginOffsetSet and other vars here;
// wait until the begin|end list is evaluated to get the current
// instance begin|end time (which may not be the sync arc that gets
// resolved herein).  Also, do this for par|seq|excl::elementResolved
CSmilTimelineElement::elementResolved(CSmilTimelineElement* pEventElement)
{
    UINT32 ulPriorPureDuration = m_pSourceElement->getPureDuration();

    BOOL bIsPlayableObjectNotInsertedInTimeline = FALSE;
    if (!pEventElement->m_pSourceElement  ||
          (pEventElement->m_pSourceElement->m_pNode  &&
          (m_pParser->isMediaObject(
          pEventElement->m_pSourceElement->m_pNode)  ||
          m_pParser->isNonMediaPlayableObject(
          pEventElement->m_pSourceElement->m_pNode) )  &&
          !pEventElement->m_pSourceElement->m_bInsertedIntoTimeline) )
    {
      bIsPlayableObjectNotInsertedInTimeline = TRUE;
    }

    // /Fixes SMIL 2.0 Interop Timing #28.2 (which is PR 52571):
    // If eventElement can't begin because it begins and ends before its
    // parent begins, then don't propagate its time to other elements:
    if (pEventElement->m_pSourceElement->m_bBeginOffsetSet  &&
          pEventElement->m_pSourceElement->m_lBeginOffset < 0)
    {
      if (0 == pEventElement->m_pSourceElement->m_ulDuration)
      {
          return;
      }
    }

    BOOL bNeedToResolveBeginTimeListVals = FALSE;
    BOOL bNeedToResolveEndTimeListVals = FALSE;
    BOOL bWasInsertedOntoTimeline = FALSE;

    BOOL bIsInExcl = m_pParser->hasAncestor(SMILExcl,
          m_pSourceElement->m_pNode);
    BOOL bPreviousDelaySetVal = m_bDelaySet;
    BOOL bUseBeginOffsetForPendingBeginList = FALSE;;
    // /If we are in an excl and we are beginning after our excl parent's
    // current child-derived end, then go ahead and insert into the timeline,
    // else see all "We need to go through ..." notes, below.  This fixes
    // Interop Timing cases #9.35 & 9.36 (that broke while fixing 15.13):
    // Note that we don't want to insert ANY element that begins after its
    // parent's immutable end time):
    BOOL bCantExtendParentDuration = FALSE;
    ULONG32 ulParentEnd = (UINT32)-1;
    SMILNode* pSyncBaseNode = m_pParser->getSyncAncestor(
          m_pSourceElement->m_pNode);
    LONG32 lSourceElementDelayAdjustmentToSyncBaseTime = 0;
    if (pSyncBaseNode  &&  pSyncBaseNode->m_pElement)
    {
      // /XXXEH- TODO: handle case where endsync is SMILEventSourceID and
      // id matches m_pSourceElement->m_pNode->m_id:
      // /XXXEH- TODO: also handle when sync parent has indefinite end|dur:
      if (!pSyncBaseNode->m_pElement->m_bHasExplicitEnd  &&
            !pSyncBaseNode->m_pElement->m_bHasExplicitDur  &&
            (SMILEventSourceFirst !=
            pSyncBaseNode->m_pElement->m_nEndsyncEventSourceTag  &&
            SMILEventSourceID !=
            pSyncBaseNode->m_pElement->m_nEndsyncEventSourceTag) )
      {
          bCantExtendParentDuration = FALSE;
          if ((UINT32)-1 != pSyncBaseNode->m_pElement->m_ulDuration  &&
                (UINT32)-1 != pSyncBaseNode->m_pElement->m_ulDelay)
          {
            ulParentEnd = pSyncBaseNode->m_pElement->m_ulDelay +
                  pSyncBaseNode->m_pElement->m_ulDuration;
          }
      }
      else
      {
          bCantExtendParentDuration = TRUE;
          if (bIsPlayableObjectNotInsertedInTimeline)
          {
            // /Fixes BUG-20010423_nothingShouldPlay_beginBasedOn....smi:
            // If eventElement begins after its parent ends, then don't
            // propagate its time to other elements:
            if ((UINT32)-1 == pEventElement->m_pSourceElement->m_ulDelay  ||
                  pEventElement->m_pSourceElement->m_ulDelay >=
                  pSyncBaseNode->m_pElement->m_ulDelay +
                  pSyncBaseNode->m_pElement->m_ulDuration)
            {
                return; // /Starts too late.
            }
          }
      }
    }

    //First, let's see if we have a begin event to resolve:
    // /Combining handling of SMILEventSourceBegin and SMILEventSourceClock
    // fixes SMIL 1.0-syntax PR 112740; the ancient fix for the SMIL2-syntax
    // version is already in the below code; it's about time we combine
    // this code, anyway. (SMILEventSourceClock is only used in SMIL 1.0-
    // syntax syncArcs with clock offsets) :
    if ( (m_pSourceElement->m_nBeginEventSourceTag == SMILEventSourceBegin  ||
          m_pSourceElement->m_nBeginEventSourceTag == SMILEventSourceClock)  &&
          m_pSourceElement->m_BeginEventSourceID == pEventElement->m_pID)
    {
      if(pEventElement->m_bDelaySet)
      {
          // /Be sure not to overflow using ULONGs since
          // beginEventClockValue might be negative:
          LONG32 lDelay =
            (LONG32)pEventElement->m_pSourceElement->m_ulDelay +
            m_pSourceElement->m_lBeginEventClockValue;
          // /Fixes SMIL 2.0 Interop Timing #28.1 and others that have
          // sync-arc to an element with a negative begin time:
          if (pEventElement->m_pSourceElement->m_bBeginOffsetSet  &&
                pEventElement->m_pSourceElement->m_lBeginOffset < 0)
          {
            lDelay += pEventElement->m_pSourceElement->m_lBeginOffset;
          }
          // /Fixes PR 82736 (begin=x.being... case) where sync-arc begin
          // results in negative offset from parent and we've already
          // adjusted for that:
          else if (pSyncBaseNode->m_pElement->m_ulDelay > lDelay  &&
                // /If already inserted, then adjustForNegativeOffset()
                // won't re-do any adjustment:
                m_pSourceElement->m_bInsertedIntoTimeline  &&
                !m_pSourceElement->m_bIsRestarting)
          {
            // /Don't go earlier than synbase:
            lDelay = pSyncBaseNode->m_pElement->m_ulDelay;
          }

          m_bDelaySet = TRUE;
          m_pSourceElement->m_ulDelay = lDelay<0? 0: (ULONG32)lDelay;
          if (lDelay < 0)
          {
            UINT32 ulDiff = (UINT32)(-lDelay);
            // /If clip-begin is invalid, set it otherwise add to orig:
            m_pSourceElement->m_ulClipBegin = ((UINT32)-1 ==
                    m_pSourceElement->m_ulAuthoredClipBegin? ulDiff :
                  ulDiff+m_pSourceElement->m_ulAuthoredClipBegin);
            // /logicChange_test.smi: check if -1 before subtracting delay!:
            if ((UINT32)-1 != m_pSourceElement->m_ulDuration)
            {
                if (m_pSourceElement->m_ulDuration > ulDiff)
                {
                  m_pSourceElement->m_ulDuration -= ulDiff;
                }
                // /else duration is negative; it can't ever play.
                else
                {
                  m_pSourceElement->m_ulDuration = 0;
                }
            }
          }
          // /Now, if our begin delay (not offset) is based on a syncArc,
          // we need to adjust our dur by the difference between our delay
          // and our syncBase element's delay:
          if ((UINT32)-1 != m_pSourceElement->m_ulDuration  &&
                m_pSourceElement->m_bEndOffsetSet  &&
                WAY_IN_THE_FUTURE != m_pSourceElement->m_ulDuration)
          {
            LONG32 lSum = m_pSourceElement->m_lEndOffset;
            // /We need to remove our delay or it will get counted twice
            lSum -= m_pSourceElement->m_ulDelay;
            HX_ASSERT(lSum >= 0  &&  "ehodge: handle neg delay propogation");
            m_pSourceElement->m_ulDuration = (UINT32)(lSum<0 ? 0 : lSum);
            // /Fixes PR 80371: If our duration was set before and is now
            // re-resolving, make sure the following flag is reset to false
            // in case it wasn't before, otherwise show/hide code will
            // subtract the delay from a duration that doesn't include the
            // delay:
            m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase = FALSE;
          }

          bNeedToResolveBeginTimeListVals = TRUE;
          if (HXR_OK == m_pParser->adjustForNegativeOffset(m_pID))
          {
            if (!m_pSourceElement->m_bHasBeenScheduled  ||
                  // /Helps fix PR 50588: if restarting, hasBeenSched
                  // will still be true, so check if inserted instead:
                  (m_pSourceElement->m_bIsRestarting  &&
                  !m_pSourceElement->m_bInsertedIntoTimeline) )
            {
                // /We need to go through the proper channels if we're
                // in an excl; a priorityClass may prevent us from
                // starting or may defer our start, so just add us to
                // the pending begin time list (unless we're extending
                // the end of our excl parent, as described above):
                // /First, see if our delay is beyond our parent's end:
                BOOL bDelayIsBeyondParentEnd = FALSE;
                if ((UINT32)-1 != ulParentEnd)
                {
                  bDelayIsBeyondParentEnd =
                        (m_pSourceElement->m_ulDelay > ulParentEnd);
                }
                BOOL bInsertElement = bIsInExcl?
                      (bDelayIsBeyondParentEnd  &&
                      !bCantExtendParentDuration) :
                      ( !(bDelayIsBeyondParentEnd  &&
                      bCantExtendParentDuration) );
                // /But hold on: if parent's delay isn't yet resolved,
                // then we can't be inserted until it resolves.  Found
                // this while fixing long-sync-arc bug PR 64498, par test:
                // "..._longSyncArcBug-ParWithoutDur...sync.smil":
                BOOL bParentDelayIsUnresolved = FALSE;
                if ((UINT32)-1 == pSyncBaseNode->m_pElement->m_ulDelay  ||
                      (pSyncBaseNode->m_pElement->m_pTimelineElement  &&
                      pSyncBaseNode->m_pElement->m_pTimelineElement->m_bDelayEvent  &&
                      !pSyncBaseNode->m_pElement->m_pTimelineElement->m_bDelaySet ))
                {
                  bInsertElement = FALSE;
                  bParentDelayIsUnresolved = TRUE;
                }

                if (m_pSourceElement->m_bBeginOffsetSet)
                {
                  // /If it's already been set, then just add this
                  // newly-resolved begin time to the pending queue
                  // and let it get sorted out there.  This can
                  // happen with begin="0s; foo.begin"
                  bInsertElement = FALSE;
                }

                if (!bInsertElement)
                {
                  // /We need to maintain old "delaySet" value so
                  // setDelay() call in eventual call to
                  // checkPendingBeginAndEndTimes() can insert this
                  // timeline element properly:
                  m_bDelaySet = bPreviousDelaySetVal;

                  // /Fixes PR 64498: flag the fact that long sync-arc
                  // begin is resolving before parent begin is resolved:
                  if (bParentDelayIsUnresolved)
                  {
                      m_pSourceElement->
                        m_bAwaitingSyncAncestorBeginNotification = TRUE;
                      m_pSourceElement->m_ulLongSyncArcBeginInGroupTime =
                            lDelay;
                  }
                  // /This else-if is the final fix for PR 64499: if
                  // sync-base has multiple begin times, then we also
                  // need to prepare for that event restarting it even
                  // though its first begin is already resolved:
                  else if (pSyncBaseNode->m_pElement->m_pBeginTimeList  &&
                        pSyncBaseNode->m_pElement->m_pBeginTimeList->
                        GetCount() > 1)
                  {
                      m_pSourceElement->m_ulLongSyncArcBeginInGroupTime =
                            lDelay;
                  }
                  else
                  {
                      m_pSourceElement->m_ulLongSyncArcBeginInGroupTime =
                            (UINT32)-1;
                  }
                }
                else
                {
                  bWasInsertedOntoTimeline = TRUE;
                  m_pSourceElement->m_ulLongSyncArcBeginInGroupTime =
                            (UINT32)-1;
                  m_pParser->insertTimelineElement(m_pID, 
                        m_pSourceElement->m_ulDelay);
                }
            }
          }
      }
    }
    else if(m_pSourceElement->m_nBeginEventSourceTag == SMILEventSourceEnd  &&
          m_pSourceElement->m_BeginEventSourceID == pEventElement->m_pID  &&
          // /Helps fix SMIL 2.0 Interop Timing #28.9 where end as set by parent
          // was being used when element's end was actually indefinite (or any
          // value greater than parent's end); that truncated end time should
          // not propogate; only the pre-truncated time (if any) should be used:
          (!pEventElement->m_pSourceElement->m_bCurEndClippedByParent) )
    {
      // /If event element's duration is "WAY_IN_THE_FUTURE" then it's
      // essentially an unresolved end time, so we should not resolve
      // based on it:
      if(pEventElement->m_bDurationSet  &&  WAY_IN_THE_FUTURE !=
            pEventElement->m_pSourceElement->m_ulDuration )
      {
          ULONG32 ulPriorDelay = m_pSourceElement->m_ulDelay;
          m_bDelaySet = TRUE;
          // /Be sure not to overflow using ULONGs since
          // beginEventClockValue might be negative:
          LONG32 lDelay =
                (LONG32)pEventElement->m_pSourceElement->m_ulDuration +
                m_pSourceElement->m_lBeginEventClockValue;
          // /If delay is not set, don't add it!:
          if(pEventElement->m_bDelaySet)
          {
            lDelay += (LONG32)pEventElement->m_pSourceElement->m_ulDelay;
            // /Fixes case where dur already accounts for begin offset
            // that's already built into the delay (e.g., begin="x.end-5"
            // where x has an explicit begin offset greater than zero):
            // /Helps fix PR 82736 (=x.begin case) by looking at flag and
            // not just blindly assuming beginOffset is included in
            // eventElement's m_ulDuration:
            if (pEventElement->m_pSourceElement->
                  m_bDurationIncludesDelayBeyondSyncbase)
            {
                HX_ASSERT((UINT32)-1 != pEventElement->m_pSourceElement->
                      m_ulBeginOffsetFromSyncBase);
                if ((UINT32)-1 != pEventElement->m_pSourceElement->
                      m_ulBeginOffsetFromSyncBase)
                {
                  lDelay -= (LONG32)pEventElement->m_pSourceElement->
                        m_ulBeginOffsetFromSyncBase;
                }
            }
            // /Fixes case where third ref has begin="second.end" and
            // second has begin="first.end" where first.end is > 0.
            // In that case, begin offset won't be set but delay WILL
            // alread be part of the duration:
            else if (pEventElement->m_pSourceElement->m_ulDelay >
                  pSyncBaseNode->m_pElement->m_ulDelay)
            {
                ULONG32 ulDelayFromSyncBase =
                      pEventElement->m_pSourceElement->m_ulDelay -
                      pSyncBaseNode->m_pElement->m_ulDelay;
                HX_ASSERT(lDelay>(LONG32)ulDelayFromSyncBase);
                if (lDelay < (LONG32)ulDelayFromSyncBase)
                {
                  ulDelayFromSyncBase = lDelay;
                }
                lDelay -= (LONG32)ulDelayFromSyncBase;
            }
          }

          // /Fixes PR 82736 (begin=x.end... case) where sync-arc begin
          // results in negative offset from parent and we've already
          // adjusted for that:
          if (pSyncBaseNode->m_pElement->m_ulDelay > lDelay  &&
                // /If already inserted, then adjustForNegativeOffset()
                // won't re-do any adjustment:
                m_pSourceElement->m_bInsertedIntoTimeline  &&
                !m_pSourceElement->m_bIsRestarting)
          {
            // /Don't go earlier than synbase:
            lDelay = pSyncBaseNode->m_pElement->m_ulDelay;
          }

          m_pSourceElement->m_ulDelay = lDelay<0? 0: (ULONG32)lDelay;
          if (lDelay < 0)
          {
            UINT32 ulDiff = (UINT32)(-lDelay);
            // /If clip-begin is invalid, set it otherwise add to orig:
            m_pSourceElement->m_ulClipBegin = ((UINT32)-1 ==
                    m_pSourceElement->m_ulAuthoredClipBegin? ulDiff :
                  ulDiff+m_pSourceElement->m_ulAuthoredClipBegin);
            if ((UINT32)-1 != m_pSourceElement->m_ulDuration)
            {
                if (m_pSourceElement->m_ulDuration > ulDiff)
                {
                  m_pSourceElement->m_ulDuration -= ulDiff;
                }
                // /else duration is negative; it can't ever play:
                else
                {
                  m_pSourceElement->m_ulDuration = 0;
#if defined(XXXEH_TESTING)
                  HX_ASSERT(m_pSourceElement->m_ulDuration);
#endif
                }
            }
          }
          
          // /Now, if our begin delay (not offset) is based on a syncArc,
          // we need to adjust our dur by the difference between our delay
          // and our syncBase element's delay:
          if ((UINT32)-1 != m_pSourceElement->m_ulDuration  &&
                m_pSourceElement->m_bEndOffsetSet  &&
                WAY_IN_THE_FUTURE != m_pSourceElement->m_ulDuration)
          {
            LONG32 lSum = m_pSourceElement->m_lEndOffset;
            // /We need to remove our delay or it will get counted twice
            lSum -= m_pSourceElement->m_ulDelay;
            m_pSourceElement->m_ulDuration = (UINT32)(lSum<0 ? 0 : lSum);
          }

          bNeedToResolveBeginTimeListVals = TRUE;
          if (HXR_OK == m_pParser->adjustForNegativeOffset(m_pID))
          {
            if (!m_pSourceElement->m_bHasBeenScheduled  ||
                  // /Fixes PR 50588 (case2): if restarting, hasBeenSched
                  // will still be true, so check if inserted instead:
                  (m_pSourceElement->m_bIsRestarting  &&
                  !m_pSourceElement->m_bInsertedIntoTimeline) )
            {
                // /See note in code above that handles
                // m_nBeginEventSourceTag == SMILEventSourceBegin:
                BOOL bDelayIsBeyondParentEnd = FALSE;
                if ((UINT32)-1 != ulParentEnd)
                {
                  bDelayIsBeyondParentEnd =
                        (m_pSourceElement->m_ulDelay > ulParentEnd);
                }
                BOOL bInsertElement = bIsInExcl?
                      (bDelayIsBeyondParentEnd  &&
                      !bCantExtendParentDuration) :
                      ( !(bDelayIsBeyondParentEnd  &&
                      bCantExtendParentDuration) );
                // /But hold on: if parent's delay isn't yet resolved,
                // then we can't be inserted until it resolves.  Found
                // this while fixing long-sync-arc bug PR 64498, par test:
                // "..._longSyncArcBug-ParWithoutDur...sync.smil":
                BOOL bParentDelayIsUnresolved = FALSE;
                if ((UINT32)-1 == pSyncBaseNode->m_pElement->m_ulDelay  ||
                      (pSyncBaseNode->m_pElement->m_pTimelineElement  &&
                      pSyncBaseNode->m_pElement->m_pTimelineElement->m_bDelayEvent  &&
                      !pSyncBaseNode->m_pElement->m_pTimelineElement->m_bDelaySet ))
                {
                  bInsertElement = FALSE;
                  bParentDelayIsUnresolved = TRUE;
                }

                if (m_pSourceElement->m_bBeginOffsetSet)
                {
                  // /If it's already been set, then just add this
                  // newly-resolved begin time to the pending queue
                  // and let it get sorted out there.  This can
                  // happen with begin="0s; foo.begin"
                  bInsertElement = FALSE;
                }

                if (!bInsertElement)
                {
                  // /See note in code above that handles
                  // m_nBeginEventSourceTag == SMILEventSourceBegin:
                  m_bDelaySet = bPreviousDelaySetVal;

                  // /Fixes "foo.end" version of PR 64498: flag the fact
                  // that long sync-arc begin is resolving before parent
                  // begin is resolved:
                  if (bParentDelayIsUnresolved)
                  {
                      m_pSourceElement->
                        m_bAwaitingSyncAncestorBeginNotification = TRUE;
                      m_pSourceElement->m_ulLongSyncArcBeginInGroupTime =
                            lDelay;
                  }
                  // /This else-if is the final fix for foo.end version of
                  // PR 64499: if sync-base has multiple begin times, then
                  // we also need to prepare for that event restarting it
                  // even though its first begin is already resolved:
                  else if (pSyncBaseNode->m_pElement->m_pBeginTimeList  &&
                        pSyncBaseNode->m_pElement->m_pBeginTimeList->
                        GetCount() > 1)
                  {
                      m_pSourceElement->m_ulLongSyncArcBeginInGroupTime =
                            lDelay;
                  }
                  else
                  {
                      m_pSourceElement->m_ulLongSyncArcBeginInGroupTime =
                            (UINT32)-1;
                  }
                }
                else
                {
                  bWasInsertedOntoTimeline = TRUE;
                  m_pSourceElement->m_ulLongSyncArcBeginInGroupTime =
                            (UINT32)-1;
                  m_pParser->insertTimelineElement(m_pID, 
                        m_pSourceElement->m_ulDelay);
                }
            }
            // /Fixes (part of) SMIL 2.0 Interop Timing #28.9:
            // If already scheduled and possibly even playing, we need to
            // reset the timeline element's delay:
            else if (ulPriorDelay != m_pSourceElement->m_ulDelay)
            {
                // /Get the matching begin time val, resolve it, and put
                // it in the pending list:
                LISTPOSITION lPos = NULL;
                if (m_pSourceElement->m_pBeginTimeList  &&  NULL !=
                      (lPos = m_pSourceElement->m_pBeginTimeList->
                      GetHeadPosition()) )
                {
                  while (lPos)
                  {
                      SmilTimeValue* pTmpVal = (SmilTimeValue*)
                            m_pSourceElement->m_pBeginTimeList->
                            GetNext(lPos);
                      if (pTmpVal)
                      {
                        if (SmilTimeSyncBase == pTmpVal->m_type)
                        {
                            if (!pTmpVal->isTimeResolved())
                            {
                              if (pTmpVal->m_idRef ==
                                    pEventElement->m_pID)
                              {
                                  BOOL bATimeWasResolved;
                                  m_pSourceElement->resolveSyncArcTimeValues(
                                        m_pSourceElement->m_ulDelay +
                                        (bUseBeginOffsetForPendingBeginList?
                                        m_pSourceElement->m_lBeginOffset:0),
                                        (const char*)pEventElement->m_pID,
                                        SmilBeginTimeList, bATimeWasResolved,
                                        TRUE, m_pParser);
                                  bNeedToResolveBeginTimeListVals = FALSE;
                              }
                            }
                            else
                            {
                              // /else get from pending and change it!
                              // See PR 50588 (case 2: begin="x.end")
                            }
                        }
                      }
                  }
                }
            }
          }
      }
    }

    SMILNode* pSyncNode = pSyncBaseNode;
    HX_ASSERT(pSyncNode  &&  pSyncNode->m_pElement);

    //[SMIL 1.0 compliance] Fixes PR 16629:
    //Next, let's see if we have an end event to resolve:
    // /XXXEH- TODO 20010525: we need to see if there already is an end time
    // that is prior to this new one and is after a begin time; if so, then
    // we want to stick this new one into the pending end time list rather
    // than use it right away:
    // /Combining handling of SMILEventSourceBegin and SMILEventSourceClock
    // fixes SMIL 1.0-syntax version of PR 63622 (part 4) where the fix for
    // part 2 gets resused if we share this code; it's about time we combine
    // this code, anyway:
    if ( (m_pSourceElement->m_nEndEventSourceTag == SMILEventSourceBegin  ||
          m_pSourceElement->m_nEndEventSourceTag == SMILEventSourceClock)  &&
          m_pSourceElement->m_EndEventSourceID == pEventElement->m_pID)
    {
      if(pEventElement->m_bDelaySet)
      {
          m_bDurationSet = TRUE;
          LONG32 lSum =(LONG32)pEventElement->m_pSourceElement->m_ulDelay +
                m_pSourceElement->m_lEndEventClockValue;

          // /Now, if our begin delay (not offset) is based on a syncArc,
          // we need to adjust our dur by the difference between our delay
          // and our syncBase element's delay:
          if (m_pSourceElement->m_bBeginOffsetSet)
          {
            if (pSyncNode  &&  pSyncNode->m_pElement)
            {
                ULONG32 ulSyncBaseDelay =
                      pSyncNode->m_pElement->m_ulDelay;
                HX_ASSERT((UINT32)-1 != ulSyncBaseDelay);
                if ((UINT32)-1 != ulSyncBaseDelay)
                {
                  HX_ASSERT(m_pSourceElement->m_ulDelay >=
                        ulSyncBaseDelay);
                  if (m_pSourceElement->m_ulDelay > ulSyncBaseDelay)
                  {
                      lSum -= (LONG32)ulSyncBaseDelay;
                  }
                        
                }
            }
          }
          // /Checking these two conditionals helps fix PR 63622 (part 2):
          else if (m_bDelaySet  &&  m_pSourceElement->m_ulDelay!=(UINT32)-1)
          {
            // /We need to remove our delay or it will get counted twice:
            lSum -= m_pSourceElement->m_ulDelay;
          }

          HX_ASSERT(lSum >= 0  &&  "ehodge: handle neg delay propogation");
          lSum = (lSum<0? 0 : lSum);  //clip off negative vals.

          m_pSourceElement->m_ulDuration = (UINT32)lSum;
          // /Fixes case where parent dur was overriding this new
          // m_ulDuration, above, in this's subsequent setDuration(d,TRUE)
          if (WAY_IN_THE_FUTURE == m_pSourceElement->m_ulAuthoredDur)
          {
            // /Change "core-tricking" value back to unset:
            m_pSourceElement->m_ulAuthoredDur = (UINT32)-1;
          }
          // /Fixes case where both dur=d & end=x.begin were specified;
          // use the lesser of the two (part 4 of PR 71386):
          else if (m_pSourceElement->m_bHasExplicitDur  &&
                (UINT32)-1 != m_pSourceElement->m_ulAuthoredDur  &&
                m_pSourceElement->m_ulAuthoredDur < (UINT32)lSum)
          {
            m_pSourceElement->m_ulDuration =
                  m_pSourceElement->m_ulAuthoredDur;
          }

          bNeedToResolveEndTimeListVals = TRUE;

          // /More of fix for PR 63622 (part 2): if our delay isn't set, then
          // when it does resolve, treat it as an end, not a relative dur:
          if (!m_bDelaySet  ||  m_pSourceElement->m_ulDelay==(UINT32)-1)
          {
            /* Removing this doesn't (now) affect PR 63622 part 2, which
             * still plays fine, while removing it *does* fix PR 81256
             * where an element wasn't restarting because its end time
             * (in its list) wasn't considered resolved on the next play:
            // /For PR 63622 (part 2): don't resolve end time(s) since
            // begin delay isn't resolved yet:
            bNeedToResolveEndTimeListVals = FALSE;
             */
            if (!m_pSourceElement->m_bEndOffsetSet)
            {
                m_pSourceElement->m_bEndOffsetSet = TRUE;
                m_pSourceElement->m_lEndOffset = (UINT32)lSum;
            }
          }
          // /Helps fix PR 63622 (part 2): changed this to "*else* if" since
          //  we don't want to do anything until our begin delay is set:
          else if (HXR_OK == m_pParser->adjustForNegativeOffset(m_pID))
          {
            if (!m_pSourceElement->m_bHasBeenScheduled  ||
                  // /Fixes PR 50588 (case4): if restarting, hasBeenSched
                  // will still be true, so check if inserted instead:
                  (m_pSourceElement->m_bIsRestarting  &&
                  !m_pSourceElement->m_bInsertedIntoTimeline) )
            {
                bWasInsertedOntoTimeline = TRUE;
                m_pParser->insertTimelineElement(m_pID, 
                  m_pSourceElement->m_ulDelay);
            }
            // /Be sure to update the timeline; fixes variant of PR 59801
            // when end="x.begin" instead of end="x.end":
            else
            {
                m_pParser->resetTimelineElementDuration(
                      (const char*)m_pSourceElement->m_pNode->m_id,
                      m_pSourceElement->getPureDuration(),
                      ulPriorPureDuration);
                m_pParser->m_pTimelineElementManager->notify(
                      (const char*)m_pSourceElement->m_pNode->m_id);
            }
          }
      }
    }
    else if(m_pSourceElement->m_nEndEventSourceTag == SMILEventSourceEnd  &&
          m_pSourceElement->m_EndEventSourceID == pEventElement->m_pID)
    {
      // /If event element's duration is "WAY_IN_THE_FUTURE" then it's
      // essentially an unresolved end time, so we should not resolve
      // based on it:
      if(pEventElement->m_bDurationSet  &&  WAY_IN_THE_FUTURE !=
            pEventElement->m_pSourceElement->m_ulDuration)
      {
          m_bDurationSet = TRUE;

          LONG32 lSum =(LONG32)pEventElement->getDuration() +
                m_pSourceElement->m_lEndEventClockValue;
          // /If the event element has a delay, we need to add that
          // minus any beginOffset (if it's set); subtracting the begin
          // offset fixes "BUG-20000921_beginSyncArcOffBy5secInBlue.smi":
          if(pEventElement->m_bDelaySet)
          {
            lSum += (LONG32)pEventElement->m_pSourceElement->m_ulDelay;
            if (pEventElement->m_pSourceElement->m_bBeginOffsetSet  &&
                  pEventElement->m_pSourceElement->m_lBeginOffset > 0)
            {
                lSum -= pEventElement->m_pSourceElement->m_lBeginOffset;
                // /20020630- Find content that may be broken if this
                // asserts.  If such a thing exists, change above call to
                // "...->getDuration()" to "...->getPureDuration()" and
                // then total delay:
                HX_ASSERT(pEventElement->m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase);
            }
            // /Final nail in PR 77406's coffin: if begin of event element
            // was event based and thus there's no m_bBeginOffsetSet but
            // there *is* a m_ulBeginOffsetFromSyncBase>0, then we need to
            // subtract that if it's included in the duration:
            else if (pEventElement->m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase  &&
                  pEventElement->m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase  &&
                  pEventElement->m_pSourceElement->m_ulBeginOffsetFromSyncBase > 0)
            {
                lSum -= pEventElement->m_pSourceElement->m_ulBeginOffsetFromSyncBase;
            }
          }
          else
          {
            HX_ASSERT(pEventElement->m_bDelaySet);
          }
          // /lSum is now in global (group) time space.  We need to convert
          // it into this's local time space:

          // /Now, if our begin delay (not offset) is based on a syncArc,
          // we need to adjust our dur by the difference between our delay
          // and our syncBase element's delay:
          if (m_pSourceElement->m_bBeginOffsetSet)
          {
            if (pSyncNode  &&  pSyncNode->m_pElement)
            {
                ULONG32 ulSyncBaseDelay =
                      pSyncNode->m_pElement->m_ulDelay;
                HX_ASSERT((UINT32)-1 != ulSyncBaseDelay);
                if ((UINT32)-1 != ulSyncBaseDelay)
                {
                  HX_ASSERT(m_pSourceElement->m_ulDelay >=
                        ulSyncBaseDelay);
                  if (m_pSourceElement->m_ulDelay > ulSyncBaseDelay)
                  {
                      lSum -= (LONG32)ulSyncBaseDelay;
                  }
                        
                }
            }

            // /This fixes PR 8XXXZ (PR 63622 revisited): if begin is set and duration includes
            // that begin delay, subtract it from the sum & reset the flag:
            if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase  &&
                      m_pSourceElement->m_ulBeginOffsetFromSyncBase > 0)
            {
                lSum -= m_pSourceElement->m_ulBeginOffsetFromSyncBase > 0?
                      m_pSourceElement->m_ulBeginOffsetFromSyncBase : 0;
                m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase =
                      FALSE;
            }
          }
          // /Checking these two conditionals helps fix PR 63622 (part 3):
          else if (m_bDelaySet  &&  m_pSourceElement->m_ulDelay!=(UINT32)-1)
          {
            // /We need to remove our delay or it will get counted twice:
// /XXXEH- 20020625: maybe subtract curBeginOffsetFromSyncBase (as 10 lines above) instead?:
            lSum -= m_pSourceElement->m_ulDelay;
          }

          HX_ASSERT(lSum >= 0  &&  "ehodge: handle neg delay propogation");
          lSum = (lSum<0? 0 : lSum);  //clip off negative vals.

          m_pSourceElement->m_ulDuration = (UINT32)lSum;
            BOOL bDurationWasPreviouslyUnresolvedIndefinite = FALSE;
          // /Fixes case where parent dur was overriding this new
          // m_ulDuration, above, in this's subsequent setDuration(d,TRUE)
          if (WAY_IN_THE_FUTURE == m_pSourceElement->m_ulAuthoredDur)
          {
                bDurationWasPreviouslyUnresolvedIndefinite = TRUE;
            // /Change "core-tricking" value back to unset:
            m_pSourceElement->m_ulAuthoredDur = (UINT32)-1;
          }
          // /Fixes case where both dur=d & end=x.end were specified;
          // use the lesser of the two (part 2 of PR 71386):
          else if (m_pSourceElement->m_bHasExplicitDur  &&
                (UINT32)-1 != m_pSourceElement->m_ulAuthoredDur  &&
                m_pSourceElement->m_ulAuthoredDur < (UINT32)lSum)
          {
            m_pSourceElement->m_ulDuration =
                  m_pSourceElement->m_ulAuthoredDur;
          }

          bNeedToResolveEndTimeListVals = TRUE; 
  
          // /More of fix for PR 63622 (part 3): if our delay isn't set, then 
          // when it does resolve, treat it as an end, not a relative dur: 
          if (!m_bDelaySet  ||  m_pSourceElement->m_ulDelay==(UINT32)-1) 
          { 
            /* Removing this doesn't (now) affect PR 63622 part 3, which
             * still plays fine, while removing it *does* fix PR 81256
             * where an element wasn't restarting because its end time
             * (in its list) wasn't considered resolved on the next play:
            // /For PR 63622 (part 3): don't resolve end time(s) since 
            // begin delay isn't resolved yet: 
            bNeedToResolveEndTimeListVals = FALSE;
             */
            if (!m_pSourceElement->m_bEndOffsetSet) 
            { 
                m_pSourceElement->m_bEndOffsetSet = TRUE; 
                m_pSourceElement->m_lEndOffset = (UINT32)lSum; 
            } 
          } 
          // /Helps fix PR 63622 (part 3): changed this to "*else* if" since 
          //  we don't want to do anything until our begin delay is set: 
          else if (HXR_OK == m_pParser->adjustForNegativeOffset(m_pID)) 
          {
            if (!m_pSourceElement->m_bHasBeenScheduled  ||
                  // /Fixes PR 50588 (case5): if restarting, hasBeenSched
                  // will still be true, so check if inserted instead:
                  (m_pSourceElement->m_bIsRestarting  &&
                  !m_pSourceElement->m_bInsertedIntoTimeline) )
            {
                bWasInsertedOntoTimeline = TRUE;
                m_pParser->insertTimelineElement(m_pID, 
                  m_pSourceElement->m_ulDelay);
            }
            // /Fixes PR 59801: the fix for PR 50535, which enabled
            // inserting of an element into the timeline before its end
            // event is resolved (as is needed when end="foo.end" and foo
            // has an event-based end) caused parent to extend to that
            // WAY_IN_THE_FUTURE dur and never brought it back in when
            // the end time resolved, so here goes:
                // /Adding the if() part to the else helps fix PR 107724: don't
                // go through all this code if this element has not had its
                // duration altered by the code, above:
                else if (m_pSourceElement->getPureDuration() !=
                        ulPriorPureDuration)
            {
                // /This fixes PR 70437 where temporary, indefinite
                // duration had been added to parent, earlier, while
                // waiting for when (or if) sync-arc'd element's end
                // ever resolves.  Then, when it resolved, parent wasn't
                // being notified of this new duration, thus the temporary
                // indef duration remained as the presentation duration:
                m_bDurationSet=FALSE; // /Force override to new value.
                HX_ASSERT(m_pSourceElement->m_ulDuration ==
                      m_pSourceElement->getPureDuration());
                m_pParser->durationResolved(
                      (const char*)m_pSourceElement->m_pNode->m_id,
                      m_pSourceElement->m_ulDuration, FALSE);

                m_pParser->resetTimelineElementDuration(
                      (const char*)m_pSourceElement->m_pNode->m_id,
                      m_pSourceElement->getPureDuration(),
                      ulPriorPureDuration);

                    // /Helps fix PR 107724: add duration to parent if
                    // it was added before as unresolved indefinite:
                    if (m_pSourceElement->m_bAddDurationAlreadyDone  &&
                            bDurationWasPreviouslyUnresolvedIndefinite)
                    {
                        m_pParent->addDuration( 
                                m_pSourceElement->m_ulDuration, 
                                m_pSourceElement->m_ulDelay,
                                m_pSourceElement->m_ulBeginOffsetFromSyncBase,
                                m_pID);
                    }

                m_pParser->m_pTimelineElementManager->notify(
                      (const char*)m_pSourceElement->m_pNode->m_id);
            }
          }
      }
    }

    BOOL bMoveNewlyResolvedsToPendingTimeList =
          !bWasInsertedOntoTimeline;
    if (bNeedToResolveBeginTimeListVals)
    {
      BOOL bATimeWasResolved;
      m_pSourceElement->resolveSyncArcTimeValues(
            m_pSourceElement->m_ulDelay +
            (bUseBeginOffsetForPendingBeginList?
            m_pSourceElement->m_lBeginOffset:0),
            (const char*)pEventElement->m_pID,
            SmilBeginTimeList, bATimeWasResolved,
            bMoveNewlyResolvedsToPendingTimeList,
            m_pParser);
    }
    if (bNeedToResolveEndTimeListVals)
    {
      // /Fixes PR 81828: if delay is unresolved but end time was just
      // resolved, above, then use end not the invalid sum of dur+delay:
      ULONG32 ulEndTime = m_pSourceElement->m_ulDuration +
            m_pSourceElement->m_ulDelay;
      if ((UINT32)-1 == m_pSourceElement->m_ulDelay  ||
            (UINT32)-1 == m_pSourceElement->m_ulDuration)
      {
          ulEndTime = m_pSourceElement->m_lEndOffset;
      }
      // /Helps fix PR 79699 (case where trackDurationResolved call order
      // is: flash, msd, vid):
      else if (m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase  &&
            m_pSourceElement->m_ulBeginOffsetFromSyncBase > 0)
      {
          ulEndTime -= m_pSourceElement->m_ulBeginOffsetFromSyncBase;
      }

      BOOL bATimeWasResolved;
      m_pSourceElement->resolveSyncArcTimeValues(
            // /Use dur+delay, not just delay here (as can be proven when
            // doing the following: begin="foo.end" end="foo.end+5s"
            // where foo.begin > 0:
            ulEndTime,
            (const char*)pEventElement->m_pID,
            SmilEndTimeList, bATimeWasResolved,
            bMoveNewlyResolvedsToPendingTimeList,
            m_pParser);
    }

    // XXXMEH - we need to check here if we should
    // update the remove time
    checkElementFillBehavior();
}

#if 0
void
CSmilTimelineElement::setEvent(SMILEventSourceTag eTag,
                        SMILSyncAttributeTag aTag,
                        const char* pEventSourceID,
                        UINT32 ulEventClockValue)
{
    m_eEventSourceTag = eTag;
    m_eSyncAttributeTag = aTag;
    if(pEventSourceID)
    {
      m_pEventSourceID = new char[strlen(pEventSourceID)+1];
      strcpy(m_pEventSourceID, pEventSourceID); /* Flawfinder: ignore */
      m_pParser->m_pTimelineElementManager->addNotification(pEventSourceID, this);
    }
    m_ulEventClockValue = ulEventClockValue;
}
#endif


void 
CSmilTimelineElement::addChild(CSmilTimelineElement* pChild)
{
    if(!m_pChildren)
    {
      m_pChildren = new CHXSimpleList;
    }
    m_pChildren->AddTail(pChild);
    pChild->setParent(this);
}

UINT32
CSmilTimelineElement::getDuration()
{
    return m_pSourceElement->m_ulDuration;
}

UINT32
CSmilTimelineElement::getDelay()
{
    return m_pSourceElement->m_ulDelay;
}

void 
CSmilTimelineElement::dump()
{
}

void CSmilTimelineElement::checkChildrenFillBehavior()
{
    if (m_pChildren && m_pParser)
    {
        LISTPOSITION pos = m_pChildren->GetHeadPosition();
        while (pos)
        {
            CSmilTimelineElement* pTime =
                (CSmilTimelineElement*) m_pChildren->GetNext(pos);
            if (pTime &&
                pTime->m_pSourceElement &&
                pTime->m_pSourceElement->m_pNode)
            {
                const char* pszID          = (const char*) pTime->m_pSourceElement->m_pNode->m_id;
                UINT32      ulComputedTime = 0;
                HX_RESULT   retVal         = m_pParser->computeRemoveTime(pszID, ulComputedTime);
                if (SUCCEEDED(retVal))
                {
// /#define XXXEHODGE_DEBUG_REMOVE_TIME_OF_VISUAL_ELEMENT
#if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG_REMOVE_TIME_OF_VISUAL_ELEMENT)
{
    FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", "a+");
    ::fprintf(f1, "checkChildrenFillBehavior() of %s, computed time=%lu, m_ulRemoveTime=%lu, m_ulDelay=%lu, m_ulDuration=%lu\n",
      pszID, ulComputedTime, pTime->m_pSourceElement->m_ulRemoveTime, pTime->m_pSourceElement->m_ulDelay, pTime->m_pSourceElement->m_ulDuration);
    ::fclose(f1);
}
#endif
                    // We've successfully computed the remove time - does
                    // this remove time match when we have the hide event scheduled?
                    if (ulComputedTime != pTime->m_pSourceElement->m_ulRemoveTime)
                    {
#if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG_REMOVE_TIME_OF_VISUAL_ELEMENT)
{
    FILE* f1 = ::fopen("c:\\smil2excl.txt", "a+");
    ::fprintf(f1, "\tcheckChildrenFillBehavior() called [%s]->updateRemoveTime(%lu   <--(%lu) ), m_ulDelay=%lu, m_ulDuration=%lu\n",
      pszID, ulComputedTime, pTime->m_pSourceElement->m_ulRemoveTime, pTime->m_pSourceElement->m_ulDelay, pTime->m_pSourceElement->m_ulDuration);
    ::fclose(f1);
}
#endif
                        // We need to update the hide event
                        pTime->m_pSourceElement->updateRemoveTime(ulComputedTime);
                    }
                    // If this child has a fill="freeze" or a fill="hold",
                    // then we need to check this child's children
                    if (pTime->m_pSourceElement->m_eActualFill == FillFreeze ||
                        pTime->m_pSourceElement->m_eActualFill == FillHold)
                    {
                        pTime->checkChildrenFillBehavior();
                    }
                }
            }
        }
    }
}

void CSmilTimelineElement::checkElementFillBehavior()
{
    if (m_pSourceElement &&
        m_pSourceElement->m_pNode)
    {
        const char* pszID          = (const char*) m_pSourceElement->m_pNode->m_id;
        UINT32      ulComputedTime = 0;
        HX_RESULT   retVal         = m_pParser->computeRemoveTime(pszID, ulComputedTime);
        if (SUCCEEDED(retVal))
        {
            // We've successfully computed the remove time - does
            // this remove time match when we have the hide event scheduled?
            if (ulComputedTime != m_pSourceElement->m_ulRemoveTime)
            {
//                char szDbgStr[128];
//                DEBUGPRINTF(szDbgStr, "Updating id=%s remove time from %lu to %lu\n",
//                            pszID, m_pSourceElement->m_ulRemoveTime, ulComputedTime);
                // We need to update the hide event
                m_pSourceElement->updateRemoveTime(ulComputedTime);
            }
        }
    }
}

void CSmilTimelineElement::setParExclDuration(UINT32 ulDuration, BOOL bSetFromParent)
{
    m_pSourceElement->m_ulDuration = ulDuration;
    // /Don't go past end of parent; fixes PR65741-related event-begun par
    if (m_pSourceElement->m_ulDuration > m_pSourceElement->m_ulMaxDuration)
    {
      m_pSourceElement->m_ulDuration = m_pSourceElement->m_ulMaxDuration;
    }
    m_bDurationSet = TRUE;
    if(m_pChildren  &&
          // /If not set from parent, make sure we've completely resolved
          // our duration before forcing it on the kids (broken by fix for
          // PR 61174(version1).  Fixes PR 56686 version 7:
          (bSetFromParent  ||  m_pSourceElement->m_bAddDurationAlreadyDone
          // /Explicit end or dur, so OK to possibly clip children; helps
          // reduce cases where PR 65676 occurs by setting max durs on kids:
          ||  m_pSourceElement->m_bHasExplicitEnd
          ||  m_pSourceElement->m_bHasExplicitDur))
    {
      CHXSimpleList::Iterator i = m_pChildren->Begin();
      for(; i != m_pChildren->End(); ++i)
      {
          CSmilTimelineElement* pElement = (CSmilTimelineElement*)(*i);
          pElement->setDuration(m_pSourceElement->m_ulDuration, TRUE);
        }
    }

    //[SMIL 1.0 comliance] Helps fix PR 14420 and 23025
    m_pParser->m_pTimelineElementManager->notify(m_pID);
}

void CSmilTimelineElement::setParExclMaxDuration(UINT32 ulMaxDuration)
{
    HX_ASSERT(m_pChildren);
    m_bMaxDurationSet = TRUE;
    m_pSourceElement->m_ulMaxDuration = ulMaxDuration;

    if (m_pChildren  &&  m_bDelaySet)
    {
      HX_ASSERT((UINT32)-1 != m_pSourceElement->m_ulDelay);

      CHXSimpleList::Iterator i = m_pChildren->Begin();
      for(; i != m_pChildren->End(); ++i)
      {
          CSmilTimelineElement* pElement = (CSmilTimelineElement*)(*i);
          pElement->setMaxDuration(ulMaxDuration);
      }
    }
}

void CSmilTimelineElement::parExclElementResolved(CSmilTimelineElement* pEventElement)
{
    // /Fixes PR 56233 (par version): if this par is resolving an end time
    // based on another element's timing and that other element is a
    // descendant of this par, then we'll get in an infinite loop when this
    // par clips its child's end, causing the child to update its end, causing
    // this par to get another elementResolved, ad infinitum.  Now, we lock
    // elementResolved() on this element by setting its m_bInElementResolved
    // flag and resetting it only when this method has completed:
    if (m_bInElementResolved)
    {
      goto cleanup;
    }
    m_bInElementResolved = TRUE;

    //First, let's see if we have a begin event to resolve:
    // /Combine handling of SMILEventSourceBegin and SMILEventSourceClock;
    // the latter is only used in SMIL 1.0-syntax syncArcs with clock offsets:
    if ( (m_pSourceElement->m_nBeginEventSourceTag == SMILEventSourceBegin  ||
          m_pSourceElement->m_nBeginEventSourceTag == SMILEventSourceClock)  &&
          m_pSourceElement->m_BeginEventSourceID == pEventElement->m_pID)
    {
      if(pEventElement->m_bDelaySet)
      {
          // /Note: no longer subtracting pEventElement->m_pSourceElement->
          // m_ulBeginOffsetFromSyncBase from the sum in the following
          // if/else fixes PR 66352 while allowing PR 14420 (SMIL2-excl
          // version) to still work

          //[SMIL 1.0 Compliance] Helps fix 14420:
          if (m_bNonEventDelaySet)
          {
            //Add non-event delay to syncArc element delay + clock offset:
            //Do the following in case sum is negative; if so, we
            // want to use zero.
            LONG32 lSum =
                  (LONG32)pEventElement->m_pSourceElement->m_ulDelay +
                  m_pSourceElement->m_lBeginEventClockValue;
            HX_ASSERT(lSum >= 0  &&  "ehodge: handle neg delay propogation");
            lSum = (lSum<0? 0 : lSum);  //clip off negative vals.
            m_pSourceElement->m_ulDelay = m_ulNonEventDelay + (ULONG32)lSum;
          }
          else
          {
            //Just set delay to syncArc element delay + clock offset:
            //Do the following in case sum is negative; if so, we
            // want to use zero.
            LONG32 lSum =
                  (LONG32)pEventElement->m_pSourceElement->m_ulDelay +
                  m_pSourceElement->m_lBeginEventClockValue;
            HX_ASSERT(lSum >= 0  &&  "ehodge: handle neg delay propogation");
            lSum = (lSum<0? 0 : lSum);  //clip off negative vals.
            m_pSourceElement->m_ulDelay = (ULONG32)lSum;
            m_ulNonEventDelay = 0;
          }
          m_bNonEventDelaySet = m_bDelaySet = TRUE;
          if(m_pChildren)
          {
            CHXSimpleList::Iterator i = m_pChildren->Begin();
            for(; i != m_pChildren->End(); ++i)
            {
                CSmilTimelineElement* pElement =
                      (CSmilTimelineElement*)(*i);
                pElement->setDelay(m_pSourceElement->m_ulDelay, TRUE);
            }
          }
      }
    }
    else if(m_pSourceElement->m_nBeginEventSourceTag == SMILEventSourceEnd  &&
          m_pSourceElement->m_BeginEventSourceID == pEventElement->m_pID)
    {
      // /If event element's duration is "WAY_IN_THE_FUTURE" then it's
      // essentially an unresolved end time, so we should not resolve
      // based on it:
      if(pEventElement->m_bDurationSet  &&  WAY_IN_THE_FUTURE !=
            pEventElement->m_pSourceElement->m_ulDuration)
      {
          //[SMIL 1.0 Compliance] Helps fix 14420:
          if (m_bNonEventDelaySet)
          {
            //Add non-event delay to syncArc element end + clock offset:
            LONG32 lSum =
                  (LONG32)pEventElement->m_pSourceElement->m_ulDuration +
                  (LONG32)pEventElement->m_pSourceElement->m_ulDelay +
                  m_pSourceElement->m_lBeginEventClockValue;
            HX_ASSERT(lSum >= 0  &&  "ehodge: handle neg delay propogation");
            lSum = (lSum<0? 0 : lSum);  //clip off negative vals.
            m_pSourceElement->m_ulDelay = m_ulNonEventDelay + (ULONG32)lSum;
          }
          else
          {
            //Just set delay to syncArc element end + clock offset:
            //Do the following in case sum is negative; if so, we
            // want to use zero.
            LONG32 lSum =
                  (LONG32)pEventElement->m_pSourceElement->m_ulDuration +
                  (LONG32)pEventElement->m_pSourceElement->m_ulDelay +
                  m_pSourceElement->m_lBeginEventClockValue;
            HX_ASSERT(lSum >= 0  &&  "ehodge: handle neg delay propogation");
            lSum = (lSum<0? 0 : lSum);  //clip off negative vals.
            m_pSourceElement->m_ulDelay = (ULONG32)lSum;
            m_ulNonEventDelay = 0;
          }
          m_bNonEventDelaySet = m_bDelaySet = TRUE;
          if(m_pChildren)
          {
            CHXSimpleList::Iterator i = m_pChildren->Begin();
            for(; i != m_pChildren->End(); ++i)
            {
                CSmilTimelineElement* pElement =
                      (CSmilTimelineElement*)(*i);
                pElement->setDelay(m_pSourceElement->m_ulDelay, TRUE);
            }
          }
      }
    }

    
    // /Combine handling of SMILEventSourceBegin and SMILEventSourceClock;
    // the latter is only used in SMIL 1.0-syntax syncArcs with clock offsets:
    if ( (m_pSourceElement->m_nEndEventSourceTag == SMILEventSourceBegin  ||
          m_pSourceElement->m_nEndEventSourceTag == SMILEventSourceClock)  &&
          m_pSourceElement->m_EndEventSourceID == pEventElement->m_pID)
    {
      if(pEventElement->m_bDelaySet)
      {
          LONG32 lSum =(LONG32)pEventElement->m_pSourceElement->m_ulDelay +
                m_pSourceElement->m_lEndEventClockValue;
          if (m_bDelaySet)
          {
            // /Fixes bug where the following had a dur that didn't
            // account for its offset:
            // <par begin="3s" end="foo.begin+5s" />
            lSum -= m_pSourceElement->m_ulDelay;
          }
          HX_ASSERT(lSum >= 0  &&  "ehodge: handle neg delay propogation");
          lSum = (lSum<0? 0 : lSum);  //clip off negative vals.
          // /Fixes PR 43068:
          m_bDurationSet = FALSE; // /We want to force override to lSum.
          parExclDurationResolved((ULONG32)lSum, TRUE);
      }
    }
    else if(m_pSourceElement->m_nEndEventSourceTag == SMILEventSourceEnd  &&
          m_pSourceElement->m_EndEventSourceID == pEventElement->m_pID)
    {
      // /If event element's duration is "WAY_IN_THE_FUTURE" then it's
      // essentially an unresolved end time, so we should not resolve
      // based on it:
      if(pEventElement->m_bDurationSet  &&  WAY_IN_THE_FUTURE !=
            pEventElement->m_pSourceElement->m_ulDuration)
      {
          LONG32 lSum =(LONG32)pEventElement->getDuration() +
                m_pSourceElement->m_lEndEventClockValue;
          // /If the event element has a delay, we need to add that
          // minus any beginOffset (if it's set):
          if(pEventElement->m_bDelaySet)
          {
            lSum += (LONG32)pEventElement->m_pSourceElement->m_ulDelay;
            if (pEventElement->m_pSourceElement->m_bBeginOffsetSet)
            {
                HX_ASSERT(0  &&  "ehodge: does this code work?!");
                lSum -= pEventElement->m_pSourceElement->m_lBeginOffset;
            }
          }
          if (m_bDelaySet)
          {
            // /Fixes bug where the following had a dur that didn't
            // account for its offset:
            // <par begin="3s" end="foo.end+5s" />
            lSum -= m_pSourceElement->m_ulDelay;
          }
          HX_ASSERT(lSum >= 0  &&  "ehodge: handle neg delay propogation");
          lSum = (lSum<0? 0 : lSum);  //clip off negative vals.
          // /Fixes PR 43068:
          m_bDurationSet = FALSE; // /We want to force override to lSum.
          parExclDurationResolved((ULONG32)lSum, TRUE);
      }
    }

    m_bInElementResolved = FALSE;

cleanup:
    return;
}

void CSmilTimelineElement::parExclDurationResolved(UINT32 ulDuration, BOOL bUpdateChildren)
{
#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION)
    {
      FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout?
            ADDDURATION_DEBUGOUT_STR_NEW_FILE :
            ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE );
      ::fprintf(f1, "CSmilTimelineElement{%s}::parExclDurationResolved(dur=%lu, bUpdateChildren=%d, "
            "m_bDurationSet=%sE (cur m_ulDuration=%lu) m_bAddDurationAlreadyDone=%d\n",
            (const char*)m_pID, ulDuration, bUpdateChildren, m_bDurationSet?"TRU":"FALS",
            m_pSourceElement->m_ulDuration, m_pSourceElement->m_bAddDurationAlreadyDone);
      ::fclose(f1);
      bFirstTimeAddDurDebugout = FALSE;
    }
#endif

    if(!m_bDurationSet  ||
          // /Final fix for PR 52110: we need to make sure parent and
          // dependent, if any, get told of our duration even if our
          // duration has already been set, which can happen if we have
          // an explicit end or dur.  We should go ahead and add ourself to
          // the parent if we haven't already done so:
          !m_pSourceElement->m_bAddDurationAlreadyDone)
    {
      // /(Note: if endsync="first" causes re-resolving of duration, then
      // it's perfectly valid for bUpdateChildren to be TRUE here.)

      m_bDurationSet = TRUE;
      m_pSourceElement->m_ulDuration = ulDuration;
      if(m_pParent)
      {
          ULONG32 ulDelayFromSyncBaseBegin = 0;
          if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase)
          {
            ulDelayFromSyncBaseBegin =
                  m_pSourceElement->m_ulBeginOffsetFromSyncBase;
            if (ulDelayFromSyncBaseBegin > 0  &&
                  !m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
            {
                m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase =
                      TRUE; // /=TRUE,not ULONG32. Helps fix PR 68190.
                m_pSourceElement->m_ulDuration += ulDelayFromSyncBaseBegin;
            }
          }
          m_pParent->addDuration(m_pSourceElement->m_ulDuration,
                m_pSourceElement->m_ulDelay,
                ulDelayFromSyncBaseBegin, m_pID);
          m_pSourceElement->m_bAddDurationAlreadyDone = TRUE;
      }
      if(m_pDependent)
      {
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
          ULONG32 ulTotalDelay = 0;
          if (HXR_OK !=
                m_pSourceElement->getCurrentScheduledStopTime(ulTotalDelay))
          {
            goto doneSettingDependent;
          }
#else
          ULONG32 ulTotalDelay = m_pSourceElement->m_ulDelay +
                m_pSourceElement->m_ulDuration;
          // /Helps fix PR 6XXXX(par version): if delay is already packed
          // into the duration, then don't count it twice (as can happen in
          // <seq><par begin="1s">...</par><par begin="1s" ...):
          if (m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
          {
            HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1);
/*OK[]*/          if (m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1)
            {
                HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                      ulTotalDelay);
                if (m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                      ulTotalDelay)
                {
                  ulTotalDelay -=
                        m_pSourceElement->m_ulBeginOffsetFromSyncBase;
                }
            }
          }
#endif

          if (WAY_IN_THE_FUTURE < ulTotalDelay)
          {
            ulTotalDelay = WAY_IN_THE_FUTURE; // /For PR 59584 (par2).
          }
          // /helps fix PR 62688 (case2) where outer seq has media after
          // par w/endsync="all": don't adjustDep.Dur. if delay is indef.:
          if ((m_pDependent->getDelay() != (UINT32)-1  &&
                m_pDependent->getDelay() >= WAY_IN_THE_FUTURE)  ||
                // /Helps fix PR 59584 (parFollowsPar version): also don't
                // adjustDep.Dur. if we're about to set the delay to indef
                (m_pDependent->getDelay() == (UINT32)-1  &&
                WAY_IN_THE_FUTURE == ulTotalDelay) )
          {
            HX_ASSERT(ulTotalDelay==WAY_IN_THE_FUTURE  &&  "send content to ehodge");
          }
          else
          {
            adjustDependentDuration(m_pDependent);
          }

#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION)
{
    FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout?
          ADDDURATION_DEBUGOUT_STR_NEW_FILE :
          ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE );
    ::fprintf(f1, "\n\t%s:CSmilTimelineElement::parExclDurationResolved();\tsetting dependent (%s)'s delay to %lu\n",
          (const char*)m_pID, (const char*)m_pDependent->m_pID, ulTotalDelay);
    ::fclose(f1);
    bFirstTimeAddDurDebugout = FALSE;
}
#endif
          // /XXXEH- TODO: figure out if we need to claim this is being set
          // by "parent" (which is really time base) so clip-begin-like
          // action can occur; I don't think so, however:
          m_pDependent->setDelay(ulTotalDelay, FALSE);          
      }
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
doneSettingDependent:
#endif

      if(bUpdateChildren)
      {
          UINT32 ulNumChildrenDursSet = 0;
          CHXSimpleList::Iterator i = m_pChildren->Begin();
          for(; i != m_pChildren->End(); ++i)
          {
            CSmilTimelineElement* pElement = (CSmilTimelineElement*)(*i);
            // /If child has no resolved, scheduled begin time yet, then
            // for crying out loud don't set its duration yet.  This is
            // needed in the case where *this has endsync="all":
            if (SMILEventSourceAll !=
                  m_pSourceElement->m_nEndsyncEventSourceTag  ||
                  pElement->m_pSourceElement->m_bInsertedIntoTimeline)
            {
                ulNumChildrenDursSet++;
                // /Don't set the child's duration unless the new duration
                // is less than the child's existing duration; the SMIL
                // spec says that a parent element can not extend the
                // duration of a child; fixes PR 50572:
                if (pElement->m_pSourceElement  &&  ( (UINT32)-1 ==
                      pElement->m_pSourceElement->m_ulDuration  ||
                      pElement->m_pSourceElement->m_ulDuration >
                      m_pSourceElement->m_ulDuration) )
                {
                  pElement->setDuration(m_pSourceElement->m_ulDuration,
                        TRUE);
                }
            }
          }
      }
    }
    // Check our children's fill behavior
    checkChildrenFillBehavior();
    //[SMIL 1.0 Compliance] Helps fix PR 14420 and 23025:
    // if a source has event-based timing based on this seq's
    // begin time (delay) then we need to notify that source
    // that we've resolved this value:
    m_pParser->m_pTimelineElementManager->notify(m_pID);
}

/***************************************************************************/

/*
 * CSmilTimelinePar methods
 */

CSmilTimelinePar::CSmilTimelinePar(CSmilElement* pSourceElement,
                           CSmilParser* pParser):
    CSmilTimelineElement(pSourceElement, pParser),
    m_nDurationAdded(0),
    m_ulFirstDuration(0),
    m_bFirstDurationHasBeenSet(FALSE),
    m_ulLastDuration(0)
{
}

CSmilTimelinePar::~CSmilTimelinePar()
{
}

void 
CSmilTimelinePar::setDelay(UINT32 ulDelay,
         // /NOTE: we ignore this in time containers that aren't media:
         BOOL bSetByParent)
{
#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION)
    {
      FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout?
            ADDDURATION_DEBUGOUT_STR_NEW_FILE :
            ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE );
      ::fprintf(f1, "CSmilTimelinePar{%s}::setDelay(delay=%lu, "
            "bSetByParent=%sE) m_bDelaySet=%sE, beginOffset=%lu\n",
            (const char*)m_pID, ulDelay,
            bSetByParent?"TRU":"FALS",
            m_bDelaySet?"TRU":"FALS", m_pSourceElement->m_lBeginOffset);
      ::fclose(f1);
      bFirstTimeAddDurDebugout = FALSE;
    }
#endif

    if(m_pSourceElement->m_bBeginOffsetSet)
    {
      m_pSourceElement->m_ulDelay = (
            ((INT32)ulDelay+m_pSourceElement->m_lBeginOffset > 0) ?
            (UINT32)((INT32)ulDelay+m_pSourceElement->m_lBeginOffset):0);
    }
    else
    {
      m_pSourceElement->m_ulDelay = ulDelay;
    }
    if (!m_bDelayEvent) //[SMIL 1.0 compliance] helps fix PR 14420.
    {
      m_bDelaySet = TRUE;
      ULONG32 ulNumChildrenWithNonEventBasedBegins = 0;
      if(m_pChildren)
      {
          CHXSimpleList::Iterator i = m_pChildren->Begin();
          for(; i != m_pChildren->End(); ++i)
          {
            CSmilTimelineElement* pElement = (CSmilTimelineElement*)(*i);
            pElement->setDelay(m_pSourceElement->m_ulDelay, TRUE);
            if (pElement->m_pSourceElement  &&  pElement->m_pSourceElement->
                  m_bHasAtLeastOneNonEventBasedBegin)
            {
                ulNumChildrenWithNonEventBasedBegins++;
            }
          }
      }
      // /Fixes PR 24046 (SMIL 2+ par version): if there are no children,
      // then the par's duration is zero, so set it to 0:
      if ((!m_pChildren  &&  m_pSourceElement->m_ulDuration == (UINT32)-1)  ||
            0 == ulNumChildrenWithNonEventBasedBegins)
      {
          // /Checking 1st for explicit end or dur re-fixes PR 57150(par)
          // which was broken by fix for PR 24046 (note: PR 57150 has dur=x
          // *and* endsync="all" which is a strange thing to author):
          if (!m_pSourceElement->m_bHasExplicitDur  &&
                !m_pSourceElement->m_bHasExplicitEnd)
          {
            m_pSourceElement->m_ulDuration = 0;
          }
          // /Helps fix PR 62688(par version): if all children are
          // event-begun and there is at least one child, and endsycn="all",
          // then we have an indefinite duration until all child ends resolve:
          if (m_pChildren  &&  SMILEventSourceAll ==
                m_pSourceElement->m_nEndsyncEventSourceTag  &&
                // /Ignore endsync if it has explicit end or dur:
                !m_pSourceElement->m_bHasExplicitDur  &&
                !m_pSourceElement->m_bHasExplicitEnd)
          {
            m_pSourceElement->m_ulDuration = WAY_IN_THE_FUTURE;
          }
      }

      if (m_pSourceElement->m_ulDuration != (UINT32)-1)
      {
          setDuration(m_pSourceElement->m_ulDuration);
#if 0 //20011024-0
          // /Fixes PR 61174(version1) and par version of PR 56686
          // (version1): we know our duration already, so let's declare it
          // resolved so we get added to our parent (in case none of our
          // children have scheduled begin times in which case our
          // ::addDuration() would not get called up front and the overall
          // presentation would not include our duration at first):
          if (m_pSourceElement->m_bHasExplicitDur  ||
                m_pSourceElement->m_bHasExplicitEnd  ||
                // /For PR 62688(par version) and other endsync="all" bugs:
                SMILEventSourceAll ==
                m_pSourceElement->m_nEndsyncEventSourceTag)
          {
            // /Be sure not to override a shorter duration that may have
            // been imposed on us by our parent:
            if (!m_bDurationSet  ||
                  !m_pSourceElement->m_bAddDurationAlreadyDone)
            {
                HX_ASSERT((UINT32)-1 != m_pSourceElement->m_ulDelay);
                durationResolved(m_pSourceElement->m_ulDuration, FALSE);
            }
            HX_ASSERT(m_bDurationSet  &&  m_pSourceElement->m_bAddDurationAlreadyDone);
          }
#else /* At least fix it for endsync="all":*/
          // /Fixes PR 61174(version1) and par version of PR 56686
          // (version1): we know our duration already, so let's declare it
          // resolved so we get added to our parent (in case none of our
          // children have scheduled begin times in which case our
          // ::addDuration() would not get called up front and the overall
          // presentation would not include our duration at first):
          if ((!m_pSourceElement->m_bHasExplicitDur  &&
                !m_pSourceElement->m_bHasExplicitEnd)  &&
                // /For PR 62688(par version) and other endsync="all" bugs:
                SMILEventSourceAll ==
                m_pSourceElement->m_nEndsyncEventSourceTag)
          {
            // /Be sure not to override a shorter duration that may have
            // been imposed on us by our parent:
            if (!m_bDurationSet  ||
                  !m_pSourceElement->m_bAddDurationAlreadyDone)
            {
                HX_ASSERT((UINT32)-1 != m_pSourceElement->m_ulDelay);
                HX_ASSERT(m_pSourceElement->m_ulDuration ==
                      m_pSourceElement->getPureDuration());
                durationResolved(m_pSourceElement->m_ulDuration, FALSE);
            }
            HX_ASSERT(m_bDurationSet  &&  m_pSourceElement->m_bAddDurationAlreadyDone);
          }
#endif
      }
    }
    else //[SMIL 1.0 compliance] for PR 14420:
      // let's not claim that the delay is set when we still
      // are awaiting a delay (begin) event; we *do* need to
      // add the delay of this to the event's begin offset.
      // This is done by setting the new "m_bNonEventDelaySet"
      // variable to TRUE and leaving m_bDelaySet to FALSE
      // until the ElementResolved() call sets it to true:
    {
      //Parent calls setDelay before we get to ElementResolved,
      // thus m_bDelaySet should never be TRUE if we have a
      // delay event:
      HX_ASSERT(!m_bDelaySet);
      m_bNonEventDelaySet = TRUE; //ElementResolved will look at this.
      m_ulNonEventDelay = ulDelay;
    }
    
    if(m_pDependent  &&  m_bDurationSet)
    {
      adjustDependentDuration(m_pDependent);

#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
      ULONG32 ulTotalDelay = 0;
      if (HXR_OK !=
            m_pSourceElement->getCurrentScheduledStopTime(ulTotalDelay))
      {
          goto doneSettingDependent;
      }
#else
      ULONG32 ulTotalDelay = m_pSourceElement->m_ulDelay +
            m_pSourceElement->m_ulDuration;
      // /Helps fix PR 6XXXX(par version): if delay is already packed
      // into the duration, then don't count it twice (as can happen in
      // <seq><par begin="1s">...</par><par begin="1s" ...):
      if (m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
      {
          HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1);
/*OK[]*/        if (m_pSourceElement->m_ulBeginOffsetFromSyncBase !=(UINT32)-1)
          {
            HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                  ulTotalDelay);
            if (m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                  ulTotalDelay)
            {
                ulTotalDelay -=
                      m_pSourceElement->m_ulBeginOffsetFromSyncBase;
            }
          }
      }
#endif

      if (WAY_IN_THE_FUTURE < ulTotalDelay)
      {
          HX_ASSERT(WAY_IN_THE_FUTURE == ulTotalDelay  &&  "PR 59584");
          ulTotalDelay = WAY_IN_THE_FUTURE; // /For PR 59584.
      }

#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION) 
{ 
    FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout? 
          ADDDURATION_DEBUGOUT_STR_NEW_FILE : 
          ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE ); 
    ::fprintf(f1, "\n\t%s:CSmilTimelinePar::setDelay(%lu): to %lu;"
          "\tsetting dependent (%s)'s delay to %lu\n", (const char*)m_pID,
          ulDelay, m_pSourceElement->m_ulDelay,
          (const char*)m_pDependent->m_pID, ulTotalDelay);
    ::fclose(f1); 
    bFirstTimeAddDurDebugout = FALSE; 
} 
#endif 
 
      // /XXXEH- TODO: figure out if we need to claim this is being set by
      // "parent" (which is really time base) so clip-begin-like action can
      // occur; I don't think so, however:
      m_pDependent->setDelay(ulTotalDelay, FALSE);
    }
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
doneSettingDependent:
#endif

    //[SMIL 1.0 comliance] Helps fix PR 14420 and 23025:
    m_pParser->m_pTimelineElementManager->notify(m_pID);
}

void
CSmilTimelinePar::setDuration(UINT32 ulDuration, BOOL bSetFromParent,
                          BOOL bDurationExtendingDueToPause)
{
    if (bDurationExtendingDueToPause)
    {
      // /Need to handle this case:
      HX_ASSERT(!bDurationExtendingDueToPause);
    }
    setParExclDuration(ulDuration, bSetFromParent);
}

void
CSmilTimelinePar::setMaxDuration(UINT32 ulMaxDuration)
{
    setParExclMaxDuration(ulMaxDuration);
}

void 
CSmilTimelinePar::resetDelay(UINT32 ulDelay)
{
    INT32 lAdjustedDelay = 0;

    UINT32 ulPriorDelay = m_pSourceElement->m_ulDelay;

    if(m_pSourceElement->m_bBeginOffsetSet)
    {
      lAdjustedDelay = (INT32)ulDelay + m_pSourceElement->m_lBeginOffset;
      m_pSourceElement->m_ulDelay = lAdjustedDelay > 0?lAdjustedDelay:0;
    }
    else
    {
      m_pSourceElement->m_ulDelay = ulDelay;
    }

    if(m_pChildren)
    {
      CHXSimpleList::Iterator i = m_pChildren->Begin();
      for(; i != m_pChildren->End(); ++i)
      {
          CSmilTimelineElement* pElement = (CSmilTimelineElement*)(*i);
          pElement->resetDelay(m_pSourceElement->m_ulDelay);
      }
    }

    // /To fix PR 59851, we need to update our next-in-seq (m_pDependent) as
    // well as make sure sync-arc listeners know we've changed our overall
    // time bounds delay as well;
    if (m_pDependent && m_bDurationSet  &&
          ulPriorDelay != m_pSourceElement->m_ulDelay)
    {
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
      ULONG32 ulTotalDelay = 0;
        if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase  &&
            m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
      {
          HX_ASSERT(0  &&  "ehodge: CHANGE NOT TESTED!");
      }

      if (HXR_OK !=
            m_pSourceElement->getCurrentScheduledStopTime(ulTotalDelay))
      {
          goto doneSettingDependent;
      }
#else
      ULONG32 ulTotalDelay = m_pSourceElement->m_ulDelay +
            m_pSourceElement->m_ulDuration;
      // /Helps fix PR 6XXXX(media version): if delay is already packed
      // into the duration, then don't count it twice (as can happen in
      // <seq><ref begin="1s" .../><ref begin="1s" .../>...):
      if (m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
      {
          HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1);
/*OK[]*/        if (m_pSourceElement->m_ulBeginOffsetFromSyncBase !=(UINT32)-1)
          {
            HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                  ulTotalDelay);
            if (m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                  ulTotalDelay)
            {
                ulTotalDelay -=
                      m_pSourceElement->m_ulBeginOffsetFromSyncBase;
            }
          }
      }
#endif

      if (WAY_IN_THE_FUTURE < ulTotalDelay)
      {
          HX_ASSERT(WAY_IN_THE_FUTURE == ulTotalDelay  &&  "PR 59584");
          ulTotalDelay = WAY_IN_THE_FUTURE; // /For PR 59584.
      }
 
#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION) 
{ 
    FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout? 
          ADDDURATION_DEBUGOUT_STR_NEW_FILE : 
          ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE ); 
    ::fprintf(f1, "\n\t%s:CSmilTimelinePar::resetDelay(%lu):from %lu to %lu;"
          "\tresetting dependent (%s)'s delay to %lu\n", (const char*)m_pID,
          ulDelay, ulPriorDelay, m_pSourceElement->m_ulDelay,
          (const char*)m_pDependent->m_pID, ulTotalDelay);
    ::fclose(f1); 
    bFirstTimeAddDurDebugout = FALSE; 
} 
#endif 
 
      m_pDependent->resetDelay(ulTotalDelay);
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
doneSettingDependent:
#endif

      // /(Added while fixing PR 59851) Let others know our begin time changed:
      m_pParser->m_pTimelineElementManager->notify(m_pID);
    }
}

void 
CSmilTimelinePar::adjustDuration()
{
    BOOL    bReset = FALSE;
    UINT32  ulDuration = 0;
    BOOL    bDurationSet = FALSE;
    BOOL    bEndsyncIdDurationFound = FALSE; // /For endsync="[Some ID]"
    // /Need this for fixing PR 50676 part 6:
    ULONG32 ulPriorPureDuration = m_pSourceElement->getPureDuration();

    if (!m_bDurationSet)
    {
      goto cleanup;
    }

    if(m_pChildren)
    {
      CHXSimpleList::Iterator i = m_pChildren->Begin();
      for(; i != m_pChildren->End(); ++i)
      {
          CSmilTimelineElement* pElement = (CSmilTimelineElement*)(*i);

          // /Checking this fixes PR 69290: if child duration wasn't set,
          // then for crying out loud don't use it here:
          if (!pElement->m_bDurationSet)
          {
            continue;
          }
          HX_ASSERT((UINT32)-1 != pElement->m_pSourceElement->m_ulDuration);

          // /Make sure we take endsync into account here; doing so helps fix
          // PR 50679 (and probably other bugs):
          if (SMILEventSourceFirst == m_pSourceElement->m_nEndsyncEventSourceTag)
          {
            if (!bDurationSet)
            {
                ulDuration = pElement->m_pSourceElement->m_ulDuration;
            }
            else
            {
                ulDuration = (ulDuration < pElement->m_pSourceElement->m_ulDuration) ?
                      ulDuration : pElement->m_pSourceElement->m_ulDuration;
            }
            bDurationSet = TRUE;
          }
          else if (SMILEventSourceID == m_pSourceElement->m_nEndsyncEventSourceTag)
          {
            if (pElement->m_pSourceElement->m_pNode  &&
                  m_pSourceElement->m_EndsyncEventSourceID ==
                  pElement->m_pSourceElement->m_pNode->m_id)
            {
                ulDuration = pElement->m_pSourceElement->m_ulDuration;
                bEndsyncIdDurationFound = TRUE;
                bDurationSet = TRUE;
            }
          }
          // /This else-if block fixes problem in PR 62688 repro case where
          // restarting a child, prior to all children playing, caused excl
          // to resolve its dur as if it were endsync="last":
          else if (SMILEventSourceAll ==
                m_pSourceElement->m_nEndsyncEventSourceTag)
          {
            if (m_pChildren  &&
                  m_nDurationAdded >= m_pChildren->GetCount())
            {
                ulDuration = (ulDuration > pElement->m_pSourceElement->m_ulDuration) ?
                      ulDuration : pElement->m_pSourceElement->m_ulDuration;
                bDurationSet = TRUE;
            }
            else
            {
                // /Don't adjust duration until all child durs are in:
                goto cleanup;
            }
          }
          else // /For "last", use the largest child duration:
          {
            ulDuration = (ulDuration > pElement->m_pSourceElement->m_ulDuration) ?
                  ulDuration : pElement->m_pSourceElement->m_ulDuration;
            bDurationSet = TRUE;
          }

          // /Fixes PR 50806 (original par version, INTEROP Timing #23.6 as
          // well as par version 2 (endsync="last")): if this has a "min"
          // attribute set, ulDuration shouldn't be less regardless of endSync:
          if (m_pSourceElement->m_ulMinActiveDur > ulDuration)
          {
            ulDuration = m_pSourceElement->m_ulMinActiveDur;
          }
      }

      // /!bDurationSet happens in PR 50588 (case 2: begin="x.end"), when
      // child has begun playing but has not yet resolved its duration:
      if (!bDurationSet)
      {
          goto cleanup;
      }

      if (SMILEventSourceID == m_pSourceElement->m_nEndsyncEventSourceTag)
      {
          if (!bEndsyncIdDurationFound)
          {
            goto cleanup; // /That id'd child not added to timeline yet.
          }
      }
//check m_ulAuthoredDur here:
      if (!m_pSourceElement->m_bHasExplicitEnd  &&
            !m_pSourceElement->m_bHasExplicitDur)
      {
          m_pSourceElement->m_ulDuration = ulDuration;
      }
    
      // /Moved this out of the above if() so it gets called every time, to
      // fix PR 6XXX? and re-fix PR 55117: we should always give our parents
      // a chance to set the outer-time-container duration so it can (re)-
      // state to the core what the group duration should be:
      if(m_pParent)
      {
          m_pParent->adjustDuration();
      }

      // /Moved this out to happen all the time, too:
      if (m_pDependent)
      {
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
          ULONG32 ulTotalDelay = 0;
          if (HXR_OK !=
                m_pSourceElement->getCurrentScheduledStopTime(ulTotalDelay))
          {
            goto doneSettingDependent;
          }
#else
          ULONG32 ulTotalDelay = m_pSourceElement->m_ulDelay +
                m_pSourceElement->m_ulDuration;
          if (m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
          {
            HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1);
/*OK[]*/                if (m_pSourceElement->m_ulBeginOffsetFromSyncBase !=(UINT32)-1)
            {
                HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                      ulTotalDelay);
                if (m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                      ulTotalDelay)
                {
                  ulTotalDelay -=
                        m_pSourceElement->m_ulBeginOffsetFromSyncBase;
                }
            }
          }
#endif
          if (WAY_IN_THE_FUTURE < ulTotalDelay)
          {
            // /XXXEH- If delay is greater than this, I want to know:
            HX_ASSERT(WAY_IN_THE_FUTURE == ulTotalDelay);
            ulTotalDelay = WAY_IN_THE_FUTURE; // /For PR 59584.
          }

#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION)
{
    FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout?
          ADDDURATION_DEBUGOUT_STR_NEW_FILE :
          ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE );
    ::fprintf(f1, "\n\t%s:CSmilTimelinePar::adjustDuration();\tresetting dependent (%s)'s delay to %lu\n",
          (const char*)m_pID, (const char*)m_pDependent->m_pID, ulTotalDelay);
    ::fclose(f1);
    bFirstTimeAddDurDebugout = FALSE;
}
#endif
          m_pDependent->resetDelay(ulTotalDelay);
      }
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
doneSettingDependent:
      ;
#endif

    }

    // /Fixes PR 69410 (with outer par): do this no matter what, even if
    // prior < ulDur; resumed element in excl descendant should extend that
    // excl but we've already told the core to limit the presentation
    // duration, so extend it here as needed:
    // /Helps fix PR 50676 part 6: if our duration got reduced, we need to
    // possibly constrain our children:
    {
      // /For PR 62688 & PR 59584: remove check for ulPriorDuration being
      // WAY_IN_THE_FUTURE since PR 50676 works without it and there are
      // cases where our dur may re-resolve, & updating children is needed.

      // /For PR 59584: the group's outer time container needs to set the
      // duration if its dur is longer than its group's so far:
      if (m_pSourceElement->m_pNode  &&  m_pSourceElement->m_pHandler)
      {
          if (m_pSourceElement->m_pNode->m_pParent  &&  (SMILBody == 
                m_pSourceElement->m_pNode->m_pParent->m_tag  ||
                m_pSourceElement->m_pNode->
                m_pParent->m_bIsOuterWrapperTimeContainer) )
          {
            BOOL bDoResolveGroupDur = TRUE;
            UINT32 ulGroup = m_pSourceElement->m_pNode->m_nGroup;
            if (m_pSourceElement->m_pNode->m_bIsOuterWrapperTimeContainer)
            {
                ulGroup = 0;
                // /If we're outer wrapper around multiple groups
                // (or "clips"), then let each group outer time container
                // resolve its group duration:
                if (m_pChildren->GetCount() > 1)
                {
                  bDoResolveGroupDur = FALSE;
                }
            }
            if (bDoResolveGroupDur)
            {
                // /The group duration should be the duration of this
                // outer-most time container:
                HX_RESULT pnrs = m_pSourceElement->m_pHandler->
                      resolveGroupDurToOuterTimeContainerDur(
                      ulGroup, m_pSourceElement->m_ulDuration);
            }
          }
      }
      if(m_pChildren)
      {
          // /Accounting for begin offset of this helps fix PR 65741(par)
          // where excl w/begin="5s' was including that 5s in dur passed
          // to children, thus children were playing 5s too long:
          ULONG32 ulSyncBaseDurationForChildren =
                m_pSourceElement->m_ulDuration;
          if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase  &&
                m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
          {
            HX_ASSERT(ulSyncBaseDurationForChildren >=
                  m_pSourceElement->m_ulBeginOffsetFromSyncBase);
            if (ulSyncBaseDurationForChildren >=
                  m_pSourceElement->m_ulBeginOffsetFromSyncBase)
            {
                ulSyncBaseDurationForChildren -=
                      m_pSourceElement->m_ulBeginOffsetFromSyncBase;
            }
          }

          CHXSimpleList::Iterator i = m_pChildren->Begin();
          for(; i != m_pChildren->End(); ++i)
          {
            CSmilTimelineElement* pElement = (CSmilTimelineElement*)(*i);
            if (pElement->m_pSourceElement  &&
                  pElement->m_pSourceElement->m_ulDuration >
                  m_pSourceElement->m_ulDuration)
            {
                pElement->setDuration(ulSyncBaseDurationForChildren, TRUE);
            }
          }
      }
    }

cleanup:

    m_pParser->m_pTimelineElementManager->notify(m_pID);

    return;
}

void 
CSmilTimelinePar::addDuration(UINT32 ulDuration,
                        UINT32 ulDelay,
                        UINT32 ulChildDelayBeyondStartOfThis, 
                        const char* pElementID)
{
    BOOL bHandled = FALSE;

    UINT32 ulPriorPureDuration = m_pSourceElement->getPureDuration();

#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION)
    {
      FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout?
            ADDDURATION_DEBUGOUT_STR_NEW_FILE :
            ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE );
      ::fprintf(f1, "CSmilTimelinePar{%s}::addDuration(dur=%lu, delay=%lu, "
            "childDelayBeyondThis=%lu, id=%s) m_bDurationSet=%sE\n",
            (const char*)m_pID, ulDuration, ulDelay,
            ulChildDelayBeyondStartOfThis, pElementID,
            m_bDurationSet?"TRU":"FALS");
      ::fclose(f1);
      bFirstTimeAddDurDebugout = FALSE;
    }
#endif

    // /If we're inside a seq, our true "sync base" is not the seq but rather
    // the prievious seq sibling (if any).  We need to adjust the ulDelay, if
    // we're in a seq, down to just ulChildDelayBeyondStartOfThis, which is
    // the delay from the prior sibling, not from the seq:
    ULONG32 ulDelayBeyondSyncBase = 0;
    SMILNode* pSyncBaseNode = NULL;
    if (m_pSourceElement->m_pNode)
    {
      pSyncBaseNode = m_pParser->getSyncAncestor(
          m_pSourceElement->m_pNode);
    }
    if (!pSyncBaseNode  ||  !pSyncBaseNode->m_pElement)
    {
      HX_ASSERT(pSyncBaseNode  &&  pSyncBaseNode->m_pElement);
    }
    // /Do this for all time containers (for part of PR52110 post-fix-delay-
    // offset-bug):
    else
    {
      ulDelayBeyondSyncBase = ulChildDelayBeyondStartOfThis;
    }

    BOOL bSetChildCurEndClippedByParent = FALSE;
    BOOL bSetCompletelyRemovedFromTimeline = FALSE;
    BOOL bIsCurChildsFirstAddDuration = FALSE;
    ULONG32 ulCurChildPriorAddedDuration = (UINT32)-1;
    if (!(*m_pChildDurAddedMap)[pElementID])
    {
      bIsCurChildsFirstAddDuration = TRUE;
    }
    else
    {
      ulCurChildPriorAddedDuration =
            (ULONG32)((*m_pChildDurAddedMap)[pElementID]);
    }

    ULONG32 ulActualDurBeyondSyncBase =
          ulDuration + ulDelayBeyondSyncBase - ulChildDelayBeyondStartOfThis;

// /XXXEH-20020106-test:    HX_ASSERT(WAY_IN_THE_FUTURE >= ulActualDurBeyondSyncBase);

    // /Start of fix for PR 55117: explicit dur or end on par should not be
    // overridden by some punk child's dur; if this has an explicit
    // end or dur, don't do anything to its duration based on children durs:
    // /XXXEH- TODO: determine what wins between endsync VS either end or dur
    // if both are specified; here, I assume end|dur wins over endsync:
    if (m_pSourceElement->m_bHasExplicitDur  ||
          m_pSourceElement->m_bHasExplicitEnd)
    {
      if ((UINT32)-1 != m_pSourceElement->m_ulDuration  &&
            (!m_bDurationSet  ||
            !m_pSourceElement->m_bAddDurationAlreadyDone) )
      {
          HX_ASSERT((UINT32)-1 != m_pSourceElement->m_ulDelay);
          HX_ASSERT(m_pSourceElement->m_ulDuration ==
                m_pSourceElement->getPureDuration());
          durationResolved(m_pSourceElement->m_ulDuration, FALSE);
      }
      // /Helps fix PR 6XXXZ (PR 55117 revisited): par in seq where par has explicit dur and
      // children all have smaller durations, we need to give outer time
      // container a chance to hold the presentation open; this is needed
      // when this par is last one in presentation.  (Note: body doesn't set
      // the presentation time during createElements() phase because it
      // doesn't have m_pHandler yet then):
      adjustDuration();
      bHandled = TRUE;
    }
    // /Fixes SMIL 1.0's endsync="id(xyz)" and enables SMIL 2.0's
    // id-based endsync: endsync="xyz":
    else if (m_pSourceElement->m_nEndsyncEventSourceTag == SMILEventSourceID)
    {
      if (!m_pSourceElement->m_EndsyncEventSourceID.IsEmpty()  &&
              !strcmp(m_pSourceElement->m_EndsyncEventSourceID,pElementID))
      {
          HX_ASSERT(m_pSourceElement->m_ulDuration ==
                m_pSourceElement->getPureDuration());
          // /Don't just use ulDuration in case child has a begin offset
          // or otherwise has a delay beyond this's delay.
          m_pSourceElement->m_ulDuration = ulActualDurBeyondSyncBase;
          durationResolved(m_pSourceElement->m_ulDuration, TRUE);
          bHandled = TRUE;
      }
      // /Fixes endsync="[ID]" part of PR 59584 where addDuration of X (!=ID)
      // happens after that of lower-duration [ID] sibling and 'X' needs to
      // be restricted to ID's duration:
      else if (!m_pSourceElement->m_EndsyncEventSourceID.IsEmpty()  &&
              m_pSourceElement->m_ulDuration < ulActualDurBeyondSyncBase)
      {
          // /Adjust for offset from parent, if any:
          bSetChildCurEndClippedByParent = TRUE;
          if (m_pSourceElement->m_ulDuration >
                ulChildDelayBeyondStartOfThis)
          {
            m_pParser->resetTimelineElementDuration(pElementID,
                  m_pSourceElement->getPureDuration(),
                  // /Changed to *child* prior dur while fixing PR 66391:
                  ulActualDurBeyondSyncBase -
                  ulChildDelayBeyondStartOfThis);
            m_pParser->m_pTimelineElementManager->notify(pElementID);
          }
          else // /Begin offset is beyond parent's end, so remove it:
          // /Fixes PR 64158 (endsync="[ID]" version)
          {
            bSetCompletelyRemovedFromTimeline = TRUE;
            HX_RESULT retval2 = m_pSourceElement->m_pHandler->
                  handleTrackRemoval((const char*)pElementID,
                  (INT32)m_pSourceElement->m_pNode->m_nGroup);
          }
      }
    }
    else if(m_pSourceElement->m_nEndsyncEventSourceTag == SMILEventSourceAll)
    {
      // /Hold par open until all children have had a chance to begin;
      // leave the par's duration unresolved awaiting the final child's
      // call to "addDuration" (which may never come if child's begin
      // never resolves):

      // /Helps fix PR 62688(par version): first, check if all children
      // have resolved already; if so, then duration is set so we can't
      // extend it if begin is after parent par ended:
      if (m_nDurationAdded >= m_pChildren->GetCount()  &&
            m_pSourceElement->m_ulDuration < ulActualDurBeyondSyncBase)
      {
          bSetChildCurEndClippedByParent = TRUE;
          HX_ASSERT(m_ulLastDuration == m_pSourceElement->m_ulDuration);
          if (m_ulLastDuration > ulChildDelayBeyondStartOfThis)
          {
            // /Helps fix PR 50660 by removing PR 62688-fix code here that
            // turned out to be unnecessary since code elsewhere completely
            // fixes PR 62688.  Child should be allowed to extend its
            // parent's duration except if it begins *after* its parent has
            // already ended, which is how we got here, so do nothing.
          }
          else // /Begin offset is beyond parent's end, so remove it:
          // helps fix PR 62688(par) (endsync="all" version of PR 64158)
          {
            bSetCompletelyRemovedFromTimeline = TRUE;
            HX_RESULT retval2 = m_pSourceElement->m_pHandler->
                  handleTrackRemoval((const char*)pElementID,
                  (INT32)m_pSourceElement->m_pNode->m_nGroup);
          }
      }

      if(ulActualDurBeyondSyncBase < m_ulFirstDuration  ||
            !m_bFirstDurationHasBeenSet)
      {
          m_ulFirstDuration = ulActualDurBeyondSyncBase;
          m_bFirstDurationHasBeenSet = TRUE;
      }
      if(ulActualDurBeyondSyncBase > m_ulLastDuration)
      {
          m_ulLastDuration = ulActualDurBeyondSyncBase;
      }
      // /This helps fix PR 62688(par version): this is used to see if
      // we've already resolved our duration (because all children have
      // weighed in):
      INT32 lTotalDurationsAddedIncludingThisOne = (INT32)m_nDurationAdded;
      if (bIsCurChildsFirstAddDuration)
      {
          lTotalDurationsAddedIncludingThisOne++;
      }
      if (lTotalDurationsAddedIncludingThisOne < m_pChildren->GetCount()  &&
            // /To help fix PR 59584(par version), only do this once:
            WAY_IN_THE_FUTURE != m_pSourceElement->m_ulDuration)
      {
          // /XXXEH- need a better way, but for now let's say it's
          // resolved to a very big number until all children have
          // resolved begins:
          durationResolved(WAY_IN_THE_FUTURE, TRUE);
      }
    }
    else if(m_pSourceElement->m_ulDuration == (UINT32)-1)
    {
      // /Added delay to duration which works in:
      // "BUG-20010430_endHappening2sTooEarlyForExclThatHas"...
      // ..."2.7sBeginAndDurBasedOnChild(totalPresentationDur5.7s).smil":
      m_pSourceElement->m_ulDuration = ulDuration + ulDelayBeyondSyncBase -
            // /Added this to fix when par child of seq has child w/begin
            // offset, as in the following smil file:
            // "BUG-20010501_(broke20010501earlyAMCheckin)beginOnFirst"...
            ulChildDelayBeyondStartOfThis;

      m_ulFirstDuration = ulActualDurBeyondSyncBase;
      m_bFirstDurationHasBeenSet = TRUE;
      m_ulLastDuration = ulActualDurBeyondSyncBase;
    }
    else
    {
      m_pSourceElement->m_ulDuration = 
          (ulActualDurBeyondSyncBase > m_pSourceElement->m_ulDuration) ?
          ulActualDurBeyondSyncBase : m_pSourceElement->m_ulDuration;
      if(ulActualDurBeyondSyncBase < m_ulFirstDuration  ||
            // /Fixes several PRs related to endsync="first"; m_ulFirstDuration
            // gets init'd to 0, so we need to see if it's been set or not:
            !m_bFirstDurationHasBeenSet)
      {
          m_ulFirstDuration = ulActualDurBeyondSyncBase;
          m_bFirstDurationHasBeenSet = TRUE;
      }
      if(ulActualDurBeyondSyncBase > m_ulLastDuration)
      {
          m_ulLastDuration = ulActualDurBeyondSyncBase;
      }
    }

    ULONG32 ulRevisedActualDurBeyondSyncBase = ulActualDurBeyondSyncBase;
    if (m_pSourceElement->m_nEndsyncEventSourceTag == SMILEventSourceFirst)
    {
      // /Helps fix PR 66391: if child is time container, make sure this's
      // duration is set to shortest child's duration:
      m_pSourceElement->m_ulDuration = m_ulFirstDuration;

      // /Fixes endsync="first" version of PR 64157 where addDuration
      // of longer vid happens after that of lower-duration sibling and
      // longer one needs to be clipped to that lower duration (or completely
      // removed if begin offset is beyond parent's end (PR 64158)):
      if (m_bFirstDurationHasBeenSet  &&
            m_ulFirstDuration < ulActualDurBeyondSyncBase)
      {
          bSetChildCurEndClippedByParent = TRUE;
          if (m_ulFirstDuration > ulChildDelayBeyondStartOfThis)
          {
            m_pParser->resetTimelineElementDuration(pElementID,
                  m_ulFirstDuration -
                  // /Fixes PR 64160 (ensync="first" version):
                  ulChildDelayBeyondStartOfThis,
                  // /Changed to *child* prior dur while fixing PR 66391:
                  ulActualDurBeyondSyncBase -
                  ulChildDelayBeyondStartOfThis);
            
            // /Update dur to be used:
            ulRevisedActualDurBeyondSyncBase = m_ulFirstDuration -
                  ulChildDelayBeyondStartOfThis;
            m_pParser->m_pTimelineElementManager->notify(pElementID);
          }
          else // /Begin offset is beyond parent's end, so remove it:
          // /Fixes PR 64158 (endsync="first" version)
          {
            bSetCompletelyRemovedFromTimeline = TRUE;
            HX_RESULT retval2 = m_pSourceElement->m_pHandler->
                  handleTrackRemoval((const char*)pElementID,
                  (INT32)m_pSourceElement->m_pNode->m_nGroup);
          }
      }
    }

    if (!(*m_pChildDurAddedMap)[pElementID])
    {
      m_nDurationAdded++;
      (*m_pChildDurAddedMap)[pElementID] = (void*)ulRevisedActualDurBeyondSyncBase;
    }
    ULONG32 ulChildrenCount = m_pChildren->GetCount();
    // /Fixes PR 56481 find children of this par that don't have a scheduled
    // begin, i.e., are awaiting an event to begin.  endsync="last" says to
    // ignore any children that never play, and we don't know if those
    // event-based begin children will play or not so ignore them for now,
    // and if they ever do begin, *then* re-compute this par's duration:
    ULONG32 ulNonEventBasedBeginChildCount = 0;
    CSmilElement* pCurChildElem = NULL;
    CHXSimpleList::Iterator i = m_pChildren->Begin();
    for(i; i != m_pChildren->End(); ++i)
    {
      CSmilTimelineElement* pTmlnElement =
            (CSmilTimelineElement*)(*i);
      if (pTmlnElement  &&  pTmlnElement->m_pSourceElement)
      {
          BOOL isCurAddDurElem = FALSE;
          if (!strcmp(pTmlnElement->m_pSourceElement->m_pNode->m_id,
                pElementID))
          {
            isCurAddDurElem = TRUE;
            pCurChildElem = pTmlnElement->m_pSourceElement;
            if (bSetChildCurEndClippedByParent  &&  pCurChildElem)
            {
                pCurChildElem->m_bCurEndClippedByParent = TRUE;
            }
            if (bSetCompletelyRemovedFromTimeline  &&  pCurChildElem)
            {
                pCurChildElem->m_bInsertedIntoTimeline = FALSE;
            }
          }
          if ((pTmlnElement->m_pSourceElement->
                m_bHasAtLeastOneNonEventBasedBegin  ||
                // /Do this so this par can re-resolve its duration if &
                // when an event-based-begin child gets added (and thus
                // technically now is a child with a clock-valued begin):
                isCurAddDurElem) )
          {
            ulNonEventBasedBeginChildCount++;
          }
      }
    }
    
    if (!bHandled  &&
          (m_nDurationAdded >= ulNonEventBasedBeginChildCount  &&
          // /If endsync is all, we need to wait for *all* to be added:
          (SMILEventSourceAll!=m_pSourceElement->m_nEndsyncEventSourceTag  ||
          m_nDurationAdded == ulChildrenCount) )  &&
          !m_bDurationEvent)
    {
      BOOL bUpdateDurMightBeNeeded = FALSE;
      // /Helps fix PR 62688(par): if duration was set before, but only to
      // hold the timeline open until all (or a particular) child duration
      // became known, then we want to ignore the durationSet flag so that
      // we call duartionResolved() instead of adjustDuration();
      BOOL bIgnoreDurationSetFlag = bIsCurChildsFirstAddDuration  &&
            (WAY_IN_THE_FUTURE <= m_pSourceElement->m_ulDelay +
            m_pSourceElement->m_ulDuration);
      // /First, if duration has already been set, then pElement must be an
      // event-based-begin child that just resolved, so we need to reset
      // our duration appropriately:
      if (m_bDurationSet  &&  pCurChildElem  &&  !bIgnoreDurationSetFlag  &&
            !pCurChildElem->m_bHasAtLeastOneNonEventBasedBegin)
      {
          bUpdateDurMightBeNeeded = TRUE;  // /(PR 59851 hits this line.)
      }

        // Switch on different endsync values
      if(m_pSourceElement->m_nEndsyncEventSourceTag == 
          SMILEventSourceFirst)
      {
          if (bUpdateDurMightBeNeeded)
          {
            if (ulActualDurBeyondSyncBase == m_ulFirstDuration)
            {
                // /XXXEH- revisit now that addDuration accts for endsync:
                ULONG32 ulOldDur = m_pSourceElement->m_ulDuration;
                adjustDuration();
                HX_ASSERT(m_pSourceElement->m_ulDuration == m_ulFirstDuration);
                // /Other half of fix for PR 50679: if updated duration
                // is less than prior dur, then update timeline element:
                if (ulOldDur > m_pSourceElement->m_ulDuration)
                {
                  // /Reset duration-set flag to FALSE since we want to
                  // override (reset) the dur now that this last child
                  // has been resolved (presumably after playback of
                  // this par began):
                  m_bDurationSet = FALSE;
                  HX_ASSERT(m_pSourceElement->m_ulDuration ==
                        m_pSourceElement->getPureDuration());
                  durationResolved(m_pSourceElement->m_ulDuration, TRUE);
                }
            }
          }
          else
          {
            HX_ASSERT(m_pSourceElement->m_ulDuration ==
                  m_pSourceElement->getPureDuration());
            durationResolved(m_ulFirstDuration, TRUE);
          }
      }
      else if(m_pSourceElement->m_nEndsyncEventSourceTag == 
          SMILEventSourceLast)
      {
          if (bUpdateDurMightBeNeeded)
          {
            if (ulActualDurBeyondSyncBase == m_ulLastDuration)
            {
                adjustDuration();
            }
          }
          else
          {
            // /Helps fix PR 62688(par version when endsync="last" is
            // explicitly declared): if we previously resolved our
            // duration to "unresolved" to hold timeline open, then we
            // need to adjust our duration down from WAY_IN_THE_FUTURE:
            if (WAY_IN_THE_FUTURE == m_pSourceElement->m_ulDuration  ||
                  WAY_IN_THE_FUTURE == m_ulLastDuration  ||
                  m_pSourceElement->m_ulDuration != m_ulLastDuration)
            {
                // /Fixes part 3 of PR 79699 (explicit endsync=last version)
                // where it plays as indefinite because outer par wasn't
                // adjusting for new non-indef dur:
                if (WAY_IN_THE_FUTURE == m_pSourceElement->m_ulDuration  &&
                      bIsCurChildsFirstAddDuration)
                {
                  HX_ASSERT(WAY_IN_THE_FUTURE == m_ulLastDuration  ||  m_bDurationSet);
                  // /Trick adjustDuration() into doing its thing
                  // since this is last child being added for 1st time:
                  m_bDurationSet = TRUE;
                }
                adjustDuration();
                m_bDurationSet = FALSE;
            }
            HX_ASSERT(m_pSourceElement->m_ulDuration ==
                  m_pSourceElement->getPureDuration());
            // /To fix PR 59584(par w/event-ended child), w/"last"), use
            // m_pSourceE.'s dur, not m_ulLastDuration since latter may
            // be wrong if some elements stopped early
            durationResolved(m_pSourceElement->m_ulDuration, TRUE);
          }
      }
      else if(m_pSourceElement->m_nEndsyncEventSourceTag == 
          SMILEventSourceAll)
      {
          if (bUpdateDurMightBeNeeded)
          {
            if (ulActualDurBeyondSyncBase == m_ulLastDuration)
            {
                // /adjustDuration() assumes endsync=last which is OK
                // since we've got all durations:
                adjustDuration();
            }
          }
          else
          {
            // /Helps fix PR 59584(simplified): if we previously resolved
            // our duration to "unresolved" to hold timeline open, then we
            // need to adjust our duration down from WAY_IN_THE_FUTURE:
            if (WAY_IN_THE_FUTURE == m_pSourceElement->m_ulDuration  ||
                  WAY_IN_THE_FUTURE == m_ulLastDuration  ||
                  m_pSourceElement->m_ulDuration != m_ulLastDuration)
            {
                if (WAY_IN_THE_FUTURE == m_pSourceElement->m_ulDuration  &&
                      bIsCurChildsFirstAddDuration)
                {
                  HX_ASSERT(WAY_IN_THE_FUTURE == m_ulLastDuration  ||  m_bDurationSet);
                  // /See "part 2 of PR 79699" below; don't want to mess
                  // with this unless there's content that asserts here:
                  HX_ASSERT(m_bDurationSet);
                }
                adjustDuration();
            }
            HX_ASSERT(m_pSourceElement->m_ulDuration ==
                  m_pSourceElement->getPureDuration());
            // /Reset duration-set flag to FALSE since we want to
            // override (reset) the dur now that this last child has been
            // resolved (presumably after playback of this par began):
            m_bDurationSet = FALSE;
            // /To fix PR 59584(par w/event-ended child), w/"all"), use
            // m_pSourceE.'s dur, not m_ulLastDuration since latter may
            // be wrong if some elements stopped early
            durationResolved(m_pSourceElement->m_ulDuration, TRUE);
          }
      }
      else
      {
          if (bUpdateDurMightBeNeeded)
          {
            if (ulActualDurBeyondSyncBase == m_pSourceElement->m_ulDuration)
            {
                adjustDuration();
            }
          }
          else
          {
            // /Helps fix PR 62688(par version): if we previously resolved
            // our duration to "unresolved" to hold timeline open, then we
            // need to adjust our duration down from WAY_IN_THE_FUTURE:
            if (WAY_IN_THE_FUTURE == m_pSourceElement->m_ulDuration  ||
                  WAY_IN_THE_FUTURE == m_ulLastDuration  ||
                  m_pSourceElement->m_ulDuration != m_ulLastDuration)
            {
                // /Fixes part 2 of PR 79699 (imlicit endsync=last version)
                // where it plays as indefinite because outer par wasn't
                // adjusting for new non-indef dur:
                if (WAY_IN_THE_FUTURE == m_pSourceElement->m_ulDuration  &&
                      bIsCurChildsFirstAddDuration)
                {
                  HX_ASSERT(WAY_IN_THE_FUTURE == m_ulLastDuration  ||  m_bDurationSet);
                  // /Trick adjustDuration() into doing its thing
                  // since this is last child being added for 1st time:
                  m_bDurationSet = TRUE;
                }
                adjustDuration();
                m_bDurationSet = FALSE;
            }
            HX_ASSERT(m_pSourceElement->m_ulDuration ==
                  m_pSourceElement->getPureDuration());
            durationResolved(m_pSourceElement->m_ulDuration, FALSE);
          }
      }

      // /This if() block fixes PR 56686 (version 3) and
      // PR 61174 (version 3): if time container has longer dur than its
      // children and it is not a time-child of the <body>, then its dur
      // was never getting accounted for, but now the outer time container
      // sets the duration if its dur is longer than its group's so far;
      // outer time contnr can only be a par if body has multiple children:
      if (m_pSourceElement->m_pNode  &&  m_pSourceElement->m_pHandler)
      {
          // /XXXEH- handle <body><switch><par> and <body><a><par>
          if (m_pSourceElement->m_pNode->m_pParent  &&  (SMILBody == 
                m_pSourceElement->m_pNode->m_pParent->m_tag  ||
                m_pSourceElement->m_pNode->
                m_pParent->m_bIsOuterWrapperTimeContainer) )
          {
            UINT32 ulGroup = m_pSourceElement->m_pNode->m_nGroup;
            // /The group duration should be the duration of this
            // outer-most time container:
            HX_RESULT pnrs = m_pSourceElement->m_pHandler->
                  resolveGroupDurToOuterTimeContainerDur(
                  ulGroup, m_pSourceElement->m_ulDuration);
          }
      }
    }
}

void
CSmilTimelinePar::elementResolved(CSmilTimelineElement* pEventElement)
{
    parExclElementResolved(pEventElement);
}

void
CSmilTimelinePar::durationResolved(UINT32 ulDuration, BOOL bUpdateChildren)
{
    parExclDurationResolved(ulDuration, bUpdateChildren);
}

#if 0

#error: **HEY: if this code ever gets enabled, handle CSmilTimelineExcl as well:

void 
CSmilTimelinePar::setEndsync(EndsyncType eType, 
                       const char* pEndsyncID,
                       UINT32 ulEndsyncClockValue)
{
    m_eEndsyncType = eType;
    m_ulEndsyncClockValue = ulEndsyncClockValue;
    if(pEndsyncID)
    {
      m_pEndsyncID = new char[strlen(pEndsyncID)+1];
      strcpy(m_pEndsyncID, pEndsyncID); /* Flawfinder: ignore */
    }
}
#endif

/***************************************************************************/

/*
 * CSmilTimelineSeq methods
 */
CSmilTimelineSeq::CSmilTimelineSeq(CSmilElement* pSourceElement,
                           CSmilParser* pParser):
    CSmilTimelineElement(pSourceElement, pParser),
    m_nDurationAdded(0)
{
}

void 
CSmilTimelineSeq::addDuration(UINT32 ulDuration, 
                        UINT32 ulDelay,
                        UINT32 ulChildDelayBeyondStartOfItsSyncBase, 
                        const char* pID)
{
    HX_ASSERT(m_pChildren);

#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION)
    {
      FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout?
            ADDDURATION_DEBUGOUT_STR_NEW_FILE :
            ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE );
      ::fprintf(f1, "CSmilTimelineSeq{%s}::addDuration(dur=%lu, delay=%lu, "
            "childDelayBeyondThis=%lu, id=%s) m_bDurationSet=%sE\n",
            (const char*)m_pID, ulDuration, ulDelay,
            ulChildDelayBeyondStartOfItsSyncBase, pID,
            m_bDurationSet?"TRU":"FALS");
      ::fclose(f1);
      bFirstTimeAddDurDebugout = FALSE;
    }
#endif

    // /I don't think we want to/need to use ulChildDelay; it is > 0 in
    // "BUG-20010502_repeatedElementWithBeginOf3sAndEndOf15s.smil" but
    // that works (offset-wise) so no need to use ulChildDelay...:

    ULONG32 ulActualDurBeyondSyncBase = ulDuration;
    // /Fixes case where this seq has a begin offset from its parent and
    // doesn't have an explicit end or dur; the child being added here
    // ended up playing too short by the amount of this's begin offset:
    BOOL bDurationIncludesDelayBeyondSyncbase = FALSE;
    if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase)
    {
      ulActualDurBeyondSyncBase +=
            m_pSourceElement->m_ulBeginOffsetFromSyncBase;
      bDurationIncludesDelayBeyondSyncbase = TRUE;
    }

    if (ulChildDelayBeyondStartOfItsSyncBase > 0)
    {
      // /Helps fix PR 6XXXX: be sure to account for child's delay beyond
      // its prior sibling in this seq, or the seq itself if no prior sib:
      ulActualDurBeyondSyncBase -= ulChildDelayBeyondStartOfItsSyncBase;
    }
    else
    {
      HX_ASSERT(0 == ulChildDelayBeyondStartOfItsSyncBase  &&
            "ehodge: negative delay in seq!?");
    }

    BOOL bIsCurChildsFirstAddDuration = FALSE;
    ULONG32 ulCurChildPriorAddedDuration = (UINT32)-1;
    if (!(*m_pChildDurAddedMap)[pID])
    {
      bIsCurChildsFirstAddDuration = TRUE;
    }
    else
    {
      ulCurChildPriorAddedDuration =
            (ULONG32)((*m_pChildDurAddedMap)[pID]);
    }

    if(!m_bDurationSet)
    {
      if(m_pSourceElement->m_ulDuration == (UINT32)-1)
      {
          m_pSourceElement->m_ulDuration = ulActualDurBeyondSyncBase;
          m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase =
                bDurationIncludesDelayBeyondSyncbase;
      }
      // /Helps fix PR 62688 and PR 59584: never go higher duration than
      // WAY_IN_THE_FUTURE so overall timeline doesn't further extend:
      else if (WAY_IN_THE_FUTURE == ulActualDurBeyondSyncBase  ||
            WAY_IN_THE_FUTURE == m_pSourceElement->m_ulDuration)
      {
          m_pSourceElement->m_ulDuration = WAY_IN_THE_FUTURE;
          if (m_pSourceElement->m_ulDelay > 0)
          {
            if (m_pSourceElement->m_ulDuration >=
                  m_pSourceElement->m_ulDelay)
            {
                m_pSourceElement->m_ulDuration -=
                      m_pSourceElement->m_ulDelay;
            }
            else
            {
                m_pSourceElement->m_ulDuration = 0;
            }
          }
          m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase =
                bDurationIncludesDelayBeyondSyncbase;
      }
      else
      {
          m_pSourceElement->m_ulDuration += ulActualDurBeyondSyncBase;
          m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase =
                bDurationIncludesDelayBeyondSyncbase;
      }
    }
    // /Fixes unfiled(?) bug found when PR 52110 was fixed: seq with begin
    // offset>0 and explicit dur was not accounting for this offset in its
    // duration, but parent's addDuration() counts on that being done:
    else if (m_pSourceElement->m_bHasExplicitDur  &&
          !m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
    {
      if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase)
      {
          m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase =
                bDurationIncludesDelayBeyondSyncbase;
          m_pSourceElement->m_ulDuration +=
                m_pSourceElement->m_ulBeginOffsetFromSyncBase;
      }
    }

    if (!(*m_pChildDurAddedMap)[pID])
    {
      m_nDurationAdded++;
      (*m_pChildDurAddedMap)[pID] = (void*)ulActualDurBeyondSyncBase;
    }
    if(m_nDurationAdded == m_pChildren->GetCount()  ||
          // /Helps fix PR 59584: if our dur is unresolved, then we need to
          // notify our parent (and on up the chain) that there is an
          // currently-indefinite-duration element in the presentation:
          WAY_IN_THE_FUTURE <= m_pSourceElement->m_ulDuration +
          m_pSourceElement->m_ulDelay)
    {
      m_bDurationSet = TRUE;
      if (m_nDurationAdded == m_pChildren->GetCount())
      {
          // /We need to adjust our duration in case it was temporarily set
          // to indefinite; now that we have all children accounted for, we
          // can correctly calculate it:  (fixes PR 59584 overall duration)
          adjustDuration();
      }
        // Add our duration to our parent
      if(m_pParent)
      {
          ULONG32 ulDelayFromSyncBaseBegin = 0;
          if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase)
          {
            ulDelayFromSyncBaseBegin =
                  m_pSourceElement->m_ulBeginOffsetFromSyncBase;
            // /Fixes PR 68875: be sure to add offset from syncbase if
            // not already included:
            if ((UINT32)-1 != ulDelayFromSyncBaseBegin
                  &&  ulDelayFromSyncBaseBegin > 0  &&
                  !m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
            {
                m_pSourceElement->m_ulDuration += ulDelayFromSyncBaseBegin;
                m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase = TRUE;
            }
          }
          m_pParent->addDuration( 
                m_pSourceElement->m_ulDuration, 
                m_pSourceElement->m_ulDelay,
                ulDelayFromSyncBaseBegin, m_pID);
          m_pSourceElement->m_bAddDurationAlreadyDone = TRUE;
      }

      // /This if() block fixes PR 56686 (version 2) and
      // PR 61174 (version 2): if time container has longer dur than its
      // children and it is not a time-child of the <body>, then its dur
      // was never getting accounted for, but now the outer time container
      // sets the duration if its dur is longer than its group's so far:
      if (m_pSourceElement->m_pNode  &&  m_pSourceElement->m_pHandler)
      {
          if (m_pSourceElement->m_pNode->m_pParent  &&  (SMILBody == 
                m_pSourceElement->m_pNode->m_pParent->m_tag  ||
                m_pSourceElement->m_pNode->
                m_pParent->m_bIsOuterWrapperTimeContainer) )
          {
            BOOL bDoResolveGroupDur = TRUE;
            UINT32 ulGroup = m_pSourceElement->m_pNode->m_nGroup;
            if (m_pSourceElement->m_pNode->m_bIsOuterWrapperTimeContainer)
            {
                ulGroup = 0;
                // /If we're outer seq wrapper around multiple groups
                // (or "clips"), then let each group outer time container
                // resolve its group duration:
                if (m_pChildren->GetCount() > 1)
                {
                  bDoResolveGroupDur = FALSE;
                }
            }
            if (bDoResolveGroupDur)
            {
                // /The group duration should be the duration of this
                // outer-most time container:
                HX_RESULT pnrs = m_pSourceElement->m_pHandler->
                      resolveGroupDurToOuterTimeContainerDur(
                      ulGroup, m_pSourceElement->m_ulDuration);
            }
          }
      }



        // Now we know the duration of this <seq>, so 
        // we need to check the fill behavior of all our
        // children
        checkChildrenFillBehavior();
      if(m_pDependent)
      {
          HX_ASSERT(m_bDurationSet);
          adjustDependentDuration(m_pDependent);

#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
          ULONG32 ulTotalDelay = 0;
          if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase  &&
                m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
          {
            HX_ASSERT(0  &&  "ehodge: CHANGE NOT TESTED!");
          }

          if (HXR_OK !=
                m_pSourceElement->getCurrentScheduledStopTime(ulTotalDelay))
          {
            goto doneSettingDependent;
          }
#else
          ULONG32 ulTotalDelay = m_pSourceElement->m_ulDelay +
                m_pSourceElement->m_ulDuration;
          // /Helps fix PR 6XXXX(seq version): if delay is already packed
          // into the duration, then don't count it twice (as can happen in
          // <seq><seq begin="1s">...</seq><seq begin="1s" ...):
          if (m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
          {
            HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1);
/*OK[]*/          if (m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1)
            {
                HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                      ulTotalDelay);
                if (m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                      ulTotalDelay)
                {
                  ulTotalDelay -=
                        m_pSourceElement->m_ulBeginOffsetFromSyncBase;
                }
            }
          }
#endif

          if (WAY_IN_THE_FUTURE < ulTotalDelay)
          {
            HX_ASSERT(WAY_IN_THE_FUTURE == ulTotalDelay  &&  "PR 59584");
            ulTotalDelay = WAY_IN_THE_FUTURE; // /For PR 59584.
          }

          // /XXXEH- TODO: figure out if we need to claim this is being set
          // by "parent" (which is really time base) so clip-begin-like
          // action can occur; I don't think so, however:
          m_pDependent->setDelay(ulTotalDelay, FALSE);          
      }
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
doneSettingDependent:
#endif

      // /[SMIL 1.0 Compliance] Fixes PR 23779:
      // if a source has event-based timing based on this seq's
      // duration, then we need to notify that source that we've
      // resolved this value:
      m_pParser->m_pTimelineElementManager->notify(m_pID);
    }
}

void 
CSmilTimelineSeq::setDelay(UINT32 ulDelay,
         // /NOTE: we ignore this in time containers that aren't media:
         BOOL bSetByParent)
{
#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION)
    {
      FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout?
            ADDDURATION_DEBUGOUT_STR_NEW_FILE :
            ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE );
      ::fprintf(f1, "CSmilTimelineSeq{%s}::setDelay(delay=%lu, "
            "bSetByParent=%sE) m_bDelaySet=%sE\n",
            (const char*)m_pID, ulDelay,
            bSetByParent?"TRU":"FALS",
            m_bDelaySet?"TRU":"FALS");
      ::fclose(f1);
      bFirstTimeAddDurDebugout = FALSE;
    }
#endif

    if(m_pSourceElement->m_bBeginOffsetSet)
    {
      m_pSourceElement->m_ulDelay = (
            ((INT32)ulDelay+m_pSourceElement->m_lBeginOffset > 0) ?
            (UINT32)((INT32)ulDelay+m_pSourceElement->m_lBeginOffset):0);
    }
    else
    {
      m_pSourceElement->m_ulDelay = ulDelay;
    }
    //XXXJHUG - we need to prevent overwriting the delay when
    // setInitalDelay is called on THIS element, changing this
    // bool causes initialDelaySet to return TRUE.
    m_bDelaySet = TRUE;
    if(m_pChildren && m_pChildren->GetCount() > 0)
    {
      // set delay on first child of seq
      CSmilTimelineElement* pElement = 
          (CSmilTimelineElement*)m_pChildren->GetHead();
      pElement->setDelay(m_pSourceElement->m_ulDelay, TRUE);

      // /To fix it so second group plays (PR6XXX5) after fix for (PR6XXX4),
      // need to set the delay of all children since each is not dependent
      // on the prior; problem is that a child 'n' with an explicit dur will
      // (now) tell its parent its dur during the above setDelay() call and
      // that will end up with this->setDuration() call happening too early,
      // farther below, resulting in all groups > n getting a 0 duration:
      SMILNode* pSyncAncestor = m_pParser? m_pParser->getSyncAncestor(
            m_pSourceElement->m_pNode) : NULL;

      if (!pSyncAncestor  ||  (SMILBody == pSyncAncestor->m_tag  &&
            m_pSourceElement->m_pNode->m_bIsOuterWrapperTimeContainer) )
      {
          // /Need to set the delays of all children to 0 since each starts its
          // own "clip" (group):
          CHXSimpleList::Iterator i = m_pChildren->Begin();
          ++i;  // /Already done for group 0, above.
          for(; i != m_pChildren->End(); ++i)
          {
            pElement = (CSmilTimelineElement*)(*i);
            // /If 0 != this's delay, then body must have begin="x" on it
            // and subsequent groups should not include that delay:
            HX_ASSERT(0 == m_pSourceElement->m_ulDelay);
            pElement->setDelay(0, TRUE);
          }
      }
    }

    // /Fixes PR 24046 (SMIL 2+ seq version): if there are no children,
    // then the seq's duration is zero, so set it to 0:
    else if (m_pSourceElement->m_ulDuration == (UINT32)-1)
    {
      m_pSourceElement->m_ulDuration = 0;
    }

    if (m_pSourceElement->m_ulDuration != (UINT32)-1)
    {
      setDuration(m_pSourceElement->m_ulDuration);

#if 0 /* 20011024 */
      // /Fixes seq version of PR 61174(version1) and PR 56686
      // (version1): we know our duration already, so let's declare it
      // resolved so we get added to our parent (in case none of our

// XXXNH: for some reason, despite being if-zeroed-out, this causes a compiler
// error on linux!
//#error: DUDE!?!: children of seq can't have unresolved begins!: 

        // children have scheduled begin times in which case our
      // ::addDuration() would not get called up front and the overall
      // presentation would not include our duration at first):
      if (m_pSourceElement->m_bHasExplicitDur  ||
            m_pSourceElement->m_bHasExplicitEnd)
      {
          // /Be sure not to override a shorter duration that may have
          // been imposed on us by our parent:
          if (!m_bDurationSet  ||
                !m_pSourceElement->m_bAddDurationAlreadyDone)
          {
            HX_ASSERT((UINT32)-1 != m_pSourceElement->m_ulDelay);

            m_bDurationSet = TRUE;
            if (m_pParent)
            {
                ULONG32 ulDelayFromSyncBaseBegin = 0;
                if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase)
                {
                  ulDelayFromSyncBaseBegin =
                        m_pSourceElement->m_ulBeginOffsetFromSyncBase;
                  if (ulDelayFromSyncBaseBegin > 0  &&
                        !m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
                  {
                      m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase =
                            TRUE; // /=TRUE,not ULONG32. Helps fix PR 68190.
                      m_pSourceElement->m_ulDuration += ulDelayFromSyncBaseBegin;
                  }
                }
                m_pParent->addDuration(m_pSourceElement->m_ulDuration,
                      m_pSourceElement->m_ulDelay,
                      ulDelayFromSyncBaseBegin, m_pID);
                m_pSourceElement->m_bAddDurationAlreadyDone = TRUE;
            }
          }
          HX_ASSERT(m_bDurationSet  &&  m_pSourceElement->m_bAddDurationAlreadyDone);
      }
#endif
    }

    //[SMIL 1.0 Compliance] Helps fix PR 14420 and 23025:
    // if a source has event-based timing based on this seq's
    // begin time (delay) then we need to notify that source
    // that we've resolved this value:
    m_pParser->m_pTimelineElementManager->notify(m_pID);
}

void
CSmilTimelineSeq::setDuration(UINT32 ulDuration, BOOL bSetFromParent,
                          BOOL bDurationExtendingDueToPause)
{
    ASSERT(m_pChildren  ||  0==ulDuration);

    if (bDurationExtendingDueToPause)
    {
      // /Need to handle this case:
      HX_ASSERT(!bDurationExtendingDueToPause);
    }

    if(!m_bDurationSet  ||
          // /Adding this fixes PR 27644 and other cases where explicit
          // dur|end of parent was being ignored by explicit (and larger)
          // dur|end of child seq.  This allows repeatDur to work when
          // parent has explicit dur|end since repeatDur creates a seq
          // with an explicit dur:
          bSetFromParent)
    {
      m_pSourceElement->m_ulDuration = ulDuration;
      m_bDurationSet = TRUE;
    }

    UINT32  ulDurationLeft = m_pSourceElement->m_ulDuration;
    RepeatTag     repeatTag = RepeatUnknown;

    if (m_pChildren) // /Fixes crash in case of a "<seq></seq>" (PR 65069).
    { 
      CHXSimpleList::Iterator i = m_pChildren->Begin(); 
      for(; i != m_pChildren->End(); ++i) 
      { 
          CSmilTimelineElement* pTmLnElement = (CSmilTimelineElement*)(*i); 
          CSmilElement* pElement = pTmLnElement->m_pSourceElement;
          if (!setElementDuration(ulDurationLeft, pTmLnElement))
          {
            break;
          }

          // /Fixes PR 99498: make sure m_pSourceElement's time values are
          // in same time-coords as pElement's before comparing the two;
          // in this bug, a seq that began at 15s (15000 delay) had a
          // duration that did not include that delay so the below PR 66391
          // fix's if() was erroneously evaluating to true, thus ending
          // this's children early.  Use this's soureElement's dur+delay,
          // not its m_ulDuration (which may or may not include delay):
          UINT32 ulDurationPlusDelayOfThisSeq =
                m_pSourceElement->getPureDuration() +
                m_pSourceElement->m_ulDelay;

          // /Helps fix PR 66391: if this's m_ulDuration has shortened and
          // its child(ren)'s duration is shortened to zero as a result,
          // then remove child track if it begins too late to ever play:
          if (pElement  &&  pElement->m_pHandler  &&
                pElement->m_ulDelay > ulDurationPlusDelayOfThisSeq  &&
                pElement->m_bInsertedIntoTimeline)
          {
            pElement->m_bCurEndClippedByParent = TRUE;

            HX_ASSERT(0 == ulDurationLeft);
            BOOL bCurElementIsTimeContainer =
                  m_pParser->isTimeContainerObject(pElement->m_pNode);
            HX_ASSERT(!bCurElementIsTimeContainer  &&  "ehodge:handle_removing_grandkids");

            HX_RESULT retvl = pElement->m_pHandler->handleTrackRemoval(
                  (const char*)pElement->m_pNode->m_id,
                  (INT32)pElement->m_pNode->m_nGroup);
            if (HXR_OK == retvl)
            {
                // /Notify syncArc dependents that it ended early:
                m_pParser->m_pTimelineElementManager->notify((const char*)pElement->m_pNode->m_id);
            }
          }
      } 
    } 

    if(m_pDependent)
    {
      HX_ASSERT(m_bDurationSet);

      adjustDependentDuration(m_pDependent);    

#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
      ULONG32 ulTotalDelay = 0;
        if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase  &&
            m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
      {
          HX_ASSERT(0  &&  "ehodge: CHANGE NOT TESTED!");
      }

      if (HXR_OK !=
            m_pSourceElement->getCurrentScheduledStopTime(ulTotalDelay))
      {
          goto doneSettingDependent;
      }
#else
      ULONG32 ulTotalDelay = m_pSourceElement->m_ulDelay +
            m_pSourceElement->m_ulDuration;
      // /Helps fix PR 6XXXX(seq version): if delay is already packed
      // into the duration, then don't count it twice (as can happen in
      // <seq><seq begin="1s">...</seq><seq begin="1s" ...):
      if (m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
      {
          HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1);
/*OK[]*/        if (m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1)
          {
            HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                  ulTotalDelay);
            if (m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                  ulTotalDelay)
            {
                ulTotalDelay -=
                      m_pSourceElement->m_ulBeginOffsetFromSyncBase;
            }
          }
      }
#endif

      if (WAY_IN_THE_FUTURE < ulTotalDelay)
      {
          HX_ASSERT(WAY_IN_THE_FUTURE == ulTotalDelay  &&  "PR 59584");
          ulTotalDelay = WAY_IN_THE_FUTURE; // /For PR 59584.
      }

      // /XXXEH- TODO: figure out if we need to claim this is being set
      // by "parent" (which is really time base) so clip-begin-like
      // action can occur; I don't think so, however:
      m_pDependent->setDelay(ulTotalDelay, FALSE);
    }
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
doneSettingDependent:
#endif

    //[SMIL 1.0 comliance] Helps fix PR 14420 and 23025:
    m_pParser->m_pTimelineElementManager->notify(m_pID);
}

void
CSmilTimelineSeq::setMaxDuration(UINT32 ulMaxDuration)
{
    HX_ASSERT(m_pChildren);
    m_bMaxDurationSet = TRUE;
    m_pSourceElement->m_ulMaxDuration = ulMaxDuration;

    if (m_pChildren  &&  m_bDelaySet)
    {
      HX_ASSERT((UINT32)-1 != m_pSourceElement->m_ulDelay);

      CSmilTimelineElement* pElement = (CSmilTimelineElement*)m_pChildren->GetHead();
      pElement->setMaxDuration(ulMaxDuration);
    }
}

void 
CSmilTimelineSeq::adjustDependentDuration(CSmilTimelineElement* pDependent)
{
    if(m_bDurationSet || m_bMaxDurationSet)
    {
      UINT32          ulDurationLeft = m_bDurationSet?m_pSourceElement->m_ulDuration:
                                        m_pSourceElement->m_ulMaxDuration;
      UINT32 ulOriginalDurationLeft = ulDurationLeft;
      if (m_pSourceElement->m_ulMinActiveDur>ulDurationLeft)
      {
          ulDurationLeft = m_pSourceElement->m_ulMinActiveDur;
      }
      BOOL      bAdjusted = FALSE;
      RepeatTag   repeatTag = RepeatUnknown;

      if (m_pChildren) // /Fixes crash in case of a "<seq></seq>" (PR 65069).
      { 
          CHXSimpleList::Iterator i = m_pChildren->Begin(); 
          for(; i != m_pChildren->End(); ++i) 
          { 
            CSmilTimelineElement* pElement = (CSmilTimelineElement*)(*i); 
            UINT32 ulChildDuration = pElement->getDuration(); 
 
            if (pElement == pDependent) 
            { 
                bAdjusted = TRUE; 
            } 
 
            if (bAdjusted) 
            { 
                if (pElement->getDelay() != (UINT32)-1)
                {
                  HX_ASSERT(pElement->getDelay() < WAY_IN_THE_FUTURE  &&
                      "need to reset delay b4 dur!");
                }
                // /Fixes PR 59584(parFollowsPar version):  If seq has
                // unresolved-dur child, don't set dur of next sibling
                // if it doesn't have delay set yet:
                else if (0 == ulDurationLeft  &&  WAY_IN_THE_FUTURE ==
                      ulOriginalDurationLeft)
                {
                  break; // /Don't do anything.
                }
                // /Helps fix full repro case of PR 59584: second par
                // in seq will have delay>0 and interim duration
                // of WAY_IN_THE_FUTURE *minus* delay:
                if (WAY_IN_THE_FUTURE <= ulOriginalDurationLeft)
                {
                  ulDurationLeft = WAY_IN_THE_FUTURE;
                  setElementDuration(ulDurationLeft, pElement);
                  break; // /Go no further for now.
                }
                if (!setElementDuration(ulDurationLeft, pElement)) 
                { 
                  break; 
                } 
            } 
            else 
            { 
                if(ulDurationLeft >= ulChildDuration) 
                { 
                  ulDurationLeft -= ulChildDuration; 
                } 
                else 
                { 
                  ulDurationLeft = 0; 
                } 
            } 
          } 
      } 

      if (!bAdjusted && m_pParent)
      {
          m_pParent->adjustDependentDuration(pDependent);
      }
    }
}

void 
CSmilTimelineSeq::resetDelay(UINT32 ulDelay)
{
    INT32 lAdjustedDelay = 0;

    UINT32 ulPriorDelay = m_pSourceElement->m_ulDelay;

    if(m_pSourceElement->m_bBeginOffsetSet)
    {
      lAdjustedDelay = (INT32)ulDelay + m_pSourceElement->m_lBeginOffset;
      m_pSourceElement->m_ulDelay = lAdjustedDelay > 0?lAdjustedDelay:0;
    }
    else
    {
      m_pSourceElement->m_ulDelay = ulDelay;
    }

    if(m_pChildren && m_pChildren->GetCount() > 0)
    {
      // set delay on first child of seq
      CSmilTimelineElement* pElement = 
          (CSmilTimelineElement*)m_pChildren->GetHead();
#if 200110241
      if (m_pSourceElement->m_ulDelay !=
            pElement->m_pSourceElement->m_ulDelay)
      {
          pElement->resetDelay(m_pSourceElement->m_ulDelay);
      }
#else
      pElement->resetDelay(m_pSourceElement->m_ulDelay);
#endif
    }

    // /To fix PR 59851(seq of seqs), we need to update our next-in-seq
    // (m_pDependent) as well as make sure sync-arc listeners know we've
    // changed our overall time bounds delay as well;
    if (m_pDependent && m_bDurationSet  &&
          ulPriorDelay != m_pSourceElement->m_ulDelay)
    {
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
      ULONG32 ulTotalDelay = 0;
        if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase  &&
            m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
      {
          HX_ASSERT(0  &&  "ehodge: CHANGE NOT TESTED!");
      }

      if (HXR_OK !=
            m_pSourceElement->getCurrentScheduledStopTime(ulTotalDelay))
      {
          goto doneSettingDependent;
      }
#else
      ULONG32 ulTotalDelay = m_pSourceElement->m_ulDelay +
            m_pSourceElement->m_ulDuration;
      if (m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
      {
          HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1);
/*OK[]*/          if (m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1)
          {
            HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                  ulTotalDelay);
            if (m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                  ulTotalDelay)
            {
                ulTotalDelay -=
                      m_pSourceElement->m_ulBeginOffsetFromSyncBase;
            }
          }
      }
#endif
      if (WAY_IN_THE_FUTURE < ulTotalDelay)
      {
          HX_ASSERT(WAY_IN_THE_FUTURE == ulTotalDelay  &&  "PR 59584");
          ulTotalDelay = WAY_IN_THE_FUTURE; // /For PR 59584.
      }
 
#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION) 
{ 
    FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout? 
          ADDDURATION_DEBUGOUT_STR_NEW_FILE : 
          ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE ); 
    ::fprintf(f1, "\n\t%s:CSmilTimelineSeq::resetDelay(%lu):from %lu to %lu;"
          "\tresetting dependent (%s)'s delay to %lu\n", (const char*)m_pID,
          ulDelay, ulPriorDelay, m_pSourceElement->m_ulDelay,
          (const char*)m_pDependent->m_pID, ulTotalDelay);
    ::fclose(f1); 
    bFirstTimeAddDurDebugout = FALSE; 
} 
#endif 
 
      m_pDependent->resetDelay(ulTotalDelay);
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
doneSettingDependent:
#endif

      // /(Added while fixing PR 59851) Let others know our begin time changed:
      m_pParser->m_pTimelineElementManager->notify(m_pID);
    }
}

void 
CSmilTimelineSeq::adjustDuration()
{
    UINT32  ulDuration = 0;

    // /Fixes seq version of PR 50676 (Added during fix for PR 59584):
    ULONG32 ulPriorPureDuration = m_pSourceElement->getPureDuration();

    if (m_pChildren)
    {
      CHXSimpleList::Iterator i = m_pChildren->Begin();
      for(; i != m_pChildren->End(); ++i)
      {
          CSmilTimelineElement* pElement = (CSmilTimelineElement*)(*i);
          if ((UINT32)-1 == pElement->m_pSourceElement->m_ulDuration)
          {
            // /Helps fix PR 59584 (parFollowsPar version): if child dur
            // is not resolved yet, then we're unresolved:
            ulDuration = WAY_IN_THE_FUTURE;
            break;
          }
          ulDuration += pElement->m_pSourceElement->m_ulDuration;
          // /For PR 59584: don't go past "unresolved" dur value:
          if (ulDuration >= WAY_IN_THE_FUTURE)
          {
            ulDuration = WAY_IN_THE_FUTURE;
            break;
          }
      }

      if (!m_pSourceElement->m_bHasExplicitEnd  &&
            !m_pSourceElement->m_bHasExplicitDur)
      {
          // /Use child durs only if seq doesn't have explicit end or dur;
          // This helps fix PR 6XXXY:
          m_pSourceElement->m_ulDuration = ulDuration;
      }

      if(m_pParent)
      {
          m_pParent->adjustDuration();
      }

      // /Fixes PR 69410: need to do this no matter what, even if prior <
      // ulDur; resumed element in excl descendent should extend that excl
      // but we've already told the core to limit the presentation duration,
      // so extend it here as needed (also fixes part of PR 50660):
      // /(Added while fixing PR 59584): if our duration got reduced, we need to
      // possibly constrain the group's duration:
      {
          // This group's outer time container, if this is one, needs
          // to set the duration if its dur is longer than its group's so far
          // or if its previous duration was unresolved and now is resolved:
          if (m_pSourceElement->m_pNode  &&  m_pSourceElement->m_pHandler)
          {
            if (m_pSourceElement->m_pNode->m_pParent  &&  (SMILBody == 
                  m_pSourceElement->m_pNode->m_pParent->m_tag  ||
                  m_pSourceElement->m_pNode->
                  m_pParent->m_bIsOuterWrapperTimeContainer) )
            {
                BOOL bDoResolveGroupDur = TRUE;
                UINT32 ulGroup = m_pSourceElement->m_pNode->m_nGroup;
                if (m_pSourceElement->m_pNode->m_bIsOuterWrapperTimeContainer)
                {
                  ulGroup = 0;
                  // /If we're outer wrapper around multiple groups
                  // (or "clips"), then let each group outer time container
                  // resolve its group duration:
                  if (m_pChildren->GetCount() > 1)
                  {
                      bDoResolveGroupDur = FALSE;
                  }
                }
                if (bDoResolveGroupDur)
                {
                  // /The group duration should be the duration of this
                  // outer-most time container:
                  HX_RESULT pnrs = m_pSourceElement->m_pHandler->
                        resolveGroupDurToOuterTimeContainerDur(
                        ulGroup, m_pSourceElement->m_ulDuration);
                }
            }
          }
      }

      if(m_pDependent)
      {
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
          ULONG32 ulTotalDelay = 0;
          if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase  &&
                m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
          {
            HX_ASSERT(0  &&  "ehodge: CHANGE NOT TESTED!");
          }

          if (HXR_OK !=
                m_pSourceElement->getCurrentScheduledStopTime(ulTotalDelay))
          {
            goto doneSettingDependent;
          }
#else
          ULONG32 ulTotalDelay = m_pSourceElement->m_ulDelay +
                m_pSourceElement->m_ulDuration;
          if (m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
          {
            HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1);
/*OK[]*/          if (m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1)
            {
                HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                      ulTotalDelay);
                if (m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                      ulTotalDelay)
                {
                  ulTotalDelay -=
                        m_pSourceElement->m_ulBeginOffsetFromSyncBase;
                }
            }
          }
#endif
          if (WAY_IN_THE_FUTURE < ulTotalDelay)
          {
            HX_ASSERT(WAY_IN_THE_FUTURE == ulTotalDelay  &&  "PR 59584");
            ulTotalDelay = WAY_IN_THE_FUTURE; // /For PR 59584.
          }

#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION)
{
    FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout?
          ADDDURATION_DEBUGOUT_STR_NEW_FILE :
          ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE );
    ::fprintf(f1, "\n\t%s:CSmilTimelineSeq::adjustDuration();\tresetting dependent (%s)'s delay to %lu\n",
          (const char*)m_pID, (const char*)m_pDependent->m_pID,
          ulTotalDelay);
    ::fclose(f1);
    bFirstTimeAddDurDebugout = FALSE;
}
#endif

          m_pDependent->resetDelay(ulTotalDelay);
      }
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
doneSettingDependent:
      ;
#endif

    }
}

BOOL
CSmilTimelineSeq::setElementDuration(UINT32& ulDurationLeft, CSmilTimelineElement* pElement)
{
    BOOL    bContinue = TRUE;
    UINT32  ulChildDuration = pElement->getDuration();      
    RepeatTag   repeatTag = pElement->m_pSourceElement->m_pNode->m_repeatTag;
      
    if (repeatTag == RepeatIndefiniteOnMe)
    {
      pElement->setMaxDuration(ulDurationLeft);
      ulDurationLeft = 0;
      goto cleanup;
    }
    else if (repeatTag == RepeatIndefiniteOnGroup)
    {
      pElement->setMaxDuration(ulDurationLeft);
      bContinue = FALSE;
      goto cleanup;
    }

    // no more duration left, take care of the duration of the rest of 
    // the elements
    if (0 == ulDurationLeft)
    {
      pElement->setDuration(ulDurationLeft, TRUE);
    }
    // if this is the last child, then enforce the duration whatever
    // left
    else if (pElement == m_pChildren->GetTail())
    {
      if (ulChildDuration == (UINT32)-1  &&
            ulDurationLeft >= WAY_IN_THE_FUTURE)
      {
          // /Doing this instead of setDuration() fixes PR 65741 when outer
          // seq gets held open due to tracks' durations setting in a
          // certain order.  In this case, don't override possible child
          // explicit dur or end:
          pElement->setMaxDuration(ulDurationLeft);
      }
      else
      {
          pElement->setDuration(ulDurationLeft, TRUE);
      }
      bContinue = FALSE;
    }
    // unknown duration, so we apply max. duration here
    else if (ulChildDuration == (UINT32)-1)
    {
      pElement->setMaxDuration(ulDurationLeft);
      bContinue = FALSE;
    }
    else    
    {
      if(ulDurationLeft >= ulChildDuration)
      {
          ulDurationLeft -= ulChildDuration;
      }
      else
      {
          pElement->setDuration(ulDurationLeft, TRUE);
          ulDurationLeft = 0;
      }
    }

cleanup:

    return bContinue;
}

/***************************************************************************/

// /XXXEH- see if any or all of the following can be combined with
// CSmilTimelinePar methods, above (with added params for dealing
// with Excl in minor places):
/*
 * CSmilTimelineExcl methods
 */

CSmilTimelineExcl::CSmilTimelineExcl(CSmilElement* pSourceElement,
                           CSmilParser* pParser):
    CSmilTimelineElement(pSourceElement, pParser),
    m_nDurationAdded(0),
    m_ulFirstDuration(0),
    m_bFirstDurationHasBeenSet(FALSE),
    m_ulLastDuration(0)
{
}

CSmilTimelineExcl::~CSmilTimelineExcl()
{
}

void 
CSmilTimelineExcl::setDelay(UINT32 ulDelay,
         // /NOTE: we ignore this in time containers that aren't media:
         BOOL bSetByParent)
{
#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION)
    {
      FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout?
            ADDDURATION_DEBUGOUT_STR_NEW_FILE :
            ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE );
      ::fprintf(f1, "CSmilTimelineExcl{%s}::setDelay(delay=%lu, "
            "bSetByParent=%sE) m_bDelaySet=%sE\n",
            (const char*)m_pID, ulDelay,
            bSetByParent?"TRU":"FALS",
            m_bDelaySet?"TRU":"FALS");
      ::fclose(f1);
      bFirstTimeAddDurDebugout = FALSE;
    }
#endif

    if(m_pSourceElement->m_bBeginOffsetSet)
    {
      m_pSourceElement->m_ulDelay = (
            ((INT32)ulDelay+m_pSourceElement->m_lBeginOffset > 0) ?
            (UINT32)((INT32)ulDelay+m_pSourceElement->m_lBeginOffset):0);
    }
    else
    {
      m_pSourceElement->m_ulDelay = ulDelay;
    }
    if (!m_bDelayEvent)
    {
      m_bDelaySet = TRUE;
      ULONG32 ulNumChildrenWithNonEventBasedBegins = 0;
      if(m_pChildren)
      {
          CHXSimpleList::Iterator i = m_pChildren->Begin();
          for(; i != m_pChildren->End(); ++i)
          {
            CSmilTimelineElement* pElement = (CSmilTimelineElement*)(*i);
            // /Don't set delay of children with no valid begin time; the
            // default begin of an excl child is "indefinite".  Note that
            // sync-arc begins of elements that are skipped during this
            // delay-setting-by-parent operation will be OK when they
            // resolve because the resolved time has the delay built in:
            // /Note: tested this with <a> child and it works fine,
            if (pElement->m_pSourceElement  &&
                  (pElement->m_pSourceElement->m_bBeginOffsetSet
#if defined(XXXEH_HANDLE_MULTIPLE_EXCL_CHILD_SCHEDULED_BEGINS)
 /*can't do this fix yet because excl child w/beginOffset>0 must wait*/
                  // /If parent excl begins on event, child with non-
                  // event begin time won't yet have beginOffsetSet;
                  // fixes PR 56686(version 7 and 8):
                  || pElement->m_pSourceElement->
                  m_bHasAtLeastOneNonEventBasedBegin) )
#else
                  ) )
#endif
            {
                pElement->setDelay(m_pSourceElement->m_ulDelay, TRUE);
            }
            // /else leave delay unresolved.
            // /However, we need to go ahead and see which children have
            // non-event-based begins (see PR 24046 fix, below, which
            // this part of fix for PR 62688 broke by putting the
            // following code inside the if(), above (which never got hit
            // in an excl):
            // /This helps fix PR 62688(excl version):
            if (pElement->m_pSourceElement  &&
                  pElement->m_pSourceElement->
                  m_bHasAtLeastOneNonEventBasedBegin)
            {
                ulNumChildrenWithNonEventBasedBegins++;
            }
          }
      }
      // /Fixes PR 24046 (SMIL 2+ excl version): if there are no children,
      // then the excl's duration is zero, so set it to 0:
      if ((!m_pChildren  &&  m_pSourceElement->m_ulDuration == (UINT32)-1)  ||
            0 == ulNumChildrenWithNonEventBasedBegins)
      {
          // /Checking 1st for explicit end or dur re-fixes PR 57150(excl)
          // which was broken by fix for PR 24046 (note: PR 57150 has dur=x
          // *and* endsync="all" which is a strange thing to author):
          if (!m_pSourceElement->m_bHasExplicitDur  &&
                !m_pSourceElement->m_bHasExplicitEnd)
          {
            m_pSourceElement->m_ulDuration = 0;
          }
          // /Helps fix PR 62688(excl version): if all children are
          // event-begun and there is at least one child, and endsync="all",
          // then we have an indefinite duration until all child ends resolve:
          if (m_pChildren  &&  SMILEventSourceAll ==
                m_pSourceElement->m_nEndsyncEventSourceTag  &&
                // /Ignore endsync if it has explicit end or dur:
                !m_pSourceElement->m_bHasExplicitDur  &&
                !m_pSourceElement->m_bHasExplicitEnd)
          {
            m_pSourceElement->m_ulDuration = WAY_IN_THE_FUTURE;
          }
      }

      if (m_pSourceElement->m_ulDuration != (UINT32)-1)
      {
          setDuration(m_pSourceElement->m_ulDuration);

#if 20011024
          // /Fixes PR 61174(version1) and excl version of PR 56686
          // (version1): we know our duration already, so let's declare it
          // resolved so we get added to our parent (in case none of our
          // children have scheduled begin times in which case our
          // ::addDuration() would not get called up front and the overall
          // presentation would not include our duration at first):
          if (m_pSourceElement->m_bHasExplicitDur  ||
                m_pSourceElement->m_bHasExplicitEnd  ||
                // /For PR 62688(excl version) and other endsync="all" bugs:
                SMILEventSourceAll ==
                m_pSourceElement->m_nEndsyncEventSourceTag)
          {
            // /Be sure not to override a shorter duration that may have
            // been imposed on us by our parent:
            if (!m_bDurationSet  ||
                  !m_pSourceElement->m_bAddDurationAlreadyDone)
            {
                HX_ASSERT(m_pSourceElement->m_ulDuration ==
                      m_pSourceElement->getPureDuration());
                HX_ASSERT((UINT32)-1 != m_pSourceElement->m_ulDelay);
                durationResolved(m_pSourceElement->m_ulDuration, FALSE);
            }
            HX_ASSERT(m_bDurationSet  &&  m_pSourceElement->m_bAddDurationAlreadyDone);
          }
#endif
      }
    }
    else 
      // /Let's not claim that the delay is set when we still
      // are awaiting a delay (begin) event; we *do* need to
      // add the delay of this to the event's begin offset.
      // This is done by setting the new "m_bNonEventDelaySet"
      // variable to TRUE and leaving m_bDelaySet to FALSE
      // until the ElementResolved() call sets it to true:
    {
      // /Parent calls setDelay before we get to ElementResolved,
      // thus m_bDelaySet should never be TRUE if we have a
      // delay event:
      HX_ASSERT(!m_bDelaySet);
      m_bNonEventDelaySet = TRUE; //ElementResolved will look at this.
      m_ulNonEventDelay = ulDelay;
    }
    
    if(m_pDependent && m_bDurationSet)
    {
      adjustDependentDuration(m_pDependent);

#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
      ULONG32 ulTotalDelay = 0;
      if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase  &&
            m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
      {
          HX_ASSERT(0  &&  "ehodge: CHANGE NOT TESTED!");
      }

      if (HXR_OK !=
            m_pSourceElement->getCurrentScheduledStopTime(ulTotalDelay))
      {
          goto doneSettingDependent;
      }
#else
      ULONG32 ulTotalDelay = m_pSourceElement->m_ulDelay +
            m_pSourceElement->m_ulDuration;
      // /Helps fix PR 6XXXX(excl version): if delay is already packed
      // into the duration, then don't count it twice (as can happen in
      // <seq><excl begin="1s">...</excl><excl begin="1s" ...):
      if (m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
      {
          HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1);
/*OK[]*/        if (m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1)
          {
            HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                  ulTotalDelay);
            if (m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                  ulTotalDelay)
            {
                ulTotalDelay -=
                      m_pSourceElement->m_ulBeginOffsetFromSyncBase;
            }
          }
      }
#endif

      if (WAY_IN_THE_FUTURE < ulTotalDelay)
      {
          HX_ASSERT(WAY_IN_THE_FUTURE == ulTotalDelay  &&  "PR 59584");
          ulTotalDelay = WAY_IN_THE_FUTURE; // /For PR 59584.
      }

#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION) 
{ 
    FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout? 
          ADDDURATION_DEBUGOUT_STR_NEW_FILE : 
          ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE ); 
    ::fprintf(f1, "\n\t%s:CSmilTimelineExcl::setDelay(%lu): to %lu;"
          "\tresetting dependent (%s)'s delay to %lu\n", (const char*)m_pID,
          ulDelay, m_pSourceElement->m_ulDelay,
          (const char*)m_pDependent->m_pID, ulTotalDelay);
    ::fclose(f1); 
    bFirstTimeAddDurDebugout = FALSE; 
} 
#endif 
 
      // /XXXEH- TODO: figure out if we need to claim this is being set
      // by "parent" (which is really time base) so clip-begin-like
      // action can occur; I don't think so, however:
      m_pDependent->setDelay(ulTotalDelay, FALSE);
    }
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
doneSettingDependent:
#endif

    m_pParser->m_pTimelineElementManager->notify(m_pID);
}

void
CSmilTimelineExcl::setDuration(UINT32 ulDuration, BOOL bSetFromParent,
                          BOOL bDurationExtendingDueToPause)
{
    if (bDurationExtendingDueToPause)
    {
      // /Need to handle this case:
      HX_ASSERT(!bDurationExtendingDueToPause);
    }

    setParExclDuration(ulDuration, bSetFromParent);
}

void
CSmilTimelineExcl::setMaxDuration(UINT32 ulMaxDuration)
{
    setParExclMaxDuration(ulMaxDuration);
}

void 
CSmilTimelineExcl::resetDelay(UINT32 ulDelay)
{
    INT32 lAdjustedDelay = 0;

    UINT32 ulPriorDelay = m_pSourceElement->m_ulDelay;

    if(m_pSourceElement->m_bBeginOffsetSet)
    {
      lAdjustedDelay = (INT32)ulDelay + m_pSourceElement->m_lBeginOffset;
      m_pSourceElement->m_ulDelay = lAdjustedDelay > 0?lAdjustedDelay:0;
    }
    else
    {
      m_pSourceElement->m_ulDelay = ulDelay;
    }

    if(m_pChildren)
    {
      CHXSimpleList::Iterator i = m_pChildren->Begin();
      for(; i != m_pChildren->End(); ++i)
      {
          CSmilTimelineElement* pElement = (CSmilTimelineElement*)(*i);

          // /Don't set delay of children with no valid begin time; the
          // default begin of an excl child is "indefinite".  Note that
          // sync-arc begins of elements that are skipped during this
          // delay-setting-by-parent operation will be OK when they
          // resolve because the resolved time has the delay built in:
          // /Note: tested this with <a> child and it works fine,
          if (pElement->m_pSourceElement  &&
                (pElement->m_pSourceElement->m_bBeginOffsetSet
#if defined(XXXEH_HANDLE_MULTIPLE_EXCL_CHILD_SCHEDULED_BEGINS)
 /*can't do this fix yet because excl child w/beginOffset>0 must wait*/
                  // /If parent excl begins on event, child with non-
                  // event begin time won't yet have beginOffsetSet;
                  // fixes PR 56686(version 7 and 8):
                  || pElement->m_pSourceElement->
                  m_bHasAtLeastOneNonEventBasedBegin) )
#else
                  // Fixes PR 86106(version2): if this excl is in
                  // 2nd or subsequent child of seq then any updates to
                  // any prior sibling's duration wasn't causing this
                  // excl to adjust its children's delays accordingly.
                  // Now, we do so if and only if m_bDelaySet and has
                  // a non-event-based begin:
                  ||  pElement->m_bDelaySet  &&
                  pElement->m_pSourceElement->
                  m_bHasAtLeastOneNonEventBasedBegin 
                  ) )
#endif
          {
            pElement->resetDelay(m_pSourceElement->m_ulDelay);
          }
          // /else leave delay unresolved.
      }
    }

    // /To fix PR 59851(seq of excls), we need to update our next-in-seq
    // (m_pDependent) as well as make sure sync-arc listeners know we've
    // changed our overall time bounds delay as well;
    if (m_pDependent && m_bDurationSet  &&
          ulPriorDelay != m_pSourceElement->m_ulDelay)
    {
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
      ULONG32 ulTotalDelay = 0;
      if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase  &&
            m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
      {
          HX_ASSERT(0  &&  "ehodge: CHANGE NOT TESTED!");
      }

      if (HXR_OK !=
            m_pSourceElement->getCurrentScheduledStopTime(ulTotalDelay))
      {
          goto doneSettingDependent;
      }
#else
      ULONG32 ulTotalDelay = m_pSourceElement->m_ulDelay +
            m_pSourceElement->m_ulDuration;
      if (m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
      {
          HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1);
/*OK[]*/          if (m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1)
          {
            HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                  ulTotalDelay);
            if (m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                  ulTotalDelay)
            {
                ulTotalDelay -=
                      m_pSourceElement->m_ulBeginOffsetFromSyncBase;
            }
          }
      }
#endif
      if (WAY_IN_THE_FUTURE < ulTotalDelay)
      {
          HX_ASSERT(WAY_IN_THE_FUTURE == ulTotalDelay  &&  "PR 59584");
          ulTotalDelay = WAY_IN_THE_FUTURE; // /For PR 59584.
      }
 
#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION) 
{ 
    FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout? 
          ADDDURATION_DEBUGOUT_STR_NEW_FILE : 
          ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE ); 
    ::fprintf(f1, "\n\t%s:CSmilTimelineExcl::resetDelay(%lu):from %lu to %lu;"
          "\tresetting dependent (%s)'s delay to %lu\n", (const char*)m_pID,
          ulDelay, ulPriorDelay, m_pSourceElement->m_ulDelay,
          (const char*)m_pDependent->m_pID, ulTotalDelay);
    ::fclose(f1); 
    bFirstTimeAddDurDebugout = FALSE; 
} 
#endif 

      m_pDependent->resetDelay(ulTotalDelay);
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
doneSettingDependent:
#endif

      // /(Added while fixing PR 59851) Let others know our begin time changed:
      m_pParser->m_pTimelineElementManager->notify(m_pID);
    }
}

void 
CSmilTimelineExcl::adjustDuration()
{
    BOOL    bReset = FALSE;
    UINT32  ulDuration = 0;
    BOOL    bDurationSet = FALSE;
    BOOL    bEndsyncIdDurationFound = FALSE; // /For endsync="[Some ID]"
    // /Fixes excl version of PR 50676 (Added during fix for PR 59584):
    ULONG32 ulPriorPureDuration = m_pSourceElement->getPureDuration();

    if (!m_bDurationSet)
    {
      // /NOTE: If this has children who have not yet resolved their begin
      // times (which is why we're in this if(), then other children whose
      // durations have extended due to pausing will have no effect on
      // this parent.  We need to let this parent update its duration
      // accordingly (and its parents' durs as well).
      goto cleanup;
    }

    if(m_pChildren)
    {
      CHXSimpleList::Iterator i = m_pChildren->Begin();
      for(; i != m_pChildren->End(); ++i)
      {
          CSmilTimelineElement* pElement = (CSmilTimelineElement*)(*i);

          // /Checking this fixes excl version of PR 69290: if child duration
          // isn't set yet, don't use it here:
          if (!pElement->m_bDurationSet)
          {
            continue;
          }
          HX_ASSERT((UINT32)-1 != pElement->m_pSourceElement->m_ulDuration);


          // /Make sure we take endsync into account here:
          if (SMILEventSourceFirst == m_pSourceElement->m_nEndsyncEventSourceTag)
          {
            if (!bDurationSet)
            {
                ulDuration = pElement->m_pSourceElement->m_ulDuration;
            }
            else
            {
                ulDuration = (ulDuration < pElement->m_pSourceElement->m_ulDuration) ?
                      ulDuration : pElement->m_pSourceElement->m_ulDuration;
            }
            bDurationSet = TRUE;
          }
          else if (SMILEventSourceID == m_pSourceElement->m_nEndsyncEventSourceTag)
          {
            if (pElement->m_pSourceElement->m_pNode  &&
                  m_pSourceElement->m_EndsyncEventSourceID ==
                  pElement->m_pSourceElement->m_pNode->m_id)
            {
                ulDuration = pElement->m_pSourceElement->m_ulDuration;
                bEndsyncIdDurationFound = TRUE;
                bDurationSet = TRUE;
            }
          }
          // /This else-if block fixes problem in PR 62688 repro case where
          // restarting a child, prior to all children playing, caused excl
          // to resolve its dur as if it were endsync="last":
          else if (SMILEventSourceAll ==
                m_pSourceElement->m_nEndsyncEventSourceTag)
          {
            if (m_pChildren  &&
                  m_nDurationAdded >= m_pChildren->GetCount())
            {
                ulDuration = (ulDuration > pElement->m_pSourceElement->m_ulDuration) ?
                      ulDuration : pElement->m_pSourceElement->m_ulDuration;
                bDurationSet = TRUE;
            }
            else
            {
                // /Don't adjust duration until all child durs are in:
                goto cleanup;
            }
          }
          else // /For "last", use the largest child duration:
          {
            ulDuration = (ulDuration > pElement->m_pSourceElement->m_ulDuration) ?
                  ulDuration : pElement->m_pSourceElement->m_ulDuration;
            bDurationSet = TRUE;
          }

          // /Fixes PR 50806 (excl versions 1 & 2): if this has "min"
          // attribute set, ulDuration shouldn't be less regardless
          // of endSync:
          if (m_pSourceElement->m_ulMinActiveDur > ulDuration)
          {
            ulDuration = m_pSourceElement->m_ulMinActiveDur;
          }
      }

      // /!bDurationSet happens in PR 50588 (case 2: begin="x.end"), when
      // child has begun playing but has not yet resolved its duration:
      if (!bDurationSet)
      {   HX_ASSERT(bDurationSet  &&  "contact-ehodge");
          goto cleanup;
      }

      if (SMILEventSourceID == m_pSourceElement->m_nEndsyncEventSourceTag)
      { 
          if (!bEndsyncIdDurationFound)
          {
            goto cleanup; // /That id'd child not added to timeline yet.
          }
      } 
//check m_ulAuthoredDur here:
      if (!m_pSourceElement->m_bHasExplicitEnd  &&
            !m_pSourceElement->m_bHasExplicitDur)
      { 
          m_pSourceElement->m_ulDuration = ulDuration;
      }
    
      // /Moved this out of the above if() so it gets called every time, to
      // fix PR 6XXX? and re-fix PR 55117: we should always give our parents
      // a chance to set the outer-time-container duration so it can (re)-
      // state to the core what the group duration should be:
      if(m_pParent)
      {
          m_pParent->adjustDuration();
      }

      // /Moved this out to happen all the time, too:
      if (m_pDependent)
      {
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
          ULONG32 ulTotalDelay = 0;
          if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase  &&
              m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
          {
            HX_ASSERT(0  &&  "ehodge: CHANGE NOT TESTED!");
          }

          if (HXR_OK != m_pSourceElement->getCurrentScheduledStopTime(
                ulTotalDelay))
          {
            goto doneSettingDependent;
          }
#else
          ULONG32 ulTotalDelay = m_pSourceElement->m_ulDelay +
                m_pSourceElement->m_ulDuration;
          if (m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
          {
            HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1);
/*OK[]*/          if (m_pSourceElement->m_ulBeginOffsetFromSyncBase != (UINT32)-1)
            {
                HX_ASSERT(m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                      ulTotalDelay);
                if (m_pSourceElement->m_ulBeginOffsetFromSyncBase <
                      ulTotalDelay)
                {
                  ulTotalDelay -=
                        m_pSourceElement->m_ulBeginOffsetFromSyncBase;
                }
            }
          }
#endif
          if (WAY_IN_THE_FUTURE < ulTotalDelay)
          {
            // /XXXEH- If delay is greater than this, I want to know:
            HX_ASSERT(WAY_IN_THE_FUTURE == ulTotalDelay  &&  "PR 59584");
            ulTotalDelay = WAY_IN_THE_FUTURE; // /For PR 59584.
          }

#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION)
{
FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout?
      ADDDURATION_DEBUGOUT_STR_NEW_FILE :
      ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE );
::fprintf(f1, "\n\t%s:CSmilTimelineExcl::adjustDuration();\tresetting dependent (%s)'s delay to %lu\n",
      (const char*)m_pID, (const char*)m_pDependent->m_pID, ulTotalDelay);
::fclose(f1);
bFirstTimeAddDurDebugout = FALSE;
}
#endif

          m_pDependent->resetDelay(ulTotalDelay);
      }
#if defined(XXXEH_WAIT_UNTIL_getCurrentScheduledStopTime_IS_FIXED_WHEN_BEGINOFFSETSET_20011022)
doneSettingDependent:
      ;
#endif
    }

    // /Fixes PR 69410 (with outer excl): do this no matter what, even if
    // prior < ulDur; resumed element in excl should extend this excl but
    // we've already told the core to limit the presentation duration,
    // so extend it here as needed:
    // /(Added while fixing PR 59584): if our duration got reduced, we need to
    // possibly constrain our children:
    {
      // /For PR 62688 & PR 59584: remove check for ulPriorDuration being
      // WAY_IN_THE_FUTURE since PR 50676 works without it and there are
      // cases where our dur may re-resolve, & updating children is needed:

      // This group's outer time container, if this is one, needs
      // to set the duration if its dur is longer than its group's so far
      // or if its previous duration was unresolved and now is resolved:
      if (m_pSourceElement->m_pNode  &&  m_pSourceElement->m_pHandler)
      {
          if (m_pSourceElement->m_pNode->m_pParent  &&  (SMILBody == 
                m_pSourceElement->m_pNode->m_pParent->m_tag  ||
                m_pSourceElement->m_pNode->
/*OK[]*/              m_pParent->m_bIsOuterWrapperTimeContainer) )
          {
            // /The group duration should be the duration of this
            // outer-most time container:
            HX_RESULT pnrs = m_pSourceElement->m_pHandler->
                  resolveGroupDurToOuterTimeContainerDur(
                  m_pSourceElement->m_pNode->m_nGroup,
                  m_pSourceElement->m_ulDuration);
          }
      }

      if(m_pChildren)
      {
          // /Accounting for begin offset of this helps fix PR 65741(excl)
          // where excl w/begin="5s' was including that 5s in dur passed
          // to children, thus children were playing 5s too long:
          ULONG32 ulSyncBaseDurationForChildren =
                m_pSourceElement->m_ulDuration;
          if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase  &&
                m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
          {
            HX_ASSERT(ulSyncBaseDurationForChildren >=
                  m_pSourceElement->m_ulBeginOffsetFromSyncBase);
            if (ulSyncBaseDurationForChildren >=
                  m_pSourceElement->m_ulBeginOffsetFromSyncBase)
            {
                ulSyncBaseDurationForChildren -=
                      m_pSourceElement->m_ulBeginOffsetFromSyncBase;
            }
          }

          CHXSimpleList::Iterator i = m_pChildren->Begin();
          for(; i != m_pChildren->End(); ++i)
          {
            CSmilTimelineElement* pElement = (CSmilTimelineElement*)(*i);
            if (pElement->m_pSourceElement  &&
                  pElement->m_pSourceElement->m_ulDuration >
                  m_pSourceElement->m_ulDuration)
            {
                pElement->setDuration(ulSyncBaseDurationForChildren, TRUE);
            }
          }
      }
    }

cleanup:

    m_pParser->m_pTimelineElementManager->notify(m_pID);

    return;
}

void 
CSmilTimelineExcl::addDuration(UINT32 ulDuration,
                        UINT32 ulDelay,
                        UINT32 ulChildDelayBeyondStartOfThis, 
                        const char* pElementID)
{
    BOOL bHandled = FALSE;

    UINT32 ulPriorPureDuration = m_pSourceElement->getPureDuration();

#if defined(_DEBUG)  &&  defined(XXXEH_DEBUGOUT_ADDDURATION)
    {
      FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout?
            ADDDURATION_DEBUGOUT_STR_NEW_FILE :
            ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE );
      ::fprintf(f1, "CSmilTimelineExcl{%s}::addDuration(dur=%lu, delay=%lu, "
            "childDelayBeyondThis=%lu, id=%s) m_bDurationSet=%sE\n",
            (const char*)m_pID, ulDuration, ulDelay,
            ulChildDelayBeyondStartOfThis, pElementID,
            m_bDurationSet?"TRU":"FALS");
      ::fclose(f1);
      bFirstTimeAddDurDebugout = FALSE;
    }
#endif

    // /If we're inside a seq, our true "sync base" is not the seq but rather
    // the prievious seq sibling (if any).  We need to adjust the ulDelay, if
    // we're in a seq, down to just ulChildDelayBeyondStartOfThis, which is
    // the delay from the prior sibling, not from the seq:
    ULONG32 ulDelayBeyondSyncBase = 0;
    SMILNode* pSyncBaseNode = NULL;
    if (m_pSourceElement->m_pNode)
    {
      pSyncBaseNode = m_pParser->getSyncAncestor(
          m_pSourceElement->m_pNode);
    }
    if (!pSyncBaseNode  ||  !pSyncBaseNode->m_pElement)
    {
      HX_ASSERT(pSyncBaseNode  &&  pSyncBaseNode->m_pElement);
    }
    // /Do this for all time containers (for part of PR52110 post-fix-delay-
    // offset-bug):
    else
    {
      ulDelayBeyondSyncBase = ulChildDelayBeyondStartOfThis;
    }

    BOOL bSetChildCurEndClippedByParent = FALSE;
    BOOL bSetCompletelyRemovedFromTimeline = FALSE;
    BOOL bIsCurChildsFirstAddDuration = FALSE;
    ULONG32 ulCurChildPriorAddedDuration = (UINT32)-1;
    if (!(*m_pChildDurAddedMap)[pElementID])
    {
      bIsCurChildsFirstAddDuration = TRUE;
    }
    else
    {
      ulCurChildPriorAddedDuration =
            (ULONG32)((*m_pChildDurAddedMap)[pElementID]);
    }

    ULONG32 ulActualDurBeyondSyncBase =
          ulDuration + ulDelayBeyondSyncBase - ulChildDelayBeyondStartOfThis;

// /XXXEH-20020106-test:    HX_ASSERT(WAY_IN_THE_FUTURE >= ulActualDurBeyondSyncBase);

    // /Start of fix for PR 55117: explicit dur or end on par should not be
    // overridden by some punk child's dur; if this has an explicit
    // end or dur, don't do anything to its duration based on children durs:
    // /XXXEH- TODO: determine what wins between endsync VS either end or dur
    // if both are specified; here, I assume end|dur wins over endsync:
    if (m_pSourceElement->m_bHasExplicitDur  ||
          m_pSourceElement->m_bHasExplicitEnd)
    {
      if ((UINT32)-1 != m_pSourceElement->m_ulDuration  &&
            (!m_bDurationSet  ||
            !m_pSourceElement->m_bAddDurationAlreadyDone) )
      {
          HX_ASSERT((UINT32)-1 != m_pSourceElement->m_ulDelay);
          HX_ASSERT(m_pSourceElement->m_ulDuration ==
                m_pSourceElement->getPureDuration());
          durationResolved(m_pSourceElement->m_ulDuration, FALSE);
      }
      // /Helps fix PR 6XXXZ (PR 55117 revisited): par in seq where par has explicit dur and
      // children all have smaller durations, we need to give outer time
      // container a chance to hold the presentation open; this is needed
      // when this par is last one in presentation.  (Note: body doesn't set
      // the presentation time during createElements() phase because it
      // doesn't have m_pHandler yet then):
      adjustDuration();
      bHandled = TRUE;
    }
    // /Fixes SMIL 1.0's endsync="id(xyz)" and enables SMIL 2.0's
    // id-based endsync: endsync="xyz":
    else if (m_pSourceElement->m_nEndsyncEventSourceTag == SMILEventSourceID)
    {
      if (!m_pSourceElement->m_EndsyncEventSourceID.IsEmpty()  &&
              !strcmp(m_pSourceElement->m_EndsyncEventSourceID,pElementID))
      {
          // /Don't just use ulDuration in case child has a begin offset
          // or otherwise has a delay beyond this's delay.
          m_pSourceElement->m_ulDuration = ulActualDurBeyondSyncBase;
          durationResolved(m_pSourceElement->m_ulDuration, TRUE);
          bHandled = TRUE;
      }
    }
    else if(m_pSourceElement->m_nEndsyncEventSourceTag == SMILEventSourceAll)
    {
      // /Hold excl open until all children have had a chance to begin;
      // leave the excl's duration unresolved awaiting the final child's
      // call to "addDuration" (which may never come if child's begin
      // never resolves):

      // /Helps fix PR 62688(excl version): first, check if all children
      // have resolved already; if so, then duration is set so we can't
      // extend it if begin is after parent excl ended:
      if (m_nDurationAdded >= m_pChildren->GetCount()  &&
            m_pSourceElement->m_ulDuration < ulActualDurBeyondSyncBase)
      {
          bSetChildCurEndClippedByParent = TRUE;
          HX_ASSERT(m_ulLastDuration == m_pSourceElement->m_ulDuration);
          if (m_ulLastDuration > ulChildDelayBeyondStartOfThis)
          {
            // /Helps fix PR 50660 by removing PR 62688-fix code here that
            // turned out to be unnecessary since code elsewhere completely
            // fixes PR 62688.  Child should be allowed to extend its
            // parent's duration except if it begins *after* its parent has
            // already ended, which is how we got here, so do nothing.
          }
          else // /Begin offset is beyond parent's end, so remove it:
          // helps fix PR 62688(excl) (endsync="all" version of PR 64158)
          {
            bSetCompletelyRemovedFromTimeline = TRUE;
            HX_RESULT retval2 = m_pSourceElement->m_pHandler->
                  handleTrackRemoval((const char*)pElementID,
                  (INT32)m_pSourceElement->m_pNode->m_nGroup);
          }
      }

      if(ulActualDurBeyondSyncBase < m_ulFirstDuration  ||
            !m_bFirstDurationHasBeenSet)
      {
          m_ulFirstDuration = ulActualDurBeyondSyncBase;
          m_bFirstDurationHasBeenSet = TRUE;
      }
      if(ulActualDurBeyondSyncBase > m_ulLastDuration)
      {
          m_ulLastDuration = ulActualDurBeyondSyncBase;
      }
      // /This helps fix PR 62688(par version): this is used to see if
      // we've already resolved our duration (because all children have
      // weighed in):
      INT32 lTotalDurationsAddedIncludingThisOne = (INT32)m_nDurationAdded;
      if (bIsCurChildsFirstAddDuration)
      {
          lTotalDurationsAddedIncludingThisOne++;
      }
      if (lTotalDurationsAddedIncludingThisOne < m_pChildren->GetCount()  &&
            // /To help fix PR 59584(excl version), only do this once:
            WAY_IN_THE_FUTURE != m_pSourceElement->m_ulDuration)
      {
          // /XXXEH- need a better way, but for now let's say it's
          // resolved to a very big number until all children have
          // resolved begins:
          durationResolved(WAY_IN_THE_FUTURE, TRUE);
      }
    }
    else if(m_pSourceElement->m_ulDuration == (UINT32)-1)
    {
      // /Added delay to duration which works in:
      // "BUG-20010430_endHappening2sTooEarlyForExclThatHas"...
      // ..."2.7sBeginAndDurBasedOnChild(totalPresentationDur5.7s).smil":
      m_pSourceElement->m_ulDuration = ulDuration + ulDelayBeyondSyncBase -
            // /Works in excl version of
            // "BUG-20010502(at0700hrs))_firstOu"..."2ndChildIsExcl.smil"
            // /(NOTE: this will be non-zero in the case where the parent
            // excl (this) has endsync="first" and is adding first child
            // due to an event:
            ulChildDelayBeyondStartOfThis;
      m_ulFirstDuration = ulActualDurBeyondSyncBase;
      m_bFirstDurationHasBeenSet = TRUE;
      if (WAY_IN_THE_FUTURE >= m_pSourceElement->m_ulDuration  &&
            !bIsCurChildsFirstAddDuration  &&
            WAY_IN_THE_FUTURE <= ulCurChildPriorAddedDuration)
      {
          HX_ASSERT(0); // /TESTING! PR 59584.
          // then don't do the next line (?):
      }
      m_ulLastDuration = ulActualDurBeyondSyncBase;
    }
    else
    // /An excl time container can only have one active track at a time,
    // but it can know that it will play subsequent ones if they have
    // resolved delays (which is how we entered this "else" block, so we
    // need to calculate the excl's duration as the latest that any resolved
    // element will play as far as we know at this point.  Excl's duration
    // in many cases will then vary as childrens' delays become resolved
    // over time:
    // /XXXEH- test this!!!  I left it the same as for Par, but we should
    // consider interrupt behavior of the excl's elements since one may
    // not start while another "uninterruptable" element is playing and
    // thus may not affect the excl's initial dur:
    {
      m_pSourceElement->m_ulDuration = 
          (ulActualDurBeyondSyncBase > m_pSourceElement->m_ulDuration) ?
          ulActualDurBeyondSyncBase : m_pSourceElement->m_ulDuration;
      // /XXXEH- TODO: handle m_ulFirst...etc. (or make sure they work) now
      // that delay is being added (as it should be) to m_ulDuration, above:
      if(ulActualDurBeyondSyncBase < m_ulFirstDuration  ||
            !m_bFirstDurationHasBeenSet)
      {
          m_ulFirstDuration = ulActualDurBeyondSyncBase;
          m_bFirstDurationHasBeenSet = TRUE;
      }
      if(ulActualDurBeyondSyncBase > m_ulLastDuration)
      {
          m_ulLastDuration = ulActualDurBeyondSyncBase;
      }
    }

    if (!(*m_pChildDurAddedMap)[pElementID])
    {
      m_nDurationAdded++;
      (*m_pChildDurAddedMap)[pElementID] = (void*)ulActualDurBeyondSyncBase;
    }
    ULONG32 ulChildrenCount = m_pChildren->GetCount();
    // /Fixes PR 56481(excl version) find children that don't have a scheduled
    // begin, i.e., are awaiting an event to begin.  endsync="last" says to
    // ignore any children that never play, and we don't know if those
    // event-based begin children will play or not so ignore them for now,
    // and if they ever do begin, *then* re-compute this excl's duration:
    ULONG32 ulNonEventBasedBeginChildCount = 0;
    CSmilElement* pCurChildElem = NULL;
    CHXSimpleList::Iterator i = m_pChildren->Begin();
    for(i; i != m_pChildren->End(); ++i)
    {
      CSmilTimelineElement* pTmlnElement =
            (CSmilTimelineElement*)(*i);
      if (pTmlnElement  &&  pTmlnElement->m_pSourceElement)
      {
          BOOL isCurAddDurElem = FALSE;
          if (!strcmp(pTmlnElement->m_pSourceElement->m_pNode->m_id,
                pElementID))
          {
            isCurAddDurElem = TRUE;
            pCurChildElem = pTmlnElement->m_pSourceElement;
            if (bSetChildCurEndClippedByParent  &&  pCurChildElem)
            {
                pCurChildElem->m_bCurEndClippedByParent = TRUE;
            }
            if (bSetCompletelyRemovedFromTimeline  &&  pCurChildElem)
            {
                pCurChildElem->m_bInsertedIntoTimeline = FALSE;
            }
          }
          if ((pTmlnElement->m_pSourceElement->
                m_bHasAtLeastOneNonEventBasedBegin  ||
                // /Do this so this par can re-resolve its duration if &
                // when an event-based-begin child gets added (and thus
                // technically now is a child with a clock-valued begin):
                isCurAddDurElem) )
          {
            ulNonEventBasedBeginChildCount++;
          }
      }
    }
    
    if (!bHandled  &&
          (m_nDurationAdded >= ulNonEventBasedBeginChildCount  &&
          // /If endsync is all, we need to wait for *all* to be added:
          (SMILEventSourceAll!=m_pSourceElement->m_nEndsyncEventSourceTag  ||
          m_nDurationAdded == ulChildrenCount) )  &&
          !m_bDurationEvent)
    {
      BOOL bUpdateDurMightBeNeeded = FALSE;
      // /Helps fix PR 62688(excl): if duration was set before, but only to
      // hold the timeline open until all (or a particular) child duration
      // became known, then we want to ignore the durationSet flag so that
      // we call duartionResolved() instead of adjustDuration();
      BOOL bIgnoreDurationSetFlag = bIsCurChildsFirstAddDuration  &&
            (WAY_IN_THE_FUTURE <= m_pSourceElement->m_ulDelay +
            m_pSourceElement->m_ulDuration);
      // /First, if duration has already been set, then pElement must be an
      // event-based-begin child that just resolved, so we need to reset
      // our duration appropriately:
      if (m_bDurationSet  &&  pCurChildElem  &&  !bIgnoreDurationSetFlag  &&
            !pCurChildElem->m_bHasAtLeastOneNonEventBasedBegin)
      {
          bUpdateDurMightBeNeeded = TRUE;
      }

      if(m_pSourceElement->m_nEndsyncEventSourceTag == 
          SMILEventSourceFirst)
      {
          if (bUpdateDurMightBeNeeded)
          {
            if (ulActualDurBeyondSyncBase == m_ulFirstDuration)
            {
                // /XXXEH- revisit now that addDuration accts for endsync:
                ULONG32 ulOldDur = m_pSourceElement->m_ulDuration;
                adjustDuration();
                HX_ASSERT(m_pSourceElement->m_ulDuration == m_ulFirstDuration);
                // /Other half of fix for PR 50679: if updated duration
                // is less than prior dur, then update timeline element:
                if (ulOldDur > m_pSourceElement->m_ulDuration)
                {
                  // /Reset duration-set flag to FALSE since we want to
                  // override (reset) the dur now that this last child
                  // has been resolved (presumably after playback of
                  // this par began):
                  m_bDurationSet = FALSE;
                  durationResolved(m_pSourceElement->m_ulDuration, TRUE);
                }
            }
          }
          else
          {
            durationResolved(m_ulFirstDuration, TRUE);
          }
      }
      else if(m_pSourceElement->m_nEndsyncEventSourceTag == 
          SMILEventSourceLast)
      {
          if (bUpdateDurMightBeNeeded)
          {
            if (ulActualDurBeyondSyncBase == m_ulLastDuration)
            {
                adjustDuration();
            }
          }
          else
          {
            // /Helps fix PR 59584(simplified): if we previously resolved
            // our duration to "unresolved" to hold timeline open, then we
            // need to adjust our duration down from WAY_IN_THE_FUTURE:
            if (WAY_IN_THE_FUTURE == m_pSourceElement->m_ulDuration  ||
                  WAY_IN_THE_FUTURE == m_ulLastDuration  ||
                  m_pSourceElement->m_ulDuration != m_ulLastDuration)
            {
                if (WAY_IN_THE_FUTURE == m_pSourceElement->m_ulDuration  &&
                      bIsCurChildsFirstAddDuration)
                {
                  // /See "part 2 of PR 79699" above; don't want to mess
                  // with this unless there's content that asserts here:
                  HX_ASSERT(m_bDurationSet);
                }
                adjustDuration();
                m_bDurationSet = FALSE;
            }
            HX_ASSERT(m_pSourceElement->m_ulDuration ==
                  m_pSourceElement->getPureDuration());
            // /To fix PR 59584(exclVersionSimplified, w/"last"), use
            // m_pSourceE.'s dur, not m_ulLastDuration since latter may
            // be wrong if some elements stopped early
            durationResolved(m_pSourceElement->m_ulDuration, TRUE);
          }
      }
      else if(m_pSourceElement->m_nEndsyncEventSourceTag == 
          SMILEventSourceAll)
      {
          if (bUpdateDurMightBeNeeded)
          {
            if (ulActualDurBeyondSyncBase == m_ulLastDuration)
            {
                // /adjustDuration() assumes endsync=last which is OK
                // since we've got all durations:
                adjustDuration();
            }
          }
          else
          {
            // /Helps fix PR 59584(excl, simpl.): if we previously resolved
            // our duration to "unresolved" to hold timeline open, then we
            // need to adjust our duration down from WAY_IN_THE_FUTURE:
            if (WAY_IN_THE_FUTURE == m_pSourceElement->m_ulDuration  ||
                  WAY_IN_THE_FUTURE == m_ulLastDuration  ||
                  m_pSourceElement->m_ulDuration != m_ulLastDuration)
            {
                if (WAY_IN_THE_FUTURE == m_pSourceElement->m_ulDuration  &&
                      bIsCurChildsFirstAddDuration)
                {
                  // /See "part 2 of PR 79699" above; don't want to mess
                  // with this unless there's content that asserts here:
                  HX_ASSERT(m_bDurationSet);
                }
                adjustDuration();
            }
            HX_ASSERT(m_pSourceElement->m_ulDuration ==
                  m_pSourceElement->getPureDuration());
            // /Reset duration-set flag to FALSE since we want to
            // override (reset) the dur now that this last child has been
            // resolved (presumably after playback of this par began):
            m_bDurationSet = FALSE;
            // /To fix PR 59584(exclVersionSimplified), use m_pSourceE.'s
            // duration, not m_ulLastDuration since latter may be wrong
            // if some elements stopped early:
            durationResolved(m_pSourceElement->m_ulDuration, TRUE);
          }
      }
      else
      {
          if (bUpdateDurMightBeNeeded)
          {
            if (ulActualDurBeyondSyncBase == m_pSourceElement->m_ulDuration)
            {
                adjustDuration();
            }
          }
          else
          {
            // /Helps fix PR 62688(excl version): if we previously resolved
            // our duration to "unresolved" to hold timeline open, then we
            // need to adjust our duration down from WAY_IN_THE_FUTURE:
            if (WAY_IN_THE_FUTURE == m_pSourceElement->m_ulDuration  ||
                  WAY_IN_THE_FUTURE == m_ulLastDuration  ||
                  m_pSourceElement->m_ulDuration != m_ulLastDuration)
            {
                if (WAY_IN_THE_FUTURE == m_pSourceElement->m_ulDuration  &&
                      bIsCurChildsFirstAddDuration)
                {
                  // /See "part 2 of PR 79699" above; don't want to mess
                  // with this unless there's content that asserts here:
                  HX_ASSERT(m_bDurationSet);
                }
                adjustDuration();
                m_bDurationSet = FALSE;
            }
            HX_ASSERT(m_pSourceElement->m_ulDuration == m_ulLastDuration);
            durationResolved(m_pSourceElement->m_ulDuration, FALSE);
          }
      }
      // /This if() block fixes PR 56686 (version 4) and
      // PR 61174 (version 4): if time container has longer dur than its
      // children and it is not a time-child of the <body>, then its dur
      // was never getting accounted for, but now the outer time container
      // sets the duration if its dur is longer than its group's so far;
      // outer time contnr can only be a par if body has multiple children:
      if (m_pSourceElement->m_pNode  &&  m_pSourceElement->m_pHandler)
      {
          // /XXXEH- handle <body><switch><par> and <body><a><par>
          if (m_pSourceElement->m_pNode->m_pParent  &&  (SMILBody == 
                m_pSourceElement->m_pNode->m_pParent->m_tag  ||
                m_pSourceElement->m_pNode->
/*OK[]*/              m_pParent->m_bIsOuterWrapperTimeContainer) )
          {
            UINT32 ulGroup = m_pSourceElement->m_pNode->m_nGroup;
            // /The group duration should be the duration of this
            // outer-most time container:
            HX_RESULT pnrs = m_pSourceElement->m_pHandler->
                  resolveGroupDurToOuterTimeContainerDur(
                  ulGroup, m_pSourceElement->m_ulDuration);
          }
      }
    }
}

void
CSmilTimelineExcl::elementResolved(CSmilTimelineElement* pEventElement)
{
    parExclElementResolved(pEventElement);
}

void
CSmilTimelineExcl::durationResolved(UINT32 ulDuration, BOOL bUpdateChildren)
{
    parExclDurationResolved(ulDuration, bUpdateChildren);
}

/***************************************************************************/

/*
 * CSmilTimelineAnchor methods
 */

CSmilTimelineAnchor::CSmilTimelineAnchor(CSmilElement* pSourceElement,
                           CSmilParser* pParser):
    CSmilTimelineElement(pSourceElement, pParser)
    , m_nDurationAdded(0)
{
}

CSmilTimelineAnchor::~CSmilTimelineAnchor()
{
}

void
CSmilTimelineAnchor::elementResolved(CSmilTimelineElement* pEventElement)
{
    //First, let's see if we have a begin event to resolve:
    if ( (m_pSourceElement->m_nBeginEventSourceTag == SMILEventSourceBegin  ||
          m_pSourceElement->m_nBeginEventSourceTag == SMILEventSourceClock)  &&
          m_pSourceElement->m_BeginEventSourceID == pEventElement->m_pID)
    {
      if(pEventElement->m_bDelaySet)
      {
          //[SMIL 1.0 Compliance] Helps fix 14420:
          if (m_bNonEventDelaySet)
          {
            //Add non-event delay to syncArc element's delay + clock offset:
            LONG32 lSum =
                  (LONG32)pEventElement->m_pSourceElement->m_ulDelay +
                  m_pSourceElement->m_lBeginEventClockValue;
            HX_ASSERT(lSum >= 0  &&  "ehodge: handle neg delay propogation");
            lSum = (lSum<0? 0 : lSum);  //clip off negative vals.
            m_pSourceElement->m_ulDelay = m_ulNonEventDelay + (ULONG32)lSum;
          }
          else
          {
            m_ulNonEventDelay = 0;
            //Just set delay to syncArc element's delay:
            //Do the following in case sum is negative; if so, we
            // want to use zero.
            LONG32 lSum =
                  (LONG32)pEventElement->m_pSourceElement->m_ulDelay +
                  // /Fixes case where anchor/area has begin="foo.begin+5s"
                  // we need to account for the 5s here:
                  m_pSourceElement->m_lBeginEventClockValue;
            HX_ASSERT(lSum >= 0  &&  "ehodge: handle neg delay propogation");
            lSum = (lSum<0? 0 : lSum);  //clip off negative vals.
            m_pSourceElement->m_ulDelay = (ULONG32)lSum;

            // /Now, we need to set the vars that keep track of our
            // offset from our syncBase element because isCurrentLink
            // uses times relative to our syncBase:
            SMILNode* pSyncNode = (!m_pParser? NULL :
                   m_pParser->getSyncAncestor(m_pSourceElement->m_pNode));
            HX_ASSERT(pSyncNode  &&  pSyncNode->m_pElement);
            if (pSyncNode  &&  pSyncNode->m_pElement)
            { 
                ULONG32 ulSyncBaseDelay =
                      pSyncNode->m_pElement->m_ulDelay;
                HX_ASSERT((UINT32)-1 != ulSyncBaseDelay);
                if ((UINT32)-1 != ulSyncBaseDelay  &&
                      (UINT32)-1 != m_pSourceElement->m_ulDelay )
                { 
                  HX_ASSERT(m_pSourceElement->m_ulDelay >=
                        ulSyncBaseDelay);
                  m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase =
                        TRUE;
                  if (m_pSourceElement->m_ulDelay >= ulSyncBaseDelay)
                  { 
                      ULONG32 ulEffectiveBeginOffset =
                            m_pSourceElement->m_ulDelay -
                            ulSyncBaseDelay;
                      m_pSourceElement->m_ulBeginOffsetFromSyncBase =
                            ulEffectiveBeginOffset;
                  } 
                  else
                  { 
                      m_pSourceElement->m_ulBeginOffsetFromSyncBase = 0;
                  } 
                } 
            } 
          }

          m_bNonEventDelaySet = m_bDelaySet = TRUE;
          if(m_pChildren)
          {
            CHXSimpleList::Iterator i = m_pChildren->Begin();
            for(; i != m_pChildren->End(); ++i)
            {
                CSmilTimelineElement* pElement =
                      (CSmilTimelineElement*)(*i);
                pElement->setDelay(m_pSourceElement->m_ulDelay, TRUE);
            }
          }
      }
    }
    else if(m_pSourceElement->m_nBeginEventSourceTag == SMILEventSourceEnd  &&
          m_pSourceElement->m_BeginEventSourceID == pEventElement->m_pID)
    {
      // /If event element's duration is "WAY_IN_THE_FUTURE" then it's
      // essentially an unresolved end time, so we should not resolve
      // based on it:
      if(pEventElement->m_bDurationSet  &&  WAY_IN_THE_FUTURE !=
            pEventElement->m_pSourceElement->m_ulDuration)
      {
          //[SMIL 1.0 Compliance] Helps fix 14420:
          if (m_bNonEventDelaySet)
          {
            //Add non-event delay to syncArc element's delay + clock offset:
            LONG32 lSum =
                  (LONG32)pEventElement->m_pSourceElement->m_ulDuration +
                  (LONG32)pEventElement->m_pSourceElement->m_ulDelay +
                  // /Fixes begin="foo.end+5s"; 5s was being ignored:
                  m_pSourceElement->m_lBeginEventClockValue;
            HX_ASSERT(lSum >= 0  &&  "ehodge: handle neg delay propogation");
            lSum = (lSum<0? 0 : lSum);  //clip off negative vals.
            m_pSourceElement->m_ulDelay = m_ulNonEventDelay + (ULONG32)lSum;
          }
          else
          {
            //Add non-event delay to syncArc element's delay + clock offset:
            LONG32 lSum =
                  (LONG32)pEventElement->m_pSourceElement->m_ulDuration +
                  (LONG32)pEventElement->m_pSourceElement->m_ulDelay +
                  // /Fixes PR 68495 begin="foo.end+5s"; 5s was ignored
                  // without the following:
                  m_pSourceElement->m_lBeginEventClockValue;
            HX_ASSERT(lSum >= 0  &&  "ehodge: handle neg delay propogation");
            lSum = (lSum<0? 0 : lSum);  //clip off negative vals.
            m_ulNonEventDelay = 0;
            m_pSourceElement->m_ulDelay = (ULONG32)lSum;
          }
          m_bNonEventDelaySet = m_bDelaySet = TRUE;
          if(m_pChildren)
          {
            CHXSimpleList::Iterator i = m_pChildren->Begin();
            for(; i != m_pChildren->End(); ++i)
            {
                CSmilTimelineElement* pElement =
                      (CSmilTimelineElement*)(*i);
                pElement->setDelay(m_pSourceElement->m_ulDelay, TRUE);
            }
          }
      }
    }

    
    //XXXEH-The following cases need to be tested!:
    if ( (m_pSourceElement->m_nEndEventSourceTag == SMILEventSourceBegin  ||
          m_pSourceElement->m_nEndEventSourceTag == SMILEventSourceClock)  &&
          m_pSourceElement->m_EndEventSourceID == pEventElement->m_pID)
    {
      if(pEventElement->m_bDelaySet)
      {
          LONG32 lSum =(LONG32)pEventElement->m_pSourceElement->m_ulDelay +
                m_pSourceElement->m_lEndEventClockValue;
          HX_ASSERT(lSum >= 0  &&  "ehodge: handle neg delay propogation");
          lSum = (lSum<0? 0 : lSum);  //clip off negative vals.
          durationResolved((ULONG32)lSum);
      }
    }
    else if(m_pSourceElement->m_nEndEventSourceTag == SMILEventSourceEnd  &&
          m_pSourceElement->m_EndEventSourceID == pEventElement->m_pID)
    {
      // /If event element's duration is "WAY_IN_THE_FUTURE" then it's
      // essentially an unresolved end time, so we should not resolve
      // based on it:
      if(pEventElement->m_bDurationSet  &&  WAY_IN_THE_FUTURE !=
            pEventElement->m_pSourceElement->m_ulDuration)
      {
          LONG32 lSum =(LONG32)pEventElement->getDuration() +
                m_pSourceElement->m_lEndEventClockValue;
          // /If the event element has a delay, we need to add that:
          if(pEventElement->m_bDelaySet)
          {
            lSum += (LONG32)pEventElement->m_pSourceElement->m_ulDelay;
            if (pEventElement->m_pSourceElement->m_bBeginOffsetSet)
            {
                lSum -= pEventElement->m_pSourceElement->m_lBeginOffset;
            }
          }
          HX_ASSERT(lSum >= 0  &&  "ehodge: handle neg delay propogation");
          lSum = (lSum<0? 0 : lSum);  //clip off negative vals.
          durationResolved((ULONG32)lSum);
      }
    }
}

void
CSmilTimelineAnchor::durationResolved(UINT32 ulDuration)
{
    if(!m_bDurationSet)
    {
      m_bDurationSet = TRUE;
      m_pSourceElement->m_ulDuration = ulDuration;
    }
}


CSmilTimelineAnimate::CSmilTimelineAnimate(CSmilElement* pSourceElement,
                                           CSmilParser* pParser)
    : CSmilTimelineElement(pSourceElement, pParser)
{
}

CSmilTimelineAnimate::~CSmilTimelineAnimate()
{
}

void CSmilTimelineAnimate::setDuration(UINT32 ulDuration, BOOL bSetFromParent,
                          BOOL bDurationExtendingDueToPause)
{
    if (!bSetFromParent)
    {
        CSmilTimelineElement::setDuration(ulDuration, bSetFromParent,
                          bDurationExtendingDueToPause);
    }
}


Generated by  Doxygen 1.6.0   Back to index