smlelem.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:89k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. // system
  36. #include <time.h>
  37. // include
  38. #include "hxtypes.h"
  39. #include "hxwintyp.h"
  40. #include "hxcom.h"
  41. #include "ihxpckts.h"
  42. #include "hxxml.h"
  43. #include "smiltype.h"
  44. // pncont
  45. #include "hxstring.h"
  46. #include "hxslist.h"
  47. #include "hxstack.h"
  48. #include "chxpckts.h"
  49. // pnmisc
  50. #include "nptime.h"
  51. #include "smpte.h"
  52. #include "hxwinver.h"
  53. #include "hxstrutl.h"  /* for new_string(). */
  54. // rnxmllib
  55. #include "hxxmlprs.h"
  56. // rmasmil
  57. #include "smlparse.h"
  58. #include "smltime.h"
  59. #include "smlprstime.h"
  60. #include "animattr.h"
  61. #include "smlelem.h"
  62. // pndebug
  63. #include "hxheap.h"
  64. #ifdef _DEBUG
  65. #undef HX_THIS_FILE
  66. static const char HX_THIS_FILE[] = __FILE__;
  67. #endif
  68.  
  69. /*
  70.  * CSmilElement methods
  71.  */
  72. CSmilElement::CSmilElement(SMILNode* pNode):
  73.     m_pNode(pNode),
  74.     m_lBeginOffset(0),
  75.     m_bBeginOffsetSet(FALSE),
  76.     m_bNegBeginOffsetAlreadyUsed(FALSE),
  77.     m_bCurBeginIsOffsetFromSyncBase(FALSE),
  78.     m_ulBeginOffsetFromSyncBase((UINT32)-1),
  79.     m_ulClipBegin((UINT32)-1),
  80.     m_ulAuthoredClipBegin((UINT32)-1),
  81.     m_ulClipEnd((UINT32)-1),
  82.     m_ulDelay((UINT32)-1),
  83.     m_ulDuration((UINT32)-1),
  84.     m_ulOriginalDuration((UINT32)-1),
  85.     m_ulDurationInAddTrack((UINT32)-1),
  86.     m_bCurEndClippedByParent(FALSE),
  87.     m_ulMaxDuration((UINT32)-1),
  88.     m_ulMaxActiveDur((UINT32)-1),
  89.     m_ulMinActiveDur(0),
  90.     m_ulAuthoredDur((UINT32)-1),
  91.     m_bHasExplicitDur(FALSE),
  92.     m_bHasExplicitEnd(FALSE),
  93.     m_bDurationIncludesDelayBeyondSyncbase(FALSE),
  94.     m_bAddDurationAlreadyDone(FALSE),
  95.     m_bUseMediaDurForMinDur(FALSE),
  96.     m_bUseMediaDurForMaxDur(FALSE),
  97.     m_lEndOffset(0),
  98.     m_bEndOffsetSet(FALSE),
  99.     m_ulAnticipatedPauseDur(0),
  100.     m_ulEndSync((UINT32)-1),
  101.     m_fRepeatValue(1.0),
  102.     m_ulTimestamp(0),
  103.     m_bInsertedIntoTimeline(FALSE),
  104.     m_bHasBeenScheduled(FALSE),
  105.     m_bIsPausedInExcl(FALSE),
  106.     m_bIsDeferredInExcl(FALSE),
  107.     m_ulTimeDeferralOccurred((UINT32)-1),
  108.     m_bIsStoppedInExcl(FALSE),
  109.     m_ulStopTimeInExcl((UINT32)-1),
  110.     m_bCurrentSourceIsLive(FALSE),
  111.     m_bRendererInitialized(FALSE),
  112.     m_bIsRestarting(FALSE),
  113.     m_bAwaitingSyncAncestorBeginNotification(FALSE),
  114.     m_ulLongSyncArcBeginInGroupTime((UINT32)-1),
  115.     m_bIndefiniteDuration(FALSE),
  116.     m_bIndefiniteEnd(FALSE),
  117.     m_bIndefiniteBegin(FALSE),
  118.     m_restartBehavior(SmilRestartAlways),
  119.     m_restartDefaultBehavior(SmilRestartInherit),
  120.     // /Defaults to "default" which means use val of syncToleranceDefault:
  121.     m_ulSyncTolerance((UINT32)-1),
  122.     // /Defaults to "inherit"; if there is no parent timed element, then
  123.     // it is implementation-dependent (but should be less than or = 2s):
  124.     m_ulSyncToleranceDefault((UINT32)-1),
  125.     m_syncBehavior(SmilSyncBehaviorDefault),
  126.     m_syncBehaviorDefault(SmilSyncBehaviorInherit),
  127.     m_ulReadIndex(0),
  128.     m_nBeginEventSourceTag(SMILEventSourceNone),
  129.     m_nEndEventSourceTag(SMILEventSourceNone),
  130.     m_nEndsyncEventSourceTag(SMILEventSourceNone),
  131.     m_lBeginEventClockValue(0),
  132.     m_lEndEventClockValue(0),
  133.     m_pHandler(0),
  134.     m_pTimelineElement(NULL),
  135.     m_pBeginTimeList(NULL),
  136.     m_pEndTimeList(NULL),
  137.     m_bWallClockBegin(FALSE),
  138.     m_bWallClockEnd(FALSE),
  139.     m_bHasAtLeastOneEventBasedBegin(FALSE),
  140.     m_bHasAtLeastOneNonEventBasedBegin(FALSE),
  141.     m_eFill(FillDefault),
  142.     m_eFillDefault(FillDefaultInherit),
  143.     m_eActualFill(FillDefault),
  144.     m_eErase(EraseWhenDone),
  145.     m_ulRemoveTime(((UINT32) -1)),
  146.     m_bUsesExternalMediaMarkerFile(FALSE),
  147.     m_bClipBeginUsesMarker(FALSE),
  148.     m_bClipBeginMarkerResolved(FALSE),
  149.     m_bWaitingOnClipBeginToResolve(FALSE),
  150.     m_pszClipBeginMarkerName(NULL),
  151.     m_pszClipBeginExternalMarkerFileName(NULL),
  152.     m_bClipEndUsesMarker(FALSE),
  153.     m_bClipEndMarkerResolved(FALSE),
  154.     m_bWaitingOnClipEndToResolve(FALSE),
  155.     m_pszClipEndMarkerName(NULL),
  156.     m_pszClipEndExternalMarkerFileName(NULL),
  157.     m_eAccessErrorBehavior(AccessErrorBehaviorInherit)
  158. {
  159.     // /XXXEH- we may need to set m_bIndefiniteBegin to TRUE if
  160.     // hasAncestor(SMILExcl, this), but setInitialDelay() fix seems to be
  161.     // all we need (...<==famous last words).
  162.     m_pHyperlinks = new CHXSimpleList;
  163.     getParentRestartDefault();
  164. }
  165. CSmilElement::~CSmilElement()
  166. {
  167.     if (m_pBeginTimeList)
  168.     {
  169. CHXSimpleList::Iterator ndx = m_pBeginTimeList->Begin();
  170. for (; ndx != m_pBeginTimeList->End(); ++ndx)
  171. {
  172.     SmilTimeValue* pTV = (SmilTimeValue*)(*ndx);
  173.     HX_DELETE(pTV);
  174. }
  175. HX_DELETE(m_pBeginTimeList);
  176.     }
  177.     if (m_pEndTimeList)
  178.     {
  179. CHXSimpleList::Iterator ndx = m_pEndTimeList->Begin();
  180. for (; ndx != m_pEndTimeList->End(); ++ndx)
  181. {
  182.     SmilTimeValue* pTV = (SmilTimeValue*)(*ndx);
  183.     HX_DELETE(pTV);
  184. }
  185. HX_DELETE(m_pEndTimeList);
  186.     }
  187.     HX_DELETE(m_pHyperlinks);
  188.     HX_DELETE(m_pTimelineElement);
  189.     HX_VECTOR_DELETE(m_pszClipBeginMarkerName);
  190.     HX_VECTOR_DELETE(m_pszClipBeginExternalMarkerFileName);
  191.     HX_VECTOR_DELETE(m_pszClipEndMarkerName);
  192.     HX_VECTOR_DELETE(m_pszClipEndExternalMarkerFileName);
  193. }
  194. void
  195. CSmilElement::addDuration(UINT32 ulDuration)
  196. {
  197.     // default add duration just attempts to add it to it's parent
  198.     m_ulDuration = ulDuration;
  199.     if(m_pNode->m_pParent && m_pNode->m_pParent->m_pElement)
  200.     {
  201. m_pNode->m_pParent->m_pElement->addDuration(m_ulDuration);
  202. m_bAddDurationAlreadyDone = TRUE;
  203.     }
  204. }
  205. void
  206. CSmilElement::addElement(CSmilElement* pElement,
  207.     UINT32& ulBeginOffset, UINT32& ulDuration)
  208. {
  209. }
  210. void
  211. CSmilElement::prepForRestart(BOOL bParentIsRestarting, LONG32 lWhen)
  212. {
  213.     m_bInsertedIntoTimeline = FALSE;
  214.     m_bRendererInitialized = FALSE;
  215.     m_bBeginOffsetSet = FALSE;
  216.     // /Reset these, too, or hiding of site will happen too early next time:
  217.     m_bCurBeginIsOffsetFromSyncBase = TRUE;
  218.     // /This seems to work fine in case where begin="x; y" where x is a
  219.     // clock value and y is an event-arc that resolves at/to a time prior
  220.     // to x.  (The other option is to set m_bCurBeginIsOffsetFromSyncBase
  221.     // to FALSE when !m_bBeginOffsetSet):
  222.     m_ulBeginOffsetFromSyncBase = 0;
  223.     m_bNegBeginOffsetAlreadyUsed = FALSE;
  224.     m_ulClipBegin = m_ulAuthoredClipBegin;
  225.     m_bAddDurationAlreadyDone = FALSE;
  226.     // /XXXEH- TODO: test this!:
  227.     m_bDurationIncludesDelayBeyondSyncbase = FALSE;
  228.     m_bIsPausedInExcl = FALSE;
  229.     m_bIsDeferredInExcl = FALSE;
  230.     m_ulTimeDeferralOccurred = (UINT32)-1;
  231.     m_bIsStoppedInExcl = FALSE;
  232.     m_ulAnticipatedPauseDur = 0;
  233.     // /If we restart a source, the next play may be a different file, even
  234.     // live one time and on-demand the next, so reset this and let next call
  235.     // to TrackDurationSet() tell us if it's live this time:
  236.     m_bCurrentSourceIsLive = FALSE;
  237.     // /Adding this helps fix a lot of restart problems, including part of
  238.     // PR 62408 and par version of PR 50660.  The playToAssoc was never
  239.     // removed when the track ended the first time, so the doc renderer
  240.     // (m_pHandler) used to see this track as already added and would
  241.     // erroneously add this restart as a repeat track:
  242.     m_bIsRestarting = TRUE;
  243.     // /Helps fix restart problems related to PR 55253:
  244.     if (bParentIsRestarting)
  245.     {
  246. LONG32 lNextResolvedEndTime = 0;
  247. BOOL bHasFutureResolvedEnd = FALSE;
  248. if (m_bHasExplicitEnd)
  249. {
  250.     SmilTimeValue* pNextResolvedEndTimeValue = NULL;
  251.     HX_RESULT rettimeval = HXR_OK;
  252.     // /lWhen must be in syncBase time space, not group time space:
  253.     rettimeval = getNextResolvedTimeValue(pNextResolvedEndTimeValue,
  254.     SMILTIME_NEGATIVE_INFINITY, lWhen, SmilEndTimeList, NULL);
  255.     if (SUCCEEDED(rettimeval)  &&  NULL != pNextResolvedEndTimeValue)
  256.     {
  257. HX_RESULT rtval = pNextResolvedEndTimeValue->
  258. getEffectiveResolvedTime(lNextResolvedEndTime);
  259. if (SUCCEEDED(rtval))
  260. {
  261.     bHasFutureResolvedEnd = TRUE;
  262.     if (lWhen < lNextResolvedEndTime)
  263.     {
  264. m_ulDuration = (UINT32)(lNextResolvedEndTime - lWhen);
  265.     }
  266. }
  267.     }
  268. }
  269. if (m_bHasExplicitDur)
  270. {
  271.     if (!bHasFutureResolvedEnd)
  272.     {
  273. m_ulDuration = m_ulAuthoredDur;
  274.     }
  275.     else if (lNextResolvedEndTime - lWhen > (LONG32)m_ulAuthoredDur)
  276.     {
  277. m_ulDuration = m_ulAuthoredDur;
  278.     }
  279. }
  280. else
  281. {
  282.     // /Let SetDelay() and insertTimeline... deal with new duration:
  283.     m_ulDuration = (UINT32)-1;
  284. }
  285.     }
  286.     // /Reset the delay since it will be new, obviously, for this restart;
  287.     // helps fix restart problems related to PR 56233:
  288.     m_ulDelay = (UINT32)-1;
  289.     // /Note: we don't want to or need to reset the delay here.  A restart
  290.     // based on either a syncArc or eventArc will take care of that.
  291.     if (m_pTimelineElement)
  292.     {
  293. m_pTimelineElement->prepForRestart();
  294.     }
  295.     // /Now, call this function for all descendants as well in case this is
  296.     // a time container (or a media object with timeline-element children);
  297.     // (Helps fix restart problems related to PR 55253)
  298.     SMILNode* pChild = m_pNode->getFirstChild();
  299.     while (pChild)
  300.     {
  301. CSmilElement* pElement = pChild->m_pElement;
  302. if (pElement  &&  pElement->m_pHandler  &&
  303. pElement->m_bInsertedIntoTimeline)
  304. {
  305.     pElement->prepForRestart(TRUE, lWhen);
  306. }
  307. pChild = m_pNode->getNextChild();
  308.     }
  309. }
  310. void
  311. CSmilElement::prepForPauseInExcl(LONG32 lCurTime)
  312. {
  313.     m_bIsPausedInExcl = TRUE;
  314.     // /If we're being set to paused state, then we need to adjust our hide
  315.     // event (removeTime) in concert with adjusting when we will end:
  316.     BOOL bHasFutureResolvedExplicitEnd = FALSE;
  317.     if (m_bHasExplicitEnd)
  318.     {
  319. SmilTimeValue* pNextResolvedEndTimeValue = NULL;
  320. HX_RESULT rettimeval = HXR_OK;
  321. // /lCurTime must be in syncBase time space, not group time space:
  322. rettimeval = getNextResolvedTimeValue(pNextResolvedEndTimeValue,
  323. SMILTIME_NEGATIVE_INFINITY, lCurTime, SmilEndTimeList, NULL);
  324. if (SUCCEEDED(rettimeval)  &&  NULL != pNextResolvedEndTimeValue)
  325. {
  326.     LONG32 lNextResolvedEndTime = SMILTIME_NEGATIVE_INFINITY;
  327.     HX_RESULT rtval = pNextResolvedEndTimeValue->
  328.     getEffectiveResolvedTime(lNextResolvedEndTime);
  329.     if (SUCCEEDED(rtval))
  330.     {
  331. HX_ASSERT(lCurTime <= lNextResolvedEndTime);
  332. bHasFutureResolvedExplicitEnd = TRUE;
  333. updateRemoveTime(lNextResolvedEndTime);
  334.     }
  335. }
  336.     }
  337.     // /If we don't have explicit end, then we'll end when we get resumed
  338.     // plus the remainder of our duration:
  339.     if (!bHasFutureResolvedExplicitEnd)
  340.     {
  341. updateRemoveTime(SMILTIME_PAUSED_INDEFINITELY);
  342.     }
  343. }
  344. void
  345. CSmilElement::prepForResumeInExcl()
  346. {
  347.     HX_ASSERT(m_bIsPausedInExcl);
  348.     LISTPOSITION lPos = NULL;
  349.     HX_ASSERT(m_pBeginTimeList);
  350.     if (m_pBeginTimeList)
  351.     {
  352. lPos = m_pBeginTimeList->GetHeadPosition();
  353.     }
  354.     while (lPos)
  355.     {
  356. SmilTimeValue* pTimeVal =
  357. (SmilTimeValue*)m_pBeginTimeList->GetAt(lPos);
  358. // /There should be only one resumeEvent:
  359. if (pTimeVal  &&  pTimeVal->isResumeEvent())
  360. {
  361.     // /Fixes PR 62408: remove resumeEvent from element's begin
  362.     // list since it was an internally-generated single-use begin
  363.     // value and we don't want it to re-resolve when (if) the
  364.     // original pausing element restarts and then raises another
  365.     // resumeEvent when it ends again:
  366.     m_pBeginTimeList->RemoveAt(lPos);
  367.     break;
  368. }
  369.      m_pBeginTimeList->GetNext(lPos);
  370.     }
  371.     m_bIsPausedInExcl = FALSE;
  372. }
  373. void
  374. CSmilElement::prepForStopInExcl(LONG32 lCurTime)
  375. {
  376.     m_bIsStoppedInExcl = TRUE;
  377.     m_ulStopTimeInExcl = (ULONG32)lCurTime;
  378. }
  379. void
  380. CSmilElement::prepForDeferralInExcl(UINT32 lCurTime)
  381. {
  382.     m_ulTimeDeferralOccurred = lCurTime;
  383.     m_bIsDeferredInExcl = TRUE;
  384. }
  385. HX_RESULT
  386. CSmilElement::setBeginTime(CSmilParser* pParser)
  387. {
  388.     HX_RESULT ret = HXR_OK;
  389.  
  390.     BOOL bBeginTimeHasBeenSet = FALSE;
  391.     UINT32 ulOffset = 0;
  392.     SmilTimeValue* pNextResolvedTimeValue = NULL;
  393.     LISTPOSITION lPos = NULL;
  394.     // /We need this so we can go through
  395.     CHXSimpleList* pListOfAllResolvedBeginTimes = new CHXSimpleList;
  396.     // /Looks at all resolved begin times in the list and
  397.     // returns the SmilTimeValue with the closest time at or
  398.     // later than the time passed in:
  399.     HX_RESULT rettimeval = HXR_OK;
  400.     rettimeval = getNextResolvedTimeValue(pNextResolvedTimeValue,
  401.     SMILTIME_NEGATIVE_INFINITY, SMILTIME_NEGATIVE_INFINITY,
  402.     SmilBeginTimeList, pListOfAllResolvedBeginTimes);
  403.     // /NOTE: ret!=HXR_OK is NOT an error condition; it means
  404.     // that no value in the begin time list was found that was
  405.     // resolved.
  406.     BOOL bIsDescendantOfExcl = pParser->hasAncestor(SMILExcl, m_pNode);
  407.     SMILNode* pSyncAncestor = pParser->getSyncAncestor(m_pNode);
  408.     HX_ASSERT(pSyncAncestor);
  409.     // make sure that we do not have an illegal begin value
  410.     // if we have a seq for a parent.
  411.     // /Note: we want to use our sync ancestor, not our parent, because
  412.     // our parent could be a non-time-container like <a>, <switch>,
  413.     // or <priorityClass>:
  414.     if ((pSyncAncestor  &&  SMILSeq == pSyncAncestor->m_tag  &&
  415. // /OK if parent seq was created to expand for repeat purposes:
  416. !m_pNode->m_bRepeatHandled)  &&
  417. ( (!SUCCEEDED(rettimeval)  ||  NULL==pNextResolvedTimeValue)  ||
  418. (pNextResolvedTimeValue->m_type != SmilTimeOffset && 
  419. pNextResolvedTimeValue->m_type != SmilTimeClockValue) ) )
  420.     {
  421. // only offsets are legal values...
  422. ret = HXR_INVALID_PARAMETER;
  423. goto cleanup;
  424.     }
  425.     // /For excl descendants, we don't want to declare that a begin time
  426.     // has been set, because we need to figure out whether or not to
  427.     // schedule it based on when other excl children begin (which we may
  428.     // not know yet):
  429.     if (SUCCEEDED(rettimeval) && NULL != pNextResolvedTimeValue)
  430.     {
  431. if (pListOfAllResolvedBeginTimes)
  432. {
  433.     // /Go through this list and insert each into the pending list:
  434.     LISTPOSITION lPosTmp =
  435.     pListOfAllResolvedBeginTimes->GetHeadPosition();
  436.     while (lPosTmp)
  437.     {
  438. SmilTimeValue* pTmpVal = (SmilTimeValue*)
  439. pListOfAllResolvedBeginTimes->GetAt(lPosTmp);
  440. if (pTmpVal  &&  pTmpVal->isTimeResolved()  &&
  441. pTmpVal->m_pElement)
  442. {
  443.     if (pTmpVal != pNextResolvedTimeValue  ||
  444.     bIsDescendantOfExcl)
  445.     {
  446. // /(?XXXEH- TODO: insert into list based on resolved
  447. // time?  note that begin="20s;0s" works OK, so...?)
  448. if (pParser->EstablishBeginTimeList())
  449. {
  450.     CHXSimpleList* pList =
  451.     pParser->GetPendingBeginTimeList();
  452.     // /Don't add if it's a duplicate:
  453.     if (!pParser->isDuplicateEntry(pList, pTmpVal))
  454.     {
  455. pList->AddTail(pTmpVal);
  456.     }
  457. }
  458.     }
  459. }
  460. else
  461. {
  462.     HX_ASSERT(0  &&  "timeval invalid");
  463. }
  464.      pListOfAllResolvedBeginTimes->GetNext(lPosTmp);
  465.     } // /end while(lPos...).
  466. }
  467. HX_DELETE(pListOfAllResolvedBeginTimes);
  468. if (!bIsDescendantOfExcl)
  469. {
  470.     bBeginTimeHasBeenSet = TRUE;
  471.     HX_ASSERT(pNextResolvedTimeValue->isTimeResolved());
  472.     switch (pNextResolvedTimeValue->m_type)
  473.     {
  474. case SmilTimeOffset:
  475. case SmilTimeClockValue:
  476. {
  477.     // /XXXEH- is this what we really want to do?
  478.     // Alternatively, we could have resolved-to "base" time
  479.     // as 0 and then m_lOffset is added to get resolved-to
  480.     // "offset" time:
  481.     m_lBeginOffset = pNextResolvedTimeValue->getTimeOffset();
  482.     m_bBeginOffsetSet = TRUE;
  483.     // /Handle this now for time containers who never get
  484.     // called with a TrackDurationSet():
  485.     m_bCurBeginIsOffsetFromSyncBase = TRUE;
  486.     m_ulBeginOffsetFromSyncBase = m_lBeginOffset;
  487. #if defined(_DEBUG) // /XXXEH- testing!:
  488.     LONG32 lResolvedToTime = 0;
  489.     HX_RESULT tmprslt =
  490.     pNextResolvedTimeValue->getEffectiveResolvedTime(
  491.     lResolvedToTime);
  492.     HX_ASSERT(tmprslt==HXR_OK  &&
  493.     m_lBeginOffset == lResolvedToTime);
  494. #endif
  495. }
  496. break;
  497. case SmilTimeEvent:
  498. #if defined(ENABLE_SYNC_TO_PREV)
  499. case SmilTimeSyncToPrev:
  500. #endif
  501. case SmilTimeSyncBase:
  502. {
  503.     // /NOTE: this's time must be *resolved* already which
  504.     // shouldn't happen yet:
  505.     HX_ASSERT(!pNextResolvedTimeValue->isTimeResolved());
  506. }
  507. break;
  508.                 case SmilTimeMediaMarker:
  509.                 {
  510.     HX_ASSERT(!pNextResolvedTimeValue->isTimeResolved());
  511.                 }
  512.                 break;
  513. case SmilTimeWallclock:
  514. {
  515.     // /XXXEH- wouldn't it be better to use
  516.     // getEffectiveResolvedTime() here(?) so as to treat all time
  517.     // types consistently?
  518.     m_lBeginOffset = pNextResolvedTimeValue->getTimeOffset();
  519.     m_bBeginOffsetSet = TRUE;
  520.     // /Handle this now for time containers who never get
  521.     // called with a TrackDurationSet():
  522.     m_bCurBeginIsOffsetFromSyncBase = TRUE;
  523.     m_ulBeginOffsetFromSyncBase = m_lBeginOffset;
  524.     m_bWallClockBegin = TRUE;
  525. }
  526. break;
  527. default:
  528.     HX_ASSERT(0);
  529.     break;
  530.     } // /end of "switch(pNextResolvedTimeValue->m_type)".
  531. } // /end of "if (!bIsDescendantOfExcl)".
  532.     }
  533.     // /Now, go through all unresolved begin times and add this element to
  534.     // the appropriate list(s) for each unresolved time value found:
  535.     if (m_pBeginTimeList)
  536.     {
  537. lPos = m_pBeginTimeList->GetHeadPosition();
  538.     }
  539.     if (NULL == lPos) // /list is empty.
  540.     {
  541. goto cleanup;
  542.     }
  543.     while (lPos  &&  HXR_OK == ret)
  544.     {
  545. SmilTimeValue* pTmpVal = (SmilTimeValue*)m_pBeginTimeList->GetAt(lPos);
  546. if (pTmpVal  &&  !pTmpVal->isTimeResolved())
  547. {
  548.     switch (pTmpVal->m_type)
  549.     {
  550.     case SmilTimeOffset:
  551.     case SmilTimeClockValue:
  552. {
  553.     // /We shouldn't ever get here because clock times are
  554.     // always resolved:
  555.     HX_ASSERT(pTmpVal->isTimeResolved());
  556. }
  557. break;
  558.     case SmilTimeSyncBase:
  559. {
  560.     pParser->addBeginTimeSyncElement(this);
  561.     if (!bBeginTimeHasBeenSet)
  562.     {
  563. m_BeginEventSourceID = pTmpVal->m_idRef;
  564. m_nBeginEventSourceTag = pTmpVal->m_position;
  565. // /NOTE: this is unresolved:
  566. m_lBeginEventClockValue =
  567. pTmpVal->getTimeOffset();
  568.     }
  569.     // /Fixes BUG-20010521_syncArcToElementWith...smil
  570.     // where begin="0s;x.end" and x.end was being ignored:
  571.     else
  572.     {
  573. if (!m_BeginEventSourceID.GetLength())
  574. {
  575.     m_BeginEventSourceID = pTmpVal->m_idRef;
  576.     m_nBeginEventSourceTag = pTmpVal->m_position;
  577.     // /NOTE: this is unresolved:
  578.     m_lBeginEventClockValue = pTmpVal->getTimeOffset();
  579. }
  580. else
  581. {
  582.     HX_ASSERT(0  &&
  583. "XXXEHodge: need to handle multiple sync-arc begins");
  584.     // /XXXEH- TODO: if m_BeginEventSourceID is already
  585.     // set due to another sync-arc begin time, we need
  586.     // to have a list of m_BeginEventSourceID's & ...etc.
  587.     // Currently, just the first one wins.  We could
  588.     // treat this sync-arc as a beginEvent event-arc...
  589.     // (We also need to handle this in SetEndTime().)
  590. }
  591.     }
  592. }
  593. break;
  594. #if defined(ENABLE_SYNC_TO_PREV)
  595.     case SmilTimeSyncToPrev:
  596. {
  597.     // /XXXEH- shouldn't we treat this just like we treat the
  598.     // sync base case above by doing the following?:
  599.     //     pParser->addBeginTimeSyncElement(this);
  600.     // /XXXEH- make sure we handle begin="3s; prev.end" where
  601.     // both are valid times; the following doesn't handle this
  602.     // case:
  603.     if (!bBeginTimeHasBeenSet)
  604.     {
  605. SMILNode* pSibling =
  606. m_pNode->m_pParent->getFirstChild();
  607. // /Spec says to use parent time container's begin if
  608. // m_pNode is the first child (and has no prev
  609. // sibling):
  610. SMILNode* pLastNode = m_pNode->m_pParent;
  611. while (pSibling)
  612. {
  613.     if (pSibling->m_id == m_pNode->m_id)
  614.     {
  615. // we found our boy...
  616. break;
  617.     }
  618.     pLastNode = pSibling;
  619.     // /XXXEH- TODO: skip over children that aren't
  620.     // *timed* elements, e.g., <a> tags; maybe we
  621.     // are supposed to use a non-timed-prev-element's
  622.     // last timed child, if any, and, if none exists,
  623.     // use it's prev timed sibling???:
  624.     pSibling = m_pNode->m_pParent->getNextChild();
  625. }
  626. HX_ASSERT(pSibling && pLastNode);
  627. if (pSibling && pLastNode)
  628. {
  629.     // /First, if we had no prev sibling, then
  630.     // we need to use our parent time container's
  631.     // begin time as our sync base:
  632.     if (pLastNode == m_pNode->m_pParent)
  633.     {
  634. SMILNode* pFirstTimeContainerAncestor =
  635. pParser->getSyncAncestor(m_pNode);
  636. // /There should ALWAYS be a time container
  637. // ancestor, even if it's the implied seq
  638. // that we create when no time container
  639. // exists as the 1st timed child of the body:
  640. HX_ASSERT(pFirstTimeContainerAncestor);
  641. if (pFirstTimeContainerAncestor)
  642. {
  643. #if XXXEH_
  644. /* /Need to figure out if this is earlier than any current times and, if
  645. so, call insertElementWithPendingBeginOrEnd() with the earlier time, else
  646. call insertElementWithPendingBeginOrEnd() with this (pTmpVal) time:
  647. */
  648. #endif
  649.     // /For parent as prev, we can just treat
  650.     // this as a SmilTimeOffset value since
  651.     // they're essentially the same thing:
  652.     pLastNode = pFirstTimeContainerAncestor;
  653.     m_lBeginOffset= pTmpVal->getTimeOffset();
  654.     pTmpVal->m_type = SmilTimeOffset;
  655.     pTmpVal->setIsTimeResolved(TRUE);
  656.     m_bBeginOffsetSet = TRUE;
  657. }
  658. // /else give up; can't do anything here.
  659.     }
  660.     else // /Use prev sibling time:
  661.     {
  662. m_BeginEventSourceID = pLastNode->m_id;
  663. // /XXXEH- wouldn't it be better to use
  664. // getEffectiveResolvedTime() here(?) so as
  665. // to treat all time types consistently?
  666. m_lBeginEventClockValue =
  667. pTmpVal->getTimeOffset();
  668. m_nBeginEventSourceTag =
  669. pTmpVal->m_position;
  670.     }
  671. }
  672. else
  673. {
  674.     ret = HXR_FAIL;
  675. }
  676.     }
  677. }
  678. break;
  679. #endif
  680.     case SmilTimeEvent:
  681. {
  682.     pParser->addBeginEventElement(pTmpVal);
  683. }
  684.                 break;
  685.             case SmilTimeMediaMarker:
  686.                 {
  687.                     pParser->addBeginMediaMarkerSyncElement(pTmpVal);
  688.                 }
  689.                 break;
  690.             case SmilTimeWallclock:
  691. {
  692.     // /We shouldn't ever get here because wallclock times
  693.     // are always resolved:
  694.     HX_ASSERT(pTmpVal->isTimeResolved());
  695. }
  696. break;
  697.     default:
  698. HX_ASSERT(0);
  699. break;
  700.     } // /end switch(pTmpVal->m_type).
  701. }
  702.      m_pBeginTimeList->GetNext(lPos);
  703.     } // /end while (lPos ...).
  704.     // else time must already be set.
  705. cleanup:
  706.     return ret;
  707. }
  708. HX_RESULT
  709. CSmilElement::setEndTime(CSmilParser* pParser)
  710. {
  711.     HX_RESULT ret = HXR_OK;
  712.     BOOL bEndTimeHasBeenSet = FALSE;
  713.     UINT32 ulOffset = 0;
  714.     SmilTimeValue* pNextResolvedTimeValue = NULL;
  715.     LISTPOSITION lPos = NULL;
  716.     CHXSimpleList* pListOfAllResolvedEndTimes = new CHXSimpleList;
  717.     // /Looks at all resolved end times in the list and
  718.     // returns the SmilTimeValue with the closest time at or
  719.     // later than the time passed in:
  720.     HX_RESULT rettimeval = HXR_OK;
  721.     rettimeval = getNextResolvedTimeValue(pNextResolvedTimeValue,
  722.     SMILTIME_NEGATIVE_INFINITY, SMILTIME_NEGATIVE_INFINITY,
  723.     SmilEndTimeList, pListOfAllResolvedEndTimes);
  724.     // /NOTE: ret!=HXR_OK is NOT an error condition; it means
  725.     // that no value in the end time list was found that was
  726.     // resolved.
  727.     
  728.     if (SUCCEEDED(rettimeval) && NULL != pNextResolvedTimeValue)
  729.     {
  730. if (pListOfAllResolvedEndTimes)
  731. {
  732.     // /Go through this list and insert each into the pending list:
  733.     LISTPOSITION lPosTmp =
  734.     pListOfAllResolvedEndTimes->GetHeadPosition();
  735.     while (lPosTmp)
  736.     {
  737. SmilTimeValue* pTmpVal = (SmilTimeValue*)
  738. pListOfAllResolvedEndTimes->GetAt(lPosTmp);
  739. if (pTmpVal  &&  pTmpVal->isTimeResolved()  &&
  740. pTmpVal->m_pElement)
  741. {
  742.     if (pTmpVal != pNextResolvedTimeValue)
  743.     {
  744. // /(?XXXEH- TODO: insert into list based on resolved
  745. // time?  end="20s;0s" works OK, so...?)
  746. if (pParser->EstablishEndTimeList())
  747. {
  748.     CHXSimpleList* pList =
  749.     pParser->GetPendingEndTimeList();
  750.     // /Don't add if it's a duplicate:
  751.     if (!pParser->isDuplicateEntry(pList, pTmpVal))
  752.     {
  753. pList->AddTail(pTmpVal);
  754.     }
  755. }
  756.     }
  757. }
  758. else
  759. {
  760.     HX_ASSERT(0  &&  "timeval invalid");
  761. }
  762.      pListOfAllResolvedEndTimes->GetNext(lPosTmp);
  763.     } // /end while(lPos...).
  764. }
  765. HX_DELETE(pListOfAllResolvedEndTimes);
  766. bEndTimeHasBeenSet = TRUE;
  767. HX_ASSERT(pNextResolvedTimeValue->isTimeResolved());
  768. switch (pNextResolvedTimeValue->m_type)
  769. {
  770. case SmilTimeOffset:
  771. case SmilTimeClockValue:
  772.     {
  773. // /XXXEH- is this what we really want to do?
  774. // Alternatively, we could have resolved-to "base" time
  775. // as 0 and then m_lOffset is added to get resolved-to
  776. // "offset" time:
  777. m_lEndOffset = pNextResolvedTimeValue->getTimeOffset();
  778. m_bEndOffsetSet = TRUE;
  779. #if defined(_DEBUG) // /XXXEH- testing!:
  780. LONG32 lResolvedToTime = 0;
  781. HX_RESULT tmprslt =
  782. pNextResolvedTimeValue->getEffectiveResolvedTime(
  783. lResolvedToTime);
  784. HX_ASSERT(tmprslt==HXR_OK  &&
  785. m_lEndOffset == lResolvedToTime);
  786. #endif
  787.     }
  788.     break;
  789. case SmilTimeSyncBase:
  790. #if defined(ENABLE_SYNC_TO_PREV)
  791. case SmilTimeSyncToPrev:
  792. #endif
  793. case SmilTimeEvent:
  794.     {
  795. // /NOTE: this's time must be *resolved* already which
  796. // shouldn't happen yet:
  797. HX_ASSERT(!pNextResolvedTimeValue->isTimeResolved());
  798.     }
  799.     break;
  800. case SmilTimeMediaMarker:
  801.     {
  802. //XXXEH- TODO: handle media markers:
  803. HX_ASSERT(0);
  804. //pParser->addEndMediaMarkerSyncElement(this);
  805.     }
  806.     break;
  807. case SmilTimeWallclock:
  808.     {
  809. // /XXXEH- wouldn't it be better to use
  810. // getEffectiveResolvedTime() here(?) so as to treat all time
  811. // types consistently?
  812. m_lEndOffset = pNextResolvedTimeValue->getTimeOffset();
  813. m_bEndOffsetSet = TRUE;
  814. m_bWallClockEnd = TRUE;
  815.     }
  816.     break;
  817. case SmilTimeNone:
  818.     break;
  819. } // /end switch(pNextResolvedTimeValue->m_type).
  820.     }
  821.     // /Now, go through all unresolved end times and add this element to
  822.     // the appropriate list(s) for each unresolved time value found:
  823.     if (m_pEndTimeList)
  824.     {
  825. lPos = m_pEndTimeList->GetHeadPosition();
  826.     }
  827.     if (NULL == lPos) // /list is empty.
  828.     {
  829. goto cleanup;
  830.     }
  831.     while (lPos  &&  HXR_OK == ret)
  832.     {
  833. SmilTimeValue* pTmpVal = (SmilTimeValue*)m_pEndTimeList->GetAt(lPos);
  834. if (pTmpVal  &&  !pTmpVal->isTimeResolved())
  835. {
  836.     switch (pTmpVal->m_type)
  837.     {
  838.     case SmilTimeOffset:
  839.     case SmilTimeClockValue:
  840. {
  841.     // /We shouldn't ever get here because clock times are
  842.     // always resolved:
  843.     HX_ASSERT(pTmpVal->isTimeResolved());
  844. }
  845. break;
  846.     case SmilTimeSyncBase:
  847. {
  848.     pParser->addEndTimeSyncElement(this);
  849.     // /XXXEH- make sure we handle end="3s; prev.end" where
  850.     // both are valid times; the following doesn't handle this
  851.     // case:
  852.     if (!bEndTimeHasBeenSet)
  853.     {
  854. m_EndEventSourceID = pTmpVal->m_idRef;
  855. m_nEndEventSourceTag = pTmpVal->m_position;
  856. // /XXXEH- wouldn't it be better to use
  857. // getEffectiveResolvedTime() here(?) so as to treat
  858. // all time types consistently?
  859. m_lEndEventClockValue =
  860. pTmpVal->getTimeOffset();
  861.     }
  862. }
  863. break;
  864. #if defined(ENABLE_SYNC_TO_PREV)
  865.     case SmilTimeSyncToPrev:
  866. {
  867.     // /XXXEH- shouldn't we treat this just like we treat the
  868.     // sync base case above by doing the following?:
  869.     //     pParser->addEndTimeSyncElement(this);
  870.     // /XXXEH- make sure we handle end="3s; prev.end" where
  871.     // both are valid times; the following doesn't handle this
  872.     // case:
  873.     if (!bEndTimeHasBeenSet)
  874.     {
  875. SMILNode* pSibling =
  876. m_pNode->m_pParent->getFirstChild();
  877. SMILNode* pLastNode = pSibling;
  878. while (pSibling)
  879. {
  880.     if (pSibling->m_id == m_pNode->m_id)
  881.     {
  882. // we found our boy...
  883. break;
  884.     }
  885.     pLastNode = pSibling;
  886.     pSibling = m_pNode->m_pParent->getNextChild();
  887. }
  888. HX_ASSERT(pSibling && pLastNode);
  889. if (pSibling && pLastNode)
  890. {
  891.     m_EndEventSourceID = pLastNode->m_id;
  892.     // /XXXEH- wouldn't it be better to use
  893.     // getEffectiveResolvedTime() here(?) so as to
  894.     // treat all time types consistently?
  895.     m_lEndEventClockValue =
  896.     pTmpVal->getTimeOffset();
  897.     m_nEndEventSourceTag =
  898.     pTmpVal->m_position;
  899. }
  900. else
  901. {
  902.     ret = HXR_FAIL;
  903. }
  904.     }
  905. }
  906. break;
  907. #endif
  908.     case SmilTimeEvent:
  909. {
  910.     pParser->addEndEventElement(pTmpVal);
  911. }
  912.                 break;
  913.             case SmilTimeMediaMarker:
  914.                 {
  915.                     pParser->addEndMediaMarkerSyncElement(pTmpVal);
  916.                 }
  917.                 break;
  918.     case SmilTimeWallclock:
  919. {
  920.     // /We shouldn't ever get here because wallclock times
  921.     // are always resolved:
  922.     HX_ASSERT(pTmpVal->isTimeResolved());
  923. }
  924. break;
  925.     case SmilTimeNone:
  926. break;
  927.     } // /end switch(pTmpVal->m_type).
  928. }
  929.      m_pEndTimeList->GetNext(lPos);
  930.     } // /end while (lPos ...).
  931.     // else time must allready be set.
  932. cleanup:
  933.     return ret;
  934. }
  935. HX_RESULT
  936. CSmilElement::getEndTimeValue(REF(SmilTimeValue*) pValue)
  937. {
  938.     HX_RESULT ret = HXR_OK;
  939.     // This function just returns the first value in the end-time list,
  940.     // even if that value is not yet resolved to a clock time:
  941.     // If you want to use the "right" value for a given time t, then
  942.     // call "getNextResolvedTimeValue()"
  943.     if (m_pEndTimeList)
  944.     {
  945. LISTPOSITION pos = m_pEndTimeList->GetHeadPosition();
  946. if (pos)
  947. {
  948.     pValue = (SmilTimeValue*)m_pEndTimeList->GetAt(pos);
  949. }
  950.     }
  951.     return ret;
  952. }
  953. HX_RESULT
  954. CSmilElement::getBeginTimeValue(REF(SmilTimeValue*) pValue)
  955. {
  956.     HX_RESULT ret = HXR_OK;
  957.     // This function just returns the first value in the begin-time list,
  958.     // even if that value is not yet resolved to a clock time:
  959.     // If you want to use the "right" value for a given time t, then
  960.     // call "getNextResolvedTimeValue()"
  961.     if (m_pBeginTimeList)
  962.     {
  963. LISTPOSITION pos = m_pBeginTimeList->GetHeadPosition();
  964. if (pos)
  965. {
  966.     pValue = (SmilTimeValue*)m_pBeginTimeList->GetAt(pos);
  967. }
  968.     }
  969.     return ret;
  970. }
  971. // /Returns HXR_OK except if the element has not ever been inserted in the
  972. // timeline, in which case the return value is HXR_NOT_INITIALIZED.
  973. // In this case, the value placed into ulActualStartTime will remain whatever
  974. // is set in the delay value of the element.  If the element has an
  975. // indefinite begin time, SMIL_TIME_INFINITY is returned in ulActualStartTime
  976. // with HXR_OK as the return value.  Note that SMIL_TIME_INFINITY is not
  977. // the same value as ((UINT32)-1) which is a possible return value and means
  978. // that the value is not initialized:
  979. HX_RESULT
  980. CSmilElement::getCurrentScheduledStartTime(REF(ULONG32) ulActualStartTime)
  981. {
  982.     HX_RESULT ret = HXR_OK;
  983.     
  984.     ulActualStartTime = m_ulDelay;
  985.     BOOL bIsMediaObject = CSmilParser::isMediaObject(m_pNode);
  986.     if (!m_bHasBeenScheduled && bIsMediaObject)
  987.     {
  988. ret = HXR_NOT_INITIALIZED;
  989.     }
  990.     else if (m_bIndefiniteBegin)
  991.     {
  992. ulActualStartTime = SMILTIME_INFINITY;
  993.     }
  994.     else if (!bIsMediaObject && ulActualStartTime == ((UINT32) -1))
  995.     {
  996. ret = HXR_NOT_INITIALIZED;
  997.     }
  998. // /#define XXXEHODGE_DEBUG_PRINTF_CURRENTSCHEDULEDSTARTTIME
  999. #if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG_PRINTF_CURRENTSCHEDULEDSTARTTIME)
  1000.     {
  1001. static BOOL bFirstTime = TRUE;
  1002. FILE* f1 = ::fopen("c:\smil2.txt", bFirstTime?"w":"a+");
  1003. ::fprintf(f1, "n[%s]->getCurrentScheduledStartTime() "
  1004. "ulActualStopTime := %lu (delay=%lu, dur=%lu, "
  1005. "beginOffsetFromSyncBase=%lu)  n", (const char*)m_pNode->m_id,
  1006. ulActualStartTime, m_ulDelay, m_ulDuration, m_ulBeginOffsetFromSyncBase);
  1007. ::fclose(f1);
  1008. bFirstTime=FALSE;
  1009.     }
  1010. #endif
  1011.     return ret;
  1012. }
  1013. // /Returns HXR_OK except if the element has not ever been inserted in the
  1014. // timeline, in which case the return value is HXR_NOT_INITIALIZED.
  1015. // In this case, the value placed into ulActualStopTime will remain whatever
  1016. // is set in the delay value of the element.  If the element has an
  1017. // indefinite end time, SMIL_TIME_INFINITY is returned in ulActualStopTime
  1018. // with HXR_OK as the return value.  Note that SMIL_TIME_INFINITY is not
  1019. // the same value as ((UINT32)-1) which is a possible return value and means
  1020. // that the value is not initialized:
  1021. HX_RESULT
  1022. CSmilElement::getCurrentScheduledStopTime(REF(ULONG32) ulActualStopTime)
  1023. {
  1024.     HX_RESULT ret = HXR_OK;
  1025.     // /Fixes PR 63733: initialize to invalid time in case caller did not:
  1026.     ulActualStopTime = (UINT32)-1;
  1027.     if (m_bIndefiniteDuration  ||  m_bIndefiniteEnd)
  1028.     {
  1029. ulActualStopTime = SMILTIME_INFINITY;
  1030.     }
  1031.     // /Helps fix PR 53531 (unwinding after string of pauses) when
  1032.     // m_ulDuration has not been updated to reflect the paused time so far:
  1033.     else if (isPausedInExcl())
  1034.     {
  1035. #if XXXEH_HANDLE_CASE_WHERE_RESOLVED_END_IS_NOW_IN_EFFECT
  1036. #else
  1037. ulActualStopTime = SMILTIME_PAUSED_INDEFINITELY;
  1038. #endif
  1039.     }
  1040.     else if (isStoppedInExcl())
  1041.     {
  1042. ulActualStopTime = m_ulStopTimeInExcl;
  1043.     }
  1044.     else if (isDeferredInExcl())
  1045.     {
  1046. ulActualStopTime = SMILTIME_DEFERRED_INDEFINITELY;
  1047.     }
  1048.     else if (m_ulDelay    != ((UINT32) -1) &&
  1049.              m_ulDuration != ((UINT32) -1))
  1050.     {
  1051.         if (m_bBeginOffsetSet)
  1052.         {
  1053.     LONG32 lBeginOffsetPast0 = m_lBeginOffset;
  1054.     if (m_lBeginOffset < 0)
  1055.     {
  1056. lBeginOffsetPast0 = 0;
  1057.     }
  1058.             ulActualStopTime = m_ulDelay + m_ulDuration - lBeginOffsetPast0;
  1059.         }
  1060.         else
  1061.         {
  1062.             if (m_bCurBeginIsOffsetFromSyncBase)
  1063.             {
  1064. ulActualStopTime = m_ulDelay + m_ulDuration;
  1065. // /Adding this if() check fixes hide-site problems exposed
  1066. // in the repro case for PR 53531 once 53531 had been fixed;
  1067. // this makes sure that the beginOffsetFromSyncBase is
  1068. // accounted for only when it should be. Fixes
  1069. // BUG-20010619_lastExclChildGetsItsOffsetFromSyncbaseIgnored.smil
  1070. if (m_bDurationIncludesDelayBeyondSyncbase)
  1071. {
  1072.     ulActualStopTime -= m_ulBeginOffsetFromSyncBase;
  1073. }
  1074.             }
  1075.             else
  1076.             {
  1077.                 ulActualStopTime = m_ulDelay + m_ulDuration;
  1078.             }
  1079.         }
  1080.     }
  1081.     else if (m_ulDelay != (UINT32)-1  &&  m_bCurrentSourceIsLive)
  1082.     {
  1083. // /Fix for PR 57230:
  1084. // live sources that have 0 dur, which means they play
  1085. // forever, should have infinity, not 0, used as
  1086. // their dur when calculating whether or not they're
  1087. // visible at the current time:
  1088. ulActualStopTime = (UINT32)SMILTIME_INFINITY;
  1089.     }
  1090.     else
  1091.     {
  1092.         ret = HXR_NOT_INITIALIZED;
  1093.     }
  1094. // /#define XXXEHODGE_DEBUG_PRINTF_CURRENTSCHEDULEDSTOPTIME
  1095. #if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG_PRINTF_CURRENTSCHEDULEDSTOPTIME)
  1096.     {
  1097. static BOOL bFirstTime = TRUE;
  1098. FILE* f1 = ::fopen("c:\smil2.txt", bFirstTime?"w":"a+");
  1099. ::fprintf(f1, "n[%s]->getCurrentScheduledStopTime() "
  1100. "ulActualStopTime := %lu (delay=%lu, dur=%lu, "
  1101. "beginOffsetFromSyncBase=%lu)  n", (const char*)m_pNode->m_id,
  1102. ulActualStopTime, m_ulDelay, m_ulDuration, m_ulBeginOffsetFromSyncBase);
  1103. ::fclose(f1);
  1104. bFirstTime=FALSE;
  1105.     }
  1106. #endif
  1107.     return ret;
  1108. }
  1109. // /This function takes a time as input and returns in pValue the begin
  1110. // or end time (depending on listType) that makes the most
  1111. // sense given the time passed in; it assumes times that are
  1112. // resolvable have already been resolved (and thus their m_bIsResolved
  1113. // is TRUE), and it thus ignores unresolved times.  It returns
  1114. // HXR_FAILED and sets pValue to NULL if no now-or-future resolved begin
  1115. // time is found.
  1116. // NOTE!!!: this will NOT return the currently-active time if the element
  1117. // is already playing at lCurTime since it would be in the past.  The
  1118. // currently-active begin and end times can be found in this->m_lBeginOffset
  1119. // or this->m_lEndOffset, respectively, and that those values are only
  1120. // valid if m_bBeginOffsetSet and m_bEndOffsetSet, respectively, are TRUE:
  1121. // Also Note: pValue, as well as the two lists, is|are filled with either
  1122. // begin or end time|times, depending on the listType value:
  1123. HX_RESULT
  1124. CSmilElement::getNextResolvedTimeValue(REF(SmilTimeValue*) pValue,
  1125. INT32 lCurTimeInGroupTime,
  1126. INT32 lCurTimeInSyncBaseTime,
  1127. SmilTimingListType listType,
  1128. CHXSimpleList* pListOfAllResolvedTimes)
  1129. {
  1130.     HX_RESULT retval = HXR_OK;
  1131.     SmilTimeValue* pTmpVal = NULL;
  1132.     SmilTimeValue* pTimeValFoundSoFar = NULL;
  1133.     CHXSimpleList* pWhichList = NULL;
  1134.     LONG32 lCurTimeInSameTimeSpace = lCurTimeInSyncBaseTime;
  1135.     LONG32 lCurUsableTimeInGroupTime = lCurTimeInGroupTime;
  1136.     // /If group time is not known, use sync-base time:
  1137.     if (SMILTIME_NEGATIVE_INFINITY == lCurTimeInGroupTime)
  1138.     {
  1139. lCurUsableTimeInGroupTime = lCurTimeInSyncBaseTime;
  1140.     }
  1141.     LISTPOSITION lPos = NULL;
  1142.     if (SmilBeginTimeList == listType) // /get begin time:
  1143.     {
  1144. pWhichList = m_pBeginTimeList;
  1145.     }
  1146.     else if (SmilEndTimeList == listType)// /get end time:
  1147.     {
  1148. pWhichList = m_pEndTimeList;
  1149.     }
  1150.     else
  1151.     {
  1152. HX_ASSERT(SmilBeginTimeList == listType  ||
  1153. SmilEndTimeList == listType);
  1154.     }
  1155.     if (NULL == pWhichList)
  1156.     {
  1157. retval = HXR_FAILED;
  1158. goto cleanup;
  1159.     }
  1160.     lPos = pWhichList->GetHeadPosition();
  1161.     if (NULL == lPos) // /list is empty.
  1162.     {
  1163. retval = HXR_FAILED;
  1164. goto cleanup;
  1165.     }
  1166.     // /The following loop simply finds the time that is nearest
  1167.     // to, but not earlier than, lCurTime:
  1168.     // *Which* curTime depends on the type; events resolve to group times,
  1169.     // while clockValues resolve to syncBase times:
  1170.     while (lPos  &&  HXR_OK == retval)
  1171.     {
  1172. pTmpVal = (SmilTimeValue*)pWhichList->GetAt(lPos);
  1173. if (pTmpVal)
  1174. {
  1175.     if (!pTmpVal->isTimeResolved())
  1176.     {
  1177.      pWhichList->GetNext(lPos);
  1178. continue;
  1179.     }
  1180.     // /It's resolved, so insert it:
  1181.     if (pListOfAllResolvedTimes)
  1182.     {
  1183. pListOfAllResolvedTimes->AddTail(pTmpVal);
  1184.     }
  1185.     LONG32 lResolvedToTimeOfTimeValFoundSoFar =SMILTIME_INFINITY;
  1186.     HX_RESULT tmprslt = HXR_OK;
  1187.     if (NULL != pTimeValFoundSoFar)
  1188.     {
  1189. // /We want to use pTimeValFoundSoFar, not pTmpVal here!
  1190. // Fixes case where there are two or more resolved times and
  1191. // the first, lexically, is higher than any of the others:
  1192. tmprslt = pTimeValFoundSoFar->getEffectiveResolvedTime(
  1193. lResolvedToTimeOfTimeValFoundSoFar);
  1194. HX_ASSERT(HXR_OK == tmprslt);
  1195. if (!SUCCEEDED(tmprslt))
  1196. {
  1197.     HX_ASSERT(SUCCEEDED(tmprslt));
  1198.     continue;
  1199. }
  1200.     }
  1201.     switch (pTmpVal->getTimeType())
  1202.     {
  1203. case SmilTimeMediaMarker:
  1204. case SmilTimeWallclock:
  1205. case SmilTimeEvent:
  1206.     lCurTimeInSameTimeSpace = lCurUsableTimeInGroupTime;
  1207.     break;
  1208. case SmilTimeOffset:
  1209. case SmilTimeClockValue:
  1210. case SmilTimeSyncBase:
  1211. default:
  1212.     lCurTimeInSameTimeSpace = lCurTimeInSyncBaseTime;
  1213.     break;
  1214.     }
  1215.     switch (pTmpVal->getTimeType())
  1216.     {
  1217. case SmilTimeNone:
  1218.     break; // /Skip this time.
  1219. case SmilTimeWallclock:
  1220. case SmilTimeOffset:
  1221. case SmilTimeClockValue:
  1222. {
  1223.     LONG32 lEffectiveResolvedToTime = 0;
  1224.     tmprslt = pTmpVal->getEffectiveResolvedTime(
  1225.     lEffectiveResolvedToTime);
  1226. #if defined(_DEBUG) // /XXXEH- testing!: 
  1227.     LONG32 lTimeOffset = pTmpVal->getTimeOffset();
  1228.     HX_ASSERT(tmprslt==HXR_OK  &&
  1229.     lTimeOffset == lEffectiveResolvedToTime);
  1230. #endif
  1231. // /XXXEH- TODO: add bool (& time val?) that says if (& when) this begin time
  1232. // was already used; if already used, don't use it again, and seeks and
  1233. // repeats must erase this bool (& time val); this is especially needed
  1234. // if we start treating all times as events, i.e., consistently:
  1235.     // /Only use times that are now or later:
  1236.     if (lEffectiveResolvedToTime >= lCurTimeInSameTimeSpace)
  1237.     {
  1238. if (NULL == pTimeValFoundSoFar  ||
  1239. lEffectiveResolvedToTime <
  1240. lResolvedToTimeOfTimeValFoundSoFar)
  1241. {
  1242.     pTimeValFoundSoFar = pTmpVal;
  1243. }
  1244.     }
  1245. }
  1246. break;
  1247. case SmilTimeMediaMarker:
  1248. case SmilTimeSyncBase:
  1249. #if defined(ENABLE_SYNC_TO_PREV)
  1250. case SmilTimeSyncToPrev:
  1251. #endif
  1252. case SmilTimeEvent:
  1253. {
  1254. // /XXXEH- TODO: finish this, and make sure m_lResolvedToTime and m_lWhenTimeWasResolved are being set:
  1255.     LONG32 lEffectiveResolvedToTime = 0;
  1256.     HX_RESULT tmprslt2 = pTmpVal->
  1257.     getEffectiveResolvedTime(
  1258.     lEffectiveResolvedToTime);
  1259.     HX_ASSERT(SUCCEEDED(tmprslt2));// /Should be resovled.
  1260.     if (SUCCEEDED(tmprslt2)  &&
  1261.     lEffectiveResolvedToTime >= lCurTimeInSameTimeSpace)
  1262.     {
  1263. LONG32 lTimeOffset = pTmpVal->getTimeOffset();
  1264. if (lEffectiveResolvedToTime <
  1265. // /XXXEH- TODO: add +offset since this is an event-based time; need
  1266. // "timecmp(x,y)" function that compares two SmilTimeValues (taking into
  1267. // account that negative offsets shouldn't be compared if this is an event
  1268. // time) and returns -1 if x is greater, 0 if same, +1 if y is later:
  1269. // /XXXEH- TODO: argue the following with W3C SYMM Smil Boston Working
  1270. // Group: if we treat event-based times with negative offset as "now"
  1271. // w/clip-begin, then why not same for sync-base (and other) values whose
  1272. // times are in the past when they first become resolved (e.g., clipped by
  1273. // parent, or sync-arc to event-arc'd time)?  For example:
  1274. // <par>
  1275. //   <ref id="x" begin="foo.activate" />
  1276. //   <par begin="10s">
  1277. //     <!-- resolves 3s after it's intended value: -->
  1278. //     <ref begin="x.begin-3s"/>
  1279. lResolvedToTimeOfTimeValFoundSoFar)
  1280. {
  1281.     pTimeValFoundSoFar = pTmpVal;
  1282. }
  1283. // /XXXEH- TODO: verify that this is how the
  1284. // SMIL Boston draft ends up dealing with the
  1285. // begin="x.focusInEvent-5s; x.focusInEvent-3s"
  1286. // issue:
  1287. // /Take the one with the earliest offset if
  1288. // the resolved time is the same, so
  1289. // "x.focusInEvent-5s" beats out "x.focusInEvent",
  1290. // and "x.focusInEvent" beats out "x.focusInEvent+2s"
  1291. // /XXXEH- I think restart might play into this
  1292. // so that x.focusInEvent-5s would be used over
  1293. // x.focusInEvent-3s if and only if (restart=="never"
  1294. // OR (restart!="never" AND this's dur <=2s)):
  1295. else if (lEffectiveResolvedToTime ==
  1296. lResolvedToTimeOfTimeValFoundSoFar  &&
  1297. lTimeOffset <
  1298. pTimeValFoundSoFar->getTimeOffset())
  1299. {
  1300.     pTimeValFoundSoFar = pTmpVal;
  1301. }
  1302.     }
  1303. }
  1304. break;
  1305.     }
  1306. }
  1307.      pWhichList->GetNext(lPos);
  1308.     } // /end while(lPos...).
  1309.     pValue = pTimeValFoundSoFar;
  1310.     if (NULL == pValue)
  1311.     {
  1312. retval = HXR_FAILED;
  1313.     }
  1314. cleanup:
  1315.     return retval;
  1316. }
  1317. HX_RESULT
  1318. CSmilElement::resolveEventTimeValues(INT32 lCurTime,
  1319. const char* pEventName,
  1320. const char* pEventElementId,
  1321. SmilTimingListType listType,
  1322. REF(BOOL) bATimeWasResolved)
  1323. {
  1324.     HX_RESULT retval = HXR_OK;
  1325.     SmilTimeValue* pValue = NULL;
  1326.     CHXSimpleList* pWhichList = NULL;
  1327.     bATimeWasResolved = FALSE;
  1328.     LISTPOSITION lPos = NULL;
  1329.     if (NULL == pEventName  ||
  1330.     // /pEventElementId can be NULL but not non-NULL and empty:
  1331.     (pEventElementId  &&  '' == *pEventElementId) )
  1332.     {
  1333. retval = HXR_FAILED;
  1334. goto cleanup;
  1335.     }
  1336.     if (SmilBeginTimeList == listType) // /get begin time:
  1337.     {
  1338. pWhichList = m_pBeginTimeList;
  1339.     }
  1340.     else if (SmilEndTimeList == listType)// /get end time:
  1341.     {
  1342. pWhichList = m_pEndTimeList;
  1343.     }
  1344.     else
  1345.     {
  1346. HX_ASSERT(SmilBeginTimeList == listType  ||
  1347. SmilEndTimeList == listType);
  1348.     }
  1349.     if (NULL == pWhichList)
  1350.     {
  1351. retval = HXR_FAILED;
  1352. goto cleanup;
  1353.     }
  1354.     // /XXXEH- is there any reason we should start from tail instead?
  1355.     lPos = pWhichList->GetHeadPosition();
  1356.     if (NULL == lPos) // /list is empty.
  1357.     {
  1358. retval = HXR_FAILED;
  1359. goto cleanup;
  1360.     }
  1361.     while (lPos  &&  HXR_OK == retval)
  1362.     {
  1363. pValue = (SmilTimeValue*)pWhichList->GetAt(lPos);
  1364. // /If this begin or end time is a time event based on this event
  1365. // from the element with pEventElementId, then we can (and do)
  1366. // resolve it here:
  1367. if(NULL!= pValue  &&  (SmilTimeEvent == pValue->m_type  ||
  1368. (pValue->m_bTreatSyncArcAsEvent  &&
  1369. pValue->isSyncBaseTimeVal()) ) )
  1370. {
  1371.     // /Now, see if we've got an element that is waiting for this
  1372.     // event from the pEventElement:
  1373.     if (!pValue->getIdRef()  ||  !pValue->getEventName())
  1374.     {
  1375. HX_ASSERT(pValue->getIdRef()  && pValue->getEventName());
  1376. pWhichList->GetNext(lPos);
  1377. continue;
  1378.     }
  1379.     if ((!pEventElementId  ||  strcmp(pValue->getIdRef(),
  1380.     pEventElementId) == 0)  &&
  1381.     strcmp(pValue->getEventName(), pEventName) == 0 )
  1382.     {
  1383. BOOL bIsResolvedAlready = pValue->isTimeResolved();
  1384. INT32 lProirResolvedToTime = (bIsResolvedAlready?
  1385. pValue->getResolvedToTimeWithoutOffset():-1);
  1386. pValue->setIsTimeResolved(TRUE);
  1387. pValue->setResolvedToTime(lCurTime);
  1388. pValue->setWhenTimeWasResolved(lCurTime);
  1389. // /[Optimization]: In case we get called twice with the
  1390. // same event at the same resolved time, let's not force
  1391. // a stop/start of the element:
  1392. if (!bIsResolvedAlready  ||  lCurTime !=lProirResolvedToTime)
  1393. {
  1394.     bATimeWasResolved = TRUE;
  1395. }
  1396.     }
  1397. }
  1398.      pWhichList->GetNext(lPos);
  1399.     } // /end while(lPos...).
  1400. cleanup:
  1401.     return retval;
  1402. }
  1403. // /This method goes through the m_pEndTimeList to see if there's an
  1404. // event-arc end time or other unresolved end time; this is important
  1405. // for use in the algorithm for determining whether or not something
  1406. // should restart (see SMIL 2.0 Spec Timing Module's getNextInterval()
  1407. // pseudocode):
  1408. BOOL
  1409. CSmilElement::hasUnresolvedEndTime()
  1410. {
  1411.     BOOL bHasUnresolvedEndTime = FALSE;
  1412.     SmilTimeValue* pValue = NULL;
  1413.     LISTPOSITION lPos = NULL;
  1414.     if (NULL == m_pEndTimeList)
  1415.     {
  1416. goto cleanup;
  1417.     }
  1418.     // /XXXEH- is there any reason we should start from tail instead?
  1419.     lPos = m_pEndTimeList->GetHeadPosition();
  1420.     if (NULL == lPos) // /list is empty.
  1421.     {
  1422. goto cleanup;
  1423.     }
  1424.     while (lPos  &&  !bHasUnresolvedEndTime)
  1425.     {
  1426. pValue = (SmilTimeValue*)m_pEndTimeList->GetAt(lPos);
  1427. if(NULL == pValue)
  1428. {
  1429.     m_pEndTimeList->GetNext(lPos);
  1430.     continue;
  1431. }
  1432. if (SmilTimeEvent == pValue->m_type)
  1433. {
  1434.     bHasUnresolvedEndTime = TRUE;
  1435. }
  1436. // /XXXEH- TODO: need to go through sync-arc element and see
  1437. // if *it* has any unresolved time(s) (begin or end, depending
  1438. // on this sync-arc time's position value) and, if not, then
  1439. // DON'T claim bHasUnresolvedEndTime is TRUE:
  1440. else if (pValue->m_bTreatSyncArcAsEvent  &&
  1441. pValue->isSyncBaseTimeVal())
  1442. {
  1443.     if (!pValue->isTimeResolved())
  1444.     {
  1445. bHasUnresolvedEndTime = TRUE;
  1446.     }
  1447. }
  1448.      m_pEndTimeList->GetNext(lPos);
  1449.     } // /end while(lPos...).
  1450. cleanup:
  1451.     return bHasUnresolvedEndTime;
  1452. }
  1453. // /This method returns the pure duration from the media's begin to its
  1454. // end, w/o any delay included:
  1455. ULONG32
  1456. CSmilElement::getPureDuration()
  1457. {
  1458.     HX_ASSERT(!m_bDurationIncludesDelayBeyondSyncbase  ||
  1459.     m_bCurBeginIsOffsetFromSyncBase);
  1460.     if (m_bDurationIncludesDelayBeyondSyncbase)
  1461.     {
  1462. return (m_ulDuration - m_ulBeginOffsetFromSyncBase);
  1463.     }
  1464.     else
  1465.     {
  1466. return m_ulDuration;
  1467.     }
  1468. /*
  1469.     return (m_bDurationIncludesDelayBeyondSyncbase?
  1470.     m_ulDuration-m_ulBeginOffsetFromSyncBase : m_ulDuration);
  1471. */
  1472. }
  1473. HX_RESULT
  1474. CSmilElement::resolveSyncArcTimeValues(INT32 lResolvedToTime,
  1475. const char* pSyncBaseElementId,
  1476. SmilTimingListType listType,
  1477. REF(BOOL) bATimeWasResolved,
  1478. BOOL bMoveNewlyResolvedsToPendingTimesList,
  1479. CSmilParser* pParser)
  1480. {
  1481.     HX_RESULT retval = HXR_OK;
  1482.     SmilTimeValue* pValue = NULL;
  1483.     CHXSimpleList* pWhichList = NULL;
  1484.     bATimeWasResolved = FALSE;
  1485.     LISTPOSITION lPos = NULL;
  1486.     if (NULL == pSyncBaseElementId)
  1487.     {
  1488. retval = HXR_FAILED;
  1489. goto cleanup;
  1490.     }
  1491.     if (SmilBeginTimeList == listType) // /get begin time:
  1492.     {
  1493. pWhichList = m_pBeginTimeList;
  1494.     }
  1495.     else if (SmilEndTimeList == listType)// /get end time:
  1496.     {
  1497. pWhichList = m_pEndTimeList;
  1498.     }
  1499.     else
  1500.     {
  1501. HX_ASSERT(SmilBeginTimeList == listType  ||
  1502. SmilEndTimeList == listType);
  1503.     }
  1504.     if (NULL == pWhichList)
  1505.     {
  1506. retval = HXR_FAILED;
  1507. goto cleanup;
  1508.     }
  1509.     // /XXXEH- is there any reason we should start from tail instead?
  1510.     lPos = pWhichList->GetHeadPosition();
  1511.     if (NULL == lPos) // /list is empty.
  1512.     {
  1513. retval = HXR_FAILED;
  1514. goto cleanup;
  1515.     }
  1516.     while (lPos  &&  HXR_OK == retval)
  1517.     {
  1518. pValue = (SmilTimeValue*)pWhichList->GetAt(lPos);
  1519. // /If this begin or end time is a time event based on this event
  1520. // from the element with pSyncBaseElementId, then we can (and do)
  1521. // resolve it here:
  1522. if(NULL!= pValue  &&  pValue->isSyncBaseTimeVal())
  1523. {
  1524.     // /Now, see if we've got an element that is waiting for this
  1525.     // event from the pEventElement:
  1526.     if (!pValue->getIdRef())
  1527.     {
  1528. HX_ASSERT(pValue->getIdRef());
  1529.      pWhichList->GetNext(lPos);
  1530. continue;
  1531.     }
  1532.     if (strcmp(pValue->getIdRef(), pSyncBaseElementId) == 0)
  1533.     {
  1534. // /Helps fix SMIL 2.0 Interop Timing #15.13:
  1535. // if we're resuming a paused element and its duration thus
  1536. // got extended, don't re-resolve (and re-insert) other
  1537. // elements who are sync-arc'd to the *begin* time of this
  1538. // resumed element:
  1539. if (pValue->isTimeResolved()  &&  lResolvedToTime ==
  1540. pValue->getResolvedToTimeWithoutOffset()  &&
  1541. SmilBeginTimeList == listType)
  1542. {
  1543.     bMoveNewlyResolvedsToPendingTimesList = FALSE;
  1544. }
  1545. pValue->setIsTimeResolved(TRUE);
  1546. pValue->setResolvedToTime(lResolvedToTime);
  1547. // /XXXEH- this shouldn't matter what we put here, but
  1548. // we *should* fill this with the current time:
  1549. pValue->setWhenTimeWasResolved(0);
  1550. bATimeWasResolved = TRUE;
  1551. if (pParser  &&  bMoveNewlyResolvedsToPendingTimesList)
  1552. {
  1553.     if (SmilBeginTimeList == listType)
  1554.     {
  1555. if (pParser->EstablishBeginTimeList())
  1556. {
  1557.     CHXSimpleList* pList =
  1558.     pParser->GetPendingBeginTimeList();
  1559.     // /Don't add if it's a duplicate:
  1560.     if (!pParser->isDuplicateEntry(pList, pValue))
  1561.     {
  1562. pList->AddTail(pValue);
  1563.     }
  1564. }
  1565.     }
  1566.     else
  1567.     {
  1568. if (pParser->EstablishEndTimeList())
  1569. {
  1570.     CHXSimpleList* pList =
  1571.     pParser->GetPendingEndTimeList();
  1572.     // /Don't add if it's a duplicate:
  1573.     if (!pParser->isDuplicateEntry(pList, pValue))
  1574.     {
  1575. pList->AddTail(pValue);
  1576.     }
  1577. }
  1578.     }
  1579. }
  1580.     }
  1581. }
  1582.      pWhichList->GetNext(lPos);
  1583.     } // /end while(lPos...).
  1584. cleanup:
  1585.     return retval;
  1586. }
  1587. // /Returns HXR_FAILED if element or its parent don't exist.  The spec says
  1588. // that "always" is what is to be used for restart and restartDefault for the
  1589. // element if it has no parent or the parent has no restartDefault value:
  1590. HX_RESULT
  1591. CSmilElement::getParentRestartDefault()
  1592. {
  1593.     HX_RESULT ret = HXR_OK;
  1594.     if (NULL == m_pNode)
  1595.     {
  1596. ret = HXR_FAILED;
  1597.     }
  1598.     else
  1599.     {
  1600. SMILNode* pParent = m_pNode->m_pParent;
  1601. if (!pParent  ||  !pParent->m_pElement)
  1602. {
  1603.     ret = HXR_FAILED;
  1604. }
  1605. else
  1606. {
  1607.     switch (pParent->m_pElement->m_restartDefaultBehavior)
  1608.     {
  1609. case SmilRestartNever:
  1610. case SmilRestartWhenNotActive:
  1611. case SmilRestartAlways:
  1612.     // /Both restartDefault and restart behavior are assigned
  1613.     // to parent's restartDefault behavior:
  1614.     m_restartDefaultBehavior =
  1615.     m_restartBehavior =
  1616.     pParent->m_pElement->m_restartDefaultBehavior;
  1617.     break;
  1618. case SmilRestartInherit:
  1619.     m_restartDefaultBehavior =
  1620.     m_restartBehavior = SmilRestartAlways;
  1621.     break;
  1622. default:
  1623.     HX_ASSERT(0);
  1624.     break;
  1625.     }
  1626. }
  1627.     }
  1628.     return ret;
  1629. }
  1630. void CSmilElement::updateRemoveTime(UINT32 ulRemoveTime)
  1631. {
  1632.     m_ulRemoveTime = ulRemoveTime;
  1633.     if (m_pHandler)
  1634.     {
  1635.         m_pHandler->handleRemoveTimeUpdate(this, ulRemoveTime);
  1636.     }
  1637. }
  1638. void CSmilElement::handleXMMF(const char* pszID, const char* pszXMMFile, const char* pszSrc)
  1639. {
  1640.     if (m_pHandler)
  1641.     {
  1642.         m_pHandler->handleExternalMediaMarkerFile(this,
  1643.                                                   pszID,
  1644.                                                   pszXMMFile,
  1645.                                                   pszSrc);
  1646.     }
  1647. }
  1648. BOOL CSmilElement::hasEventBasedBeginTime()
  1649. {
  1650.     BOOL bRet = FALSE;
  1651.     if (m_pBeginTimeList)
  1652.     {
  1653.         LISTPOSITION pos = m_pBeginTimeList->GetHeadPosition();
  1654.         while (pos)
  1655.         {
  1656.             SmilTimeValue* pValue =
  1657.                 (SmilTimeValue*) m_pBeginTimeList->GetNext(pos);
  1658.             if (pValue &&
  1659.                 pValue->m_type == SmilTimeEvent)
  1660.             {
  1661.                 bRet = TRUE;
  1662.                 break;
  1663.             }
  1664.         }
  1665.     }
  1666.     // We also have to check our sync ancestor because
  1667.     // if our sync ancestor has an event based begin
  1668.     // time, then so do we. However, if we already
  1669.     // know we have an event based time, then we don't
  1670.     // need to check
  1671.     if (!bRet)
  1672.     {
  1673.         CSmilElement* pSyncAnc = getSyncAncestorElement();
  1674.         if (pSyncAnc)
  1675.         {
  1676.             bRet = pSyncAnc->hasEventBasedBeginTime();
  1677.         }
  1678.     }
  1679.     return bRet;
  1680. }
  1681. CSmilElement* CSmilElement::getSyncAncestorElement()
  1682. {
  1683.     CSmilElement* pRet = NULL;
  1684.     if (m_pNode)
  1685.     {
  1686.         BOOL bLegalMediaObjectChild = FALSE;
  1687.         if (m_pNode->m_tag == SMILArea         ||
  1688.             m_pNode->m_tag == SMILAnchor       ||
  1689.             m_pNode->m_tag == SMILAnimate      ||
  1690.             m_pNode->m_tag == SMILSet          ||
  1691.             m_pNode->m_tag == SMILAnimateColor ||
  1692.             m_pNode->m_tag == SMILAnimateMotion)
  1693.         {
  1694.             bLegalMediaObjectChild = TRUE;
  1695.         }
  1696.         SMILNode* pAnc = m_pNode->m_pParent;
  1697.         while (pAnc)
  1698.         {
  1699.             if (pAnc->m_tag == SMILPar  ||
  1700.                 pAnc->m_tag == SMILExcl ||
  1701.                 pAnc->m_tag == SMILSeq)
  1702.             {
  1703.                 pRet = pAnc->m_pElement;
  1704.                 break;
  1705.             }
  1706.             else if ((pAnc->m_tag == SMILRef        ||
  1707.                       pAnc->m_tag == SMILText       ||
  1708.                       pAnc->m_tag == SMILImg        ||
  1709.                       pAnc->m_tag == SMILAudio      ||
  1710.                       pAnc->m_tag == SMILVideo      ||
  1711.                       pAnc->m_tag == SMILAnimation  ||
  1712.                       pAnc->m_tag == SMILTextstream ||
  1713.                       pAnc->m_tag == SMILBrush      ||
  1714.                       pAnc->m_tag == SMILPrefetch) &&
  1715.                      bLegalMediaObjectChild)
  1716.             {
  1717.                 pRet = pAnc->m_pElement;
  1718.                 break;
  1719.             }
  1720.             pAnc = pAnc->m_pParent;
  1721.         }
  1722.     }
  1723.     return pRet;
  1724. }
  1725. BOOL CSmilElement::hasEventBasedEndTime()
  1726. {
  1727.     BOOL bRet = FALSE;
  1728.     if (m_pEndTimeList)
  1729.     {
  1730.         LISTPOSITION pos = m_pEndTimeList->GetHeadPosition();
  1731.         while (pos)
  1732.         {
  1733.             SmilTimeValue* pValue =
  1734.                 (SmilTimeValue*) m_pEndTimeList->GetNext(pos);
  1735.             if (pValue &&
  1736.                 pValue->m_type == SmilTimeEvent)
  1737.             {
  1738.                 bRet = TRUE;
  1739.                 break;
  1740.             }
  1741.         }
  1742.     }
  1743.     return bRet;
  1744. }
  1745. HX_RESULT
  1746. CSmilElement::GetElementProperties(REF(IHXValues*) pProperties)
  1747. {
  1748.     HX_RESULT rc = HXR_OK;
  1749.     BOOL bDone = FALSE;
  1750.     ElementWithinTag elementWithinTag = WithinUnknown;
  1751.     SMILNode* pNode = m_pNode;
  1752.     HX_ASSERT(pNode);
  1753.     while (pNode->m_pParent && !bDone)
  1754.     {
  1755. switch (pNode->m_pParent->m_tag)
  1756. {
  1757. case SMILPar:
  1758.     if (elementWithinTag == WithinSeq)
  1759.     {
  1760. elementWithinTag = WithinSeqInPar;
  1761.     }
  1762.     else
  1763.     {
  1764. elementWithinTag = WithinPar;
  1765.     }
  1766.     bDone = TRUE;
  1767.     break;
  1768. case SMILSeq:
  1769.     elementWithinTag = WithinSeq;
  1770.     break;
  1771. default:
  1772.     break;
  1773. }
  1774. pNode = pNode->m_pParent;
  1775.     }
  1776.     pProperties = new CHXHeader();
  1777.     pProperties->AddRef();
  1778.     pProperties->SetPropertyULONG32("ElementWithinTag", elementWithinTag);
  1779.     pProperties->SetPropertyULONG32("Delay", m_ulDelay);
  1780.     if (m_bHasExplicitDur)
  1781.     {
  1782. pProperties->SetPropertyULONG32("Duration", m_ulDuration);
  1783.     }
  1784.     return rc;
  1785. }
  1786. void
  1787. CSmilElement::checkElementFillBehavior()
  1788. {
  1789.     if (m_pTimelineElement)
  1790.     {
  1791. m_pTimelineElement->checkElementFillBehavior();
  1792.     }
  1793. }
  1794. /*
  1795.  * CSmilRootLayout methods
  1796.  */
  1797. CSmilRootLayout::CSmilRootLayout(SMILNode* pNode) :
  1798.     CSmilElement(pNode)
  1799. {
  1800.     m_dWidth               = 0.0;
  1801.     m_eWidthType           = CSS2TypeAuto;
  1802.     m_dHeight              = 0.0;
  1803.     m_eWidthType           = CSS2TypeAuto;
  1804.     m_ulBackgroundColor    = 0;
  1805.     m_eBackgroundColorType = CSS2TypeTransparent;
  1806.     m_eResizeBehavior      = ResizeZoom;
  1807.     m_eContextWindow       = ContextWindowAuto;
  1808. }
  1809. CSmilRootLayout::~CSmilRootLayout()
  1810. {
  1811. }
  1812. HX_RESULT
  1813. CSmilRootLayout::handleElement()
  1814. {
  1815.     HX_RESULT rc = HXR_OK;
  1816.     if(m_pHandler)
  1817.     {
  1818. rc = m_pHandler->handleRootLayout(this);
  1819.     }
  1820.     return rc;
  1821. }
  1822. /*
  1823.  * CSmilRegion methods
  1824.  */
  1825. CSmilRegion::CSmilRegion(SMILNode* pNode) :
  1826.     CSmilElement(pNode)
  1827. {
  1828.     m_Rect.m_dLeft         = 0.0;
  1829.     m_Rect.m_eLeftType     = CSS2TypeAuto;
  1830.     m_Rect.m_dTop          = 0.0;
  1831.     m_Rect.m_eTopType      = CSS2TypeAuto;
  1832.     m_Rect.m_dRight        = 0.0;
  1833.     m_Rect.m_eRightType    = CSS2TypeAuto;
  1834.     m_Rect.m_dBottom       = 0.0;
  1835.     m_Rect.m_eBottomType   = CSS2TypeAuto;
  1836.     m_Rect.m_dWidth        = 0.0;
  1837.     m_Rect.m_eWidthType    = CSS2TypeAuto;
  1838.     m_Rect.m_dHeight       = 0.0;
  1839.     m_Rect.m_eHeightType   = CSS2TypeAuto;
  1840.     m_lZIndex              = 0;
  1841.     m_eZIndexType          = CSS2TypeAuto;
  1842.     m_eFit                 = FitHidden;
  1843.     m_eShowBackground      = ShowBackgroundAlways;
  1844.     m_ulBackgroundColor    = 0xFF000000;
  1845.     m_eBackgroundColorType = CSS2TypeTransparent;
  1846.     m_dSoundLevel          = 100.0;
  1847.     m_bRegionNameSpecified = FALSE;
  1848. }
  1849. CSmilRegion::~CSmilRegion()
  1850. {
  1851. }
  1852. HX_RESULT
  1853. CSmilRegion::handleElement()
  1854. {
  1855.     HX_RESULT rc = HXR_OK;
  1856.     if(m_pHandler)
  1857.     {
  1858. rc = m_pHandler->handleRegion(this);
  1859.     }
  1860.     return rc;
  1861. }
  1862. CSmilRegPoint::CSmilRegPoint(SMILNode* pNode) :
  1863.     CSmilElement(pNode)
  1864. {
  1865.     m_RegPoint.m_dLeft       = 0.0;
  1866.     m_RegPoint.m_eLeftType   = CSS2TypeAuto;
  1867.     m_RegPoint.m_dTop        = 0.0;
  1868.     m_RegPoint.m_eTopType    = CSS2TypeAuto;
  1869.     m_RegPoint.m_dRight      = 0.0;
  1870.     m_RegPoint.m_eRightType  = CSS2TypeAuto;
  1871.     m_RegPoint.m_dBottom     = 0.0;
  1872.     m_RegPoint.m_eBottomType = CSS2TypeAuto;
  1873.     m_RegPoint.m_eRegAlign   = RegAlignTopLeft;
  1874. }
  1875. CSmilRegPoint::~CSmilRegPoint()
  1876. {
  1877. }
  1878. HX_RESULT
  1879. CSmilRegPoint::handleElement()
  1880. {
  1881.     HX_RESULT rc = HXR_OK;
  1882.     if(m_pHandler)
  1883.     {
  1884. rc = m_pHandler->handleRegPoint(this);
  1885.     }
  1886.     return rc;
  1887. }
  1888. #if defined(HELIX_FEATURE_SMIL2_MULTIWINDOWLAYOUT)
  1889. CSmilViewport::CSmilViewport(SMILNode* pNode) :
  1890.     CSmilElement(pNode)
  1891. {
  1892.     m_ulBackgroundColor    = 0;
  1893.     m_eBackgroundColorType = CSS2TypeTransparent;
  1894.     m_dWidth               = 0.0;
  1895.     m_eWidthType           = CSS2TypeAuto;
  1896.     m_dHeight              = 0.0;
  1897.     m_eHeightType          = CSS2TypeAuto;
  1898.     m_eOpen                = ViewportOpenOnStart;
  1899.     m_eClose               = ViewportCloseOnRequest;
  1900.     m_eResizeBehavior      = ResizeZoom;
  1901.     m_eContextWindow       = ContextWindowAuto;
  1902. }
  1903. CSmilViewport::~CSmilViewport()
  1904. {
  1905. }
  1906. HX_RESULT
  1907. CSmilViewport::handleElement()
  1908. {
  1909.     HX_RESULT rc = HXR_OK;
  1910.     if(m_pHandler)
  1911.     {
  1912. rc = m_pHandler->handleViewport(this);
  1913.     }
  1914.     return rc;
  1915. }
  1916. #endif /* #if defined(HELIX_FEATURE_SMIL2_MULTIWINDOWLAYOUT) */
  1917. /*
  1918.  * CSmilMeta methods
  1919.  */
  1920. CSmilMeta::CSmilMeta(SMILNode* pNode):
  1921.     CSmilElement(pNode)
  1922. {
  1923. }
  1924. CSmilMeta::~CSmilMeta()
  1925. {
  1926. }
  1927. HX_RESULT
  1928. CSmilMeta::handleElement()
  1929. {
  1930.     HX_RESULT rc = HXR_OK;
  1931.     if(m_pHandler)
  1932.     {
  1933. rc = m_pHandler->handleMeta(this);
  1934.     }
  1935.     return rc;
  1936. }
  1937. /*
  1938.  * CSmilMetadata methods
  1939.  */
  1940. CSmilMetadata::CSmilMetadata(SMILNode* pNode):
  1941.     CSmilElement(pNode)
  1942. {
  1943. }
  1944. CSmilMetadata::~CSmilMetadata()
  1945. {
  1946. }
  1947. HX_RESULT
  1948. CSmilMetadata::handleElement()
  1949. {
  1950.     HX_RESULT rc = HXR_OK;
  1951.     if(m_pHandler)
  1952.     {
  1953. rc = m_pHandler->handleMetadata(this);
  1954.     }
  1955.     return rc;
  1956. }
  1957. /*
  1958.  * CSmilRendererPreFetch methods
  1959.  */
  1960. CSmilRendererPreFetch::CSmilRendererPreFetch(SMILNode* pNode):
  1961.     CSmilElement(pNode)
  1962. {
  1963. }
  1964. CSmilRendererPreFetch::~CSmilRendererPreFetch()
  1965. {
  1966. }
  1967. HX_RESULT
  1968. CSmilRendererPreFetch::handleElement()
  1969. {
  1970.     HX_RESULT rc = HXR_OK;
  1971.     if(m_pHandler)
  1972.     {
  1973. rc = m_pHandler->handleRendererPreFetch(this);
  1974.     }
  1975.     return rc;
  1976. }
  1977. /*
  1978.  * CSmilEndLayout methods
  1979.  */
  1980. CSmilEndLayout::CSmilEndLayout():
  1981.     CSmilElement(NULL)
  1982. {
  1983. }
  1984. CSmilEndLayout::~CSmilEndLayout()
  1985. {
  1986. }
  1987. HX_RESULT
  1988. CSmilEndLayout::handleElement()
  1989. {
  1990.     HX_RESULT rc = HXR_OK;
  1991.     if(m_pHandler)
  1992.     {
  1993. rc = m_pHandler->handleEndLayout(this);
  1994.     }
  1995.     return rc;
  1996. }
  1997. /*
  1998.  * CSmilMetaValues methods
  1999.  */
  2000. CSmilMetaValues::CSmilMetaValues():
  2001.     CSmilElement(NULL),
  2002.     m_pValues(0)
  2003. {
  2004. }
  2005. CSmilMetaValues::~CSmilMetaValues()
  2006. {
  2007.     HX_RELEASE(m_pValues);
  2008. }
  2009. /*
  2010.  * CSmilCustomTest methods:
  2011.  */
  2012. CSmilCustomTest::CSmilCustomTest(SMILNode* pNode) :
  2013.     CSmilElement(pNode)
  2014.     , m_bDefaultState(FALSE)
  2015.     , m_bOverrideVisible(FALSE)
  2016. {
  2017. }
  2018. CSmilCustomTest::~CSmilCustomTest()
  2019. {
  2020. }
  2021. /*
  2022.  * CSmilSource methods
  2023.  */
  2024. CSmilSource::CSmilSource(SMILNode* pNode):
  2025.     CSmilElement(pNode)
  2026. {
  2027.     m_ulColor                       = 0;
  2028.     m_eColorType                    = CSS2TypeTransparent;
  2029.     m_Rect.m_dLeft                  = 0.0;
  2030.     m_Rect.m_eLeftType              = CSS2TypeAuto;
  2031.     m_Rect.m_dTop                   = 0.0;
  2032.     m_Rect.m_eTopType               = CSS2TypeAuto;
  2033.     m_Rect.m_dRight                 = 0.0;
  2034.     m_Rect.m_eRightType             = CSS2TypeAuto;
  2035.     m_Rect.m_dBottom                = 0.0;
  2036.     m_Rect.m_eBottomType            = CSS2TypeAuto;
  2037.     m_Rect.m_dWidth                 = 0.0;
  2038.     m_Rect.m_eWidthType             = CSS2TypeAuto;
  2039.     m_Rect.m_dHeight                = 0.0;
  2040.     m_Rect.m_eHeightType            = CSS2TypeAuto;
  2041.     m_lZIndex                       = 0;
  2042.     m_eZIndexType                   = CSS2TypeAuto;
  2043.     m_eFit                          = FitHidden;
  2044.     m_bFitSpecified                 = FALSE;
  2045.     m_ulBackgroundColor             = 0;
  2046.     m_eBackgroundColorType          = CSS2TypeTransparent;
  2047.     m_bRegPointIsPredef             = TRUE;
  2048.     m_ePredefRegPoint               = RegAlignTopLeft;
  2049.     m_eRegAlign                     = RegAlignTopLeft;
  2050.     m_bRegAlignSpecified            = FALSE;
  2051.     m_bBackgroundOpacitySpecified   = FALSE;
  2052.     m_ulBackgroundOpacity           = 255;
  2053.     m_bMediaOpacitySpecified        = FALSE;
  2054.     m_ulMediaOpacity                = 255;
  2055.     m_bChromaKeySpecified           = FALSE;
  2056.     m_ulChromaKey                   = 0;
  2057.     m_ulChromaKeyTolerance          = 0;
  2058.     m_ulChromaKeyOpacity            = 0;
  2059.     m_bAudioDeviceReflushHintNeeded = FALSE;
  2060.     m_eHandledBy                    = HandledByAuto;
  2061.     m_bBackgroundColorSpecified     = FALSE;
  2062.     m_ulLinkTargetDestnLevel_pct    = 100;
  2063.     m_ulLinkTargetSourceLevel_pct   = 100;
  2064.     m_ulPrefetchAmount              = 0;
  2065.     m_typeOfPrefetchAmount          = PrefetchUnknown;
  2066. }
  2067. CSmilSource::~CSmilSource()
  2068. {
  2069. }
  2070. HX_RESULT
  2071. CSmilSource::handleElement()
  2072. {
  2073.     HX_RESULT rc = HXR_OK;
  2074.     if(m_pHandler)
  2075.     {
  2076. rc = m_pHandler->handleSource(this);
  2077.     }
  2078.     return rc;
  2079. }
  2080. void
  2081. CSmilSource::setRange(const char* pRange)
  2082. {
  2083.     // parse smpte/npt ranges:
  2084.     //    smpte:12:03:14.21-12:15:26.03
  2085.     //   npt:3:02.5-4:38.6
  2086.     //
  2087.     char* pPtr = (char *)strstr(pRange, "npt:");
  2088.     if(pPtr)
  2089.     {
  2090. pPtr += 4; // point to beginning of range
  2091. char* pHyphen = (char *)strchr(pRange, '-'); // find '-'
  2092. if(pHyphen > pPtr)
  2093. {
  2094.     NPTime beginTime((const char*)CHXString(pPtr, pHyphen-pPtr));
  2095.     m_ulAuthoredClipBegin = (UINT32)beginTime;
  2096.     m_ulClipBegin = m_ulAuthoredClipBegin;
  2097.     if(strlen(pHyphen+1) > 0)
  2098.     {
  2099. NPTime endTime((const char*)CHXString(pHyphen+1));
  2100. m_ulClipEnd = (UINT32)endTime;
  2101.     }
  2102. }
  2103. else if(pHyphen)
  2104. {
  2105.     NPTime endTime((const char*)CHXString(pHyphen+1));
  2106.     m_ulClipEnd = (UINT32)endTime;
  2107. }
  2108.     }
  2109.     else
  2110.     {
  2111. pPtr = (char *)strstr(pRange, "smpte:");
  2112. if(pPtr)
  2113. {
  2114.     pPtr += 6; // point to beginning of range
  2115.     char* pHyphen = (char *)strchr(pRange, '-'); // find '-'
  2116.     if(pHyphen > pPtr)
  2117.     {
  2118. SMPTETimeCode beginTime = 
  2119.     ((const char*)CHXString(pPtr, pHyphen-pPtr));
  2120. m_ulAuthoredClipBegin = (UINT32)beginTime;
  2121. m_ulClipBegin = m_ulAuthoredClipBegin;
  2122. if(strlen(pHyphen+1) > 0)
  2123. {
  2124.     SMPTETimeCode endTime =
  2125. ((const char*)CHXString(pPtr, pHyphen-pPtr));
  2126.     m_ulClipEnd = (UINT32)endTime;
  2127. }
  2128.     }
  2129.     else if(pHyphen)
  2130.     {
  2131. SMPTETimeCode endTime((const char*)CHXString(pHyphen+1));
  2132. m_ulClipEnd = (UINT32)endTime;
  2133.     }
  2134. }
  2135.     }
  2136. }
  2137. /*
  2138.  * CSmilSourceUpdate methods
  2139.  */
  2140. CSmilSourceUpdate::CSmilSourceUpdate():
  2141.     CSmilElement(NULL)
  2142. {
  2143.     m_updateTag = UpdateUnknown;
  2144.     m_ulUpdatedDuration = 0;
  2145.     m_bDurationIsPureOfDelay = TRUE;
  2146.     m_ulUpdatedDelay = 0;
  2147. }
  2148. CSmilSourceUpdate::~CSmilSourceUpdate()
  2149. {
  2150. }
  2151. HX_RESULT
  2152. CSmilSourceUpdate::handleElement()
  2153. {
  2154.     HX_RESULT rc = HXR_OK;
  2155.     if(m_pHandler)
  2156.     {
  2157. rc = m_pHandler->handleSourceUpdate(this);
  2158.     }
  2159.     return rc;
  2160. }
  2161. #if defined(HELIX_FEATURE_SMIL2_ANIMATION)
  2162. // CSmilAnimateElement methods
  2163. CSmilAnimateElement::CSmilAnimateElement(SMILNode* pNode)
  2164.     : CSmilElement(pNode)
  2165. {
  2166.     // Set defaults
  2167.     m_ulSimpleDuration          = ((UINT32) -1);
  2168.     m_ulActiveDuration          = ((UINT32) -1);
  2169.     m_ulADNoSpeed               = ((UINT32) -1);
  2170.     m_pTargetElementID          = NULL;
  2171.     m_eTargetElementTag         = SMILUnknown;
  2172.     m_ulNumValues               = 0;
  2173.     m_ppValue                   = NULL;
  2174.     m_ucAttributeName           = kAttrNameUnknown;
  2175.     m_ucCalcMode                = kCalcModeLinear;
  2176.     m_ucAccumulate              = kAccumulateNone;
  2177.     m_ucAdditive                = kAdditiveReplace;
  2178.     m_ucAnimationType           = kAnimTypeValues;
  2179.     m_dRepeatCount              = 1.0;
  2180.     m_ulRepeatDur               = ((UINT32) -1);
  2181.     m_bRepeatDurIsIndefinite    = FALSE;
  2182.     m_dAccelerate               = 0.0;
  2183.     m_dDecelerate               = 0.0;
  2184.     m_bAutoReverse              = FALSE;
  2185.     m_dSpeed                    = 1.0;
  2186.     m_bIndefiniteSimpleDuration = FALSE;
  2187.     m_bIndefiniteActiveDuration = FALSE;
  2188.     m_bCancelAnimation          = FALSE;
  2189. #if defined(XXXMEH_SPLINE_ANIMATION)
  2190.     m_ulNumKeyTimes             = 0;
  2191.     m_pdKeyTime                 = NULL;
  2192.     m_ulNumKeySplines           = 0;
  2193.     m_pKeySpline                = NULL;
  2194.     m_ulNumPathCmds             = 0;
  2195.     m_ppPathCmd                 = NULL;
  2196. #endif
  2197. }
  2198. CSmilAnimateElement::~CSmilAnimateElement()
  2199. {
  2200.     HX_DELETE(m_pTargetElementID);
  2201.     if (m_ppValue)
  2202.     {
  2203.         for (UINT32 i = 0; i < m_ulNumValues; i++)
  2204.         {
  2205.             HX_DELETE(m_ppValue[i]);
  2206.         }
  2207.         HX_VECTOR_DELETE(m_ppValue);
  2208.     }
  2209. #if defined(XXXMEH_SPLINE_ANIMATION)
  2210.     HX_VECTOR_DELETE(m_pdKeyTime);
  2211.     HX_VECTOR_DELETE(m_pKeySpline);
  2212.     if (m_ppPathCmd && m_ulNumPathCmds)
  2213.     {
  2214.         for (UINT32 i = 0; i < m_ulNumPathCmds; i++)
  2215.         {
  2216.             HX_DELETE(m_ppPathCmd[i]);
  2217.         }
  2218.     }
  2219.     HX_VECTOR_DELETE(m_ppPathCmd);
  2220. #endif
  2221. }
  2222. HX_RESULT CSmilAnimateElement::handleElement()
  2223. {
  2224.     HX_RESULT retVal = HXR_OK;
  2225.     if(m_pHandler)
  2226.     {
  2227. retVal = m_pHandler->handleAnimate(this);
  2228.     }
  2229.     return retVal;
  2230. }
  2231. HX_RESULT CSmilAnimateElement::getCurrentScheduledStopTime(REF(ULONG32) ulActualStopTime)
  2232. {
  2233.     HX_RESULT ret = HXR_OK;
  2234.     if (m_ulDelay != ((UINT32) -1))
  2235.     {
  2236.         if (m_bIndefiniteActiveDuration)
  2237.         {
  2238.             ulActualStopTime = SMILTIME_INFINITY;
  2239.         }
  2240.         else
  2241.         {
  2242.             ulActualStopTime = m_ulDelay + m_ulActiveDuration;
  2243.         }
  2244.     }
  2245.     else
  2246.     {
  2247.         ret = HXR_NOT_INITIALIZED;
  2248.     }
  2249.     return ret;
  2250. }
  2251. #endif /* #if defined(HELIX_FEATURE_SMIL2_ANIMATION) */
  2252. CSmilParamElement::CSmilParamElement(SMILNode* pNode)
  2253.     : CSmilElement(pNode)
  2254. {
  2255.     m_pName     = NULL;
  2256.     m_pValue    = NULL;
  2257.     m_eDelivery = DeliveryClient;
  2258. }
  2259. CSmilParamElement::~CSmilParamElement()
  2260. {
  2261.     HX_RELEASE(m_pName);
  2262.     HX_RELEASE(m_pValue);
  2263. }
  2264. /*
  2265.  * CSmilParElement methods
  2266.  */
  2267. CSmilParElement::CSmilParElement(SMILNode* pNode):
  2268.     CSmilElement(pNode)
  2269. {
  2270. }
  2271. CSmilParElement::~CSmilParElement()
  2272. {
  2273. }
  2274. /*
  2275.  * CSmilSeqElement methods
  2276.  */
  2277. CSmilSeqElement::CSmilSeqElement(SMILNode*  pNode):
  2278.     CSmilElement(pNode)
  2279. {
  2280. }
  2281. CSmilSeqElement::~CSmilSeqElement()
  2282. {
  2283. }
  2284. /*
  2285.  * CSmilExclElement methods
  2286.  */
  2287. CSmilExclElement::CSmilExclElement(SMILNode* pNode):
  2288.     CSmilElement(pNode)
  2289.     , m_pPauseStack(NULL)
  2290. {
  2291. }
  2292. CSmilExclElement::~CSmilExclElement()
  2293. {
  2294.     HX_DELETE(m_pPauseStack);
  2295. }
  2296. /*
  2297.  * CSmilPriorityClassElement methods
  2298.  */
  2299. CSmilPriorityClassElement::CSmilPriorityClassElement(SMILNode* pNode):
  2300. CSmilElement(pNode)
  2301. , m_pauseDisplay(SMILPriorityClassPauseDisplayShow)
  2302. , m_peers(SMILPriorityClassStop)
  2303. , m_higher(SMILPriorityClassPause)
  2304. , m_lower(SMILPriorityClassDefer)
  2305. {
  2306. }
  2307. CSmilPriorityClassElement::~CSmilPriorityClassElement()
  2308. {
  2309. }
  2310. /*
  2311.  * CSmilAAnchor methods
  2312.  */
  2313. CSmilAAnchorElement::CSmilAAnchorElement(SMILNode* pNode):
  2314.     CSmilElement(pNode),
  2315.     m_show("replace")
  2316.     , m_ulSourceLevel_pct(100)
  2317.     , m_ulDestinationLevel_pct(100)
  2318.     // /XXXEH- TODO: make sure that, if show="new", this changes to play:
  2319.     , m_sourcePlaystate(SMILLinkPlaystatePause)
  2320.     , m_destinationPlaystate(SMILLinkPlaystatePlay)
  2321.     , m_bExternal(FALSE)
  2322.     , m_actuate("onRequest")
  2323.     , m_accesskey("") // /(an ISO10646 character.  Default unspecified)
  2324.     , m_ulTabindex ((UINT32)-1)
  2325.     , m_target("")
  2326.     , m_bTargetIsARegion(FALSE)
  2327.     , m_bTimeValueSet(FALSE)
  2328.     , m_lAnchorBeginOffset(0)
  2329.     , m_bAnchorBeginOffsetSet(FALSE)
  2330.     , m_lAnchorEndOffset(0)
  2331.     , m_bAnchorEndOffsetSet(FALSE)
  2332.     , m_ulAnchorDuration((UINT32)-1)
  2333.     , m_ulAnchorMinActiveDur(0)
  2334.     , m_ulAnchorMaxActiveDur((UINT32)-1)
  2335. {
  2336. }
  2337. CSmilAAnchorElement::~CSmilAAnchorElement()
  2338. {
  2339. }
  2340. BOOL
  2341. CSmilAAnchorElement::isCurrentLink(UINT32 ulTimeOffset,
  2342.    UINT32 ulXOffset, UINT32 ulYOffset,
  2343.    HXxRect regionRect,
  2344.    // /These 3 are ignored for <a> links:
  2345.    BOOL bResizeBehaviorIsZoom,
  2346.    double dZoomX, double dZoomY)
  2347. {
  2348.     BOOL rc = TRUE;
  2349.     ULONG32 ulBeginRelativeToSyncBase = (UINT32)-1;
  2350.     // coords only - check for out of bounds region
  2351.     UINT32 ulRegionWidth = regionRect.right - regionRect.left;
  2352.     UINT32 ulRegionHeight = regionRect.bottom - regionRect.top;
  2353.     if(ulXOffset > ulRegionWidth ||
  2354. ulYOffset > ulRegionHeight)
  2355.     {
  2356. if (ANCHOR_POS_DONTCARE != ulXOffset  &&
  2357. ANCHOR_POS_DONTCARE != ulYOffset)
  2358. {
  2359.     rc = FALSE;
  2360.     goto exit;
  2361. }
  2362.     }
  2363.     if(m_href.GetLength() == 0)
  2364.     {
  2365. rc = FALSE;
  2366.     }
  2367.     // /In SMIL 2.0, "a" links can also be timed, so check time offset:
  2368.     else if (!isLinkActiveAtTime(ulTimeOffset, ulBeginRelativeToSyncBase))
  2369.     {
  2370. rc = FALSE;
  2371.     }
  2372. exit:
  2373.     return rc;
  2374. }
  2375. BOOL
  2376. CSmilAAnchorElement::isLinkActiveAtTime(UINT32 ulTimeOffset,
  2377. REF(ULONG32)rulAnchorRelativeStartTime)
  2378. {
  2379.     BOOL bIsActiveAtTimeOffset = TRUE;
  2380.     rulAnchorRelativeStartTime = (UINT32)-1;
  2381.     if(m_bTimeValueSet)
  2382.     {
  2383. bIsActiveAtTimeOffset = FALSE;
  2384. BOOL bValidDelay = m_ulDelay != (UINT32)-1;
  2385. if(m_bAnchorBeginOffsetSet  ||  bValidDelay)
  2386. {
  2387.     if((m_bAnchorBeginOffsetSet  &&
  2388.     (INT32)ulTimeOffset >= m_lAnchorBeginOffset)  ||
  2389.     (bValidDelay  &&  ulTimeOffset >= m_ulDelay) ) 
  2390.     {
  2391. // /For PR 67170 fix, caller needs anchor's begin time to tell
  2392. // which of multiple, active onLoad anchors to use after a seek:
  2393. if (m_bAnchorBeginOffsetSet  &&
  2394.     (INT32)ulTimeOffset >= m_lAnchorBeginOffset)
  2395. {
  2396.     rulAnchorRelativeStartTime = m_lAnchorBeginOffset;
  2397. }
  2398. else
  2399. {
  2400.     rulAnchorRelativeStartTime = m_ulDelay;
  2401. }
  2402. LONG32 lAnchorEndTime = -1;
  2403. if (m_bAnchorEndOffsetSet)
  2404. {
  2405.     lAnchorEndTime = m_lAnchorEndOffset;
  2406. }
  2407. else if ((UINT32)-1 != m_ulAnchorDuration)
  2408. {
  2409.     lAnchorEndTime = (INT32)m_ulAnchorDuration;
  2410.     if (m_bAnchorBeginOffsetSet)
  2411.     {
  2412. lAnchorEndTime += m_lAnchorBeginOffset;
  2413.     }
  2414. }
  2415. if(-1 != lAnchorEndTime)
  2416. {
  2417.     if((INT32)ulTimeOffset <= lAnchorEndTime)
  2418.     {
  2419. bIsActiveAtTimeOffset = TRUE;
  2420.     }
  2421. }
  2422. else
  2423. {
  2424.     bIsActiveAtTimeOffset = TRUE;
  2425. }
  2426.     }
  2427. }
  2428. else if(m_bAnchorEndOffsetSet)
  2429. {
  2430.     if((INT32)ulTimeOffset <= m_lAnchorEndOffset)
  2431.     {
  2432. bIsActiveAtTimeOffset = TRUE;
  2433.     }
  2434. }
  2435.     }
  2436.     return bIsActiveAtTimeOffset;
  2437. }
  2438. BOOL
  2439. CSmilAnchorElement::isLinkActiveAtTime(UINT32 ulTimeOffset,
  2440.        REF(ULONG32)rulAnchorRelativeStartTime)
  2441. {
  2442.     BOOL bIsActiveAtTimeOffset = TRUE;
  2443.     if(m_bTimeValueSet)
  2444.     {
  2445. bIsActiveAtTimeOffset = FALSE;
  2446. //[SMIL 1.0 compliance] the following variable and its use, below,
  2447. // helps fix PR 26471.  We may have had only our delay set:
  2448. BOOL bValidDelay = m_ulDelay != (UINT32)-1;
  2449. if(m_bBeginOffsetSet  ||  bValidDelay)
  2450. {
  2451.     // /First, we need to make sure we're in the same time-coordinate
  2452.     // system as our syncbase (parent):
  2453.     ULONG32 ulTimeOffsetFromSyncBase = m_ulDelay;
  2454.     if (m_bCurBeginIsOffsetFromSyncBase)
  2455.     {
  2456. ulTimeOffsetFromSyncBase =
  2457. m_ulBeginOffsetFromSyncBase;
  2458.     }
  2459.     if ((m_bBeginOffsetSet  &&
  2460. (INT32)ulTimeOffset >= m_lBeginOffset)  ||
  2461. (bValidDelay  &&  ulTimeOffset >= ulTimeOffsetFromSyncBase) )
  2462.     {
  2463. // /For PR 67170 fix, caller needs anchor's begin time to tell
  2464. // which of multiple, active onLoad anchors to use after a seek:
  2465. if (m_bBeginOffsetSet  &&
  2466.     (INT32)ulTimeOffset >= m_lBeginOffset)
  2467. {
  2468.     rulAnchorRelativeStartTime = m_lBeginOffset;
  2469. }
  2470. else
  2471. {
  2472.     rulAnchorRelativeStartTime = ulTimeOffsetFromSyncBase;
  2473. }
  2474. LONG32 lAnchorEndTime = -1;
  2475. if (m_bEndOffsetSet)
  2476. {
  2477.     lAnchorEndTime = m_lEndOffset;
  2478. }
  2479. else if ((UINT32)-1 != m_ulDuration)
  2480. {
  2481.     lAnchorEndTime = (INT32)m_ulDuration;
  2482.     if (m_bBeginOffsetSet)
  2483.     {
  2484. lAnchorEndTime += m_lBeginOffset;
  2485.     }
  2486. }
  2487. if(-1 != lAnchorEndTime)
  2488. {
  2489.     if((INT32)ulTimeOffset <= lAnchorEndTime)
  2490.     {
  2491. bIsActiveAtTimeOffset = TRUE;
  2492.     }
  2493. }
  2494. else
  2495. {
  2496.     bIsActiveAtTimeOffset = TRUE;
  2497. }
  2498.     }
  2499. }
  2500. else if(m_bEndOffsetSet)
  2501. {
  2502.     if((INT32)ulTimeOffset <= m_lEndOffset)
  2503.     {
  2504. bIsActiveAtTimeOffset = TRUE;
  2505.     }
  2506. }
  2507.     }
  2508.     return bIsActiveAtTimeOffset;
  2509. }
  2510. void
  2511. CSmilAAnchorElement::rescale(double dXScale, double dYScale,
  2512.      BOOL bResetOriginalCoords)
  2513. {
  2514.     // nothing to do
  2515. }
  2516. /*
  2517.  * CSmilAnchor methods
  2518.  */
  2519. CSmilAnchorElement::CSmilAnchorElement(SMILNode* pNode):
  2520.     CSmilAAnchorElement(pNode),
  2521.     m_zIndex(0),
  2522.     m_bCoordsSet(FALSE),
  2523.     m_ulLeftX(0),
  2524.     m_ulOriginalLeftX(0),
  2525.     m_bLeftXIsPercent(FALSE),
  2526.     m_ulTopY(0),
  2527.     m_ulOriginalTopY(0),
  2528.     m_bTopYIsPercent(FALSE),
  2529.     m_ulRightX((UINT32)-1),
  2530.     m_ulOriginalRightX((UINT32)-1),
  2531.     m_bRightXIsPercent(FALSE),
  2532.     m_ulBottomY((UINT32)-1),
  2533.     m_ulOriginalBottomY((UINT32)-1),
  2534.     m_bBottomYIsPercent(FALSE),
  2535.     m_ulRadius((UINT32)-1),
  2536.     m_ulOriginalRadius((UINT32)-1),
  2537.     m_bRadiusIsPercent(FALSE)
  2538.     , m_pVertexArray(NULL)
  2539.     , m_pOriginalVertexArray(NULL)
  2540.     , m_uiNumPoints(0)
  2541. {
  2542. }
  2543. CSmilAnchorElement::~CSmilAnchorElement()
  2544. {
  2545.     deleteVertexArrays();
  2546. }
  2547. void CSmilAnchorElement::deleteVertexArrays()
  2548. {
  2549.     if (m_pVertexArray)
  2550.     {
  2551. delete [] m_pVertexArray;
  2552. m_pVertexArray = NULL;
  2553.     }
  2554.     if (m_pOriginalVertexArray)
  2555.     {
  2556. delete [] m_pOriginalVertexArray;
  2557. m_pOriginalVertexArray = NULL;
  2558.     }
  2559. }
  2560. void
  2561. CSmilAnchorElement::rescale(double dXScale, double dYScale,
  2562.      BOOL bResetOriginalCoords)
  2563. {
  2564.     if(bResetOriginalCoords)
  2565.     {
  2566. m_ulLeftX = m_ulOriginalLeftX;
  2567. m_ulRightX = m_ulOriginalRightX;
  2568. m_ulTopY = m_ulOriginalTopY;
  2569. m_ulBottomY = m_ulOriginalBottomY;
  2570. m_ulRadius = m_ulOriginalRadius;
  2571. if (m_pVertexArray)// /is poly shape:
  2572. {
  2573.     for (int i=0; i < m_uiNumPoints; i++)
  2574.     {
  2575. m_pVertexArray[i].m_lX = m_pOriginalVertexArray[i].m_lX;
  2576. m_pVertexArray[i].m_lY = m_pOriginalVertexArray[i].m_lY;
  2577.     }
  2578. }
  2579.     }
  2580.     else if (!m_pVertexArray)
  2581.     {
  2582. if(!m_bLeftXIsPercent)
  2583. {
  2584.     m_ulLeftX = (UINT32)(dXScale * (double)m_ulLeftX);
  2585. }
  2586. if(!m_bRightXIsPercent)
  2587. {
  2588.     m_ulRightX = (UINT32)(dXScale * (double)m_ulRightX);
  2589. }
  2590. if(!m_bTopYIsPercent)
  2591. {
  2592.     m_ulTopY = (UINT32)(dYScale * (double)m_ulTopY);
  2593. }
  2594. if(!m_bBottomYIsPercent)
  2595. {
  2596.     m_ulBottomY = (UINT32)(dYScale * (double)m_ulBottomY);
  2597. }
  2598. if(!m_bRadiusIsPercent)
  2599. {
  2600.     // /XXXEH- TODO: don't just average x&y scaling, but
  2601.     // make an elipse by keeping an x-radius and a y-radius val
  2602.     // and then use a formula for an elipse in the hit-test code
  2603.     // in isCurrentLink():
  2604.     m_ulRadius = (UINT32)(((dXScale+dYScale)/2.0) *
  2605.     (double)m_ulRadius);
  2606. }
  2607.     }
  2608.     else // /is "poly" (polygon) shape:
  2609.     {
  2610. for (int i=0; i < m_uiNumPoints; i++)
  2611. {
  2612.     m_pVertexArray[i].m_lX =
  2613.     (LONG32)((double)((float)m_pVertexArray[i].m_lX) * dXScale);
  2614.     m_pVertexArray[i].m_lY =
  2615.     (LONG32)((double)((float)m_pVertexArray[i].m_lY) * dYScale);
  2616. }
  2617.     }
  2618. }
  2619. BOOL
  2620. CSmilAnchorElement::isCurrentLink(UINT32 ulTimeOffset,
  2621.    UINT32 ulXOffset, UINT32 ulYOffset,
  2622.    HXxRect regionRect,
  2623.    BOOL bResizeBehaviorIsZoom,
  2624.    double dZoomX, double dZoomY)
  2625. {
  2626.     BOOL bRetval = TRUE;
  2627.     UINT32 ulRegionWidth = regionRect.right - regionRect.left;
  2628.     UINT32 ulRegionHeight = regionRect.bottom - regionRect.top;
  2629.     if(m_href.GetLength() == 0)
  2630.     {
  2631. return FALSE;
  2632.     }
  2633.     ULONG32 ulBeginRelativeToSyncBase = (UINT32)-1;
  2634.     // first check time offset:
  2635.     if (!isLinkActiveAtTime(ulTimeOffset, ulBeginRelativeToSyncBase))
  2636.     {
  2637. return FALSE;
  2638.     }
  2639.     if(m_bCoordsSet  &&  (!m_shape.GetLength()  ||  m_shape=="rect"))
  2640.     {
  2641. UINT32 ulLeftX = m_ulLeftX;
  2642. UINT32 ulRightX = m_ulRightX;
  2643. UINT32 ulTopY = m_ulTopY;
  2644. UINT32 ulBottomY = m_ulBottomY;
  2645. // /Doing this resizing of absolute (not percent) coordinate values
  2646. // fixes PR 77231; the hotspot should scale along with the media
  2647. // when the player is resized:
  2648. // (NOTE: This only fixes "rect" version of PR 77231):
  2649. if (bResizeBehaviorIsZoom  &&  dZoomX != 1.0  && dZoomY != 1.0)
  2650. {
  2651.     if (!m_bLeftXIsPercent)
  2652.     {
  2653. ulLeftX *= dZoomX;
  2654.     }
  2655.     if (!m_bRightXIsPercent)
  2656.     {
  2657. ulRightX *= dZoomX;
  2658.     }
  2659.     if (!m_bTopYIsPercent)
  2660.     {
  2661. ulTopY *= dZoomX;
  2662.     }
  2663.     if (!m_bBottomYIsPercent)
  2664.     {
  2665. ulBottomY *= dZoomX;
  2666.     }
  2667. }
  2668. // normalize to pixel coords
  2669. if(m_bLeftXIsPercent)
  2670. {
  2671.     ulLeftX = (UINT32)(((double)m_ulLeftX/100.0) * ulRegionWidth);
  2672. }
  2673. if(m_bRightXIsPercent)
  2674. {
  2675.     ulRightX = (UINT32)(((double)m_ulRightX/100.0) * ulRegionWidth);
  2676. }
  2677. if(m_bTopYIsPercent)
  2678. {
  2679.     ulTopY = (UINT32)(((double)m_ulTopY/100.0) * ulRegionHeight);
  2680. }
  2681. if(m_bBottomYIsPercent)
  2682. {
  2683.     ulBottomY = (UINT32)(((double)m_ulBottomY/100.0) * ulRegionHeight);
  2684. }
  2685. if(ulXOffset >= ulLeftX &&
  2686.    ulXOffset <= ulRightX &&
  2687.    ulYOffset >= ulTopY &&
  2688.    ulYOffset <= ulBottomY)
  2689. {
  2690.     return TRUE;
  2691. }
  2692. else
  2693. {
  2694.     if (ANCHOR_POS_DONTCARE != ulXOffset  &&
  2695.     ANCHOR_POS_DONTCARE != ulYOffset)
  2696.     {
  2697. return FALSE;
  2698.     }
  2699.     return TRUE;
  2700. }
  2701.     }
  2702.     else if(m_bCoordsSet  &&  (m_shape=="circle"))
  2703.     {
  2704. UINT32 ulCenterX = m_ulLeftX;
  2705. UINT32 ulCenterY = m_ulTopY;
  2706. UINT32 ulRadius = m_ulRadius;
  2707. // /Doing this resizing of absolute (not percent) coordinate values
  2708. // fixes "circle" version of PR 77231; the hotspot should scale along
  2709. // with the media when the player is resized:
  2710. if (bResizeBehaviorIsZoom  &&  dZoomX != 1.0  && dZoomY != 1.0)
  2711. {
  2712.     if (!m_bLeftXIsPercent)
  2713.     {
  2714. ulCenterX *= dZoomX;
  2715.     }
  2716.     if (!m_bTopYIsPercent)
  2717.     {
  2718. ulCenterY *= dZoomX;
  2719.     }
  2720.     if (!m_bRadiusIsPercent)
  2721.     {
  2722. ulRadius *= dZoomY;
  2723.     }
  2724. }
  2725. // normalize to pixel coords
  2726. if(m_bLeftXIsPercent)
  2727. {
  2728.     ulCenterX = (UINT32)(((double)ulCenterX/100.0) * ulRegionWidth);
  2729. }
  2730. if(m_bTopYIsPercent)
  2731. {
  2732.     ulCenterY = (UINT32)(((double)ulCenterY/100.0) * ulRegionHeight);
  2733. }
  2734. if(m_bRadiusIsPercent)
  2735. {
  2736.     ulRadius = (UINT32)(((double)m_ulRadius/100.0) * ulRegionHeight);
  2737. }
  2738. double dXDistanceToCenter = double( (ulXOffset>ulCenterX)?
  2739. ulXOffset-ulCenterX : ulCenterX-ulXOffset);
  2740. double dYDistanceToCenter = double( (ulYOffset>ulCenterY)?
  2741. ulYOffset-ulCenterY : ulCenterY-ulYOffset);
  2742. // /Compare squared distances rather than doing expensive sqare root:
  2743. double dDistanceToCenterSquared =
  2744. (dXDistanceToCenter*dXDistanceToCenter) +
  2745. (dYDistanceToCenter*dYDistanceToCenter);
  2746. double dRadiusSquared = double(ulRadius*ulRadius);
  2747. // /It's within the circle if it's within the radius:
  2748. if (dDistanceToCenterSquared <= dRadiusSquared)
  2749. {
  2750.     return TRUE;
  2751. }
  2752. else
  2753. {
  2754.     if (ANCHOR_POS_DONTCARE != ulXOffset  &&
  2755.     ANCHOR_POS_DONTCARE != ulYOffset)
  2756.     {
  2757. return FALSE;
  2758.     }
  2759.     return TRUE;
  2760. }
  2761.     }
  2762.     else if (m_bCoordsSet  &&  (m_shape=="poly"))
  2763.     {
  2764. bRetval = isPointInPolygon(ulXOffset, ulYOffset, regionRect,
  2765. bResizeBehaviorIsZoom? dZoomX : 1.0,
  2766. bResizeBehaviorIsZoom? dZoomY : 1.0);
  2767.     }
  2768.     else if(ulXOffset > ulRegionWidth ||
  2769.     ulYOffset > ulRegionHeight)     
  2770.     // assume time OK, coords OK if within bounds of region
  2771.     {
  2772. if (ANCHOR_POS_DONTCARE != ulXOffset  &&
  2773. ANCHOR_POS_DONTCARE != ulYOffset)
  2774. {
  2775.     return FALSE;
  2776. }
  2777.     }
  2778.     return bRetval;
  2779. }
  2780. BOOL
  2781. CSmilAnchorElement::isPointInPolygon(INT32 lXOffset, INT32 lYOffset,
  2782.      HXxRect regionRect,
  2783.      double dZoomX, double dZoomY)
  2784. {
  2785.     INT32 xnew,ynew;
  2786.     INT32 xold,yold;
  2787.     INT32 x1,y1;
  2788.     INT32 x2,y2;
  2789.     BOOL    bIsInside=FALSE;
  2790.     UINT32 ulRegionWidth = regionRect.right - regionRect.left;
  2791.     UINT32 ulRegionHeight = regionRect.bottom - regionRect.top;
  2792.     // We must have at least 3 points to have a polygon
  2793.     if (m_uiNumPoints >= 3)
  2794.     {
  2795.         xold = m_pVertexArray[m_uiNumPoints-1].m_lX;
  2796.         yold = m_pVertexArray[m_uiNumPoints-1].m_lY;
  2797. // /Convert percentages to coords:
  2798. if(m_pVertexArray[m_uiNumPoints-1].m_bXIsPercent)
  2799. {
  2800.     xold = (UINT32)(((double)xold/100.0) * ulRegionWidth);
  2801. }
  2802. // /NOTE: to fix PR 77231 (poly version) it would have been nice to
  2803. // just apply 1/dZoomX and 1/dZoomY to lXOffset and lYOffset but we
  2804. // can't because some vertices could be percentages while others not,
  2805. // so we're stuck multiplying each non-percent value, one at a time:
  2806. else if (dZoomX != 1.0)
  2807. {
  2808.     xold *= dZoomX; // /Helps fix poly version of PR 77231.
  2809. }
  2810. if(m_pVertexArray[m_uiNumPoints-1].m_bYIsPercent)
  2811. {
  2812.     yold = (UINT32)(((double)yold/100.0) * ulRegionHeight);
  2813. }
  2814. else if (dZoomY != 1.0)
  2815. {
  2816.     yold *= dZoomY; // /Helps fix poly version of PR 77231.
  2817. }
  2818.         for (UINT16 i=0; i < m_uiNumPoints; i++)
  2819.         {
  2820.             xnew = m_pVertexArray[i].m_lX;
  2821.             ynew = m_pVertexArray[i].m_lY;
  2822.     // /Convert percentages to coords:
  2823.     if(m_pVertexArray[i].m_bXIsPercent)
  2824.     {
  2825. xnew = (UINT32)(((double)xnew/100.0) * ulRegionWidth);
  2826.     }
  2827.     else if (dZoomX != 1.0)
  2828.     {
  2829. xnew *= dZoomX; // /Helps fix poly version of PR 77231.
  2830.     }
  2831.     if(m_pVertexArray[i].m_bYIsPercent)
  2832.     {
  2833. ynew = (UINT32)(((double)ynew/100.0) * ulRegionHeight);
  2834.     }
  2835.     else if (dZoomY != 1.0)
  2836.     {
  2837. ynew *= dZoomY; // /Helps fix poly version of PR 77231.
  2838.     }
  2839.             if (xnew > xold)
  2840.             {
  2841.                 x1 = xold;
  2842.                 x2 = xnew;
  2843.                 y1 = yold;
  2844.                 y2 = ynew;
  2845.             }
  2846.             else
  2847.             {
  2848.                 x1 = xnew;
  2849.                 x2 = xold;
  2850.                 y1 = ynew;
  2851.                 y2 = yold;
  2852.             }
  2853.             if ((xnew < lXOffset) == (lXOffset <= xold) &&
  2854.                     ((LONG32)lYOffset - (LONG32)y1) * (LONG32)(x2-x1) < 
  2855.                     ((LONG32)y2 - (LONG32)y1) * (LONG32)(lXOffset - x1))
  2856.             {
  2857.                 bIsInside = !bIsInside;
  2858.             }
  2859.             xold = xnew;
  2860.             yold = ynew;
  2861.         }
  2862.     }
  2863.     return bIsInside;
  2864. }
  2865. HX_RESULT
  2866. CSmilAnchorElement::convertRawPolyData(const char* pCoords)
  2867. {
  2868.     HX_RESULT   retval = HXR_OK;
  2869.     const char* pchData = pCoords;
  2870.     UINT16 uiNumValues=0;
  2871.     UINT16 uiLength=0;
  2872.     char* szBuffer=NULL;
  2873.     UINT16 uiX=0;
  2874.     UINT16 uiY=0;
  2875.     if (!pCoords  ||  strlen(pCoords) < 3)
  2876.     {
  2877. retval = HXR_INVALID_PARAMETER;
  2878.     }
  2879.     else
  2880.     {
  2881. UINT16 uiNumCommas = 0;
  2882. // /First, get number of points:
  2883. while (*pchData)
  2884. {
  2885.     if (',' == *pchData)
  2886.     {
  2887. uiNumCommas++;
  2888.     }
  2889.     pchData++;
  2890. };
  2891. // /There *must* be an odd # of commas in order to have x,y pairs:
  2892. if (0 == (uiNumCommas % 2))
  2893. {
  2894.     retval = HXR_INVALID_PARAMETER;
  2895. }
  2896. // /Can't have poly with fewer than 3 pts.  It's not an error, but
  2897. // it's useless so we ignore it:
  2898. else if (uiNumCommas < 5)
  2899. {
  2900.     retval = HXR_OK;
  2901. }
  2902. else
  2903. {
  2904.     deleteVertexArrays();
  2905.     // /Get polygon values: (x1,y1,x2,y2,...xn,yn)
  2906.     m_uiNumPoints = (uiNumCommas+1) / 2;
  2907.     m_pVertexArray = new CSmilAnchorVertex[m_uiNumPoints];
  2908.     m_pOriginalVertexArray = new CSmilAnchorVertex[m_uiNumPoints];
  2909.     if (!m_pVertexArray  ||  !m_pOriginalVertexArray)
  2910.     {
  2911. retval = HXR_OUTOFMEMORY;
  2912.     }
  2913.     else
  2914.     {
  2915. retval = HXR_OK;
  2916. int i = 0;
  2917. char* pCoordCopy = new_string(pCoords);
  2918. char* pTok = strtok(pCoordCopy, ",");
  2919. for(i=0; i<m_uiNumPoints,pTok; ++i)
  2920. {
  2921.     char* pEndPtr = 0;
  2922.     // /First, get x coord:
  2923.     double dVal = strtod(pTok, &pEndPtr);
  2924.     m_pOriginalVertexArray[i].m_lX = m_pVertexArray[i].m_lX =
  2925.     (INT32)((float)dVal);
  2926.     m_pOriginalVertexArray[i].m_bXIsPercent =
  2927.     m_pVertexArray[i].m_bXIsPercent =
  2928.     (*pEndPtr == '%') ? TRUE: FALSE;
  2929.     pTok = strtok(NULL, ",");
  2930.     // /Next, get y coord:
  2931.     dVal = strtod(pTok, &pEndPtr);
  2932.     m_pOriginalVertexArray[i].m_lY = m_pVertexArray[i].m_lY =
  2933.     (INT32)((float)dVal);
  2934.     m_pOriginalVertexArray[i].m_bYIsPercent =
  2935.     m_pVertexArray[i].m_bYIsPercent =
  2936.     (*pEndPtr == '%') ? TRUE: FALSE;
  2937.     pTok = strtok(NULL, ",");
  2938. } // end for(i...
  2939. delete [] pCoordCopy;
  2940.     }
  2941. }
  2942.     }
  2943.     return retval;
  2944. }
  2945. /*
  2946.  * CSmilAddGroup methods
  2947.  */
  2948. CSmilAddGroup::CSmilAddGroup():
  2949.     CSmilElement(NULL),
  2950.     m_nGroup(0),
  2951.     m_pValues(NULL),
  2952.     m_nTotalTracks(0),
  2953.     m_nInitTracks(0),
  2954.     m_ulDuration((UINT32)-1)
  2955. {
  2956. }
  2957. CSmilAddGroup::~CSmilAddGroup()
  2958. {
  2959.     HX_RELEASE(m_pValues);
  2960. }
  2961. HX_RESULT
  2962. CSmilAddGroup::handleElement()
  2963. {
  2964.     HX_RESULT rc = HXR_OK;
  2965.     if(m_pHandler)
  2966.     {
  2967. rc = m_pHandler->handleAddGroup(this);
  2968.     }
  2969.     return rc;
  2970. }
  2971. #if defined(HELIX_FEATURE_SMIL2_TRANSITIONS)
  2972. CSmilTransition::CSmilTransition(SMILNode* pNode) :
  2973.     CSmilElement(pNode)
  2974. {
  2975.     m_dStartProgress = 0.0;
  2976.     m_dEndProgress   = 1.0;
  2977.     m_eDirection     = TransitionDirectionForward;
  2978.     m_ulFadeColor    = 0x00000000; // black
  2979.     m_ulHorzRepeat   = 1;
  2980.     m_ulVertRepeat   = 1;
  2981.     m_ulBorderWidth  = 0;
  2982.     m_ulBorderColor  = 0;
  2983.     m_bBlendBorder   = FALSE;
  2984. }
  2985. CSmilTransition::~CSmilTransition()
  2986. {
  2987. }
  2988. HX_RESULT CSmilTransition::handleElement()
  2989. {
  2990.     HX_RESULT retVal = HXR_OK;
  2991.     if(m_pHandler)
  2992.     {
  2993.         retVal = m_pHandler->handleTransition(this);
  2994.     }
  2995.     return retVal;
  2996. }
  2997. #endif /* #if defined(HELIX_FEATURE_SMIL2_TRANSITIONS) */
  2998. CSmilBodyElement::CSmilBodyElement(SMILNode* pNode) :
  2999.     CSmilElement(pNode)
  3000. {
  3001.     m_eAccessErrorBehavior = AccessErrorBehaviorContinue;
  3002. }
  3003. CSmilBodyElement::~CSmilBodyElement()
  3004. {
  3005. }