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

Symbian

开发平台:

C/C++

  1. }
  2. #endif
  3.     HX_ASSERT(HXR_OK == retval);
  4.     // /Helps fix PR 53531: this will prevent
  5.     // this one from being seen as the current
  6.     // "active" sibling if another excl track
  7.     // gets added while this one is paused; it
  8.     // also resets some vars to prolong its
  9.     // existence during pause past its original
  10.     // end time if that end is not explicit:
  11.     if (HXR_OK == retval)
  12.     {
  13. pActiveSibling->m_pElement->
  14. prepForPauseInExcl(
  15. lEffectiveResolvedTime);
  16.     }
  17.     if (pTimelineParentOfActiveSibling  &&
  18.     SMILExcl !=
  19.     pTimelineParentOfActiveSibling->m_tag)
  20.     {
  21. // /Find next timeline sibling:
  22. do
  23. {
  24.     pActiveSibling = findNextSibling(
  25.     pActiveSibling);
  26. } while (pActiveSibling  &&
  27.     // /XXXEH- TODO: handle deeper
  28.     // nesting of timed objects:
  29.     !isMediaObject(pActiveSibling));
  30.     }
  31.     else // /No parent par or seq:
  32.     {
  33. break;
  34.     }
  35. } while (pActiveSibling);
  36.     }
  37.     break;
  38.     case SMILPriorityClassDefer:
  39.     {
  40. // /XXXEH- TODO: determine if there is more
  41. // than one currently-playing track:
  42. // /We need to set the begin time of the
  43. // would-be interrupter to that of the
  44. // currently-playing one(s); if there is
  45. // more than one media track playing (in a
  46. // par) then we want to defer until the
  47. // end of the par:
  48. SMILNode* pDeferUntilAfterThisNode = pActiveSibling;
  49. // /To fix PR 85885 where multiple clips get
  50. // deferred while first sibling plays, we need
  51. // to defer the second-deferred one to after
  52. // its deferred sibling ends, not to after the
  53. // first one ends:
  54. SMILNode* pLastDeferredInSameExcl =
  55. findLastDeferredChildOfAncestorExcl(
  56. pTmpVal->m_pElement->m_pNode, lCurTime);
  57. ULONG32 ulNewStartTime = pDeferUntilAfterThisNode->
  58. m_pElement->m_ulDuration +
  59. pDeferUntilAfterThisNode->m_pElement->m_ulDelay;
  60. // /Fixes PR 69638: active sib's duration can
  61. // include its delay so end is not always
  62. // dur+delay; getCurrent...() handles this:
  63. ULONG32 ulTotalDelay = 0;
  64. if (HXR_OK == pDeferUntilAfterThisNode->m_pElement->
  65. getCurrentScheduledStopTime(ulTotalDelay))
  66. {
  67.     ulNewStartTime = ulTotalDelay;
  68. }
  69. else
  70. {
  71.     HX_ASSERT(0); // /getCurrent...() failed!
  72. }
  73. // /lEffectiveResolvedTime is our current begin
  74. // time, so we need to add the difference;
  75. INT32 lDiff = (INT32)ulNewStartTime -
  76. lEffectiveResolvedTime;
  77. // /For PR 85885, just set defer-to time to indef and
  78. // await endEvent of prior-in-queue deferred element:
  79. if (pLastDeferredInSameExcl)
  80. {
  81.     HX_ASSERT(1); // /debug only.
  82.     pDeferUntilAfterThisNode = pLastDeferredInSameExcl;
  83.     ulNewStartTime = SMILTIME_DEFERRED_INDEFINITELY;
  84.     // /Helps fix PR 85885:
  85.     // /Ceate a new SmilTimeValue watching for
  86.     // "undeferEvent" on prior-in-defer-queue element;
  87.     SmilTimeValue* pNewTimeVal =
  88.     new SmilTimeValue(m_pContext,
  89.     /* start line don't care:*/ 0,
  90.     pTmpVal->m_pElement);
  91.     HX_ASSERT(pNewTimeVal);
  92.     if(pNewTimeVal)
  93.     {
  94. CHXString pStr =
  95. pLastDeferredInSameExcl->m_id;
  96. pStr += ".undeferEvent";
  97. HX_RESULT pnr1 = pNewTimeVal->parseValue(
  98. pStr, SMILSyncAttrBegin,
  99. (const char*)
  100. pTmpVal->m_pElement->m_pNode->m_id);
  101. // /Note: this function gets rid of any
  102. // existing resumeEvent on this element
  103. // since it can only be in the "defer
  104. // stack" once:
  105. BOOL bOldUndeferEventWasRemoved = FALSE;
  106. HX_RESULT rslt = addUndeferEvent(
  107. pNewTimeVal,
  108. bOldUndeferEventWasRemoved);
  109.     }
  110. }
  111. // /If par in excl is deferring, then mark it
  112. // as such so it won't be seen as
  113. // "currently playing" next time:
  114. if (pTimelineParentOfInterruptor  &&
  115. SMILExcl !=
  116. pTimelineParentOfInterruptor->m_tag  &&
  117. pTimelineParentOfInterruptor->m_pElement)
  118. {
  119.     pTimelineParentOfInterruptor->m_pElement->
  120.     prepForDeferralInExcl((UINT32)lCurTime);
  121. }
  122. // /This is needed to fix PR 57120; it's the
  123. // *interruptor* that defers, not the active
  124. // sibling (unlike with pause):
  125. pTmpVal->m_pElement->prepForDeferralInExcl((UINT32)lCurTime);
  126. HX_ASSERT(lDiff >=
  127. FUDGE_FACTOR_WHEN_DEFERRING_PAST_END_OF_GROUP);
  128. if (lDiff >
  129. FUDGE_FACTOR_WHEN_DEFERRING_PAST_END_OF_GROUP)
  130. {
  131.     // /Only handle this by the early fudge
  132.     // factor if needed; if presentation is
  133.     // already long enough, no need to do this:
  134.     UINT32 ulCurGroupDuration = 0;
  135.     pActiveSibling->m_pElement->m_pHandler->
  136. GetCurGroupDuration(ulCurGroupDuration);
  137.     if (ulNewStartTime +
  138.     FUDGE_FACTOR_FOR_DEFERRING_PRIOR_TO_END_OF_GROUP
  139.     >= ulCurGroupDuration  &&
  140.     SMILTIME_DEFERRED_INDEFINITELY !=
  141.     ulNewStartTime  &&
  142.     // /If it's 0, then presentation dur
  143.     // is unresolved (indefinite):
  144.     ulCurGroupDuration !=0)
  145.     {
  146. // /Fixes Interop Timing #25.6:
  147. // Subtract fudge factor so this has a
  148. // chance to begin before player stops:
  149. ulNewStartTime -=
  150. FUDGE_FACTOR_WHEN_DEFERRING_PAST_END_OF_GROUP;
  151.     }
  152.     else if (SMILTIME_DEFERRED_INDEFINITELY !=
  153.     ulNewStartTime)
  154.     {
  155. // /To fix PR 69671, we *add* fudge
  156. // factor so any track that gets paused
  157. // by the active one can resume before
  158. // this deferred (lower) tries to begin:
  159. ulNewStartTime +=
  160. FUDGE_FACTOR_FOR_DEFERRING_PRIOR_TO_END_OF_GROUP;
  161.     }
  162.     if (pTmpVal->deferUntil(
  163.     (INT32)ulNewStartTime))
  164.     {
  165. bTimeValWasDeferred = TRUE;
  166. bAddTrack = FALSE;
  167.     }
  168. }
  169.     }
  170.     break;
  171.     case SMILPriorityClassNever:
  172.     {
  173. ; // /Don't need to do diddly, and we should
  174. // prevent the new track from playing:
  175. bAddTrack = FALSE;
  176. bREFSomeScheduleWasChanged = FALSE;
  177.     }
  178.     break;
  179.     case SMILPriorityClassStop:
  180.     default:
  181.     {
  182. #if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG_EXCL_TRACK_REMOVAL)
  183. {
  184.     FILE* f1 = ::fopen("c:\smil2excl.txt", bFirstExclTrackChangeDebugOut?"w":"a+");
  185.     bFirstExclTrackChangeDebugOut = FALSE;
  186.     ::fprintf(f1, "At %6ld: timeVal's id = %s, pActiveSibling id=%s, "
  187.     "bPrepForRestartNeeded=%lu  n",
  188.     lCurTime, (const char*)pTmpVal->m_pElement->m_pNode->m_id,
  189.     (const char*)pActiveSibling->m_id, (UINT32)bPrepForRestartNeeded);
  190.     ::fclose(f1);
  191. }
  192. #endif
  193. // /Helps fix PR 56053: if par in excl is
  194. // stopping, then mark it as such so it won't
  195. // be seen as "currently playing" next time:
  196. if (pTimelineParentOfActiveSibling  &&
  197. SMILExcl !=
  198. pTimelineParentOfActiveSibling->m_tag  &&
  199. pTimelineParentOfActiveSibling->m_pElement)
  200. {
  201.     pTimelineParentOfActiveSibling->m_pElement->
  202.     prepForStopInExcl(lCurTime);
  203. }
  204. do
  205. {
  206.     retval = pActiveSibling->m_pElement->
  207.     m_pHandler->handleTrackRemoval(
  208.     (const char*)pActiveSibling->m_id,
  209.     (INT32)pActiveSibling->m_nGroup);
  210. #if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG_EXCL_TRACK_REMOVAL)
  211. {
  212.     FILE* f1 = ::fopen("c:\smil2excl.txt", bFirstExclTrackChangeDebugOut?"w":"a+");
  213.     bFirstExclTrackChangeDebugOut = FALSE;
  214.     ::fprintf(f1, "At %6ld: timeVal's id = %s, pActiveSibling id=%s, "
  215.     "handleTrackRemoval() retval=0x%08x  n",
  216.     lCurTime, (const char*)pTmpVal->m_pElement->m_pNode->m_id,
  217.     (const char*)pActiveSibling->m_id, retval);
  218.     ::fclose(f1);
  219. }
  220. #endif
  221.     // /Helps fix PR 56053: if child in excl
  222.     // is stopping, then mark it as such so
  223.     // it won't be seen as "currently
  224.     // playing" next time:
  225.     pActiveSibling->m_pElement->
  226.     prepForStopInExcl(lCurTime);
  227.     // /Needed for where element has a sync
  228.     // arc to this end time and we need to
  229.     // notify it that it has ended early:
  230.     if (HXR_OK == retval)
  231.     {
  232. // /Set this to false so elementResolved
  233. // will allow sync-arcs to resolve on
  234. // our new end:
  235. pTmpVal->m_pElement->m_bCurEndClippedByParent =
  236. FALSE;
  237. m_pTimelineElementManager->notify((const char*) pActiveSibling->m_id);
  238.     }
  239.     if (pTimelineParentOfActiveSibling  &&
  240.     SMILExcl !=
  241.     pTimelineParentOfActiveSibling->m_tag)
  242.     {
  243. // /Find next timeline sibling:
  244. do
  245. {
  246.     pActiveSibling = findNextSibling(
  247.     pActiveSibling);
  248. } while (pActiveSibling  &&
  249.     // /XXXEH- TODO: handle deeper
  250.     // nesting of timed objects:
  251.     !isMediaObject(pActiveSibling));
  252.     }
  253.     else // /No parent par or seq:
  254.     {
  255. break;
  256.     }
  257. } while (pActiveSibling);
  258. bREFSomeScheduleWasChanged = TRUE;
  259.     }
  260.     break;
  261. }
  262.     }
  263. }
  264.     }
  265. #if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG)
  266. {FILE* f1 = ::fopen("c:\smil2.txt", "a+"); ::fprintf(f1, "npTmpVal->m_idRef= %s, bAddTrack= %lun", (const char*)pTmpVal->m_idRef, (UINT32)bAddTrack);  ::fclose(f1);}
  267. #endif
  268.     if (bAddTrack)
  269.     {
  270. // /We should never add a track that was deferred:
  271. HX_ASSERT(!bTimeValWasDeferred);
  272. // /Start the element @ NOW+offset by inserting into the
  273. // timeline (via setDelay()) and adding track (via
  274. // handleNextElement())
  275. // /First, see if there is a resolved end time
  276. // that's after this begin time, that might affect the dur;
  277. // if not, then play until its syncBase ends if
  278. // it is restarting, otherwise just use its originalDur:
  279. SmilTimeValue* pNextResolvedEndTimeValue = NULL;
  280. HX_RESULT rettimeval = HXR_OK;
  281. rettimeval = pTmpVal->m_pElement->getNextResolvedTimeValue(
  282. pNextResolvedEndTimeValue,
  283. // /Use this since we're not sure what group time is:
  284. SMILTIME_NEGATIVE_INFINITY,
  285. lEffectiveResolvedTime,
  286. SmilEndTimeList,
  287. /* Don't need list of resolved times:*/ NULL);
  288. LONG32 lNextResolvedEndTime;
  289. HX_RESULT rtvalx = HXR_FAIL;
  290. if (SUCCEEDED(rettimeval)  &&
  291. NULL != pNextResolvedEndTimeValue)
  292. {
  293.     rtvalx = pNextResolvedEndTimeValue->
  294.     getEffectiveResolvedTime(
  295.     lNextResolvedEndTime);
  296. }
  297. // /Fixes PR 50589: check for toggle behavior if
  298. // begin and end times are the same and pTmpVal has same
  299. // timeValue values as pNextResolvedEndTimeValue, then
  300. // mark pNextResolvedEndTimeValue so it won't be used as an
  301. // end time, and get next-next resolved end
  302. if (HXR_OK == rtvalx  &&
  303. lEffectiveResolvedTime == lNextResolvedEndTime  &&
  304. pNextResolvedEndTimeValue  &&
  305. pTmpVal->isSameTimeValue(pNextResolvedEndTimeValue))
  306. {
  307.     pTimeValEndToggleToBeIgnored =
  308.     pNextResolvedEndTimeValue;
  309.     // /Get next one:
  310.     rettimeval =
  311.     pTmpVal->m_pElement->getNextResolvedTimeValue(
  312.     pNextResolvedEndTimeValue,
  313.     // /Use this since we're not sure what group time is:
  314.     SMILTIME_NEGATIVE_INFINITY,
  315.     lEffectiveResolvedTime + 1, SmilEndTimeList,
  316.     /* Don't need list of resolved times:*/ NULL);
  317. }
  318. BOOL bHasFutureResolvedEnd = FALSE;
  319. // /In case we're restarting, we need to either have an
  320. // explicit dur or a future end that's either in the future
  321. // because it's unresolved or is resolved to a future time:
  322. // If it's playing for the first time, then it has a default
  323. // dur/end in lieu of an explicit one:
  324. BOOL bIsntRestartingOrHasExplicitDurOrFutureEnd =
  325. !bPrepForRestartNeeded;
  326. if (SUCCEEDED(rettimeval)  &&
  327. NULL != pNextResolvedEndTimeValue)
  328. {
  329.     HX_RESULT rtval = pNextResolvedEndTimeValue->
  330.     getEffectiveResolvedTime(
  331.     lNextResolvedEndTime);
  332.     if (SUCCEEDED(rtval))
  333.     {
  334. bHasFutureResolvedEnd = TRUE;
  335. bIsntRestartingOrHasExplicitDurOrFutureEnd = TRUE;
  336.     }
  337. }
  338. ULONG32 ulNewDuration = (bPrepForRestartNeeded?
  339. (UINT32)-1:
  340. pTmpVal->m_pElement->m_ulOriginalDuration);
  341. BOOL bHasExplicitValidDur = FALSE;
  342. // /If has explicitly authored simple dur, use it instead:
  343. if (pTmpVal->m_pElement->m_bHasExplicitDur  &&
  344. (UINT32)-1 != pTmpVal->m_pElement->m_ulAuthoredDur)
  345. {
  346.     bHasExplicitValidDur = TRUE;
  347.     ulNewDuration = pTmpVal->m_pElement->m_ulAuthoredDur;
  348.     bIsntRestartingOrHasExplicitDurOrFutureEnd = TRUE;
  349. }
  350. SMILNode* pSyncNode = NULL;
  351. if (bHasFutureResolvedEnd)
  352. {
  353.     HX_ASSERT(lEffectiveResolvedTime < lNextResolvedEndTime);
  354.     // /We need to use the new end time and ignore the
  355.     // m_ulOriginalDuration:
  356.     if (lEffectiveResolvedTime < lNextResolvedEndTime)
  357.     {
  358. ulNewDuration = (UINT32)(lNextResolvedEndTime -
  359. lEffectiveResolvedTime);
  360.     }
  361. }
  362. // /If not restarting and has no future end time and has no
  363. // explcitly-authored dur, and has an explicit end time that
  364. // is now or in the past, then don't insert this.
  365. // Fixes SMIL 2.0 Interop Timing #18.8 endsync_first_par5_RM:
  366. else if (!bPrepForRestartNeeded  &&  !bHasExplicitValidDur  &&
  367. (pTmpVal->m_pElement->m_bHasExplicitEnd  &&
  368. // /Need to make sure explicit end is in the past:
  369. pTmpVal->m_pElement->m_lEndOffset <= lCurTime)  &&
  370. // /Allow for begin="[some event]" end="indefinite":
  371. !pTmpVal->m_pElement->m_bIndefiniteEnd  &&
  372. // /Adding this check helps fix PR 52006: if there is an
  373. // end value that is not yet resolved, we want to treat
  374. // its end as indefinite which is a valid future end time:
  375. !pTmpVal->m_pElement->hasUnresolvedEndTime())
  376. {
  377.     goto doneWithRestartCode;
  378. }
  379. // /First, see if we need to look for a future unresolved end
  380. // in case we're restarting, have no explicit dur, and have
  381. // an explicit end but none that's in the future.  According
  382. // to "getNextInterval" in the SMIL 2.0 Timing draft, we
  383. // should restart only in this case if there's an event-based
  384. // end:
  385. if (!bIsntRestartingOrHasExplicitDurOrFutureEnd)
  386. {
  387.     if (!pTmpVal->m_pElement->m_bHasExplicitDur  &&
  388.     !pTmpVal->m_pElement->m_bHasExplicitEnd)
  389.     {
  390. bIsntRestartingOrHasExplicitDurOrFutureEnd = TRUE;
  391.     }
  392.     else if (pTmpVal->m_pElement->hasUnresolvedEndTime())
  393.     {
  394. bIsntRestartingOrHasExplicitDurOrFutureEnd = TRUE;
  395.     }
  396. }
  397. // /We shouldn't restart because we're beyond our end time(s)
  398. if (!bIsntRestartingOrHasExplicitDurOrFutureEnd)
  399. {
  400.     // /XXXEH- How do we handle the following at 10s?:
  401.     // <par begin="0s;10s" end="5s" endsync="last">,,,</par>.
  402.     // It has no valid end after 10s, but it does have an
  403.     // endsync and the SMIL 2.0 Timing draft doesn't say if
  404.     // that counts like a dur would have.
  405.     goto doneWithRestartCode;
  406. }
  407. // /This is needed for PR 63650 fix:
  408. ULONG32 ulMaxDuration = (UINT32)-1;
  409. // /This is needed to keep us from extending past our
  410. // sync-base's end, (if there is an explicit end):
  411. pSyncNode = getSyncAncestor(pTmpVal->m_pElement->m_pNode);
  412. ULONG32 ulMaxEndTime = (UINT32)-1;
  413. if (pSyncNode  &&  pSyncNode->m_pElement)
  414. {
  415.     ULONG32 ulSyncBaseDuration = (UINT32)-1;
  416.     ULONG32 ulSyncBaseDelay = 0;
  417.     if ((UINT32)-1 != pSyncNode->m_pElement->m_ulDelay)
  418.     {
  419. ulSyncBaseDelay =
  420. pSyncNode->m_pElement->m_ulDelay;
  421.     }
  422.     if ((UINT32)-1 != pSyncNode->m_pElement->m_ulDuration
  423.     &&  pSyncNode->m_pElement->
  424.     m_pTimelineElement->durationSet())
  425.     {
  426. ulSyncBaseDuration =
  427. pSyncNode->m_pElement->m_ulDuration;
  428.     }
  429.     // /For final PR 62688 fix (par & excl versions):
  430.     BOOL bEndsyncIsAllAndAllAreDone =
  431.     pSyncNode->m_pElement->m_nEndsyncEventSourceTag ==
  432.     SMILEventSourceAll  &&
  433.     pSyncNode->m_pElement->m_pTimelineElement->
  434.     getNumChildren() >=
  435.     pSyncNode->m_pElement->m_pTimelineElement->
  436.     numChildDursAdded()  &&
  437.     // /Helps fix PR 62408 and PR 50660; if endsync="all" and
  438.     // all children have weighed in, we still need to allow
  439.     // children to restart before parent has ended:
  440.     // Note: PR 62688 is still fixed with this change:
  441.     lEffectiveResolvedTime >
  442.     ulSyncBaseDelay+ulSyncBaseDuration;
  443.     // /Calculate the end time constraints, if any,
  444.     // imposed by syncBase:
  445.     // /XXXEH- check delay constraints as well?  I think
  446.     // that's already handled in setDelay:
  447.     if ((UINT32)-1 != ulSyncBaseDuration  &&
  448.     // /All this logic fixes restarting of element
  449.     // when parent does *not* have an explicit dur
  450.     // or end and thus its dur or end can be extended
  451.     // (but wasn't being extended due to maxEndTime
  452.     // begin set here):
  453.     (pSyncNode->m_pElement->m_bHasExplicitDur  ||
  454.     pSyncNode->m_pElement->m_bHasExplicitEnd   ||
  455.     // /Final(?) fix for PR 62688 (par & excl
  456.     // versions): endsync="all" also should constrain
  457.     // if it has fully resolved:
  458.     bEndsyncIsAllAndAllAreDone  ||
  459.     // /Or it has a (resolved) endsync=first:
  460.     (pSyncNode->m_pElement->m_nEndsyncEventSourceTag ==
  461.     SMILEventSourceFirst)  ||
  462.     // /Or it has an (resolved) endsycn=[some ID]:
  463.     (pSyncNode->m_pElement->m_nEndsyncEventSourceTag ==
  464.     SMILEventSourceID) ) )
  465.     {
  466. ulMaxEndTime = ulSyncBaseDelay + ulSyncBaseDuration;
  467. #if 1 /* XXXEH- this works with PR 59584 and PR 62688 but needs more testing: */
  468. if (pSyncNode->m_pElement->
  469. m_bDurationIncludesDelayBeyondSyncbase)
  470. {
  471.     // /Fixes PR 56686 case 1 where click extends parent's
  472.     // set duration:
  473.     ulMaxEndTime -= pSyncNode->m_pElement->
  474.     m_ulBeginOffsetFromSyncBase;
  475. }
  476. #else /* XXXEH- remove this when above code is better tested: */
  477. ulDelayBeyondSyncBase = ulChildDelayBeyondStartOfThis;
  478. // /This fixes case where excl has begin offset and child does too:
  479. // I'm unsure if this works under all conditions, thus the assert:
  480. if (m_pSourceElement->m_bCurBeginIsOffsetFromSyncBase)
  481. {
  482.     if (!m_pSourceElement->m_bDurationIncludesDelayBeyondSyncbase)
  483.     {
  484. ulDelayBeyondSyncBase +=
  485. m_pSourceElement->m_ulBeginOffsetFromSyncBase;
  486. bNeedToSet_DurationIncludesDelayBeyondSyncbase = TRUE;
  487.     }
  488. }
  489. ULONG32 ulActualDurBeyondSyncBase =
  490. ulDuration + ulDelayBeyondSyncBase - ulChildDelayBeyondStartOfThis;
  491. #endif
  492. BOOL isEndsyncIDrestarting = (SMILEventSourceID ==
  493. pSyncNode->m_pElement->m_nEndsyncEventSourceTag  &&
  494. pTmpVal->m_pElement->m_pNode->m_id ==
  495. pSyncNode->m_pElement->m_EndsyncEventSourceID  &&
  496. // /Not really restarting if starting *early*:
  497. SMILTimelineStatusStartScheduledForLater !=
  498. curSMILTimelineStatus);
  499. BOOL isEndsyncFirst = SMILEventSourceFirst ==
  500.         pSyncNode->m_pElement->m_nEndsyncEventSourceTag;
  501. BOOL isEndsyncFirstRestarting = isEndsyncFirst  &&
  502. bPrepForRestartNeeded  &&
  503. // /Make sure this is the first one restarting:
  504. (ulMaxEndTime-
  505. CHECKPENDING_TIME_VS_CURTIME_FUDGE_FACTOR <
  506. lEffectiveResolvedTime);
  507. ULONG32 ulParentHardStop = ulMaxEndTime;
  508. // /If ID or first is restarting at end, we should just
  509. // end without using a fudge factor):
  510. if (!isEndsyncIDrestarting  &&  !isEndsyncFirstRestarting)
  511. {
  512.     ulParentHardStop +=
  513.     CHECKPENDING_TIME_VS_CURTIME_FUDGE_FACTOR;
  514. }
  515. else
  516. {
  517.     // /Must be restarting if parent dur is based on us:
  518.     HX_ASSERT(bPrepForRestartNeeded  &&
  519.     SMILTimelineStatusNeverScheduled !=
  520.     pSyncNode->m_pElement->m_nEndsyncEventSourceTag);
  521. }
  522. // /If endsync is first and restarting of this element
  523. // means its prior play ended and thus a *first*
  524. // child of parent has ended, parent should end *now*:
  525. if ( (ulParentHardStop <= lEffectiveResolvedTime  ||
  526. // /If ID or 1st is restarting, parent is done:
  527. isEndsyncIDrestarting  ||  isEndsyncFirstRestarting)  &&
  528. (isEndsyncFirst  ||
  529. // /Fixes PR 59584(endsyncIDwithRestart ver)
  530. // where ID'd element restarts, thus ending
  531. // itself and its parent in the process:
  532. isEndsyncIDrestarting  ||
  533. // /For final PR 62688 fix: don't start if
  534. // endsync="all" parent has played all kids:
  535. bEndsyncIsAllAndAllAreDone) )
  536. {
  537.     goto doneWithRestartCode;
  538. }
  539.     }
  540.     else if (SMILExcl == pSyncNode->m_tag  &&
  541.     pSyncNode->m_pElement->m_pTimelineElement  &&
  542.     !pSyncNode->m_pElement->m_bHasExplicitDur  &&
  543.     !pSyncNode->m_pElement->m_bHasExplicitEnd  &&
  544.     pSyncNode->m_pElement->m_pTimelineElement->
  545.     numChildDursAdded() == 0                   &&
  546.     // /Resolved *at* time must be <= excl's delay
  547.     // otherwise excl has come and gone:
  548.     (ULONG32)pTmpVal->getWhenTimeWasResolved() >
  549.     ulSyncBaseDelay  &&
  550.     // /Fixes case where scheduled begin time >0 wasn't
  551.     // used until just-in-time & we do want to use it:
  552.     pTmpVal->getTimeType() == SmilTimeEvent  &&
  553.     // /In case 1st child begin="5s" and other child
  554.     // event-begins prior to that, we want it to begin:
  555.     !pSyncNode->m_pElement->m_pTimelineElement->
  556.     hasChildWithScheduledBegin()  &&
  557.     // /However, if it has endsync="all", then it has
  558.     // unresolved (open) duration, not 0; fixes PR 53527:
  559.     pSyncNode->m_pElement->m_nEndsyncEventSourceTag !=
  560.     SMILEventSourceAll)
  561.     {
  562. // /Fixes version of PR 56690 where excl has no explicit
  563. // end or dur and has no children with already-scheduled
  564. // begin time(s); sucn an excl has a 0 duration:
  565. goto doneWithRestartCode;
  566.     }
  567.     if ((UINT32)-1 != ulMaxEndTime)
  568.     {
  569. UINT32 ulNewEndTime =(UINT32)lEffectiveResolvedTime +
  570. ulNewDuration;
  571. if ((UINT32)-1 != ulNewDuration)
  572. {
  573.     if (ulNewEndTime > ulMaxEndTime)
  574.     {
  575. // /Reduce it so it ends when parent does:
  576. // /XXXEH- need to reverse these --v
  577. ulNewDuration -= (ulNewEndTime-ulMaxEndTime);
  578.     }
  579. }
  580. else
  581. {
  582.     // /Fixed this logic once and for all so PR 56690
  583.     // stays fixed & repro for PR 50572 doesn't break
  584.     // on first click:
  585.     // /(Using a temp var instead of actually changing
  586.     // ulNewDuration here fixes PR 62408  and doesn't
  587.     // break PR 56690 nor PR 50572 (and even fixes post-
  588.     // 1st restart bug in PR 50572 repro):
  589.     ULONG32 ulTmpNewDuration = ( (LONG32)ulMaxEndTime >
  590.     lEffectiveResolvedTime) ?
  591.     ulMaxEndTime -
  592.     (ULONG32)lEffectiveResolvedTime : 0;
  593.     // /This is needed for PR 63650 fix:
  594.     ulMaxDuration = ulTmpNewDuration;
  595.     if (0 == ulTmpNewDuration)
  596.     {
  597. // /Fixes version of PR 56690 where parent
  598. // has an explicit end or dur and
  599. // pTmpVal->m_pElement is a time container
  600. // (if it were media, instertTimelineElem...()
  601. // would handle the out-of-bounds begin):
  602. goto doneWithRestartCode;
  603.     }
  604. }
  605.     }
  606. }
  607. #if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG)
  608. {FILE* f1 = ::fopen("c:\smil2.txt", "a+"); ::fprintf(f1, "npTmpVal->m_idRef= %s, ulNewDuration=%lu, lEffectiveResolvedTime=%ld ulMaxEndTime=%lu, bPrepForRestartNeeded=%lu  n", (const char*)pTmpVal->m_idRef, ulNewDuration, lEffectiveResolvedTime, ulMaxEndTime, (UINT32)bPrepForRestartNeeded);  ::fclose(f1);}
  609. #endif
  610. // /Now, add the track in:
  611. HX_ASSERT(pTmpVal->m_pElement->m_pTimelineElement);
  612. pTmpVal->m_pElement->m_pTimelineElement->
  613. setDelayEventResolved(TRUE);
  614. if (bPrepForRestartNeeded)
  615. {
  616.     // /FALSE means restart is not due to parent restart:
  617.     pTmpVal->m_pElement->prepForRestart(FALSE,
  618.     lEffectiveResolvedTime);
  619. }
  620. if (ulMaxDuration == (UINT32)-1)
  621. {
  622.     // /Makes sure <excl end="30s"><ref end="40s"/></excl>
  623.     // only plays for 30s (along with fix for PR 63650):
  624.     ulMaxDuration = ulNewDuration;
  625. }
  626. // /If we're restarting, we need to reset the duration
  627. if (bPrepForRestartNeeded)
  628. {
  629.     // /XXXEH- need to account for min/max constraints here:
  630.     // /If we're restarting and we're not being constrained
  631.     // by our time container and we don't have an explicitly-
  632.     // set duration, then we need to reset these and play
  633.     // indefinitely:
  634.     if ((UINT32)-1 == ulNewDuration)
  635.     {
  636. #if defined(XXXEH_20010620_OLD_SMIL2_DRAFT_SEMANTICS_FOR_RESTART_DUR_CALCULATION)
  637. HX_ASSERT(0  &&  "ehodge note to self: check spec on restart dur.");
  638. pTmpVal->m_pElement->m_ulOriginalDuration =
  639. pTmpVal->m_pElement->m_ulMaxDuration = (UINT32)-1;
  640. /* XXXEH- need to reset this to FALSE via new method:
  641. pTmpVal->m_pElement->m_pTimelineElement->
  642. m_bMaxDurationSet = FALSE;
  643. */
  644. // /This should be *unresolved*, not  *intrinsic dur
  645. // of media*, if this has no resolved end time after
  646. // lEffectiveResolvedTime and is being restarted but
  647. // *does* have an event-based end time.  (See
  648. // "// if all ends are before the begin, bad interval"
  649. // in SMIL 2.0 Timing Spec):
  650. // /We need to do this otherwise it will only play
  651. // for the media's intrinsic duration:
  652. ulNewDuration = WAY_IN_THE_FUTURE;
  653. #endif
  654.     }
  655.     // /XXXEH- need to account for min/max constraints here:
  656.     pTmpVal->m_pElement->m_pTimelineElement->resetDuration(
  657.     ulNewDuration);
  658.     // /Fixes restarting an element whose parent has a set
  659.     // dur; prior to this, it would override the parent dur:
  660.     pTmpVal->m_pElement->m_pTimelineElement->setMaxDuration(
  661.     ulMaxDuration);
  662. }
  663. // /we just want to set the max duration to avoid affecting
  664. // our parent's end time:
  665. else
  666. {
  667.     pTmpVal->m_pElement->m_pTimelineElement->setMaxDuration(
  668.     // /Using this instead of ulNewDuration fixes
  669.     // PR 63650 (which broke when fix for PR 62408,
  670.     // above, was put in):
  671.     ulMaxDuration);
  672. }
  673. // /While fixing PR 55253, a par that restarts was imposing
  674. // old duration on its children when setDelay() was called
  675. // before resetDuration(), above, so that's why setDelay()
  676. // is now being called later, here:
  677. pTmpVal->m_pElement->m_pTimelineElement->setDelay(
  678. lEffectiveResolvedTime, FALSE);
  679. bREFSomeScheduleWasChanged = TRUE;
  680. // /iF there are two children that start at time 0, and the
  681. // first should play but pause immediately while the second
  682. // plays, then we must add the first before playback and then
  683. // let the second interrupt the first during blackback:
  684. if (bDoHandleExclBeforePlaybackStarts  &&  bIsInExcl)
  685. {
  686.     HX_ASSERT(!((*pExclChildAddedBeforePlayback)[(const char*)
  687.     pExclAncestor->m_id]));
  688.     if (pExclChildAddedBeforePlayback  &&  pExclAncestor)
  689.     {
  690. (*pExclChildAddedBeforePlayback)[(const char*)
  691. pExclAncestor->m_id] = (void*)TRUE;
  692.     }
  693. }
  694.     } // /End if(bAddTrack).
  695. doneWithRestartCode:
  696.     // /We need to be sure to remove a time that is in the past (or
  697.     // is otherwise used herein) from the pendingList; this also
  698.     // advances the lPos to the next one:
  699.     // /But wait, there's more!:  We don't want to remove a time if
  700.     // we just updated its time to later due to a priorityClass
  701.     // deferral (via peers or higher="defer"):
  702.     if (!bTimeValWasDeferred)
  703.     {
  704. HX_ASSERT(m_pPendingBeginTimeList->GetCount());
  705. // /Checking the count before deleting fixes a random crash
  706. // in "BUG-20010611_firstExclChild...".  I can't figure out
  707. // where else it might have been deleted during lPos's life:
  708. if (m_pPendingBeginTimeList->GetCount())
  709. {
  710.     m_pPendingBeginTimeList->RemoveAt(lPosOfCurTmpVal);
  711. }
  712. // /Post-PR 85885-fix cleanup fix: need to remove undeferEvent
  713. // from pTmpVal->m_pElement's m_pBeginTimeList if resume just
  714. // happened, otherwise a subsequent play-to-end of the media
  715. // that pTmpVal's element originally deferred past would result
  716. // in that element erroneously playing again:
  717. if (pTmpVal->isUndeferEvent())
  718. {
  719.     HX_ASSERT(pTmpVal->m_pElement->m_pBeginTimeList);
  720.     if (pTmpVal->m_pElement->m_pBeginTimeList)
  721.     {
  722. CHXSimpleList* pBeginList =
  723. pTmpVal->m_pElement->m_pBeginTimeList;
  724. // /First, remove any resume events in the list:
  725. lPos = pBeginList->GetHeadPosition();
  726. while (lPos)
  727. {
  728.     LISTPOSITION lPosOfCurTmpVal = lPos;
  729.     // /Gets val @ lPos then moves it to next node:
  730.     SmilTimeValue* pCurListValue =
  731.     (SmilTimeValue*)pBeginList->GetNext(lPos);
  732.     if (!pCurListValue  ||  !pCurListValue->m_pElement)
  733.     {
  734. HX_ASSERT(pCurListValue  &&
  735. pCurListValue->m_pElement);
  736. continue;
  737.     }
  738.     if (pCurListValue->isUndeferEvent())
  739.     {
  740. HX_ASSERT(pTmpVal == pCurListValue);
  741. // /Get rid of it from the list:
  742. pBeginList->RemoveAt(lPosOfCurTmpVal);
  743. break; // /Done; only 1 defer can be in list.
  744.     }
  745. }
  746.     }
  747. }
  748.     }
  749. }
  750. else // / i.e., !(lEffectiveResolvedTime <= lCurTime)
  751. {
  752.     // /Since the list is sorted by time, we know we're done handling
  753.     // times that are resolved to lCurTime or earlier:
  754.     // /XXXEH- revisit this (and make sure the @%$#@! list is
  755.     // temporally sorted; as of 20010307, if you have
  756.     // <ref1 begin="ref2.beginEvent"/> and <ref2 begin="0s;7s"/>,
  757.     // the following break will happen before the event-arc time
  758.     // gets seen because ref2's begin of 7s is ahead in the list:
  759. #if defined(XXXEH_NEED_TEMPORAL_SORTING_FOR_THIS_OPTIMIZATION)
  760.     break;
  761. #endif /* XXXEH_NEED_TEMPORAL_SORTING_FOR_THIS_OPTIMIZATION. */
  762. }
  763.     } // /End while (lPos...)  [end handling pending begin times].
  764.     // /Go through m_pPendingEndTimeList now:
  765.     lPos = NULL;
  766.     if (m_pPendingEndTimeList)
  767.     {
  768. lPos = m_pPendingEndTimeList->GetHeadPosition();
  769.     }
  770.     if (bDoHandleExclBeforePlaybackStarts)
  771.     {
  772. goto cleanup;
  773.     }
  774.     while (lPos  &&  HXR_OK == retval)
  775.     {
  776. LISTPOSITION lPosOfCurTmpVal = lPos;
  777. // /Gets val at lPos and then moves lPos to next node in list:
  778. SmilTimeValue* pTmpVal =
  779. (SmilTimeValue*)m_pPendingEndTimeList->GetNext(lPos);
  780. if (!pTmpVal  ||  !pTmpVal->m_pElement)
  781. {
  782.     // /List shouldn't have an empty node or a node w/NULL element:
  783.     HX_ASSERT(pTmpVal  &&  pTmpVal->m_pElement);
  784.     // /Get rid of it from the list:
  785.     m_pPendingEndTimeList->RemoveAt(lPosOfCurTmpVal);
  786.     continue;
  787. }
  788. LONG32 lEffectiveResolvedTime = 0;
  789. HX_RESULT tmprslt =
  790. pTmpVal->getEffectiveResolvedTime(lEffectiveResolvedTime);
  791. if (HXR_OK!=tmprslt)
  792. {
  793.     // /No element should ever have been inserted in this list if it
  794.     // didn't have a resolved time so we shouldn't get here!
  795.     HX_ASSERT(HXR_OK==tmprslt);
  796.     // /Get rid of it from the list:
  797.     m_pPendingEndTimeList->RemoveAt(lPosOfCurTmpVal);
  798.     continue;
  799. }
  800. if (pTimeValEndToggleToBeIgnored  &&
  801. pTmpVal->isSameTimeValue(pTimeValEndToggleToBeIgnored))
  802. {
  803.     // /Ignore it since it was used, above, to begin the element and
  804.     // shouldn't also be used to end it:
  805.     m_pPendingEndTimeList->RemoveAt(lPosOfCurTmpVal);
  806.     continue;
  807. }
  808. ULONG32 ulActualStartTime = 0;
  809. ULONG32 ulActualStopTime = 0;
  810. HX_RESULT pnrStart =
  811. pTmpVal->m_pElement->getCurrentScheduledStartTime(
  812. ulActualStartTime);
  813. LONG32 lElementCurBeginTime = (LONG32)ulActualStartTime;
  814. HX_RESULT pnrStop =
  815. pTmpVal->m_pElement->getCurrentScheduledStopTime(
  816. ulActualStopTime);
  817. LONG32 lElementCurEndTime = (LONG32)ulActualStopTime;
  818. BOOL bCurElementIsTimeContainer =
  819. isTimeContainerObject(pTmpVal->m_pElement->m_pNode);
  820. // /NOTE:we need to recalculate all these here, even though they were
  821. // calculated above for begin-time-list handling, because that begin-
  822. // time-handling code may have altered some of the values used here:
  823. SMILTimelineStatus curSMILTimelineStatus = SMILTimelineStatusUnknown;
  824. if (!pTmpVal->m_pElement->m_bInsertedIntoTimeline)
  825. {
  826.     curSMILTimelineStatus = SMILTimelineStatusNeverScheduled;
  827. }
  828. else
  829. {
  830.     HX_ASSERT(HXR_OK == pnrStart  &&
  831.     (UINT32)-1 != lElementCurBeginTime  &&
  832.     SMILTIME_INFINITY != lElementCurBeginTime);
  833.     if (lElementCurBeginTime > lCurTime)
  834.     {
  835. curSMILTimelineStatus =
  836. SMILTimelineStatusStartScheduledForLater;
  837.     }
  838.     else
  839.     {
  840. if (lElementCurEndTime==(-1)  ||
  841. lElementCurEndTime > lCurTime)
  842. {
  843.     curSMILTimelineStatus =
  844.     SMILTimelineStatusCurrentlyPlaying;
  845. }
  846. else
  847. {
  848.     curSMILTimelineStatus =
  849.     SMILTimelineStatusFinishedPlaying;
  850. }
  851.     }
  852. }
  853. // /We should be in one of these four states; anything else means
  854. // there's an inconsistency somewhere:
  855. HX_ASSERT (SMILTimelineStatusUnknown != curSMILTimelineStatus);
  856. INT32 lResolvedToTimeWithoutOffset =
  857. pTmpVal->getResolvedToTimeWithoutOffset();
  858. INT32 lEventTimeOffset = pTmpVal->getTimeOffset();
  859. INT32 lTimeWithFullOffset =
  860. lResolvedToTimeWithoutOffset + lEventTimeOffset;
  861. // /Now, see if this pending end time is ready to be used:
  862. if (lEffectiveResolvedTime <= lCurTime)
  863. {
  864.     // /Unless this element is currently playing, we don't need to
  865.     // do anything until a valid begin time gets resolved:
  866.     if (SMILTimelineStatusCurrentlyPlaying == curSMILTimelineStatus)
  867.     {
  868. if (!pTmpVal->m_pElement->m_pTimelineElement)
  869. {
  870.     retval = HXR_UNEXPECTED;
  871.     HX_ASSERT(pTmpVal->m_pElement->m_pTimelineElement);
  872.     goto cleanup;
  873. }
  874. else
  875. {
  876.     // /Just call RemoveTrack() at the time we want it gone,
  877.     // and this function we're in has waited for any positive
  878.     // offset to an event before trying to remove the track,
  879.     // so we've managed the scheduling part so, unlike with
  880.     // AddTrack(), the core hasn't had to:
  881.     if (NULL != pTmpVal->m_pElement->m_pHandler  ||
  882.     bCurElementIsTimeContainer)
  883.     {
  884. // /See if pID is a time container; if so, call
  885. // handleTrackRemoval() on all its descendant media:
  886. if (bCurElementIsTimeContainer)
  887. {
  888.     retval = HXR_OK;
  889.     SMILNode* pChild = pTmpVal->m_pElement->
  890.     m_pNode->getFirstChild();
  891.     while (pChild)
  892.     {
  893. CSmilElement* pElement = pChild->m_pElement;
  894. if (pElement  &&  pElement->m_pHandler  &&
  895. pElement->m_bInsertedIntoTimeline)
  896. {
  897.     HX_RESULT retval2 = pElement->m_pHandler->
  898.     handleTrackRemoval((const char*)
  899.     pElement->m_pNode->m_id,
  900.     (INT32)pElement->m_pNode->m_nGroup);
  901.     if (HXR_OK == retval2)
  902.     {
  903. // /The duration changed due to an
  904. // event, not due to clipping by
  905. // our sync-parent.  Set this to
  906. // false so elementResolved() will
  907. // allow sync-arcs to resolve on
  908. // our new end:
  909. pElement->m_bCurEndClippedByParent =
  910. FALSE;
  911. // /Fixes case where element has
  912. // sync arc to this end time and
  913. // we need to notify it that
  914. // we've ended early:
  915. m_pTimelineElementManager->notify((const char*) pElement->m_pNode->m_id);
  916.     }
  917. }
  918. pChild = pTmpVal->m_pElement->m_pNode->
  919. getNextChild();
  920.     }
  921. }
  922. else
  923. {
  924.     retval = pTmpVal->m_pElement->m_pHandler->
  925.     handleTrackRemoval(
  926.     (const char*)pTmpVal->
  927.     m_pElement->m_pNode->m_id,
  928.     (INT32)pTmpVal->
  929.     m_pElement->m_pNode->m_nGroup);
  930. }
  931. // /Fixes case where element has a sync arc to this
  932. // end time and we need to notify it that we've
  933. // ended early:
  934. if (HXR_OK == retval)
  935. {
  936.     // /The duration changed due to an event, not due
  937.     // to clipping by our sync-parent.  Set this to
  938.     // false so elementResolved() will allow
  939.     // sync-arcs to resolve on our new end:
  940.     pTmpVal->m_pElement->m_bCurEndClippedByParent =
  941.     FALSE;
  942.     // /Fixes PR 50676 part 5: we need to notify our
  943.     // parent that the duration has changed since our
  944.     // end may determine our parent's end (e.g.,
  945.     // parent endsync="[our ID]" or endsync="first"):
  946.     pTmpVal->m_pElement->m_pTimelineElement->resetDuration(
  947.     pTmpVal->m_pElement->m_ulDuration);
  948.     m_pTimelineElementManager->notify((const char*) pTmpVal->m_pElement->m_pNode->m_id);
  949. }
  950. bREFSomeScheduleWasChanged = TRUE;
  951.     }
  952.     else
  953.     {
  954.                         // XXXMEH - removed since we sometimes get multiple
  955.                         // char events, before the events have even been
  956.                         // processed.
  957. // HX_ASSERT(pTmpVal->m_pElement->m_pHandler);
  958. retval = HXR_UNEXPECTED;
  959. goto cleanup;
  960.     }
  961. }
  962.     }
  963.     // /We need to be sure to remove a time that we use from the
  964.     // pendingList; this also advances the lPos to the next one:
  965.     m_pPendingEndTimeList->RemoveAt(lPosOfCurTmpVal);
  966. }
  967. else // /effective resolved time is in the future:
  968. {
  969.     // /Note: if no earlier begin time has yet been resolved then
  970.     // there's no reason to set the end time, even if it is
  971.     // resolved:
  972.     if (SMILTimelineStatusStartScheduledForLater ==
  973.     curSMILTimelineStatus  &&
  974.     lElementCurEndTime > lEffectiveResolvedTime )
  975.     {
  976. // /If element is scheduled to play later and this new
  977. // end time is prior to that, then we should just ignore
  978. // this end time for now.  Note: if this end time is in
  979. // the future but still earlier than any resolved begin,
  980. // we still may need this end time if another begin
  981. // gets resolved to a time that is prior to this end time:
  982. if (lEffectiveResolvedTime > // /XXXEH- TODO: ">=" instead?!?
  983. lElementCurBeginTime)
  984. {
  985.     // /OK, so this new end time is later than the currently-
  986.     // scheduled begin time and is earlier than the currently-
  987.     // scheduled end time (if any), so let's use it as the
  988.     // end time of the next "interval":
  989.     retval = pTmpVal->m_pElement->setEndTime(this);
  990.     bREFSomeScheduleWasChanged = TRUE;
  991.     // /XXXEH- do we want to call resetDuration()?!?
  992.     // ASSERT for debugging purposes:
  993.     HX_ASSERT(0);
  994.     // /XXXEH- use m_ulDelay+m_ulDuration in
  995.     // comparisons below if m_bEndOffsetSet is false?!?:
  996.     // otherwise, use that sum PLUS m_lEndOffset?????
  997.     // /Recalculate cur end time now that it's been
  998.     // set, above:
  999.     lElementCurEndTime =
  1000.     // /XXXEH-??:
  1001.     // (pTmpVal->m_pElement->m_bEndOffsetSet?
  1002.     // pTmpVal->m_pElement->m_lEndOffset:0) +
  1003.     pTmpVal->m_pElement->m_ulDelay +
  1004.     pTmpVal->m_pElement->m_ulDuration;
  1005.     // /XXXEH- TODO: is this all and/or what we want to do?:
  1006.     pTmpVal->m_pElement->m_pTimelineElement->resetDuration(
  1007.     lElementCurEndTime -
  1008.     lElementCurBeginTime);
  1009. }
  1010.     }
  1011.     // /Since the list is sorted by time, we know we're done handling
  1012.     // times that are resolved to lCurTime or earlier:
  1013.     break;
  1014. } // /End "else // /effective resolved time is in the future".
  1015.     } // /End handling pending end times.
  1016. #if 0 // /XXXEH- TODO: enable this code and test it!!
  1017.     if (bREFSomeScheduleWasChanged)
  1018.     {
  1019. // /XXXEH- TODO: prevent circular references from causing
  1020. // this to spin out of control, e.g.,
  1021. //   <ref id="ref1" begin="0s; ref2.begin" />
  1022. //   <ref id="ref2" begin="ref1.begin" />
  1023. // /Now, call this function in case some dependent
  1024. // element's timing became resolved to now due to the update
  1025. // to pTmpVal->m_pElement's timing, above:
  1026. BOOL bSomeDependentElementScheduleChanged = FALSE;
  1027. HX_RESULT pnr = HXR_OK;
  1028. do
  1029. {
  1030.     pnr = checkPendingBeginAndEndTimes(lCurTime, iCurrentGroupIndex,
  1031.     bSomeDependentElementScheduleChanged,
  1032.     ++lRecursionCount,
  1033.     pPauseDisplayHideElementList,
  1034.     pPauseDisplayDisableElementList, FALSE);
  1035. }while (lRecursionCount<MAX_PENDING_CHECK_CALLDEPTH  &&
  1036.     HXR_OK==pnr  &&  bSomeDependentElementScheduleChanged);
  1037.     }
  1038. #endif
  1039. cleanup:
  1040.     HX_DELETE(pExclChildAddedBeforePlayback);
  1041.     return retval;
  1042. }
  1043. /* This looks to see if any stream events in the list have a begin time
  1044.  * that is now at or earlier than lCurTime.  If any such are found, then
  1045.  * the associated URL is hurled.
  1046.  */
  1047. CHXMapStringToOb*
  1048. CSmilParser::findNextPendingOnLoadURL(UINT32 ulCurTime)
  1049. {
  1050.     // /Look through the list of "onLoad" URLs and fire off any whose time
  1051.     // has been exceeded:
  1052.     // /Handle begin times that are ready to go:
  1053.     LISTPOSITION lPos = NULL;
  1054.     if (m_pOnLoadURLList)
  1055.     {
  1056. lPos = m_pOnLoadURLList->GetHeadPosition();
  1057.     }
  1058.     // /Helps Fix PR 67170: this now handles removing all but the last of
  1059.     // simultaneous hurls to the same rn:sendTo+target, so a long seek back
  1060.     // or a long seek forward will skip all but the last of each rn-sendTo
  1061.     // link whose time is less than the seeked-to time.  Otherwise we'd be
  1062.     // simultaneously hurling possibly many links that would be immediately
  1063.     // replaced.  The end result is a better user experience, but will not
  1064.     // necessarily leave the sendTo app in the state it would have been had
  1065.     // normal (seek-less) playback arrived at that time in the presentation
  1066.     // (especially if a "back" button exists in the app).
  1067.     // /Keep a map of rn:sendTo+target names, each entry containing the most
  1068.     // temporally-recent-but-not-exceeding-ulCurTime one, and a matching map
  1069.     // for their start times, calculated below:
  1070.     CHXMapStringToOb* pSendToTargetMapOfAnchorsToBeHurledNow = NULL;
  1071.     CHXMapStringToOb* pMapStartTimeToSendToPlusTarget = NULL;
  1072.     // /Go through and see if anybody has a begin time that's ready to become
  1073.     // their active begin time:
  1074.     while (lPos)
  1075.     {
  1076. LISTPOSITION lPosOfCurAnchor = lPos;
  1077. // /Gets val at lPos and then moves lPos to next node in list:
  1078. CSmilAAnchorElement* pCurAnchor =
  1079. (CSmilAAnchorElement*)m_pOnLoadURLList->GetNext(lPos);
  1080. if (!pCurAnchor)
  1081. {
  1082.     // /List shouldn't have an empty node:
  1083.     HX_ASSERT(pCurAnchor);
  1084.     // /Get rid of it from the list:
  1085.     m_pOnLoadURLList->RemoveAt(lPosOfCurAnchor);
  1086.     continue;
  1087. }
  1088. BOOL bLaunchHyperlink = FALSE;
  1089. // /First, we need to get ulCurTime into local, sync-base time
  1090. // coordinates because isLinkActiveAtTime() expects a time relative
  1091. // to the anchor's sync-base, not to the start of the group:
  1092. ULONG32 ulCurSyncBaseTime = ulCurTime;
  1093. SMILNode* pSyncAncestor = getSyncAncestor(
  1094. pCurAnchor->m_pNode);
  1095. if (pSyncAncestor  &&  pSyncAncestor->m_pElement  &&
  1096. (UINT32)-1 != pSyncAncestor->m_pElement->m_ulDelay)
  1097. {
  1098.     if (ulCurTime < pSyncAncestor->m_pElement->m_ulDelay)
  1099.     {
  1100. continue; // /Parent not even active yet.
  1101.     }
  1102.     else
  1103.     {
  1104. ulCurSyncBaseTime =
  1105. ulCurTime - pSyncAncestor->m_pElement->m_ulDelay;
  1106.     }
  1107. }
  1108. else
  1109. {
  1110.     continue;  // /Has no sync-base or has an unresolved one.
  1111. }
  1112. ULONG32 ulAnchorBeginOffset = 0;
  1113. ULONG32 ulAnchorStartTime = 0;
  1114. ULONG32 ulBeginRelativeToSyncBase = (UINT32)-1;
  1115. // /If delay isn't set, then fall through to else, below, which
  1116. // calculates the anchor's delay based on its sync-base time (which
  1117. // is its sync-parent's begin time unless its sync-parent is a seq,
  1118. // in which case the sync-base time is the end of the prev timeline
  1119. // element child in the seq):
  1120. if ((UINT32)-1 != pCurAnchor->m_ulDelay  &&
  1121. pCurAnchor->m_bTimeValueSet)
  1122. {
  1123.             // /Moving this out of the above if() and inside this block fixes
  1124.             // PR 99597; before, if isLinkActiveAtTime() returned FALSE, even
  1125.             // though there was explicit timing on the linke, the else, below,
  1126.             // would get executed, often setting bLaunchHyperlink to TRUE when
  1127.             // it should have just been left FALSE:
  1128.             if (pCurAnchor->isLinkActiveAtTime(ulCurSyncBaseTime,
  1129.                     ulBeginRelativeToSyncBase))
  1130.             {
  1131.                 ulAnchorStartTime = ulBeginRelativeToSyncBase +
  1132.         // /Get it into group time, not local time:
  1133.         (ulCurTime - ulCurSyncBaseTime);
  1134.         bLaunchHyperlink = TRUE;
  1135.             }
  1136.             // /else link no longer or not yet active, so ignore it.
  1137. }
  1138. // /no explicit timing was set on the anchor, so see if it's
  1139. // got a delay set &/or a begin offset set; if not, use its sync-
  1140. // parent's begin (or use end of its prev seq sibling if in a seq):
  1141. else
  1142. {
  1143.     ulAnchorStartTime = pCurAnchor->m_ulDelay;
  1144.     if ((UINT32)-1 == ulAnchorStartTime)
  1145.     {
  1146. if (pCurAnchor->m_bAnchorBeginOffsetSet)
  1147. {
  1148.     ulAnchorBeginOffset = pCurAnchor->m_lAnchorBeginOffset;
  1149. }
  1150. else if (pCurAnchor->m_bBeginOffsetSet)
  1151. {
  1152.     ulAnchorBeginOffset = (UINT32)pCurAnchor->m_lBeginOffset;
  1153.     if (pCurAnchor->m_lBeginOffset < 0)
  1154.     {
  1155. ulAnchorBeginOffset = 0;
  1156.     }
  1157. }
  1158. // /Be sure to add on parent's delay, if any:
  1159. if (pCurAnchor->m_pNode  &&
  1160. pCurAnchor->m_pNode->m_pParent  &&
  1161. pCurAnchor->m_pNode->m_pParent->m_pElement)
  1162. {
  1163.     SMILNode* pSyncAncestor =
  1164.     getSyncAncestor(pCurAnchor->m_pNode);
  1165.     if (pSyncAncestor  &&
  1166.     SMILSeq == pSyncAncestor->m_tag)
  1167.     {
  1168. CSmilElement* pSyncBaseElement =
  1169. pSyncAncestor->m_pElement;
  1170. // /Fixes PR 53363: syncBase of seq child is
  1171. // end of prior sibling, not parent's begin:
  1172. SMILNode* pPriorSibling =
  1173. getPrevNode(pCurAnchor->m_pNode);
  1174. if (!pPriorSibling)
  1175. {
  1176.     // /No prev sibling so sync base is seq parent:
  1177.     pSyncBaseElement = pSyncAncestor->m_pElement;
  1178. }
  1179. else if (pPriorSibling->m_pElement  &&  (UINT32)-1 !=
  1180. pPriorSibling->m_pElement->m_ulDelay  &&
  1181. (UINT32)-1 !=
  1182. pPriorSibling->m_pElement->m_ulDuration)
  1183. {
  1184.     pSyncBaseElement = pPriorSibling->m_pElement;
  1185. }
  1186. // /Prior sibling should not be a timeline object
  1187. // otherwise its end should be known:
  1188. else if (!isTimelineObject(pPriorSibling))
  1189. {
  1190.     SMILNode* pPriorSiblingFirstChild =
  1191.     pPriorSibling->getFirstChild();
  1192.     if (!pPriorSiblingFirstChild)
  1193.     {
  1194. // /XXXEH- TODO: get prior-prior sibling and
  1195. // try again:
  1196. continue;
  1197.     }
  1198.     pSyncBaseElement =
  1199.     pPriorSiblingFirstChild->m_pElement;
  1200.     BOOL bPriorSibIsTimelineObject =
  1201.     isTimelineObject(pPriorSiblingFirstChild);
  1202.     HX_ASSERT(bPriorSibIsTimelineObject);
  1203. }
  1204. // /Skip this link because prior timeline object does
  1205. // not yet have a resolved end time (which it should):
  1206. else
  1207. {
  1208.     HX_ASSERT(0);
  1209.     continue;
  1210. }
  1211. if (pSyncBaseElement)
  1212. {
  1213.     HX_RESULT pnrStart = HXR_OK;
  1214.     // /Fixes PR 58429: if syncBaseElement is actually
  1215.     // the parent seq, then use its begin time, not
  1216.     // its end time, as the sync base:
  1217.     if (pSyncBaseElement == pSyncAncestor->m_pElement)
  1218.     {
  1219. pnrStart = pSyncBaseElement->
  1220. getCurrentScheduledStartTime(
  1221. ulAnchorStartTime);
  1222.     }
  1223.     else // /Use end of prior seq sibling as sync base:
  1224.     {
  1225. pnrStart = pSyncBaseElement->
  1226. getCurrentScheduledStopTime(
  1227. ulAnchorStartTime);
  1228.     }
  1229.     // /Now, add begin offset, if any, to
  1230.     // sync base's end time (but not if end time
  1231.     // is not valid or is indefinite):
  1232.     if (HXR_OK == pnrStart  &&
  1233.     ulAnchorStartTime < WAY_IN_THE_FUTURE)
  1234.     {
  1235. ulAnchorStartTime += ulAnchorBeginOffset
  1236. // /Add fudge factor in case
  1237. // syncBaseElement ends when parent
  1238. // does, in which case we don't want
  1239. // to hurl because we're past the end:
  1240. +100;
  1241.     }
  1242. }
  1243.     }
  1244.     else if (pSyncAncestor  &&  pSyncAncestor->m_pElement)
  1245.     {
  1246. #if XXXEH_HOLD_UNTIL_I_FIX_BUG_WHEN_PAR_OR_EXCL_PARENT_HAS_DELAY
  1247. ulAnchorStartTime = (UINT32)-1; // /Start unresolved...
  1248. if ((UINT32)-1 != pSyncAncestor->m_pElement->m_ulDelay)
  1249. {
  1250.     ulAnchorStartTime =
  1251.     pSyncAncestor->m_pElement->m_ulDelay;
  1252. }
  1253. if (pSyncAncestor->m_pElement->m_bBeginOffsetSet  &&
  1254. WAY_IN_THE_FUTURE !=
  1255. pSyncAncestor->m_pElement->m_ulDelay)
  1256. {
  1257.     ulAnchorStartTime += (UINT32)
  1258.     (pSyncAncestor->m_pElement->m_lBeginOffset);
  1259. }
  1260. #else
  1261. HX_RESULT pnrStart = pSyncAncestor->m_pElement->
  1262. getCurrentScheduledStartTime(ulAnchorStartTime);
  1263. // /Now, add begin offset, if any, to
  1264. // sync base's end time:
  1265. ulAnchorStartTime += ulAnchorBeginOffset;
  1266. #endif
  1267. #if defined(_DEBUG)
  1268. ULONG32 ulStartTime2 = (UINT32)
  1269. (pSyncAncestor->m_pElement->m_lBeginOffset >= 0?
  1270. pSyncAncestor->m_pElement->m_lBeginOffset : 0);
  1271. ulStartTime2 += ulAnchorBeginOffset;
  1272. HX_ASSERT(ulAnchorStartTime == ulStartTime2);
  1273. #endif
  1274.     }
  1275.     else
  1276.     {
  1277. ulAnchorStartTime = (UINT32)-1; // /Unresolved time.
  1278.     }
  1279. }
  1280.     }
  1281.     if (ulAnchorStartTime <= ulCurTime)
  1282.     {
  1283. // /XXXEH: check if ulAnchorEndTime >= ulCurTime as well (see:
  1284. // "BUG-20011113_letOnLoadURLhurlAt10sThenStopItAndResumeMainThenSeek..."):
  1285. bLaunchHyperlink = TRUE;
  1286.     }
  1287. }
  1288. if (!bLaunchHyperlink)
  1289. {
  1290.     /* // /XXXEH- TODO: pre-sort this temporally:
  1291.     // But, NOTE: we *can't* sort these due to not-yet-knowable
  1292.     parental timing, e.g.,  excl pause & defer, and par begin=[event]:
  1293.     // /This one's begin time has not yet been reached, and this
  1294.     // list is temporally sorted so we're done for now:
  1295.     break;
  1296.     */
  1297.     continue; // /do this until list is temporally sorted.
  1298. }
  1299. else
  1300. {
  1301.     // /Remove: it'll be hurled now or be determined to be ignored:
  1302.     m_pOnLoadURLList->RemoveAt(lPosOfCurAnchor);
  1303.     // /Helps fix PR 67170: don't return until we've found the last
  1304.     // of the ones ready to go for the associated "sendTo" app,
  1305.     // ignoring the others since they'll be replaced immediately
  1306.     // anyway:
  1307.     if (!pSendToTargetMapOfAnchorsToBeHurledNow)
  1308.     {
  1309. pSendToTargetMapOfAnchorsToBeHurledNow = new CHXMapStringToOb;
  1310. if (!pSendToTargetMapOfAnchorsToBeHurledNow)
  1311. {
  1312.     goto cleanup; // /Do nothing if system is out of memory.
  1313. }
  1314.     }
  1315.     // /If no sendTo specified, then defaults to "_rpbrowser" if
  1316.     // external=TRUE, otherwise defaults to "_rpengine":
  1317.     CHXString keyStr;
  1318.     if (pCurAnchor->m_sendTo.IsEmpty()  ||
  1319.     // /If external is FALSE, sendTo is ignored:
  1320.     !pCurAnchor->m_bExternal)
  1321.     {
  1322. if (pCurAnchor->m_bExternal)
  1323. {
  1324.     keyStr = "_rpbrowser";
  1325. }
  1326. else
  1327. {
  1328.     keyStr = "_rpengine";
  1329. }
  1330.     }
  1331.     else // /use sendTo value as the key:
  1332.     {
  1333. keyStr = (const char*)pCurAnchor->m_sendTo;
  1334.     }
  1335.     // /If link "target" is specified, append it to the key since a
  1336.     // target is a specific instance of the sendTo app:
  1337.     if (!pCurAnchor->m_target.IsEmpty())
  1338.     {
  1339. keyStr += pCurAnchor->m_target;
  1340.     }
  1341.     HX_ASSERT(!keyStr.IsEmpty());
  1342.     if (!keyStr.IsEmpty())
  1343.     {
  1344. // /If we didn't just seek, then just return the first one found
  1345. // that's time-valid and let the next, if any, be hurled at the
  1346. // next onTimeSync:
  1347. if (!m_bHandlePostSeekOnLoadURLs)
  1348. {
  1349.     (*pSendToTargetMapOfAnchorsToBeHurledNow)[keyStr] =
  1350.     (void*)pCurAnchor;
  1351.     goto cleanup;
  1352. }
  1353. if (!pMapStartTimeToSendToPlusTarget)
  1354. {
  1355.     pMapStartTimeToSendToPlusTarget = new CHXMapStringToOb;
  1356.     if (!pMapStartTimeToSendToPlusTarget)
  1357.     {
  1358. goto cleanup; // /Do nothing if system is out of memory.
  1359.     }
  1360. }
  1361. // /Now, see if map[key] time is earlier than current; if so,
  1362. // replace it with current anchor start time:
  1363. UINT32 ulCurrentlyMappedAnchorStartTime = (UINT32)-1;
  1364. BOOL bCurrentlyMappedAnchorStartTimeIsValid = FALSE;
  1365. if (pMapStartTimeToSendToPlusTarget->Lookup(
  1366. (const char*)keyStr, (void*&)ulCurrentlyMappedAnchorStartTime))
  1367. {
  1368.     bCurrentlyMappedAnchorStartTimeIsValid = TRUE;
  1369. }
  1370. // /If map entry didn't already exist or it did but new time
  1371. // is same or more recent, then replace it with the new value:
  1372. if (!bCurrentlyMappedAnchorStartTimeIsValid  ||
  1373. // /Note: do ">=", not just ">", to make sure lexically-
  1374. // last of a same-timed pair wins:
  1375. ulAnchorStartTime >= ulCurrentlyMappedAnchorStartTime)
  1376. {
  1377.     (*pSendToTargetMapOfAnchorsToBeHurledNow)[(const char*)
  1378.     keyStr] = (void*)pCurAnchor;
  1379.     (*pMapStartTimeToSendToPlusTarget)[(const char*)keyStr] =
  1380.     (void*)ulAnchorStartTime;
  1381. }
  1382.     }
  1383.     else
  1384.     {
  1385. goto cleanup; // /can't recover from error.
  1386.     }
  1387. }
  1388.     }
  1389. cleanup:
  1390.     m_bHandlePostSeekOnLoadURLs = FALSE;
  1391.     HX_DELETE(pMapStartTimeToSendToPlusTarget);
  1392.     // /NOTE: May be NULL; if not, caller must delete when done:
  1393.     return (pSendToTargetMapOfAnchorsToBeHurledNow);
  1394. }
  1395. // /Returns TRUE if any other element is awaiting an activateEvent (click or
  1396. // other form of user activation) to begin or end (fixes PR 56503):
  1397. BOOL
  1398. CSmilParser::hasActivateEventListener(const char* pMediaID,
  1399.       INT16 iCurrentGroupIndex)
  1400. {
  1401.     BOOL bSomeoneIsListeningForActivateEvent = FALSE;
  1402.     // /Look for begin times that are awaiting pMediaID user activation:
  1403.     LISTPOSITION lPos = NULL;
  1404.     CHXSimpleList* pCurList = m_pBeginEventList;
  1405.     for (INT16 iList=0; iList<2  &&  !bSomeoneIsListeningForActivateEvent; iList++)
  1406.     {
  1407. if (1==iList)
  1408. {
  1409.     pCurList = m_pEndEventList;
  1410. }
  1411. if (pCurList)
  1412. {
  1413.     lPos = pCurList->GetHeadPosition();
  1414. }
  1415. else
  1416. {
  1417.     continue;
  1418. }
  1419. // /Go through and see if anybody has a begin time that's ready to
  1420. // become their active begin time:
  1421. while (lPos)
  1422. {
  1423.     LISTPOSITION lPosOfCurTmpVal = lPos;
  1424.     // /Gets val at lPos and then moves lPos to next node in list:
  1425.     SmilTimeValue* pTmpVal =
  1426.     (SmilTimeValue*)pCurList->GetNext(lPos);
  1427.     if (!pTmpVal  ||  !pTmpVal->m_pElement  ||
  1428.     !pTmpVal->m_pElement->m_pNode)
  1429.     {
  1430. // /List shouldn't have empty node or node w/NULL element:
  1431. HX_ASSERT(pTmpVal  &&  pTmpVal->m_pElement  &&
  1432. pTmpVal->m_pElement->m_pNode);
  1433. // /Get rid of it from the list:
  1434. pCurList->RemoveAt(lPosOfCurTmpVal);
  1435. continue;
  1436.     }
  1437.     // Ignore this timeValue if it's element is not in the current
  1438.     // group:
  1439.     if (pTmpVal->m_pElement->m_pNode->m_nGroup != iCurrentGroupIndex)
  1440.     {
  1441. continue;
  1442.     }
  1443.     const char* pEventName = pTmpVal->getEventName();
  1444.     const char* pIDRef = pTmpVal->getIdRef();
  1445.     if (pEventName  &&  pIDRef  &&
  1446.     0==strcmp("activateEvent", pEventName)  &&
  1447.     0==strcmp(pMediaID, pIDRef))
  1448.     {
  1449. // /XXXEH- optimize for the following cases; if any evaluate
  1450. // to TRUE, then don't return TRUE from here:
  1451. // (1) If pTmpVal->m_pElement's restart="never" & m_pElement
  1452. //     has played already.
  1453. // (2) If pTmpVal->m_pElement's restart="whenNotActive" and
  1454. //     m_pElement is currently playing
  1455. // (3) If pTmpVal->m_pElement's parent begin is too late for
  1456. //     m_pElement to play based on this activateEvent
  1457. // (4) if pTmpVal->m_pElement's parent end is too early for
  1458. //     m_pElement to play based on this activateEvent
  1459. // (5) if pTmpVal is going to *end* on this activateEvent and
  1460. //     its parent's end time is earlier than the computed end
  1461. //     based on this activateEvent::
  1462. bSomeoneIsListeningForActivateEvent = TRUE;
  1463. break; // /We only need to know if *any* is listening.
  1464.     }
  1465. } // end while().
  1466.     } // end for().
  1467.     return bSomeoneIsListeningForActivateEvent;
  1468. }
  1469. // /This function checks to see if there is already a time value with the
  1470. // exact same characteristics as the one being passed in:
  1471. BOOL
  1472. CSmilParser::isDuplicateEntry(CHXSimpleList* pList,
  1473.       SmilTimeValue* pTimeValue)
  1474. {
  1475.     BOOL bHasEvilTwin = FALSE;
  1476.     if (pList  &&  pTimeValue)
  1477.     {
  1478. LISTPOSITION lPos = NULL;
  1479. if (pList)
  1480. {
  1481.     lPos = pList->GetHeadPosition();
  1482. }
  1483. while (lPos)
  1484. {
  1485.     // /Gets val at lPos and then moves lPos to next node in list:
  1486.     SmilTimeValue* pTmpValue = (SmilTimeValue*)pList->GetNext(lPos);
  1487.     if (!pTmpValue  ||  !pTmpValue->m_pElement)
  1488.     {
  1489. // /List shouldn't have an empty node or a node w/NULL element:
  1490. HX_ASSERT(pTmpValue  &&  pTmpValue->m_pElement);
  1491. continue;
  1492.     }
  1493.     if (pTimeValue->isSameTimeValue(pTmpValue))
  1494.     {
  1495. bHasEvilTwin = TRUE;
  1496. break;
  1497.     }
  1498. }
  1499.     }
  1500.     return bHasEvilTwin;
  1501. }
  1502. HX_RESULT CSmilParser::computeRemoveTime(const char* pszID,
  1503.                                          REF(UINT32) rulRemoveTime)
  1504. {
  1505.     HX_RESULT retVal = HXR_FAIL;
  1506.     if (pszID)
  1507.     {
  1508.         // Get this element
  1509.         CSmilElement* pElement = findElement(pszID);
  1510.         if (pElement)
  1511.         {
  1512.             // Check our erase value
  1513.             if (pElement->m_eErase == EraseWhenDone)
  1514.             {
  1515.                 // Get our fill value
  1516.                 FillType eOurFill = pElement->m_eActualFill;
  1517.                 // See if our parent is resolved
  1518.                 BOOL        bKnowParentEnd    = FALSE;
  1519.                 BOOL        bHasParentElement = FALSE;
  1520.                 FillType    eParentFill       = FillDefault;
  1521.                 const char* pszParentID       = NULL;
  1522.                 UINT32      ulParentEnd       = 0;
  1523.                 if (pElement->m_pNode)
  1524.                 {
  1525.                     SMILNode* pSANode = getSyncAncestor(pElement->m_pNode);
  1526.                     if (pSANode && pSANode->m_pElement)
  1527.                     {
  1528.                         UINT32    ulStop  = 0;
  1529.                         HX_RESULT rv      = pSANode->m_pElement->getCurrentScheduledStopTime(ulStop);
  1530.                         if (SUCCEEDED(rv))
  1531.                         {
  1532.                             bKnowParentEnd = TRUE;
  1533.                             ulParentEnd    = ulStop;
  1534.                         }
  1535.                         // Get the parent's fill value
  1536.                         eParentFill = pSANode->m_pElement->m_eActualFill;
  1537.                         // Save the parent id
  1538.                         pszParentID = (const char*) pSANode->m_id;
  1539.                         // Do we have a parent CSmilElement?
  1540.                         CSmilElement* pTmpEl = findElement(pszParentID);
  1541.                         if (pTmpEl)
  1542.                         {
  1543.                             // Set the flag
  1544.                             bHasParentElement = TRUE;
  1545.                         }
  1546.                     }
  1547.                 }
  1548.                 // Get the type of time container we're in
  1549.                 SMILNodeTag eTimeContTag = getSyncTag(pElement->m_pNode);
  1550.                 // If we are in a <seq>, then get the delay of the
  1551.                 // next element in the <seq>.
  1552.                 BOOL   bKnowNextDelay = FALSE;
  1553.                 BOOL   bLastInSeq     = FALSE;
  1554.                 UINT32 ulNextDelay    = 0;
  1555.                 if (eTimeContTag == SMILSeq &&
  1556.                     pElement->m_pTimelineElement)
  1557.                 {
  1558.                     CSmilTimelineElement* pDep = pElement->m_pTimelineElement->getDependent();
  1559.                     if (pDep)
  1560.                     {
  1561.                         CSmilElement* pSrcEl = pDep->getSourceElement();
  1562.                         if (pSrcEl)
  1563.                         {
  1564.                             UINT32    ulStart = 0;
  1565.                             HX_RESULT rv      = pSrcEl->getCurrentScheduledStartTime(ulStart);
  1566.                             if (SUCCEEDED(rv))
  1567.                             {
  1568.                                 bKnowNextDelay = TRUE;
  1569.                                 ulNextDelay    = ulStart;
  1570.                             }
  1571.                         }
  1572. //                        if (pDep->initialDelaySet())
  1573. //                        {
  1574. //                            bKnowNextDelay = TRUE;
  1575. //                            // XXXMEH - DELAY_DUR_FIX
  1576. //                            ulNextDelay    = pDep->getDelay();
  1577. //                        }
  1578.                     }
  1579.                     else
  1580.                     {
  1581.                         // If we have no dependent timeline element,
  1582.                         // then we are the last element in the <seq>
  1583.                         bLastInSeq = TRUE;
  1584.                     }
  1585.                 }
  1586.                 else if (eTimeContTag == SMILExcl)
  1587.                 {
  1588.                     // Get our currently scheduled stop time
  1589.                     UINT32    ulOurStopTime = 0;
  1590.                     HX_RESULT rv            = pElement->getCurrentScheduledStopTime(ulOurStopTime);
  1591.                     if (SUCCEEDED(rv))
  1592.                     {
  1593.                         // Now we need to look for all our siblings
  1594.                         // which have a currently scheduled start time
  1595.                         // after our stop time.
  1596.                         //
  1597.                         // Get our excl parent
  1598.                         SMILNode* pExclParentNode = getSyncAncestor(pElement->m_pNode);
  1599.                         if (pExclParentNode)
  1600.                         {
  1601.                             BOOL      bValidMin  = FALSE;
  1602.                             UINT32    ulMinStart = 0;
  1603.                             SMILNode* pSibling   = getTimelineDescendent(pExclParentNode);
  1604.                             while (pSibling)
  1605.                             {
  1606.                                 if (pSibling->m_pElement &&
  1607.                                     pSibling->m_pElement != pElement)
  1608.                                 {
  1609.                                     UINT32 ulSibStart = 0;
  1610.                                     rv = pSibling->m_pElement->getCurrentScheduledStartTime(ulSibStart);
  1611.                                     if (SUCCEEDED(rv))
  1612.                                     {
  1613.                                         if (ulSibStart > ulOurStopTime)
  1614.                                         {
  1615.                                             if (bValidMin)
  1616.                                             {
  1617.                                                 if (ulSibStart < ulMinStart)
  1618.                                                 {
  1619.                                                     ulMinStart = ulSibStart;
  1620.                                                 }
  1621.                                             }
  1622.                                             else
  1623.                                             {
  1624.                                                 ulMinStart = ulSibStart;
  1625.                                                 bValidMin  = TRUE;
  1626.                                             }
  1627.                                         }
  1628. // /Fixes PR 53175 (& PR 54540):
  1629. // if sibling start time is earlier
  1630. // *but* end time is later, then it
  1631. // resumed after we ended and we
  1632. // should be removed if fill="freeze"
  1633. // as if another sibling just started:
  1634. else
  1635. {
  1636. #if XXXEH_2010419_secondPlayOfFirstInExclNotPlaying_LEGAL_BUT_HITS_THIS_AT_3s
  1637. #error: need to find content that trips this assert and is broken:
  1638.     HX_ASSERT(ulSibStart != ulOurStopTime  &&
  1639.       "same begins in excl; pls email ehodge");
  1640. #endif
  1641.     UINT32 ulSibEnd = 0;
  1642.     HX_RESULT rcSibEnd =
  1643.     pSibling->m_pElement->
  1644.     getCurrentScheduledStopTime(
  1645.     ulSibEnd);
  1646.     HX_ASSERT(HXR_OK == rcSibEnd);
  1647.     if (HXR_OK == rcSibEnd  &&
  1648.     ulSibEnd >= ulOurStopTime)
  1649.     {
  1650. // /Guaranteed to be lower
  1651. // than ulMinStart so far:
  1652.                                                 ulMinStart = ulOurStopTime;
  1653.                                                 bValidMin  = TRUE;
  1654. // /All we need is one:
  1655. break;
  1656.     }
  1657. }
  1658.                                     }
  1659.                                 }
  1660.                                 pSibling = getTimelineDescendent(pExclParentNode, pSibling);
  1661.                             }
  1662.                             // Did we get a valid next start?
  1663.     // or a valid resume after our end?
  1664.                             if (bValidMin)
  1665.                             {
  1666.                                 bKnowNextDelay = TRUE;
  1667.                                 ulNextDelay    = ulMinStart;
  1668.                             }
  1669.                         }
  1670.                     }
  1671.                 }
  1672.                 // Switch based on our fill value
  1673.                 // Note that we use "actual" fill here - that is
  1674.                 // the "resolved" fill value after all fillDefault and
  1675.                 // auto are taken into consideration.
  1676.                 switch (eOurFill)
  1677.                 {
  1678.                     // If we don't support transitions, but for some
  1679.                     // reason have a fill="transition", then we treat
  1680.                     // it as fill="remove"
  1681. #if !defined(HELIX_FEATURE_SMIL2_TRANSITIONS)
  1682.                     case FillTransition:
  1683. #endif /* #if !defined(HELIX_FEATURE_SMIL2_TRANSITIONS) */
  1684.                     case FillRemove:
  1685.                         {
  1686.                             // SPEC
  1687.                             // Specifies that the element will not extend past the end
  1688.                             // of the last instance of the simple duration
  1689.                             //
  1690.                             // Our remove time will be the end of our duration
  1691. //                            // XXXMEH - DELAY_DUR_FIX
  1692. //                            rulRemoveTime = pElement->m_ulDelay + pElement->m_ulDuration -
  1693. //                                            (pElement->m_bBeginOffsetSet ? pElement->m_lBeginOffset : 0);
  1694.                             UINT32 ulStop = 0;
  1695.                             retVal        = pElement->getCurrentScheduledStopTime(ulStop);
  1696.                             if (SUCCEEDED(retVal))
  1697.                             {
  1698.                                 rulRemoveTime = ulStop;
  1699.                                 // Do we know our parent's end?
  1700.                                 if (bKnowParentEnd)
  1701.                                 {
  1702.                                     // We know our parent's end, so we need to check if
  1703.                                     // our parent cuts us off. Note that we intentionally
  1704.                                     // check for ">" instead of ">=".
  1705.                                     if (rulRemoveTime > ulParentEnd)
  1706.                                     {
  1707.                                         // Do we actually have a parent?
  1708.                                         if (bHasParentElement)
  1709.                                         {
  1710.                                             // Our parent cuts us off, so we are still active
  1711.                                             // when our parent ends. Therefore, if our parent
  1712.                                             // has a fill value of "freeze" or "hold", then
  1713.                                             // we will have to look at remove time of our
  1714.                                             // parent to know when we need to remove.
  1715.                                             retVal = computeRemoveTime(pszParentID,
  1716.                                                                        rulRemoveTime);
  1717.                                         }
  1718.                                     }
  1719.                                 }
  1720.                             }
  1721.                         }
  1722.                         break;
  1723.                     case FillFreeze:
  1724.                         {
  1725.                             // SPEC
  1726.                             // Specifies that the element will extend past the end of the
  1727.                             // last instance of the simple duration by "freezing" the element
  1728.                             // state at that point. An element with "freeze" behavior is
  1729.                             // extended according to the parent time container:
  1730.                             // - In a par, the element is frozen to extend to the end of the simple
  1731.                             //   duration of the par. In this case, fill="freeze" is equivalent to
  1732.                             //   fill="hold".
  1733.                             // - In a seq, the element is frozen to extend to the begin of the next
  1734.                             //   element in the seq or until the end of the simple duration of the
  1735.                             //   seq.This will fill any gap in the presentation (although it may have
  1736.                             //   no effect if the next element begins immediately). ]
  1737.                             // - In an excl, the element is frozen to extend to the begin of the next
  1738.                             //   element to be activated in the excl or until the end of the simple
  1739.                             //   duration of the excl. This will fill any gap in the presentation
  1740.                             //   (although it may have no effect if the next element interrupts the
  1741.                             //   current element). Note that if an element is paused, the active
  1742.                             //   duration has not ended, and so the fill attribute does not (yet)
  1743.                             //   apply.
  1744.                             //
  1745.                             // What kind of time container are we in?
  1746.                             if (eTimeContTag == SMILPar)
  1747.                             {
  1748.                                 // Do we know our parent's end time? If we
  1749.                                 // don't, then we can't set the remove time
  1750.                                 if (bKnowParentEnd)
  1751.                                 {
  1752.                                     // Is our parent frozen or held?
  1753.                                     if (eParentFill == FillFreeze || eParentFill == FillHold)
  1754.                                     {
  1755.                                         // Do we have a parent CSmilElement?
  1756.                                         if (bHasParentElement)
  1757.                                         {
  1758.                                             // We have a parent CSmilElement and
  1759.                                             // our parent is frozen or held, so we need
  1760.                                             // to check the remove time for our parent
  1761.                                             retVal = computeRemoveTime(pszParentID,
  1762.                                                                        rulRemoveTime);
  1763.                                         }
  1764.                                         else
  1765.                                         {
  1766.                                             // We don't have a parent CSmilElement,
  1767.                                             // so we must simply take our parent's end time
  1768.                                             rulRemoveTime = ulParentEnd;
  1769.                                             retVal        = HXR_OK;
  1770.                                         }
  1771.                                     }
  1772.                                     else
  1773.                                     {
  1774.                                         // Our parent is not frozen or held, so our
  1775.                                         // remove time is the end of our parent
  1776.                                         rulRemoveTime = ulParentEnd;
  1777.                                         retVal        = HXR_OK;
  1778.                                     }
  1779.                                 }
  1780.                             }
  1781.                             else if (eTimeContTag == SMILSeq)
  1782.                             {
  1783.                                 // Are we the last element in the <seq>?
  1784.                                 if (!bLastInSeq)
  1785.                                 {
  1786.                                     // We are not the last element in the <seq>,
  1787.                                     // so do we know the delay of the next element
  1788.                                     // in the <seq>?
  1789.                                     if (bKnowNextDelay)
  1790.                                     {
  1791.                                         // If we are in a <seq> and we have fill="freeze",
  1792.                                         // then we should remove at the start of the
  1793.                                         // next element in the <seq>, taking into account
  1794.                                         // any begin offset of that next element.
  1795.                                         rulRemoveTime = ulNextDelay;
  1796.                                         retVal        = HXR_OK;
  1797.                                     }
  1798.                                 }
  1799.                                 else
  1800.                                 {
  1801.                                     // We are the last element in the <seq>, so
  1802.                                     // we will freeze until the end of our time
  1803.                                     // container.
  1804.                                     if (bKnowParentEnd)
  1805.                                     {
  1806.                                         // Is our parent frozen or held?
  1807.                                         if (eParentFill == FillFreeze || eParentFill == FillHold)
  1808.                                         {
  1809.                                             // Do we have a parent CSmilElement?
  1810.                                             if (bHasParentElement)
  1811.                                             {
  1812.                                                 // We have a parent CSmilElement, and
  1813.                                                 // our parent is frozen or held, so we need
  1814.                                                 // to check the remove time for our parent
  1815.                                                 retVal = computeRemoveTime(pszParentID,
  1816.                                                                            rulRemoveTime);
  1817.                                             }
  1818.                                             else
  1819.                                             {
  1820.                                                 // We don't have a parent CSmilElement,
  1821.                                                 // so we simply take our parent's end time
  1822.                                                 // as our remove time.
  1823.                                                 rulRemoveTime = ulParentEnd;
  1824.                                                 retVal        = HXR_OK;
  1825.                                             }
  1826.                                         }
  1827.                                         else
  1828.                                         {
  1829.                                             // Our parent is not frozen or held, so our
  1830.                                             // remove time is the end of our parent
  1831.                                             rulRemoveTime = ulParentEnd;
  1832.                                             retVal        = HXR_OK;
  1833.                                         }
  1834.                                     }
  1835.                                 }
  1836.                             }
  1837.                             else if (eTimeContTag == SMILExcl)
  1838.                             {
  1839.                                 // Do we know the delay of the next element
  1840.                                 // in the <excl>?
  1841.                                 if (bKnowNextDelay)
  1842.                                 {
  1843.                                     // If we are in a <seq> and we have fill="freeze",
  1844.                                     // then we should remove at the start of the
  1845.                                     // next element in the <seq>, taking into account
  1846.                                     // any begin offset of that next element.
  1847.                                     rulRemoveTime = ulNextDelay;
  1848.                                     retVal        = HXR_OK;
  1849.                                 }
  1850.                             }
  1851.                         }
  1852.                         break;
  1853.                     case FillHold:
  1854.                         {
  1855.                             // SPEC:
  1856.                             // Setting this to "hold" has the same effect as setting to
  1857.                             // "freeze", except that the element is always frozen to extend to the end
  1858.                             // of the simple duration of the parent time container of the element
  1859.                             // (independent of the type of time container). For profiles that support
  1860.                             // a layered layout model (e.g., SMIL 2.0 Language Profile), held elements
  1861.                             // (elements with fill="hold") will refresh their display area when a layer
  1862.                             // is added on top then later removed.
  1863.                             //
  1864.                             // Do we know our parent's end time? If we
  1865.                             // don't, then we can't set the remove time
  1866.                             if (bKnowParentEnd)
  1867.                             {
  1868.                                 // Is our parent frozen or held?
  1869.                                 if (eParentFill == FillFreeze || eParentFill == FillHold)
  1870.                                 {
  1871.                                     // Do we have a parent CSmilElement?
  1872.                                     if (bHasParentElement)
  1873.                                     {
  1874.                                         // We have a parent CSmilElement, and
  1875.                                         // our parent is frozen or held, so we need
  1876.                                         // to check the remove time for our parent
  1877.                                         retVal = computeRemoveTime(pszParentID,
  1878.                                                                    rulRemoveTime);
  1879.                                     }
  1880.                                     else
  1881.                                     {
  1882.                                         // We don't have a parent CSmilElement,
  1883.                                         // so we just take our parent's end time
  1884.                                         rulRemoveTime = ulParentEnd;
  1885.                                         retVal        = HXR_OK;
  1886.                                     }
  1887.                                 }
  1888.                                 else
  1889.                                 {
  1890.                                     // Our parent is not frozen or held, so our
  1891.                                     // remove time is the end of our parent
  1892.                                     rulRemoveTime = ulParentEnd;
  1893.                                     retVal        = HXR_OK;
  1894.                                 }
  1895.                             }
  1896.                         }
  1897.                         break;
  1898. #if defined(HELIX_FEATURE_SMIL2_TRANSITIONS)
  1899.                     case FillTransition:
  1900.                         {
  1901.                             // XXXMEH - temporary fix for fill="transition"
  1902.                             // XXXMEH - TODO
  1903.                             // The correct implementation for fill="transition" is to
  1904.                             // look through all currently scheduled transitions and find the
  1905.                             // next transition which begins after the end of the active
  1906.                             // duration of this element covering any part of the screen in
  1907.                             // which this element is playing. This transition could be
  1908.                             // on a media element which is outside of this element's
  1909.                             // time container. However, in most cases, the element will
  1910.                             // be a sibling of this element. Therefore, temporarily, we
  1911.                             // will simply look at the elements which are children
  1912.                             // of our time container. If we don't find a transIn for one
  1913.                             // on one of these elements, then we treat this as fill="remove".
  1914.                             UINT32    ulTime = 0;
  1915.                             HX_RESULT rv     = getNextTransitionEnd(pElement, ulTime);
  1916.                             if (SUCCEEDED(rv))
  1917.                             {
  1918.                                 rulRemoveTime = ulTime;
  1919.                                 retVal        = HXR_OK;
  1920.                             }
  1921.                             else
  1922.                             {
  1923.                                 // We didn't find a transition inside our time
  1924.                                 // time container, so treat this as fill="remove".
  1925.                                 UINT32 ulStop = 0;
  1926.                                 retVal        = pElement->getCurrentScheduledStopTime(ulStop);
  1927.                                 if (SUCCEEDED(retVal))
  1928.                                 {
  1929.                                     rulRemoveTime = ulStop;
  1930.                                 }
  1931. //                                // XXXMEH - DELAY_DUR_FIX
  1932. //                                rulRemoveTime = pElement->m_ulDelay + pElement->m_ulDuration -
  1933. //                                                (pElement->m_bBeginOffsetSet ? pElement->m_lBeginOffset : 0);
  1934. //                                retVal        = HXR_OK;
  1935.                             }
  1936.                         }
  1937.                         break;
  1938. #endif /* #if defined(HELIX_FEATURE_SMIL2_TRANSITIONS) */
  1939.                 }
  1940.             }
  1941.             else
  1942.             {
  1943.                 // XXXMEH - TODO - final fix for erase="never". Spec says:
  1944.                 // "The effects of erase=never apply after the active duration
  1945.                 //  of the media object and any fill period (defined by SMIL
  1946.                 //  Timing and Synchronization), and only until other media
  1947.                 //  plays to the region targeted by the media object, or until
  1948.                 //  the same media object restarts."
  1949.                 //
  1950.                 // We will implement erase="never" by setting the
  1951.                 // remove time for erase="never" elements as WAY_IN_THE_FUTURE.
  1952.                 rulRemoveTime = WAY_IN_THE_FUTURE;
  1953.                 // Clear the return value
  1954.                 retVal = HXR_OK;
  1955.             }
  1956.         }
  1957.     }
  1958.     return retVal;
  1959. }
  1960. void
  1961. CSmilParser::InitPersistent(UINT32 ulPersistentComponentID,
  1962.     IHXValues* pProperties)
  1963. {
  1964.     m_ulPersistentComponentID = ulPersistentComponentID;
  1965.     if (pProperties)
  1966.     {
  1967. pProperties->GetPropertyULONG32("Delay", m_ulPersistentComponentDelay);
  1968. pProperties->GetPropertyULONG32("Duration", m_ulPersistentComponentDuration);
  1969. pProperties->GetPropertyULONG32("ElementWithinTag", (UINT32&)m_elementWithinTag);
  1970.     }
  1971. }
  1972. HX_RESULT
  1973. CSmilParser::addResumeEvent(SmilTimeValue* pTimeValue,
  1974.   REF(BOOL) bOldResumeEventWasRemoved)
  1975. {
  1976.     return addResumeOrUndeferEvent(pTimeValue, bOldResumeEventWasRemoved,
  1977.     TRUE);
  1978. }
  1979. HX_RESULT
  1980. CSmilParser::addUndeferEvent(SmilTimeValue* pTimeValue,
  1981.   REF(BOOL) bOldDeferEventWasRemoved)
  1982. {
  1983.     return addResumeOrUndeferEvent(pTimeValue, bOldDeferEventWasRemoved,
  1984.     FALSE);
  1985. }
  1986. // /This function inserts the time value into the pending list, but first
  1987. // checks to see if there is already a pending time value for this element;
  1988. // if so, it removes the old one.  It returns TRUE in
  1989. // bOldResumeEventWasRemoved if existing one was removed herein:
  1990. HX_RESULT
  1991. CSmilParser::addResumeOrUndeferEvent(SmilTimeValue* pTimeValue,
  1992.   REF(BOOL) bOldEventWasRemoved,
  1993.   BOOL bIsResumeEvent)
  1994. {
  1995. #if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG_EXCL_TRACK_REMOVAL)
  1996. {
  1997.     FILE* f1 = ::fopen("c:\smil2excl.txt", bFirstExclTrackChangeDebugOut?"w":"a+");
  1998.     bFirstExclTrackChangeDebugOut = FALSE;
  1999.     ::fprintf(f1, "add%sEvent(timeVal's = %s)n", bIsResumeEvent?"Resume":"Undefer",
  2000. (const char*)pTimeValue->m_pElement->m_pNode->m_id);
  2001.     ::fclose(f1);
  2002. }
  2003. #endif
  2004.     HX_RESULT pnr = HXR_OK;
  2005.     bOldEventWasRemoved = FALSE;
  2006.     if (pTimeValue)
  2007.     {
  2008. LISTPOSITION lPos = NULL;
  2009. if (!m_pBeginEventList)
  2010. {
  2011.     m_pBeginEventList = new CHXSimpleList;
  2012. }
  2013. if (!m_pBeginEventList)
  2014. {
  2015.     pnr = HXR_OUTOFMEMORY;
  2016. }
  2017. else
  2018. {
  2019.     lPos = m_pBeginEventList->GetHeadPosition();
  2020. }
  2021. while (lPos)
  2022. {
  2023.     LISTPOSITION lPosOfCurTmpVal = lPos;
  2024.     // /Gets val at lPos and then moves lPos to next node in list:
  2025.     SmilTimeValue* pTmpValue =
  2026.     (SmilTimeValue*)m_pBeginEventList->GetNext(lPos);
  2027.     if (!pTmpValue  ||  !pTmpValue->m_pElement)
  2028.     {
  2029. // /List shouldn't have an empty node or one w/NULL element:
  2030. HX_ASSERT(pTmpValue  &&  pTmpValue->m_pElement);
  2031. continue;
  2032.     }
  2033.     if (pTimeValue->m_pElement == pTmpValue->m_pElement)
  2034.     {
  2035. if ((bIsResumeEvent  &&  pTmpValue->isResumeEvent())  ||
  2036. (!bIsResumeEvent  &&  pTmpValue->isUndeferEvent()) )
  2037. {
  2038. #if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG_EXCL_TRACK_REMOVAL)
  2039. {
  2040.     FILE* f1 = ::fopen("c:\smil2excl.txt", bFirstExclTrackChangeDebugOut?"w":"a+");
  2041.     bFirstExclTrackChangeDebugOut = FALSE;
  2042.     ::fprintf(f1, "tadd%sEvent(timeVal's = %s): removing %s %sEvent from event listn",
  2043. bIsResumeEvent? "Resume":"Undefer",
  2044. (const char*)pTimeValue->m_pElement->m_pNode->m_id,
  2045. (const char*)pTmpValue->m_pElement->m_pNode->m_id);
  2046. bIsResumeEvent? "resume":"undefer",
  2047.     ::fclose(f1);
  2048. }
  2049. #endif
  2050.     // /Get rid of it from the pending list:
  2051.     m_pBeginEventList->RemoveAt(lPosOfCurTmpVal);
  2052.                     // Get rid of it from the map
  2053.                     removeFromBeginOrEndTimeMap(pTmpValue, SmilBeginTimeList);
  2054.     bOldEventWasRemoved = TRUE;
  2055.     break;
  2056. }
  2057.     }
  2058. }
  2059. // /XXXEH- TODO: add this in temporal order; break out the bottom
  2060. // part of CSmilParser::insertElementWithPendingBeginOrEnd() into
  2061. // its own function 'insertPendingInTemporalOrder()' or the like:
  2062. // /OK to insert the new one now:
  2063. pnr = addBeginEventElement(pTimeValue);
  2064. // /Next, we have to add this as a begin time to the element's
  2065. // begin-time list so it can get resolved the normal way when the
  2066. // resume|defer event happens, which is when the interrupting sibling ends:
  2067. if (HXR_OK == pnr  &&  pTimeValue->m_pElement)
  2068. {
  2069.     if (!pTimeValue->m_pElement->m_pBeginTimeList)
  2070.     {
  2071. pTimeValue->m_pElement->m_pBeginTimeList = new CHXSimpleList;
  2072.     }
  2073.     if (!pTimeValue->m_pElement->m_pBeginTimeList)
  2074.     {
  2075. pnr = HXR_OUTOFMEMORY;
  2076.     }
  2077.     else
  2078.     {
  2079. CHXSimpleList* pBeginList =
  2080. pTimeValue->m_pElement->m_pBeginTimeList;
  2081. // /First, remove any resume events in the list:
  2082. lPos = pBeginList->GetHeadPosition();
  2083. while (lPos)
  2084. {
  2085.     LISTPOSITION lPosOfCurTmpVal = lPos;
  2086.     // /Gets val at lPos and then moves lPos to next node in list:
  2087.     SmilTimeValue* pTmpValue =
  2088.     (SmilTimeValue*)pBeginList->GetNext(lPos);
  2089.     if (!pTmpValue  ||  !pTmpValue->m_pElement)
  2090.     {
  2091. HX_ASSERT(pTmpValue  &&  pTmpValue->m_pElement);
  2092. continue;
  2093.     }
  2094.     if ((bIsResumeEvent  &&  pTmpValue->isResumeEvent())  ||
  2095. (!bIsResumeEvent  &&  pTmpValue->isUndeferEvent()) )
  2096.     {
  2097. // /Get rid of it from the list:
  2098. pBeginList->RemoveAt(lPosOfCurTmpVal);
  2099. bOldEventWasRemoved = TRUE;
  2100. break;
  2101.     }
  2102. }
  2103. // /Now it's OK to stick this new one in:
  2104. pBeginList->AddTail(pTimeValue);
  2105.     }
  2106. }
  2107.     }
  2108.     return pnr;
  2109. }
  2110. HX_RESULT
  2111. CSmilParser::parseDuration(const char* pDuration, CSmilElement* pElement,
  2112.     SMILSyncAttributeTag nTag)
  2113. {
  2114.     HX_RESULT rc = HXR_OK;
  2115.     if(!pDuration)
  2116.     {
  2117. return HXR_FAIL;
  2118.     }
  2119.     const char* pCh = pDuration;
  2120.     // check for event-source
  2121.     // syntax is: id(a)(4s)
  2122.     if(strncmp(pCh, "id(", 3) == 0)
  2123.     {
  2124. rc = parseSmil1SyncbaseValue(pCh, pElement, nTag);
  2125. if (SMILSyncAttrEnd == nTag)
  2126. {
  2127.     // /This is needed to trick the core into letting the
  2128.     // media play when we give it a yet-unresolved end:
  2129.     pElement->m_ulDuration = WAY_IN_THE_FUTURE;
  2130. }
  2131.     }
  2132.     else if(strcmp(pCh, "first") == 0)
  2133.     {
  2134. if(nTag == SMILSyncAttrEndsync)
  2135. {
  2136.     pElement->m_nEndsyncEventSourceTag = SMILEventSourceFirst;
  2137. }
  2138.     }
  2139.     else if(strcmp(pCh, "last") == 0)
  2140.     {
  2141. if(nTag == SMILSyncAttrEndsync)
  2142. {
  2143.     pElement->m_nEndsyncEventSourceTag = SMILEventSourceLast;
  2144. }
  2145.     }
  2146.     else if(strcmp(pCh, "all") == 0)
  2147.     {
  2148. if(nTag == SMILSyncAttrEndsync)
  2149. {
  2150.     pElement->m_nEndsyncEventSourceTag = SMILEventSourceAll;
  2151. }
  2152.     }
  2153.     else if(strcmp(pCh, "indefinite") == 0)
  2154.     {
  2155. // /Fixes PR-28674: dur="indefinite" should be allowed on time
  2156. // containers, too:
  2157. #if defined(DONT_ALLOW_INDEFINITE_ON_TIME_CONTAINERS)
  2158. // /XXXEH- TODO: find out from Henry Ping why we're limiting this:
  2159. // this is contrary to the SMIL 1 and SMIL 2 specs:
  2160. if (pElement->m_pNode->m_tag == SMILSeq ||
  2161.     pElement->m_pNode->m_tag == SMILExcl  ||
  2162.     pElement->m_pNode->m_tag == SMILPar)
  2163. {
  2164.     rc = HXR_FAIL;
  2165.     CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  2166.     errHandler.ReportError(SMILErrorIndefiniteNotSupported, NULL,
  2167. pElement->m_pNode->m_ulTagStartLine);
  2168. }
  2169. else
  2170. #endif
  2171. if (nTag == SMILSyncAttrMax)
  2172. {
  2173.     ; // /Nothing to do;"indefinite" is equivalent to ignoring max value
  2174. }
  2175. else if (nTag == SMILSyncAttrEnd  ||
  2176. // /end AND dur can each have the value "indefinite":
  2177. nTag == SMILSyncAttrDur)
  2178. {
  2179.     // /NOT setting the following to TRUE helps fix
  2180.     // SMIL 2.0 Interop Timing #18.8 where setDuration()
  2181.     // wasn't being called on indef-dur element in
  2182.     // CSmilParser::durationResolved() so parent never
  2183.     // got a chance to properly calculate its endsync behavior.
  2184.     // (The player won't go from "live" to a duration once
  2185.     // a stream that's still playing is declared to be "live"
  2186.     // via the setProperty...("indefiniteduration"...) in
  2187.     // handleSource() in SMIL doc renderer:
  2188. #if defined(XXXEH_OLD_SPECIAL_CASE_HANDLING_OF_INDEF_DUR)
  2189.     pElement->m_bIndefiniteDuration = TRUE;
  2190. #endif
  2191.     // /XXXEH- this is needed to trick the core into letting the
  2192.     // media play when we give it an indefinite end:
  2193.     pElement->m_ulDuration = WAY_IN_THE_FUTURE;
  2194. }
  2195.     }
  2196.     else if (strncmp(pCh, "marker=", 7) == 0 &&
  2197.              (nTag == SMILSyncAttrClipBegin ||
  2198.               nTag == SMILSyncAttrClipEnd))
  2199.     {
  2200.         // Advance past the "marker="
  2201.         pCh += 7;
  2202.         // Parse the marker
  2203.         if (nTag == SMILSyncAttrClipBegin)
  2204.         {
  2205.             rc = parseMarkerClipBeginEnd(pCh,
  2206.                                          pElement->m_pszClipBeginMarkerName,
  2207.                                          pElement->m_pszClipBeginExternalMarkerFileName);
  2208.             if (SUCCEEDED(rc))
  2209.             {
  2210.                 pElement->m_bClipBeginUsesMarker = TRUE;
  2211.                 if (pElement->m_pszClipBeginExternalMarkerFileName)
  2212.                 {
  2213.                     pElement->m_bUsesExternalMediaMarkerFile = TRUE;
  2214.                     // Add this element to the list
  2215.                     if (!m_pClipBeginMarkerList)
  2216.                     {
  2217.                         m_pClipBeginMarkerList = new CHXSimpleList();
  2218.                     }
  2219.                     if (m_pClipBeginMarkerList)
  2220.                     {
  2221.                         m_pClipBeginMarkerList->AddTail((void*) pElement);
  2222.                     }
  2223.                 }
  2224.             }
  2225.         }
  2226.         else
  2227.         {
  2228.             rc = parseMarkerClipBeginEnd(pCh,
  2229.                                          pElement->m_pszClipEndMarkerName,
  2230.                                          pElement->m_pszClipEndExternalMarkerFileName);
  2231.             if (SUCCEEDED(rc))
  2232.             {
  2233.                 pElement->m_bClipEndUsesMarker = TRUE;
  2234.                 if (pElement->m_pszClipEndExternalMarkerFileName)
  2235.                 {
  2236.                     pElement->m_bUsesExternalMediaMarkerFile = TRUE;
  2237.                     // Add this element to the list
  2238.                     if (!m_pClipEndMarkerList)
  2239.                     {
  2240.                         m_pClipEndMarkerList = new CHXSimpleList();
  2241.                     }
  2242.                     if (m_pClipEndMarkerList)
  2243.                     {
  2244.                         m_pClipEndMarkerList->AddTail((void*) pElement);
  2245.                     }
  2246.                 }
  2247.             }
  2248.         }
  2249.     }
  2250.     else if (strcmp(pCh, "media") == 0)
  2251.     {
  2252. if(nTag == SMILSyncAttrMin)
  2253. {
  2254.     pElement->m_bUseMediaDurForMinDur = TRUE;
  2255. }
  2256. else if(nTag == SMILSyncAttrMax)
  2257. {
  2258.     pElement->m_bUseMediaDurForMaxDur = TRUE;
  2259. }
  2260.     }
  2261.     else
  2262.     {
  2263. UINT32 ulClockValue = 0;
  2264. // /First, see if this is pointing to a child id:
  2265. // Don't waste time if it doesn't start with alpha char, '_', or ':'
  2266. BOOL bHandled = FALSE;
  2267.         if (':' == *pCh  ||  '_' == *pCh  ||  isalpha(*pCh) )
  2268. {
  2269.     if (HXR_OK == parseSmil1SyncbaseValue(pCh, pElement, nTag))
  2270.     {
  2271. bHandled = TRUE;
  2272.     }
  2273. }
  2274. if(!bHandled)
  2275. {
  2276.     if (HXR_OK == parseClockValue(pCh, ulClockValue))
  2277.     {
  2278. switch(nTag)
  2279. {
  2280.     case SMILSyncAttrBegin:
  2281.     {
  2282. pElement->m_lBeginOffset = (INT32)ulClockValue;
  2283. pElement->m_bBeginOffsetSet = TRUE;
  2284. // /This needs to be handled here for time containers:
  2285. pElement->m_bCurBeginIsOffsetFromSyncBase = TRUE;
  2286. pElement->m_ulBeginOffsetFromSyncBase =
  2287. pElement->m_lBeginOffset;
  2288.     }
  2289.     break;
  2290.     case SMILSyncAttrEnd:
  2291.     {
  2292. pElement->m_lEndOffset = (INT32)ulClockValue;
  2293. pElement->m_bEndOffsetSet = TRUE;
  2294.     }
  2295.     break;
  2296.     case SMILSyncAttrDur:
  2297.     {
  2298. pElement->m_ulDuration = ulClockValue;
  2299.     }
  2300.     break;
  2301.     case SMILSyncAttrMin:
  2302.     {
  2303. // /Spec says that, if min>max, we should ignore
  2304. // both of their values:
  2305. if (pElement->m_ulMaxActiveDur != ((UINT32)-1)  &&
  2306. pElement->m_ulMaxActiveDur < ulClockValue)
  2307. {
  2308.     // /Reset max to essentially indefinite:
  2309.     pElement->m_ulMaxActiveDur = ((UINT32)-1);
  2310. }
  2311. else // /OK to set min:
  2312. {
  2313.     pElement->m_ulMinActiveDur = ulClockValue;
  2314. }
  2315.     }
  2316.     break;
  2317.     case SMILSyncAttrMax:
  2318.     {
  2319. // /Spec says that, if min>max, we should ignore
  2320. // both of their values:
  2321. if (pElement->m_ulMinActiveDur != 0  &&
  2322. pElement->m_ulMinActiveDur > ulClockValue)
  2323. {
  2324.     // /Reset min to 0:
  2325.     pElement->m_ulMinActiveDur = 0;
  2326. }
  2327. else  // /OK to set max:
  2328. {
  2329.     pElement->m_ulMaxActiveDur = ulClockValue;
  2330. }
  2331.     }
  2332.     break;
  2333.     case SMILSyncAttrEndsync:
  2334.     {
  2335. pElement->m_ulEndSync = ulClockValue;
  2336.     }
  2337.     break;
  2338.     case SMILSyncAttrClipBegin:
  2339.     {
  2340. pElement->m_ulAuthoredClipBegin = ulClockValue;
  2341. pElement->m_ulClipBegin = ulClockValue;
  2342.     }
  2343.     break;
  2344.     case SMILSyncAttrClipEnd:
  2345.     {
  2346. pElement->m_ulClipEnd = ulClockValue;
  2347.     }
  2348.     break;
  2349.     case SMILSyncAttrSyncTolerance:
  2350.     {
  2351. pElement->m_ulSyncTolerance = ulClockValue;
  2352.     }
  2353.     break;
  2354.     case SMILSyncAttrSyncToleranceDefault:
  2355.     {
  2356. pElement->m_ulSyncToleranceDefault = ulClockValue;
  2357.     }
  2358.     break;
  2359.     default:
  2360.     break;
  2361. }
  2362.     }
  2363.     else
  2364.     {
  2365. rc = HXR_FAIL;
  2366. CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  2367. errHandler.ReportError(SMILErrorBadDuration, pCh,
  2368.     pElement->m_pNode->m_ulTagStartLine);
  2369.     }
  2370. }
  2371.     }
  2372.     return rc;
  2373. }
  2374. HX_RESULT CSmilParser::parseMarkerClipBeginEnd(const char* pszStr,
  2375.                                                REF(char*)  rpszMarkerName,
  2376.                                                REF(char*)  rpszExtFileName)
  2377. {
  2378.     HX_RESULT retVal = HXR_OK;
  2379.     if (pszStr)
  2380.     {
  2381.         // Parse the marker
  2382.         CHXString cMarker;
  2383.         CHXString cExtFileName;
  2384.         BOOL      bIsExternal = FALSE;
  2385.         retVal = parseMarkerURI(pszStr, cMarker, bIsExternal, cExtFileName);
  2386.         if (SUCCEEDED(retVal))
  2387.         {
  2388.             // Copy the marker name
  2389.             HX_VECTOR_DELETE(rpszMarkerName);
  2390.             rpszMarkerName = new char [cMarker.GetLength() + 1];
  2391.             if (rpszMarkerName)
  2392.             {
  2393.                 strcpy(rpszMarkerName, cMarker); /* Flawfinder: ignore */
  2394.                 // If the marker is external, then copy the external file name
  2395.                 if (bIsExternal)
  2396.                 {
  2397.                     HX_VECTOR_DELETE(rpszExtFileName);
  2398.                     rpszExtFileName = new char [cExtFileName.GetLength() + 1];
  2399.                     if (rpszExtFileName)
  2400.                     {
  2401.                         // Copy the string
  2402.                         strcpy(rpszExtFileName, cExtFileName); /* Flawfinder: ignore */
  2403.                     }
  2404.                     else
  2405.                     {
  2406.                         retVal = HXR_OUTOFMEMORY;
  2407.                     }
  2408.                 }
  2409.             }
  2410.             else
  2411.             {
  2412.                 retVal = HXR_OUTOFMEMORY;
  2413.             }
  2414.         }
  2415.     }
  2416.     else
  2417.     {
  2418.         retVal = HXR_FAIL;
  2419.     }
  2420.     return retVal;
  2421. }
  2422. HX_RESULT
  2423. CSmilParser::adjustDuration(CSmilElement* pElement)
  2424. {
  2425.     HX_RESULT rc = HXR_OK;
  2426.     // check for duration errors
  2427.     if(pElement->m_bEndOffsetSet)
  2428.     {
  2429. // /We weren't taking MIN(end-b, dur) as we should in the case where
  2430. // there is no begin offset set.  So, <ref dur="5s" end="8s"/> now
  2431. // plays for 5s but used to play for 8s, while adding begin="0s" to
  2432. // that *did* work before (and still does):
  2433. LONG32 lBeginOffset = 0;
  2434. if(pElement->m_bBeginOffsetSet)
  2435. {
  2436.     lBeginOffset = pElement->m_lBeginOffset;
  2437. }
  2438. if (!pElement->m_bIndefiniteBegin) // /Else all this is moot.
  2439. {
  2440.     if(pElement->m_lEndOffset <
  2441. pElement->m_lBeginOffset)
  2442.     {
  2443. pElement->m_ulDuration = 0;
  2444. goto exit;
  2445.     }
  2446.     if(pElement->m_ulDuration != (UINT32)-1)
  2447.     {
  2448. if((INT32)pElement->m_ulDuration !=
  2449.     pElement->m_lEndOffset -
  2450.     pElement->m_lBeginOffset)
  2451. {
  2452.     // If the element has both an explicit dur and an explicit
  2453.     // end, the desired end is the minimum of: the sum of the
  2454.     // desired begin and the explicit dur; and the explicit end.
  2455.     // override "dur"
  2456.     if (pElement->m_lBeginOffset + (INT32)pElement->m_ulDuration >
  2457. pElement->m_lEndOffset)
  2458.     {
  2459. // we want to override the duration, because it is
  2460. // greater than the end offset.
  2461. INT32 offset = pElement->m_lEndOffset -
  2462.     pElement->m_lBeginOffset;
  2463. pElement->m_ulDuration = (offset >= 0 ? (UINT32)offset: 0);
  2464.     }
  2465.     else
  2466.     {
  2467. // else we want to use the current duration,
  2468. // and override the end offset.
  2469. pElement->m_lEndOffset = pElement->m_lBeginOffset
  2470.     + pElement->m_ulDuration;
  2471.     }
  2472.     goto exit;
  2473. }
  2474.     }
  2475. }
  2476. else // /No valid begin offset
  2477. {
  2478.     HX_ASSERT(0  &&  "ehodge: can't adjust dur when begin is indef");
  2479. #if defined(XXXEH_REMOVE_THIS_IF_TESTING_PROVES_OK_TO)
  2480.     if(pElement->m_ulDuration != (UINT32)-1)
  2481.     {
  2482. if(pElement->m_lEndOffset <
  2483.     (INT32)pElement->m_ulDuration)
  2484. {
  2485.     pElement->m_ulDuration = (pElement->m_lEndOffset >= 0 ?
  2486. (UINT32)pElement->m_lEndOffset: 0);
  2487.     goto exit;
  2488. }
  2489.     }
  2490. #endif
  2491. }
  2492.     }
  2493.     // adjust for begin/end/dur attributes
  2494.     if(pElement->m_ulDuration == (UINT32)-1) // duration not set
  2495.     {
  2496. if(pElement->m_bEndOffsetSet)
  2497. {
  2498.     // has an end but no duration
  2499.     if(pElement->m_bBeginOffsetSet)
  2500.     {
  2501. // /We need to do the following to protect from the case
  2502. // where (end-begin) overflows LONG32 val and otherwise
  2503. // results in a bad duration value:
  2504. double dEndOffset = (double)
  2505. ((float)pElement->m_lEndOffset);
  2506. double dBeginOffset = (double)
  2507. ((float)pElement->m_lBeginOffset);
  2508. double diff = dEndOffset - dBeginOffset;
  2509. BOOL bDurationTooLarge = (diff > 0x7FFFFFFF);
  2510. if (bDurationTooLarge)
  2511. {
  2512.     // /XXXEH- TODO: figure out a way to have a longer
  2513.     // duration than 23 days (as in SMIL 2.0 Interop
  2514.     // Timing test #26.1):
  2515.     if (dBeginOffset < 0  &&
  2516.     pElement->m_lEndOffset<WAY_IN_THE_FUTURE)
  2517.     {
  2518. pElement->m_ulDuration = pElement->m_lEndOffset;
  2519. // /Now, we'll use negative begin as our clip-begin
  2520. // and then set the begin to 0:
  2521. if ((UINT32)-1 == pElement->m_ulClipBegin)
  2522. {
  2523.     pElement->m_ulClipBegin =
  2524.     (UINT32)(-pElement->m_lBeginOffset);
  2525. }
  2526. else // /Add to it:
  2527. {
  2528.     pElement->m_ulClipBegin -=
  2529.     pElement->m_lBeginOffset;
  2530. }
  2531. pElement->m_lBeginOffset = 0;
  2532.     }
  2533.     else
  2534.     {
  2535. pElement->m_ulDuration = WAY_IN_THE_FUTURE;
  2536.     }
  2537. }
  2538. else
  2539. {
  2540.     pElement->m_ulDuration = (pElement->m_lEndOffset -
  2541. pElement->m_lBeginOffset >= 0 ?
  2542. (UINT32)(pElement->m_lEndOffset -
  2543. pElement->m_lBeginOffset): 0);
  2544. }
  2545.     }
  2546.     else
  2547.     {
  2548. pElement->m_ulDuration = (pElement->m_lEndOffset >= 0 ?
  2549. (UINT32)pElement->m_lEndOffset: 0);
  2550.     }
  2551. }
  2552.     }
  2553.     else    // explicit duration set
  2554.     {
  2555. if(pElement->m_bEndOffsetSet)
  2556. {
  2557.     // has a duration and an end
  2558.     UINT32 ulDur = 0;
  2559.     if(pElement->m_bBeginOffsetSet)
  2560.     {
  2561. ulDur = (pElement->m_lEndOffset -
  2562.          pElement->m_lBeginOffset >= 0 ?
  2563. (UINT32)(pElement->m_lEndOffset -
  2564.          pElement->m_lBeginOffset): 0);
  2565.     }
  2566.     else
  2567.     {
  2568. ulDur = (pElement->m_lEndOffset >= 0 ?
  2569. (UINT32)pElement->m_lEndOffset: 0);
  2570.     }
  2571.     pElement->m_ulDuration = ulDur;
  2572. }
  2573.     }
  2574. exit:
  2575.     return rc;
  2576. }
  2577. void
  2578. CSmilParser::badAttributeError(SMILNodeTag tag, const char* pAttrName,
  2579.        UINT32 ulLineNumber, BOOL bJustStore)
  2580. {
  2581.     const char* pTagName = "unknown";
  2582.     // get tag name from table
  2583.     int i = 0;
  2584.     SMILNodeTag thisTag = SmilTagTable[i].m_tag;
  2585.     while(thisTag != SMILUnknown)
  2586.     {
  2587. if(thisTag == tag)
  2588. {
  2589.     pTagName = SmilTagTable[i].m_name;
  2590.     break;
  2591. }
  2592. ++i;
  2593. thisTag = SmilTagTable[i].m_tag;
  2594.     }
  2595.     char tmpBuf[256]; /* Flawfinder: ignore */
  2596.     SafeSprintf(tmpBuf, 256, "<%s>: %s",
  2597. pTagName, pAttrName);
  2598.     if (m_bStoreErrors)
  2599.     {
  2600. storeError(SMILErrorUnrecognizedAttribute, tmpBuf, 0,
  2601.     ulLineNumber, 0, FALSE);
  2602.     }
  2603.     if (!bJustStore)
  2604.     {
  2605. CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  2606. errHandler.ReportError(SMILErrorUnrecognizedAttribute, tmpBuf, ulLineNumber);
  2607.     }
  2608. }
  2609. CSmilMeta*
  2610. CSmilParser::makeMeta(SMILNode* pNode)
  2611. {
  2612.     CSmilMeta* pMeta = new CSmilMeta(pNode);
  2613.     if(pNode->m_pValues)
  2614.     {
  2615. const char* pName = 0;
  2616. IHXBuffer* pBuf = 0;
  2617. HX_RESULT rc = pNode->m_pValues->GetFirstPropertyCString(pName, pBuf);
  2618. while(HXR_OK == rc)
  2619. {
  2620.             SMIL2Attribute eAttr = getSMIL2Attribute(pName);
  2621.             switch(eAttr)
  2622.             {
  2623.                 case SMIL2AttrName:
  2624.             {
  2625.         pMeta->m_name = (const char*)pBuf->GetBuffer();
  2626.             }
  2627.                     break;
  2628.                 case SMIL2AttrContent:
  2629.             {
  2630.         pMeta->m_content = (const char*)pBuf->GetBuffer();
  2631.             }
  2632.                     break;
  2633.             }
  2634.     HX_RELEASE(pBuf);
  2635.     rc = pNode->m_pValues->GetNextPropertyCString(pName, pBuf);
  2636. }
  2637. HX_RELEASE(pBuf);
  2638. // check for 'base'
  2639. if(pMeta->m_name == "base")
  2640. {
  2641.     HX_DELETE(m_pBasePath);
  2642.     m_pBasePath = new_string((const char*)pMeta->m_content);
  2643.     HX_RELEASE(pBuf);
  2644. }
  2645.     }
  2646.     return pMeta;
  2647. }
  2648. CSmilMetadata*
  2649. CSmilParser::makeMetadata(SMILNode* pNode)
  2650. {
  2651.     CSmilMetadata* pMetadata = new CSmilMetadata(pNode);
  2652.     return pMetadata;
  2653. }
  2654. CSmilRendererPreFetch*
  2655. CSmilParser::makeRendererPreFetch(SMILNode* pNode)
  2656. {
  2657.     CSmilRendererPreFetch* pRenderer =
  2658. new CSmilRendererPreFetch(pNode);
  2659.     if(pNode->m_pValues)
  2660.     {
  2661. const char* pName = 0;
  2662. IHXBuffer* pBuf = 0;
  2663. HX_RESULT rc = pNode->m_pValues->GetFirstPropertyCString(pName, pBuf);
  2664. while(HXR_OK == rc)
  2665. {
  2666.     if(strcmp(pName, "type") == 0)
  2667.     {
  2668. pRenderer->m_mimeType = (const char*)pBuf->GetBuffer();
  2669.     }
  2670.     rc = pNode->m_pValues->GetNextPropertyCString(pName, pBuf);
  2671. }
  2672.     }
  2673.     return pRenderer;
  2674. }
  2675. CSmilRootLayout*
  2676. CSmilParser::makeRootLayout(SMILNode* pNode)
  2677. {
  2678.     CSmilRootLayout* pRoot  = NULL;
  2679.     HX_RESULT        retVal = HXR_OK;
  2680.     if (pNode && pNode->m_pValues)
  2681.     {
  2682.         if (!m_bSMILRootLayoutAlreadyFound)
  2683.         {
  2684.             pRoot = new CSmilRootLayout(pNode);
  2685.             if (pRoot)
  2686.             {
  2687.                 BOOL        bFoundBGColor = FALSE;
  2688.                 const char* pName         = NULL;
  2689.                 IHXBuffer* pBuf          = NULL;
  2690.                 HX_RESULT rc = pNode->m_pValues->GetFirstPropertyCString(pName, pBuf);
  2691.                 while(SUCCEEDED(rc) && SUCCEEDED(retVal))
  2692.                 {
  2693.     const char* pszValue =
  2694.     NULL!=pBuf?(const char*) pBuf->GetBuffer():NULL;
  2695.                     // Check if the attribute is a legal namespaced attribute
  2696.                     const char*     pszNSAttr = NULL;
  2697.                     CNamespaceInfo* pNSInfo = getNamespaceInfo(pName, pszNSAttr);
  2698.                     SMIL2Attribute eAttr = getSMIL2Attribute(pName);
  2699.                     switch (eAttr)
  2700.                     {
  2701.                         case SMIL2AttrWidth:
  2702.                             {
  2703.                                 retVal = parseRegionDimension(pszValue,
  2704.                                                               pRoot->m_dWidth,
  2705.                                                               pRoot->m_eWidthType);
  2706.                             }
  2707.                             break;
  2708.                         case SMIL2AttrHeight:
  2709.                             {
  2710.                                 retVal = parseRegionDimension(pszValue,
  2711.                                                               pRoot->m_dHeight,
  2712.                                                               pRoot->m_eHeightType);
  2713.                             }
  2714.                             break;
  2715.                         case SMIL2AttrBackgroundColor:
  2716.                             {
  2717.                                 bFoundBGColor = TRUE;
  2718.                                 retVal = parseColor(pszValue,
  2719.                                                     pRoot->m_ulBackgroundColor,
  2720.                                                     pRoot->m_eBackgroundColorType);
  2721.                             }
  2722.                             break;
  2723.                         default:
  2724.                             {
  2725.                                 if (!strcmp(pName, "background-color"))
  2726.                                 {
  2727.                                     // This check makes the parse prefer backgroundColor over
  2728.                                     // background-color if both are present
  2729.                                     if (!bFoundBGColor)
  2730.                                     {
  2731.                                         retVal = parseColor(pszValue,
  2732.                                                             pRoot->m_ulBackgroundColor,
  2733.                                                             pRoot->m_eBackgroundColorType);
  2734.                                     }
  2735.                                 }
  2736.                                 else if (pNSInfo && pszNSAttr &&
  2737.                                          (pNSInfo->m_eNamespace == NamespaceSizeControl ||
  2738.                                           pNSInfo->m_eNamespace == NamespaceSendTo ||
  2739.                                           pNSInfo->m_eNamespace == NamespaceAllSMIL2Extensions))
  2740.                                 {
  2741.                                     if (!strcmp(pszNSAttr, "resizeBehavior"))
  2742.                                     {
  2743.                                         if (!strcmp(pszValue, "zoom"))
  2744.                                         {
  2745.                                             pRoot->m_eResizeBehavior = ResizeZoom;
  2746.                                         }
  2747.                                         else if (!strcmp(pszValue, "percentOnly"))
  2748.                                         {
  2749.                                             pRoot->m_eResizeBehavior = ResizePercentOnly;
  2750.                                         }
  2751.                                         else
  2752.                                         {
  2753.                                             retVal = HXR_FAIL;
  2754.                                         }
  2755.                                     }
  2756.                                     else if (!strcmp(pszNSAttr, "contextWindow"))
  2757.                                     {
  2758.                                         if (!strcmp(pszValue, "auto"))
  2759.                                         {
  2760.                                             pRoot->m_eContextWindow = ContextWindowAuto;
  2761.                                         }
  2762.                                         else if (!strcmp(pszValue, "openAtStart"))
  2763.                                         {
  2764.                                             pRoot->m_eContextWindow = ContextWindowOpenAtStart;
  2765.                                         }
  2766.                                         else
  2767.                                         {
  2768.                                             retVal = HXR_FAIL;
  2769.                                         }
  2770.                                     }
  2771.                                 }
  2772.                             }
  2773.                     }
  2774.                     if (FAILED(retVal))
  2775.                     {
  2776.                         CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  2777.                         errHandler.ReportError(SMILErrorBadAttribute,
  2778.                                                pszValue,
  2779.                                                pNode->m_ulTagStartLine);
  2780.                     }
  2781.                     HX_RELEASE(pBuf);
  2782.                     if (SUCCEEDED(retVal))
  2783.                     {
  2784.                         rc = pNode->m_pValues->GetNextPropertyCString(pName, pBuf);
  2785.                     }
  2786.                 }
  2787.             }
  2788.             else
  2789.             {
  2790.                 retVal = HXR_OUTOFMEMORY;
  2791.             }
  2792.         }
  2793.         else
  2794.         {
  2795.             CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  2796.             errHandler.ReportError(SMILErrorUnexpectedTag,
  2797.                                    (const char*) pNode->m_name,
  2798.                                    pNode->m_ulTagStartLine);
  2799.             retVal = HXR_FAIL;
  2800.         }
  2801.     }
  2802.     if (SUCCEEDED(retVal))
  2803.     {
  2804.         m_bSMILRootLayoutAlreadyFound = TRUE;
  2805.     }
  2806.     else
  2807.     {
  2808.         HX_DELETE(pRoot);
  2809.     }
  2810.     return pRoot;
  2811. }
  2812. CSmilRegion*
  2813. CSmilParser::makeRegion(SMILNode* pNode)
  2814. {
  2815.     HX_RESULT    retVal  = HXR_OK;
  2816.     CSmilRegion* pRegion = NULL;
  2817.     if (pNode && pNode->m_pValues)
  2818.     {
  2819.         pRegion = new CSmilRegion(pNode);
  2820.         if (pRegion)
  2821.         {
  2822.             BOOL        bParsedBGColor = FALSE;
  2823.             BOOL        bParsedOpacity = FALSE;
  2824.             BOOL        bGotNewStyleBG = FALSE;
  2825.             UINT32      ulOpacity      = 0;
  2826.             const char* pName          = NULL;
  2827.             IHXBuffer* pBuf           = NULL;
  2828.             HX_RESULT   rc             = pNode->m_pValues->GetFirstPropertyCString(pName, pBuf);
  2829.             while(SUCCEEDED(rc) && SUCCEEDED(retVal))
  2830.             {
  2831.                 // Get the attribute value
  2832. const char* pszValue =
  2833. NULL!=pBuf?(const char*) pBuf->GetBuffer():NULL;
  2834.                 // Map the attribute name
  2835.                 SMIL2Attribute eAttr = getSMIL2Attribute(pName);
  2836.                 switch (eAttr)
  2837.                 {
  2838.                     case SMIL2AttrLeft:
  2839.                         {
  2840.                             retVal = parseRegionDimension(pszValue,
  2841.                                                           pRegion->m_Rect.m_dLeft,
  2842.                                                           pRegion->m_Rect.m_eLeftType);
  2843.                         }
  2844.                         break;
  2845.                     case SMIL2AttrTop:
  2846.                         {
  2847.                             retVal = parseRegionDimension(pszValue,
  2848.                                                           pRegion->m_Rect.m_dTop,
  2849.                                                           pRegion->m_Rect.m_eTopType);
  2850.                         }
  2851.                         break;
  2852.                     case SMIL2AttrRight:
  2853.                         {
  2854.                             retVal = parseRegionDimension(pszValue,
  2855.                                                           pRegion->m_Rect.m_dRight,
  2856.                                                           pRegion->m_Rect.m_eRightType);
  2857.                         }
  2858.                         break;
  2859.                     case SMIL2AttrBottom:
  2860.                         {
  2861.                             retVal = parseRegionDimension(pszValue,
  2862.                                                           pRegion->m_Rect.m_dBottom,
  2863.                                                           pRegion->m_Rect.m_eBottomType);
  2864.                         }
  2865.                         break;
  2866.                     case SMIL2AttrWidth:
  2867.                         {
  2868.                             retVal = parseRegionDimension(pszValue,
  2869.                                                           pRegion->m_Rect.m_dWidth,
  2870.                                                           pRegion->m_Rect.m_eWidthType);
  2871.                         }
  2872.                         break;
  2873.                     case SMIL2AttrHeight:
  2874.                         {
  2875.                             retVal = parseRegionDimension(pszValue,
  2876.                                                           pRegion->m_Rect.m_dHeight,
  2877.                                                           pRegion->m_Rect.m_eHeightType);
  2878.                         }
  2879.                         break;
  2880.                     case SMIL2AttrZ_Index:
  2881.                         {
  2882.                             retVal = parseZIndex(pszValue,
  2883.                                                  pRegion->m_lZIndex,
  2884.                                                  pRegion->m_eZIndexType);
  2885.                         }
  2886.                         break;
  2887.                     case SMIL2AttrFit:
  2888.                         {
  2889.                             retVal = parseFit(pszValue, pRegion->m_eFit);
  2890.                         }
  2891.                         break;
  2892.                     case SMIL2AttrShowBackground:
  2893.                         {
  2894.                             if (!strcmp(pszValue, "always"))
  2895.                             {
  2896.                                 pRegion->m_eShowBackground = ShowBackgroundAlways;
  2897.                             }
  2898.                             else if (!strcmp(pszValue, "whenActive"))
  2899.                             {
  2900.                                 pRegion->m_eShowBackground = ShowBackgroundWhenActive;
  2901.                             }
  2902.                             else
  2903.                             {
  2904.                                 retVal = HXR_FAIL;
  2905.                             }
  2906.                         }
  2907.                         break;
  2908.                     case SMIL2AttrSoundLevel:
  2909.                         {
  2910.                             char*  pEndPtr = NULL;
  2911.                             double dVal    = strtod(pszValue, &pEndPtr);
  2912.                             if (pEndPtr && *pEndPtr == '%')
  2913.                             {
  2914.                                 pRegion->m_dSoundLevel = dVal;
  2915.                             }
  2916.                             else
  2917.                             {
  2918.                                 retVal = HXR_FAIL;
  2919.                             }
  2920.                         }
  2921.                         break;
  2922.                     case SMIL2AttrRegionName:
  2923.                         {
  2924.                             pRegion->m_RegionName           = pszValue;
  2925.                             pRegion->m_bRegionNameSpecified = TRUE;
  2926.                         }
  2927.                         break;
  2928.                     case SMIL2AttrBackgroundColor:
  2929.                         {
  2930.                             // Get the background color
  2931.                             retVal = parseColor(pszValue,
  2932.                                                 pRegion->m_ulBackgroundColor,
  2933.                                                 pRegion->m_eBackgroundColorType);
  2934.                             if (SUCCEEDED(retVal))
  2935.                             {
  2936.                                 bParsedBGColor = TRUE;
  2937.                                 bGotNewStyleBG = TRUE;
  2938.                             }
  2939.                         }
  2940.                         break;
  2941.                     default:
  2942.                         {
  2943.                             if (strcmp(pName, "background-color") == 0 &&
  2944.                                 !bGotNewStyleBG)
  2945.                             {
  2946.                                 // Get the background color
  2947.                                 retVal = parseColor(pszValue,
  2948.                                                     pRegion->m_ulBackgroundColor,
  2949.                                                     pRegion->m_eBackgroundColorType);
  2950.                                 if (SUCCEEDED(retVal))
  2951.                                 {
  2952.                                     bParsedBGColor = TRUE;
  2953.                                 }
  2954.                             }
  2955.                             else
  2956.                             {
  2957.                                 // Check if the attribute is a legal namespaced attribute
  2958.                                 const char*     pszNSAttr = NULL;
  2959.                                 CNamespaceInfo* pNSInfo = getNamespaceInfo(pName, pszNSAttr);
  2960.                                 if (pNSInfo)
  2961.                                 {
  2962.                                     if (pNSInfo->m_eNamespace == NamespaceAlphaControl ||
  2963.                                         pNSInfo->m_eNamespace == NamespaceAllSMIL2Extensions)
  2964.                                     {
  2965.                                         if(!strcmp(pszNSAttr, "opacity"))
  2966.                                         {
  2967.                                             // Parse the opacity
  2968.                                             retVal = parseOpacity(pszValue, ulOpacity);
  2969.                                             if (SUCCEEDED(retVal))
  2970.                                             {
  2971.                                                 bParsedOpacity = TRUE;
  2972.                                             }
  2973.                                         }
  2974.                                     }
  2975.                                 }
  2976.                             }
  2977.                         }
  2978.                 }
  2979.                 HX_RELEASE(pBuf);
  2980.                 if (SUCCEEDED(retVal))
  2981.                 {
  2982.                     rc = pNode->m_pValues->GetNextPropertyCString(pName, pBuf);
  2983.                 }
  2984.                 else
  2985.                 {
  2986.                     CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  2987.                     errHandler.ReportError(SMILErrorBadAttribute,
  2988.                                            pName,
  2989.                                            pRegion->m_pNode->m_ulTagStartLine);
  2990.                 }
  2991.             }
  2992.             if (SUCCEEDED(retVal))
  2993.             {
  2994.                 // Compute alpha from opacity - the value
  2995.                 // coming out of parseOpacity() is guaranteed to
  2996.                 // be in the range [0,255]
  2997.                 UINT32 ulAlpha = 255 - ulOpacity;
  2998.                 // Process the opacity and background color. By default,
  2999.                 // m_ulBackgroundColor = 0xFF000000 (transparent). Here are
  3000.                 // the four cases:
  3001.                 //
  3002.                 // 1) Both backgroundColor and rn:opacity are specified - we
  3003.                 //    should use the RRGGBB from parseColor and the opacity
  3004.                 //    value from rn:opacity
  3005.                 // 2) backgroundColor is specified, but rn:opacity is not.
  3006.                 //    The resulting color must be opaque in order to be
  3007.                 //    backwards-compatible. Since parseColor() puts in 0x00
  3008.                 //    for the alpha channel (opaque), then we don't have to
  3009.                 //    do anything here.
  3010.                 // 3) rn:opacity was specified, but backgroundColor was not.
  3011.                 //    Kinda unclear what to do here, since the backgroundColor
  3012.                 //    default is "transparent", but I will take this to mean
  3013.                 //    that the author wants this to be "partially transparent".
  3014.                 //    So we will use the alpha from opacity and put "#000000"
  3015.                 //    (black) for the color. We just as easily chould use
  3016.                 //    "#FFFFFF" (white).
  3017.                 // 4) Neither backgroundColor nor rn:opacity was specified.
  3018.                 //    We have to go with the default of backgroundColor, which
  3019.                 //    is "transparent".
  3020.                 if (bParsedBGColor)
  3021.                 {
  3022.                     if (bParsedOpacity)
  3023.                     {
  3024.                         // Both backgroundColor and rn:opacity are specified
  3025.                         pRegion->m_ulBackgroundColor = (pRegion->m_ulBackgroundColor & 0x00FFFFFF) |
  3026.                                                        (ulAlpha << 24);
  3027.                     }
  3028.                     else
  3029.                     {
  3030.                         // backgroundColor is specified but not rn:opacity. So for
  3031.                         // backwards-compatibility, the resulting color must be
  3032.                         // opaque. So zero out the alpha channel of the color.
  3033.                         // We really shouldn't have to do this, since parseColor
  3034.                         // generally puts 0x00 in the alpha, but we force it here
  3035.                         // "just to be sure".
  3036.                         // The only exception to this rule is if the
  3037.                         // backgroundColor is explicity specified as
  3038.                         // backgroundColor="transparent"
  3039.                         if (pRegion->m_eBackgroundColorType != CSS2TypeTransparent)
  3040.                         {
  3041.                             pRegion->m_ulBackgroundColor &= 0x00FFFFFF;
  3042.                         }
  3043.                     }
  3044.                 }
  3045.                 else
  3046.                 {
  3047.                     if (bParsedOpacity)
  3048.                     {
  3049.                         // rn:opacity was specified, but not backgroundColor, so
  3050.                         // we need to insert the alpha value into the backgroundColor
  3051.                         // We will let the color be #000000.
  3052.                         pRegion->m_ulBackgroundColor = (ulAlpha << 24);
  3053.                     }
  3054.                     else
  3055.                     {
  3056.                         // Neither rn:opacity was specified nor backgroundColor, so
  3057.                         // we must take the backgroundColor default, which is "transparent".
  3058.                         // We really should not have to do anything here, since the
  3059.                         // default of m_ulBackgroundColor in the constructor is 0xFF000000.
  3060.                         // However, we set it here "just to be sure".
  3061.                         pRegion->m_ulBackgroundColor = 0xFF000000;
  3062.                     }
  3063.                 }
  3064.             }
  3065.         }
  3066.         else
  3067.         {
  3068.             retVal = HXR_OUTOFMEMORY;
  3069.         }
  3070.     }
  3071.     else
  3072.     {
  3073.         retVal = HXR_FAIL;
  3074.     }
  3075.     if (FAILED(retVal))
  3076.     {
  3077.         HX_DELETE(pRegion);
  3078.     }
  3079.     return pRegion;
  3080. }
  3081. CSmilRegPoint*
  3082. CSmilParser::makeRegPoint(SMILNode* pNode)
  3083. {
  3084.     HX_RESULT      retVal = HXR_OK;
  3085.     CSmilRegPoint* pRegPt = NULL;
  3086.     if (pNode && pNode->m_pValues)
  3087.     {
  3088.         pRegPt = new CSmilRegPoint(pNode);
  3089.         if (pRegPt)
  3090.         {
  3091.             const char* pName = NULL;
  3092.             IHXBuffer* pBuf  = NULL;
  3093.             HX_RESULT   rc    = pNode->m_pValues->GetFirstPropertyCString(pName, pBuf);
  3094.             while(SUCCEEDED(rc) && SUCCEEDED(retVal))
  3095.             {
  3096.                 // Get the attribute value
  3097. const char* pszValue =
  3098. NULL!=pBuf?(const char*) pBuf->GetBuffer():NULL;
  3099.                 // Get the SMIL2Attribute
  3100.                 SMIL2Attribute eAttr = getSMIL2Attribute(pName);
  3101.                 switch (eAttr)
  3102.                 {
  3103.                     case SMIL2AttrLeft:
  3104.                         {
  3105.                             retVal = parseRegionDimension(pszValue,
  3106.                                                           pRegPt->m_RegPoint.m_dLeft,
  3107.                                                           pRegPt->m_RegPoint.m_eLeftType);
  3108.                         }
  3109.                         break;
  3110.                     case SMIL2AttrTop:
  3111.                         {
  3112.                             retVal = parseRegionDimension(pszValue,
  3113.                                                           pRegPt->m_RegPoint.m_dTop,
  3114.                                                           pRegPt->m_RegPoint.m_eTopType);
  3115.                         }
  3116.                         break;
  3117.                     case SMIL2AttrRight:
  3118.                         {
  3119.                             retVal = parseRegionDimension(pszValue,
  3120.                                                           pRegPt->m_RegPoint.m_dRight,
  3121.                                                           pRegPt->m_RegPoint.m_eRightType);
  3122.                         }
  3123.                         break;
  3124.                     case SMIL2AttrBottom:
  3125.                         {
  3126.                             retVal = parseRegionDimension(pszValue,
  3127.                                                           pRegPt->m_RegPoint.m_dBottom,
  3128.                                                           pRegPt->m_RegPoint.m_eBottomType);
  3129.                         }
  3130.                         break;
  3131.                     case SMIL2AttrRegAlign:
  3132.                         {
  3133.                             retVal = parseRegAlign(pszValue, pRegPt->m_RegPoint.m_eRegAlign);
  3134.                         }
  3135.                         break;
  3136.                 }
  3137.                 HX_RELEASE(pBuf);
  3138.                 if (SUCCEEDED(retVal))
  3139.                 {
  3140.                     rc = pNode->m_pValues->GetNextPropertyCString(pName, pBuf);
  3141.                 }
  3142.                 else
  3143.                 {
  3144.                     CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  3145.                     errHandler.ReportError(SMILErrorBadAttribute,
  3146.                                            pName,
  3147.                                            pRegPt->m_pNode->m_ulTagStartLine);
  3148.                 }
  3149.             }
  3150.         }
  3151.         else
  3152.         {
  3153.             retVal = HXR_OUTOFMEMORY;
  3154.         }
  3155.     }
  3156.     else
  3157.     {
  3158.         retVal = HXR_FAIL;
  3159.     }
  3160.     if (FAILED(retVal))
  3161.     {
  3162.         HX_DELETE(pRegPt);
  3163.     }
  3164.     return pRegPt;
  3165. }
  3166. #if defined(HELIX_FEATURE_SMIL2_MULTIWINDOWLAYOUT)
  3167. CSmilViewport*
  3168. CSmilParser::makeViewport(SMILNode* pNode)
  3169. {
  3170.     HX_RESULT      retVal = HXR_OK;
  3171.     CSmilViewport* pView  = NULL;
  3172.     if (pNode && pNode->m_pValues)
  3173.     {
  3174.         pView = new CSmilViewport(pNode);
  3175.         if (pView)
  3176.         {
  3177.             BOOL        bOldStyleBG = FALSE;
  3178.             const char* pName       = NULL;
  3179.             IHXBuffer* pBuf        = NULL;
  3180.             HX_RESULT   rc          = pNode->m_pValues->GetFirstPropertyCString(pName, pBuf);
  3181.             while(SUCCEEDED(rc) && SUCCEEDED(retVal))
  3182.             {
  3183.                 // Get the attribute value
  3184. const char* pszValue =
  3185. NULL!=pBuf?(const char*) pBuf->GetBuffer():NULL;
  3186.                 // Check if the attribute is a legal namespaced attribute
  3187.                 const char*     pszNSAttr = NULL;
  3188.                 CNamespaceInfo* pNSInfo = getNamespaceInfo(pName, pszNSAttr);
  3189.                 // Get the SMIL2Attribute
  3190.                 SMIL2Attribute eAttr = getSMIL2Attribute(pName);
  3191.                 switch (eAttr)
  3192.                 {
  3193.                     case SMIL2AttrWidth:
  3194.                         {
  3195.                             retVal = parseRegionDimension(pszValue,
  3196.                                                           pView->m_dWidth,
  3197.                                                           pView->m_eWidthType);
  3198.                         }
  3199.                         break;
  3200.                     case SMIL2AttrHeight:
  3201.                         {
  3202.                             retVal = parseRegionDimension(pszValue,
  3203.                                                           pView->m_dHeight,
  3204.                                                           pView->m_eHeightType);
  3205.                         }
  3206.                         break;
  3207.                     case SMIL2AttrBackgroundColor:
  3208.                         {
  3209.                             retVal = parseColor(pszValue,
  3210.                                                 pView->m_ulBackgroundColor,
  3211.                                                 pView->m_eBackgroundColorType);
  3212.                         }
  3213.                         break;
  3214.                     case SMIL2AttrOpen:
  3215.                         {
  3216.                             if (!strcmp(pszValue, "onStart"))
  3217.                             {
  3218.                                 pView->m_eOpen = ViewportOpenOnStart;
  3219.                             }
  3220.                             else if (!strcmp(pszValue, "whenActive"))
  3221.                             {
  3222.                                 pView->m_eOpen = ViewportOpenWhenActive;
  3223.                             }
  3224.                             else
  3225.                             {
  3226.                                 retVal = HXR_FAIL;
  3227.                             }
  3228.                         }
  3229.                         break;
  3230.                     case SMIL2AttrClose:
  3231.                         {
  3232.                             if (!strcmp(pszValue, "onRequest"))
  3233.                             {
  3234.                                 pView->m_eClose = ViewportCloseOnRequest;
  3235.                             }
  3236.                             else if(!strcmp(pszValue, "whenNotActive"))
  3237.                             {
  3238.                                 pView->m_eClose = ViewportCloseWhenNotActive;
  3239.                             }
  3240.                             else
  3241.                             {
  3242.                                 retVal = HXR_FAIL;
  3243.                             }
  3244.                         }
  3245.                         break;
  3246.                     default:
  3247.                         {
  3248.                             if (!strcmp(pName, "background-color") &&
  3249.                                 !bOldStyleBG)
  3250.                             {
  3251.                                 retVal = parseColor(pszValue,
  3252.                                                     pView->m_ulBackgroundColor,
  3253.                                                     pView->m_eBackgroundColorType);
  3254.                             }
  3255.                             else if (pNSInfo && pszNSAttr &&
  3256.                                      (pNSInfo->m_eNamespace == NamespaceSizeControl ||
  3257.                                       pNSInfo->m_eNamespace == NamespaceSendTo ||
  3258.                                       pNSInfo->m_eNamespace == NamespaceAllSMIL2Extensions))
  3259.                             {
  3260.                                 if (!strcmp(pszNSAttr, "resizeBehavior"))
  3261.                                 {
  3262.                                     if (!strcmp(pszValue, "zoom"))
  3263.                                     {
  3264.                                         pView->m_eResizeBehavior = ResizeZoom;
  3265.                                     }
  3266.                                     else if (!strcmp(pszValue, "percentOnly"))
  3267.                                     {
  3268.                                         pView->m_eResizeBehavior = ResizePercentOnly;
  3269.                                     }
  3270.                                     else
  3271.                                     {
  3272.                                         retVal = HXR_FAIL;
  3273.                                     }
  3274.                                 }
  3275.                                 else if (!strcmp(pszNSAttr, "contextWindow"))
  3276.                                 {
  3277.                                     if (!strcmp(pszValue, "auto"))
  3278.                                     {
  3279.                                         pView->m_eContextWindow = ContextWindowAuto;
  3280.                                     }
  3281.                                     else if (!strcmp(pszValue, "openAtStart"))
  3282.                                     {
  3283.                                         pView->m_eContextWindow = ContextWindowOpenAtStart;
  3284.                                     }
  3285.                                     else
  3286.                                     {
  3287.                                         retVal = HXR_FAIL;
  3288.                                     }
  3289.                                 }
  3290.                             }
  3291.                         }
  3292.                 }
  3293.                 HX_RELEASE(pBuf);
  3294.                 if (SUCCEEDED(retVal))
  3295.                 {
  3296.                     rc = pNode->m_pValues->GetNextPropertyCString(pName, pBuf);
  3297.                 }
  3298.                 else
  3299.                 {
  3300.                     CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  3301.                     errHandler.ReportError(SMILErrorBadAttribute,
  3302.                                            pName,
  3303.                                            pView->m_pNode->m_ulTagStartLine);
  3304.                 }
  3305.             }
  3306.         }
  3307.         else
  3308.         {
  3309.             retVal = HXR_OUTOFMEMORY;
  3310.         }
  3311.     }
  3312.     else
  3313.     {
  3314.         retVal = HXR_FAIL;
  3315.     }
  3316.     if (FAILED(retVal))
  3317.     {
  3318.         HX_DELETE(pView);
  3319.     }
  3320.     return pView;
  3321. }
  3322. #endif /* #if defined(HELIX_FEATURE_SMIL2_MULTIWINDOWLAYOUT) */
  3323. CSmilCustomTest*
  3324. CSmilParser::makeCustomTest(SMILNode* pNode, REF(HX_RESULT) retVal)
  3325. {
  3326.     retVal = HXR_OK;
  3327.     CSmilCustomTest* pCustomTest  = NULL;
  3328.     if (pNode  &&  pNode->m_pValues)
  3329.     {
  3330.         pCustomTest = new CSmilCustomTest(pNode);
  3331.         if (pCustomTest)
  3332.         {
  3333.             const char* pName = NULL;
  3334.             IHXBuffer* pBuf  = NULL;
  3335.             HX_RESULT   rc    = pNode->m_pValues->GetFirstPropertyCString(
  3336.     pName, pBuf);
  3337.             while(SUCCEEDED(rc) && SUCCEEDED(retVal))
  3338.             {
  3339.                 // Get the attribute value
  3340. const char* pszValue =
  3341. NULL!=pBuf?(const char*) pBuf->GetBuffer():NULL;
  3342. if (pszValue)
  3343. {
  3344.     const char* pWhitespaceRemoved =
  3345.     removeSurroundingWhitespace(pszValue);
  3346.     // Parse the attribute value
  3347.     if (0 == strcmp(pName, "defaultState"))
  3348.     {
  3349. if (!strcmp(pWhitespaceRemoved, "true"))
  3350. {
  3351.     pCustomTest->m_bDefaultState = TRUE;
  3352. }
  3353. else if (!strcmp(pWhitespaceRemoved, "false"))
  3354. {
  3355.     pCustomTest->m_bDefaultState = FALSE;
  3356. }
  3357. else
  3358. {
  3359.     retVal = HXR_INVALID_PARAMETER;
  3360. }
  3361.     }
  3362.     else if (0 == strcmp(pName, "override"))
  3363.     {
  3364. if (!strcmp(pWhitespaceRemoved, "visible"))
  3365. {
  3366.     pCustomTest->m_bOverrideVisible = TRUE;
  3367. }
  3368. else if (!strcmp(pWhitespaceRemoved, "hidden"))
  3369. {
  3370.     pCustomTest->m_bOverrideVisible = FALSE;
  3371. }
  3372. else
  3373. {
  3374.     retVal = HXR_INVALID_PARAMETER;
  3375. }
  3376.     }
  3377.     else if (0 == strcmp(pName, "uid"))
  3378.     {
  3379. pCustomTest->m_uid = pWhitespaceRemoved;
  3380.     }
  3381.     HX_RELEASE(pBuf);
  3382.     if (SUCCEEDED(retVal))
  3383.     {
  3384. rc = pNode->m_pValues->GetNextPropertyCString(
  3385. pName, pBuf);
  3386.     }
  3387.     else
  3388.     {
  3389. CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  3390. errHandler.ReportError(SMILErrorBadAttribute,
  3391. pName,
  3392. pCustomTest->m_pNode->m_ulTagStartLine);
  3393.     }
  3394. }
  3395.             }
  3396.         }
  3397.         else
  3398.         {
  3399.             retVal = HXR_OUTOFMEMORY;
  3400.         }
  3401.     }
  3402.     else
  3403.     {
  3404.         retVal = HXR_UNEXPECTED;
  3405.     }
  3406.     if (FAILED(retVal))
  3407.     {
  3408.         HX_DELETE(pCustomTest);
  3409.     }
  3410.     return pCustomTest;
  3411. }
  3412. HX_RESULT
  3413. CSmilParser::parseCoord(IHXBuffer* pBuf, REF(float) f)
  3414. {
  3415.     HX_RESULT ret = HXR_OK;
  3416.     double d = 0.0;
  3417.     ret = HXParseDouble((const char*)pBuf->GetBuffer(), d);
  3418.     if (d < -2.0 ||
  3419. d > 2.0)
  3420.     {
  3421. ret = HXR_INVALID_PARAMETER;
  3422.     }
  3423.     else
  3424.     {
  3425. f = (float)d;
  3426.     }
  3427.     return ret;
  3428. }
  3429. HX_RESULT
  3430. CSmilParser::parseDigit(IHXBuffer* pBuf, REF(UINT32) ul)
  3431. {
  3432.     HX_RESULT ret = HXR_OK;
  3433.     INT32 num = 0;
  3434.     ret = HXParseDigit((const char*)pBuf->GetBuffer(), num);
  3435.     if (num < 0)
  3436.     {
  3437. ret = HXR_INVALID_PARAMETER;
  3438.     }
  3439.     else
  3440.     {
  3441. ul = (UINT32)num;
  3442.     }
  3443.     return ret;
  3444. }
  3445. #if defined(HELIX_FEATURE_SMIL2_TRANSITIONS)
  3446. CSmilTransition* CSmilParser::makeTransition(SMILNode* pNode, REF(HX_RESULT) retVal)
  3447. {
  3448.     // Initialize the error out parameter
  3449.     retVal = HXR_OK;
  3450.     // Initialize the return value
  3451.     CSmilTransition* pTrans = NULL;
  3452.     // Initialize our flags
  3453.     BOOL bTypePresent    = FALSE;
  3454.     BOOL bTypeLegal      = FALSE;
  3455.     BOOL bSubTypePresent = FALSE;
  3456.     BOOL bSubTypeLegal   = FALSE;
  3457.     // Make sure we have a node
  3458.     if (pNode && pNode->m_pValues)
  3459.     {
  3460.         // Create a CSmilTransition class
  3461.         pTrans = new CSmilTransition(pNode);
  3462.         if (pTrans)
  3463.         {