smlelem.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:90k
源码类别:

Symbian

开发平台:

Visual C++

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