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

Symbian

开发平台:

C/C++

  1.         }
  2.         HX_RELEASE(pFact);
  3.     }
  4. }
  5. const char* CSmilParser::getEnumAttrString(SMIL2Attribute eAttr, BYTE ucVal)
  6. {
  7.     const char* pRet = NULL;
  8.     struct EnumAttrTable* pEntry = (struct EnumAttrTable*) &g_EnumAttrTable[0];
  9.     while (pEntry && pEntry->m_eAttr != NumSMIL2Attributes)
  10.     {
  11.         if (pEntry->m_eAttr  == eAttr &&
  12.             pEntry->m_ucEnum == ucVal)
  13.         {
  14.             pRet = pEntry->m_pszStr;
  15.             break;
  16.         }
  17.         pEntry++;
  18.     }
  19.     return pRet;
  20. }
  21. BOOL CSmilParser::isAttributeAnimated(const char* pszElementID,
  22.                                       UINT32      ulAttrName)
  23. {
  24.     BOOL bRet = FALSE;
  25. #if defined(HELIX_FEATURE_SMIL2_ANIMATION)
  26.     if (m_pAnimateElementList)
  27.     {
  28.         LISTPOSITION pos = m_pAnimateElementList->GetHeadPosition();
  29.         while (pos)
  30.         {
  31.             CSmilAnimateElement* pAnim =
  32.                 (CSmilAnimateElement*) m_pAnimateElementList->GetNext(pos);
  33.             if (pAnim &&
  34.                 ((UINT32) pAnim->m_ucAttributeName) == ulAttrName &&
  35.                 pAnim->m_pTargetElementID &&
  36.                 *pAnim->m_pTargetElementID == pszElementID)
  37.             {
  38.                 bRet = TRUE;
  39.                 break;
  40.             }
  41.         }
  42.     }
  43. #endif /* #if defined(HELIX_FEATURE_SMIL2_ANIMATION) */
  44.     return bRet;
  45. }
  46. SMIL2Element CSmilParser::getSMIL2Element(const char* pszStr)
  47. {
  48.     SMIL2Element eRet = NumSMIL2Elements;
  49.     if (pszStr && m_pElementMap)
  50.     {
  51.         void* pVoid = NULL;
  52.         if (m_pElementMap->Lookup(pszStr, pVoid))
  53.         {
  54.             eRet = (SMIL2Element) (UINT32) pVoid;
  55.         }
  56.     }
  57.     return eRet;
  58. }
  59. SMIL2Attribute CSmilParser::getSMIL2Attribute(const char* pszStr)
  60. {
  61.     SMIL2Attribute eRet = NumSMIL2Attributes;
  62.     if (pszStr && m_pAttributeMap)
  63.     {
  64.         void* pVoid = NULL;
  65.         if (m_pAttributeMap->Lookup(pszStr, pVoid))
  66.         {
  67.             eRet = (SMIL2Attribute) (UINT32) pVoid;
  68.         }
  69.     }
  70.     return eRet;
  71. }
  72. void CSmilParser::checkForExternalEvents()
  73. {
  74.     // Get the <body> node
  75.     SMILNode* pBody = findFirstNode(SMILBody);
  76.     if (pBody)
  77.     {
  78.         // Check recursively for custom events
  79.         checkNodeForExternalEvents(pBody);
  80.     }
  81. }
  82. BOOL CSmilParser::anyExternalEvents(const char* pszID)
  83. {
  84.     BOOL bRet = FALSE;
  85.     if (m_pExternalEventList)
  86.     {
  87.         LISTPOSITION pos = m_pExternalEventList->GetHeadPosition();
  88.         while (pos)
  89.         {
  90.             ExternalEventInfo* pInfo =
  91.                 (ExternalEventInfo*) m_pExternalEventList->GetNext(pos);
  92.             if (pInfo &&
  93.                 pInfo->m_EventBaseID == pszID)
  94.             {
  95.                 bRet = TRUE;
  96.                 break;
  97.             }
  98.         }
  99.     }
  100.     return bRet;
  101. }
  102. ExternalEventInfo* CSmilParser::getFirstExternalEvent(const char* pszID)
  103. {
  104.     ExternalEventInfo* pRet = NULL;
  105.     if (m_pExternalEventList)
  106.     {
  107.         // Initialize the iterator to the first external
  108.         // event in the list
  109.         m_pExternalEventListPos = m_pExternalEventList->GetHeadPosition();
  110.         // Now just call getNextExternalEvent()
  111.         pRet = getNextExternalEvent(pszID);
  112.     }
  113.     return pRet;
  114. }
  115. ExternalEventInfo* CSmilParser::getNextExternalEvent(const char* pszID)
  116. {
  117.     ExternalEventInfo* pRet = NULL;
  118.     if (m_pExternalEventList)
  119.     {
  120.         while (m_pExternalEventListPos)
  121.         {
  122.             ExternalEventInfo* pInfo =
  123.                 (ExternalEventInfo*) m_pExternalEventList->GetNext(m_pExternalEventListPos);
  124.             if (pInfo &&
  125.                 pInfo->m_EventBaseID == pszID)
  126.             {
  127.                 pRet = pInfo;
  128.                 break;
  129.             }
  130.         }
  131.     }
  132.     return pRet;
  133. }
  134. void CSmilParser::checkForEventHandlers()
  135. {
  136.     if (m_pElementsWithHandlerList)
  137.     {
  138.         LISTPOSITION pos = m_pElementsWithHandlerList->GetHeadPosition();
  139.         while (pos)
  140.         {
  141.             CSmilSource* pSrc =
  142.                 (CSmilSource*) m_pElementsWithHandlerList->GetNext(pos);
  143.             if (pSrc && pSrc->m_pNode && pSrc->m_HandlerID.GetLength() > 0)
  144.             {
  145.                 // Look up the element with this handler id
  146.                 CSmilElement* pEl =
  147.                     findElement((const char*) pSrc->m_HandlerID);
  148.                 if (pEl && isMediaObject(pEl->m_pNode))
  149.                 {
  150.                     // Cast to a source
  151.                     CSmilSource* pHandlerSrc = (CSmilSource*) pEl;
  152.                     // Set the "handler-for" member in this element
  153.                     pHandlerSrc->m_HandlerFor = pSrc->m_pNode->m_id;
  154.                 }
  155.             }
  156.         }
  157.     }
  158. }
  159. AccessErrorBehavior CSmilParser::getAccessErrorBehavior(SMILNode* pNode)
  160. {
  161.     // This is default
  162.     AccessErrorBehavior eRet = AccessErrorBehaviorInherit;
  163.     if (pNode)
  164.     {
  165.         // Now init the value to be AccessErrorBehaviorInherit
  166.         // Get the value from the CSmilElement if there is one
  167.         if (pNode->m_pElement)
  168.         {
  169.             eRet = pNode->m_pElement->m_eAccessErrorBehavior;
  170.         }
  171.         // If this value is inherit, then look to the parent
  172.         if (eRet == AccessErrorBehaviorInherit)
  173.         {
  174.             if (pNode->m_pParent)
  175.             {
  176.                 eRet = getAccessErrorBehavior(pNode->m_pParent);
  177.             }
  178.             else
  179.             {
  180.                 eRet = AccessErrorBehaviorContinue;
  181.             }
  182.         }
  183.     }
  184.     return eRet;
  185. }
  186. #ifdef XXXMEH_EXTERNAL_MEDIA_MARKER_HACK
  187. HX_RESULT CSmilParser::getExternalMarkerFileTime(const char* pszMarker,
  188.                                                  const char* pszSMILFileURL,
  189.                                                  const char* pszSrcURL,
  190.                                                  REF(UINT32) rulTime)
  191. {
  192.     HX_RESULT retVal = HXR_FAIL;
  193.     if (pszMarker)
  194.     {
  195.         CHXString cMarker;
  196.         CHXString cExtFile;
  197.         BOOL      bExternal = FALSE;
  198.         retVal = parseMarkerURI(pszMarker, cMarker, bExternal, cExtFile);
  199.         if (SUCCEEDED(retVal))
  200.         {
  201.             if (bExternal)
  202.             {
  203.                 CHXString cExtFileName;
  204.                 retVal = constructExternalMarkerFileName(cExtFile,
  205.                                                          pszSMILFileURL,
  206.                                                          pszSrcURL,
  207.                                                          cExtFileName);
  208.                 if (SUCCEEDED(retVal))
  209.                 {
  210.                     // Strip the "file://" off the front
  211.                     const char* pszExtFileName = (const char*) cExtFileName;
  212.                     if (!strncmp(pszExtFileName, "file://", 7))
  213.                     {
  214.                         pszExtFileName += 7;
  215.                     }
  216.                     // Open the file
  217.                     FILE* fp = fopen(pszExtFileName, "r");
  218.                     if (fp)
  219.                     {
  220.                         char szLine[128]; /* Flawfinder: ignore */
  221.                         fgets(szLine, 128, fp);
  222.                         if (szLine[strlen(szLine) - 1] == 'r' ||
  223.                             szLine[strlen(szLine) - 1] == 'n')
  224.                         {
  225.                             szLine[strlen(szLine) - 1] = '';
  226.                         }
  227.                         if (szLine[strlen(szLine) - 1] == 'r' ||
  228.                             szLine[strlen(szLine) - 1] == 'n')
  229.                         {
  230.                             szLine[strlen(szLine) - 1] = '';
  231.                         }
  232.                         if (!strcmp(szLine, "// The format of this file is solely for SMIL 2.0 Interop testing."))
  233.                         {
  234.                             fgets(szLine, 128, fp);
  235.                             if (szLine[strlen(szLine) - 1] == 'r' ||
  236.                                 szLine[strlen(szLine) - 1] == 'n')
  237.                             {
  238.                                 szLine[strlen(szLine) - 1] = '';
  239.                             }
  240.                             if (szLine[strlen(szLine) - 1] == 'r' ||
  241.                                 szLine[strlen(szLine) - 1] == 'n')
  242.                             {
  243.                                 szLine[strlen(szLine) - 1] = '';
  244.                             }
  245.                             if (!strcmp(szLine, "// It must not be supported in publicly-released software."))
  246.                             {
  247.                                 // Now loop through the lines
  248.                                 while (!feof(fp))
  249.                                 {
  250.                                     fgets(szLine, 128, fp);
  251.                                     if (strlen(szLine) > 0)
  252.                                     {
  253.                                         if (szLine[strlen(szLine) - 1] == 'r' ||
  254.                                             szLine[strlen(szLine) - 1] == 'n')
  255.                                         {
  256.                                             szLine[strlen(szLine) - 1] = '';
  257.                                         }
  258.                                         if (szLine[strlen(szLine) - 1] == 'r' ||
  259.                                             szLine[strlen(szLine) - 1] == 'n')
  260.                                         {
  261.                                             szLine[strlen(szLine) - 1] = '';
  262.                                         }
  263.                                         if (strlen(szLine) > 0)
  264.                                         {
  265.                                             // Parse the line
  266.                                             char* pszToken = strtok(szLine, " t");
  267.                                             if (pszToken)
  268.                                             {
  269.                                                 if (!strcmp(pszToken, (const char*) cMarker))
  270.                                                 {
  271.                                                     pszToken = strtok(NULL, " t");
  272.                                                     if (pszToken)
  273.                                                     {
  274.                                                         HX_RESULT rv = parseClockValue(pszToken, rulTime);
  275.                                                         if (SUCCEEDED(rv))
  276.                                                         {
  277.                                                             retVal  = HXR_OK;
  278.                                                             break;
  279.                                                         }
  280.                                                     }
  281.                                                 }
  282.                                             }
  283.                                         }
  284.                                     }
  285.                                 }
  286.                             }
  287.                         }
  288.                         fclose(fp);
  289.                     }
  290.                 }
  291.             }
  292.             else
  293.             {
  294.                 retVal = HXR_FAIL;
  295.             }
  296.         }
  297.     }
  298.     return retVal;
  299. }
  300. HX_RESULT CSmilParser::constructExternalMarkerFileName(const char*    pszMarkerFile,
  301.                                                        const char*    pszSMILFileURL,
  302.                                                        const char*    pszSrcURL,
  303.                                                        REF(CHXString) rcExtMarkerFileName)
  304. {
  305.     HX_RESULT retVal = HXR_OK;
  306.     if (pszMarkerFile && pszSMILFileURL && pszSrcURL)
  307.     {
  308.         // Get the URL prefix, root, and fragment
  309.         CHXString cPrefix;
  310.         CHXString cURLRoot;
  311.         char*     pURLFragment = NULL;
  312.         CHXURL::GeneratePrefixRootFragment(pszSMILFileURL,
  313.                                            cPrefix,
  314.                                            cURLRoot,
  315.                                            pURLFragment);
  316.         // Get the full URL for the src
  317.         CHXString  cFullSrcURL;
  318.         CHXURL     urlObj(pszSrcURL);
  319.         CHXHeader* pHeader = urlObj.GetProperties();
  320.         if (pHeader)
  321.         {
  322.             IHXBuffer* pBuffer = NULL;
  323.             HX_RESULT   rc      = pHeader->GetPropertyBuffer(PROPERTY_SCHEME, pBuffer);
  324.             if (SUCCEEDED(rc))
  325.             {
  326.                 // fully qualified URL
  327.                 cFullSrcURL = pszSrcURL;
  328.             }
  329.             else
  330.             {
  331.                 // relative URL
  332.                 // if it starts with '/', make it relative to the root of
  333.                 // the URL prefix
  334.                 if(*pszSrcURL == '/')
  335.                 {
  336.                     cFullSrcURL = cURLRoot + pszSrcURL;
  337.                 }
  338.                 else
  339.                 {
  340.                     cFullSrcURL = cPrefix + pszSrcURL;
  341.                 }
  342.             }
  343.             HX_RELEASE(pBuffer);
  344.             HX_RELEASE(pHeader);
  345.         }
  346.         if (cFullSrcURL.GetLength() > 0)
  347.         {
  348.             HX_VECTOR_DELETE(pURLFragment);
  349.             CHXURL::GeneratePrefixRootFragment(cFullSrcURL,
  350.                                                cPrefix,
  351.                                                cURLRoot,
  352.                                                pURLFragment);
  353.             // Now we need to create the external marker file name
  354.             CHXString  cFullMarkerURL;
  355.             CHXURL     urlObj2(pszMarkerFile);
  356.             CHXHeader* pHeader2 = urlObj2.GetProperties();
  357.             if (pHeader2)
  358.             {
  359.                 IHXBuffer* pBuffer = NULL;
  360.                 HX_RESULT   rc      = pHeader2->GetPropertyBuffer(PROPERTY_SCHEME, pBuffer);
  361.                 if (SUCCEEDED(rc))
  362.                 {
  363.                     // fully qualified URL
  364.                     cFullMarkerURL = pszMarkerFile;
  365.                 }
  366.                 else
  367.                 {
  368.                     // relative URL
  369.                     // if it starts with '/', make it relative to the root of
  370.                     // the URL prefix
  371.                     if(*pszMarkerFile == '/')
  372.                     {
  373.                         cFullMarkerURL = cURLRoot + pszMarkerFile;
  374.                     }
  375.                     else
  376.                     {
  377.                         cFullMarkerURL = cPrefix + pszMarkerFile;
  378.                     }
  379.                 }
  380.                 HX_RELEASE(pBuffer);
  381.                 HX_RELEASE(pHeader);
  382.             }
  383.             rcExtMarkerFileName = cFullMarkerURL;
  384.         }
  385.         HX_VECTOR_DELETE(pURLFragment);
  386.     }
  387.     else
  388.     {
  389.         retVal = HXR_OK;
  390.     }
  391.     return retVal;
  392. }
  393. #endif // XXXMEH_EXTERNAL_MEDIA_MARKER_HACK
  394. HX_RESULT CSmilParser::parseMarkerURI(const char*    pszStr,
  395.                                       REF(CHXString) rcMarker,
  396.                                       REF(BOOL)      rbExternal,
  397.                                       REF(CHXString) rcExternalFileName)
  398. {
  399.     HX_RESULT retVal = HXR_OK;
  400.     if (pszStr)
  401.     {
  402.         // Look for a '#'
  403.         char* pHash = (char *)strchr(pszStr, '#');
  404.         if (pHash)
  405.         {
  406.             // We DO have a hash. Is there a file
  407.             // name in front of it?
  408.             if (pHash > pszStr)
  409.             {
  410.                 // We DO have a hash, so parse out the
  411.                 // external file name AND the marker name
  412.                 *pHash             = '';
  413.                 rbExternal         = TRUE;
  414.                 rcExternalFileName = pszStr;
  415.                 rcMarker           = (const char*) pHash + 1;
  416.             }
  417.             else
  418.             {
  419.                 // No file name in front of hash, so
  420.                 // it's still an internal marker
  421.                 rbExternal = FALSE;
  422.                 rcMarker   = (const char*) pHash + 1;
  423.             }
  424.         }
  425.         else
  426.         {
  427.             // No '#', so we know it's NOT an external marker
  428.             rbExternal = FALSE;
  429.             // So the marker is just the entire string
  430.             rcMarker = pszStr;
  431.         }
  432.     }
  433.     else
  434.     {
  435.         retVal = HXR_FAIL;
  436.     }
  437.     return retVal;
  438. }
  439. HX_RESULT CSmilParser::parseHandlerForID(const char*    pszStr,
  440.                                          REF(CHXString) rcHandlerID)
  441. {
  442.     HX_RESULT retVal = HXR_FAIL;
  443.     if (pszStr)
  444.     {
  445.         const char* pPnd = strchr(pszStr, '#');
  446.         if (pPnd)
  447.         {
  448.             rcHandlerID = pPnd + 1;
  449.         }
  450.     }
  451.     return retVal;
  452. }
  453. HX_RESULT CSmilParser::parseAccessErrorBehavior(const char*              pszStr,
  454.                                                 REF(AccessErrorBehavior) reErr)
  455. {
  456.     HX_RESULT retVal = HXR_OK;
  457.     if (pszStr)
  458.     {
  459.         if (!strcmp(pszStr, "inherit"))
  460.         {
  461.             reErr = AccessErrorBehaviorInherit;
  462.         }
  463.         else if (!strcmp(pszStr, "continue"))
  464.         {
  465.             reErr = AccessErrorBehaviorContinue;
  466.         }
  467.         else if (!strcmp(pszStr, "stop"))
  468.         {
  469.             reErr = AccessErrorBehaviorStop;
  470.         }
  471.         else
  472.         {
  473.             retVal = HXR_FAIL;
  474.         }
  475.     }
  476.     else
  477.     {
  478.         retVal = HXR_FAIL;
  479.     }
  480.     return retVal;
  481. }
  482. #if defined(XXXMEH_SPLINE_ANIMATION)
  483. HX_RESULT CSmilParser::parseKeyTimes(const char* pszVal, CSmilAnimateElement* pAnim)
  484. {
  485.     HX_RESULT retVal = HXR_OK;
  486.     if (pszVal && pAnim)
  487.     {
  488.         // Allocate some temporary memory to hold
  489.         // a copy of the string
  490.         char* pTmp = new char [strlen(pszVal) + 1];
  491.         if (pTmp)
  492.         {
  493.             // Make a copy of the string, because
  494.             // strtok() is destructive
  495.             strcpy(pTmp, pszVal); /* Flawfinder: ignore */
  496.             // First run through and count the number of tokens
  497.             UINT32        ulNum    = 0;
  498.             const char*   pszSep   = " ;trn";
  499.             char*         pszToken = strtok(pTmp, pszSep);
  500.             while (pszToken)
  501.             {
  502.                 // Increment the number of tokens
  503.                 ++ulNum;
  504.                 // Get the next token
  505.                 pszToken = strtok(NULL, pszSep);
  506.             }
  507.             // Recopy the string
  508.             strcpy(pTmp, pszVal); /* Flawfinder: ignore */
  509.             // Set the number of keyTimes
  510.             pAnim->m_ulNumKeyTimes = ulNum;
  511.             // Allocate space for the keyTimes
  512.             HX_VECTOR_DELETE(pAnim->m_pdKeyTime);
  513.             pAnim->m_pdKeyTime = new double [pAnim->m_ulNumKeyTimes];
  514.             if (pAnim->m_pdKeyTime)
  515.             {
  516.                 // Parse the string using strtok()
  517.                 ulNum    = 0;
  518.                 pszToken = strtok(pTmp, pszSep);
  519.                 while (pszToken && SUCCEEDED(retVal))
  520.                 {
  521.                     // Parse the current token
  522.                     double dTmp = 0.0;
  523.                     retVal = HXParseDouble(pszToken, dTmp);
  524.                     if (SUCCEEDED(retVal))
  525.                     {
  526.                         // SPEC: Each time value in the keyTimes list is specified
  527.                         // as a floating point value between 0 and 1 (inclusive),
  528.                         // representing a proportional offset into the simple
  529.                         // duration of the animation element.
  530.                         if (dTmp >= 0.0 && dTmp <= 1.0)
  531.                         {
  532.                             // Set the value
  533.                             pAnim->m_pdKeyTime[ulNum++] = dTmp;
  534.                             // Get the next token
  535.                             pszToken = strtok(NULL, pszSep);
  536.                         }
  537.                         else
  538.                         {
  539.                             retVal = HXR_FAIL;
  540.                         }
  541.                     }
  542.                 }
  543.             }
  544.             else
  545.             {
  546.                 retVal = HXR_OUTOFMEMORY;
  547.             }
  548.         }
  549.         else
  550.         {
  551.             retVal = HXR_OUTOFMEMORY;
  552.         }
  553.         HX_VECTOR_DELETE(pTmp);
  554.     }
  555.     else
  556.     {
  557.         retVal = HXR_FAIL;
  558.     }
  559.     return retVal;
  560. }
  561. HX_RESULT CSmilParser::parseKeySplines(const char* pszVal, CSmilAnimateElement* pAnim)
  562. {
  563.     HX_RESULT retVal = HXR_OK;
  564.     if (pszVal && pAnim)
  565.     {
  566.         // Allocate some temporary memory to hold
  567.         // a copy of the string
  568.         char* pTmp = new char [strlen(pszVal) + 1];
  569.         if (pTmp)
  570.         {
  571.             // Make a copy of the string, because
  572.             // strtok() is destructive
  573.             strcpy(pTmp, pszVal); /* Flawfinder: ignore */
  574.             // First run through and count the number of keySplines
  575.             UINT32        ulNum    = 0;
  576.             const char*   pszSep   = ";";
  577.             char*         pszToken = strtok(pTmp, pszSep);
  578.             while (pszToken)
  579.             {
  580.                 // Increment the number of tokens
  581.                 ++ulNum;
  582.                 // Get the next token
  583.                 pszToken = strtok(NULL, pszSep);
  584.             }
  585.             // Recopy the string
  586.             strcpy(pTmp, pszVal); /* Flawfinder: ignore */
  587.             // Set the number of keyTimes
  588.             pAnim->m_ulNumKeySplines = ulNum;
  589.             // Allocate space for the keyTimes
  590.             HX_VECTOR_DELETE(pAnim->m_pKeySpline);
  591.             pAnim->m_pKeySpline = new KeySpline [pAnim->m_ulNumKeySplines];
  592.             if (pAnim->m_pKeySpline)
  593.             {
  594.                 // Null out the array
  595.                 UINT32 i = 0;
  596.                 for (i = 0; i < pAnim->m_ulNumKeySplines; i++)
  597.                 {
  598.                     pAnim->m_pKeySpline[i].x1 = 0.0;
  599.                     pAnim->m_pKeySpline[i].y1 = 0.0;
  600.                     pAnim->m_pKeySpline[i].x2 = 0.0;
  601.                     pAnim->m_pKeySpline[i].y2 = 0.0;
  602.                 }
  603.                 // Allocate a buffer for holding the char*'s
  604.                 char** ppTok = new char * [pAnim->m_ulNumKeySplines]; /* Flawfinder: ignore */
  605.                 if (ppTok)
  606.                 {
  607.                     // Null out the array
  608.                     memset(ppTok, 0, pAnim->m_ulNumKeySplines * sizeof(char*));
  609.                     // Parse the string using strtok(). We simply
  610.                     // run through and save the pointers to the
  611.                     // keySplines so that we can parse them separately
  612.                     // in a separate loop. This is due to restrictions
  613.                     // of using strtok().
  614.                     ulNum    = 0;
  615.                     pszToken = strtok(pTmp, pszSep);
  616.                     while (pszToken)
  617.                     {
  618.                         ppTok[ulNum++] = pszToken;
  619.                         // Get the next keySpline
  620.                         pszToken = strtok(NULL, pszSep);
  621.                     }
  622.                     // Now we can individually parse each keySpline
  623.                     for (UINT32 i = 0; i < pAnim->m_ulNumKeySplines && SUCCEEDED(retVal); i++)
  624.                     {
  625.                         if (ppTok[i])
  626.                         {
  627.                             char*       pszKS      = ppTok[i];
  628.                             const char* pszKSSep   = " ,trn";
  629.                             char*       pszKSToken = strtok(pszKS, pszKSSep);
  630.                             for (UINT32 j = 0; j < 4 && SUCCEEDED(retVal); j++)
  631.                             {
  632.                                 if (pszKSToken)
  633.                                 {
  634.                                     // Parse the current token
  635.                                     double dTmp = 0.0;
  636.                                     retVal = HXParseDouble(pszKSToken, dTmp);
  637.                                     if (SUCCEEDED(retVal))
  638.                                     {
  639.                                         // SPEC: The [keySplines] values must
  640.                                         // all be in the range 0 to 1.
  641.                                         if (dTmp >= 0.0 && dTmp <= 1.0)
  642.                                         {
  643.                                             // Set the value
  644.                                             switch (j)
  645.                                             {
  646.                                                 case 0: pAnim->m_pKeySpline[i].x1 = dTmp; break;
  647.                                                 case 1: pAnim->m_pKeySpline[i].y1 = dTmp; break;
  648.                                                 case 2: pAnim->m_pKeySpline[i].x2 = dTmp; break;
  649.                                                 case 3: pAnim->m_pKeySpline[i].y2 = dTmp; break;
  650.                                             }
  651.                                             // Get the next token
  652.                                             pszKSToken = strtok(NULL, pszKSSep);
  653.                                         }
  654.                                         else
  655.                                         {
  656.                                             retVal = HXR_FAIL;
  657.                                         }
  658.                                     }
  659.                                 }
  660.                                 else
  661.                                 {
  662.                                     retVal = HXR_FAIL;
  663.                                 }
  664.                             }
  665.                         }
  666.                         else
  667.                         {
  668.                             retVal = HXR_FAIL;
  669.                         }
  670.                     }
  671.                 }
  672.                 HX_VECTOR_DELETE(ppTok);
  673.             }
  674.             else
  675.             {
  676.                 retVal = HXR_OUTOFMEMORY;
  677.             }
  678.         }
  679.         else
  680.         {
  681.             retVal = HXR_OUTOFMEMORY;
  682.         }
  683.         HX_VECTOR_DELETE(pTmp);
  684.     }
  685.     else
  686.     {
  687.         retVal = HXR_FAIL;
  688.     }
  689.     return retVal;
  690. }
  691. HX_RESULT CSmilParser::parseSVGPath(const char* pszVal, CSmilAnimateElement* pAnim)
  692. {
  693.     HX_RESULT retVal = HXR_OK;
  694.     if (pszVal && pAnim)
  695.     {
  696.         // XXXMEH - first we make a more restrictive parser that
  697.         // requires whitespace or commas in between all tokens.
  698.         // We will need to go back later and make a looser parser
  699.         // that complies with the BNF.
  700.         //
  701.         // Allocate some memory to copy the string
  702.         char* pTmp = new char [strlen(pszVal) + 1];
  703.         if (pTmp)
  704.         {
  705.             // Copy the string, since strtok() is destructive
  706.             strcpy(pTmp, pszVal); /* Flawfinder: ignore */
  707.             // This array will hold PathCmd*'s and we
  708.             // will copy them into the final array at the end
  709.             CHXPtrArray cTmpArr;
  710.             UINT32 ulNumCmd = 0;
  711.             // This array will hold the list of coordinates
  712.             // until we know how many there are
  713.             UINT32  ulNumTmp      = 0;
  714.             UINT32  ulNumTmpAlloc = 0;
  715.             double* pdTmp         = NULL;
  716.             // Loop through the tokens
  717.             const char* pszSep  = " ,trn";
  718.             char*       pTok    = strtok(pTmp, pszSep);
  719.             PathCmd*    pCurCmd = NULL;
  720.             while (pTok && SUCCEEDED(retVal))
  721.             {
  722.                 // Is this token a command?
  723.                 BOOL        bIsCmdType = FALSE;
  724.                 BOOL        bRelative  = FALSE;
  725.                 PathCmdType eType      = PathCmdTypeMoveTo;
  726.                 if (strlen(pTok) == 1)
  727.                 {
  728.                     char c = *pTok;
  729.                     if (isalpha(c))
  730.                     {
  731.                         if (islower(c))
  732.                         {
  733.                             bRelative = TRUE;
  734.                             c = toupper(c);
  735.                         }
  736.                         bIsCmdType = TRUE;
  737.                         switch(c)
  738.                         {
  739.                             case 'M': eType = PathCmdTypeMoveTo;             break;
  740.                             case 'Z': eType = PathCmdTypeClosePath;          break;
  741.                             case 'L': eType = PathCmdTypeLineTo;             break;
  742.                             case 'H': eType = PathCmdTypeHorzLineTo;         break;
  743.                             case 'V': eType = PathCmdTypeVertLineTo;         break;
  744.                             case 'C': eType = PathCmdTypeCubicBezierCurveTo; break;
  745.                             default: bIsCmdType = FALSE;
  746.                         }
  747.                     }
  748.                 }
  749.                 // We now know whether or not this token
  750.                 // is a command or not. It either has to
  751.                 // be a command or a coordinate. If it's a command
  752.                 // and we already have a current PathCmd, then
  753.                 // add the current one to the list and create
  754.                 // another one. If it's not a command (and thus
  755.                 // is a coordinate), then we have to decide where
  756.                 // it goes in the current PathCmd.
  757.                 if (bIsCmdType)
  758.                 {
  759.                     // This is a command type. Do
  760.                     // we already have a current PathCmd?
  761.                     if (pCurCmd)
  762.                     {
  763.                         // Check the number of coordinates against
  764.                         // the type. MoveTo and LineTo commands must
  765.                         // have an even number of coordinates. ClosePath
  766.                         // commands should have zero coordinates.
  767.                         // BezierCurveTo should have a multiple of 6
  768.                         // coordinates.
  769.                         BOOL bLegalNumber = TRUE;
  770.                         switch (pCurCmd->m_eType)
  771.                         {
  772.                             case PathCmdTypeMoveTo:
  773.                             case PathCmdTypeLineTo:
  774.                                 {
  775.                                     if (!ulNumTmp || (ulNumTmp%2))
  776.                                     {
  777.                                         bLegalNumber = FALSE;
  778.                                     }
  779.                                 }
  780.                                 break;
  781.                             case PathCmdTypeHorzLineTo:
  782.                             case PathCmdTypeVertLineTo:
  783.                                 {
  784.                                     if (!ulNumTmp)
  785.                                     {
  786.                                         bLegalNumber = FALSE;
  787.                                     }
  788.                                 }
  789.                                 break;
  790.                             case PathCmdTypeClosePath:
  791.                                 {
  792.                                     if (ulNumTmp)
  793.                                     {
  794.                                         bLegalNumber = FALSE;
  795.                                     }
  796.                                 }
  797.                                 break;
  798.                             case PathCmdTypeCubicBezierCurveTo:
  799.                                 {
  800.                                     if (!ulNumTmp || (ulNumTmp%6))
  801.                                     {
  802.                                         bLegalNumber = FALSE;
  803.                                     }
  804.                                 }
  805.                                 break;
  806.                         }
  807.                         // Do we have a legal number of coordinates?
  808.                         if (bLegalNumber)
  809.                         {
  810.                             // Set the number of coordinates
  811.                             pCurCmd->m_ulNumCoords = ulNumTmp;
  812.                             // Alloc space
  813.                             if (ulNumTmp)
  814.                             {
  815.                                 pCurCmd->m_pdCoord = new double [ulNumTmp];
  816.                                 if (pCurCmd->m_pdCoord)
  817.                                 {
  818.                                     // Copy the values and zero out the
  819.                                     // tmp array
  820.                                     for (UINT32 i = 0; i < ulNumTmp; i++)
  821.                                     {
  822.                                         pCurCmd->m_pdCoord[i] = pdTmp[i];
  823.                                         pdTmp[i]              = 0.0;
  824.                                     }
  825.                                     // Reset the number of coordinates
  826.                                     ulNumTmp = 0;
  827.                                 }
  828.                                 else
  829.                                 {
  830.                                     retVal = HXR_OUTOFMEMORY;
  831.                                 }
  832.                             }
  833.                             if (SUCCEEDED(retVal))
  834.                             {
  835.                                 // We already have a current PathCmd,
  836.                                 // so add the current one to the array
  837.                                 cTmpArr.SetAt(ulNumCmd++, (void*) pCurCmd);
  838.                             }
  839.                         }
  840.                         else
  841.                         {
  842.                             retVal = HXR_FAIL;
  843.                         }
  844.                     }
  845.                     if (SUCCEEDED(retVal))
  846.                     {
  847.                         // Create a new PathCmd
  848.                         pCurCmd = new PathCmd();
  849.                         if (pCurCmd)
  850.                         {
  851.                             pCurCmd->m_eType     = eType;
  852.                             pCurCmd->m_bRelative = bRelative;
  853.                         }
  854.                         else
  855.                         {
  856.                             retVal = HXR_OUTOFMEMORY;
  857.                         }
  858.                     }
  859.                 }
  860.                 else
  861.                 {
  862.                     // This must be a coordinate, so parse it as
  863.                     // a coordinate
  864.                     double dTmp = 0;
  865.                     retVal = HXParseDouble(pTok, dTmp);
  866.                     if (SUCCEEDED(retVal))
  867.                     {
  868.                         // We successfully parsed a coordinate, so check
  869.                         // and see if the array has enough space to add
  870.                         // one more element
  871.                         if (ulNumTmp >= ulNumTmpAlloc)
  872.                         {
  873.                             // Not enough space, so we need to alloc
  874.                             // some more space. Double the size of
  875.                             // the array
  876.                             UINT32 ulNewNumTmpAlloc = ulNumTmpAlloc << 1;
  877.                             if (!ulNewNumTmpAlloc)
  878.                             {
  879.                                 ulNewNumTmpAlloc = 8;
  880.                             }
  881.                             double* pCpy = new double [ulNewNumTmpAlloc];
  882.                             if (pCpy)
  883.                             {
  884.                                 // Copy the old values
  885.                                 UINT32 i = 0;
  886.                                 for (i = 0; i < ulNumTmpAlloc; i++)
  887.                                 {
  888.                                     pCpy[i] = pdTmp[i];
  889.                                 }
  890.                                 // NULL out the rest of the array
  891.                                 for (i = ulNumTmpAlloc; i < ulNewNumTmpAlloc; i++)
  892.                                 {
  893.                                     pCpy[i] = 0.0;
  894.                                 }
  895.                                 // Delete the old array
  896.                                 HX_VECTOR_DELETE(pdTmp);
  897.                                 // Assign it to the new array
  898.                                 pdTmp = pCpy;
  899.                                 // Update the number allocated
  900.                                 ulNumTmpAlloc = ulNewNumTmpAlloc;
  901.                             }
  902.                             else
  903.                             {
  904.                                 retVal = HXR_OUTOFMEMORY;
  905.                             }
  906.                         }
  907.                         if (SUCCEEDED(retVal))
  908.                         {
  909.                             pdTmp[ulNumTmp++] = dTmp;
  910.                         }
  911.                     }
  912.                 }
  913.                 // Get the next token
  914.                 pTok = strtok(NULL, pszSep);
  915.             }
  916.             // Copy the last PathCmd* to the list
  917.             if (pCurCmd)
  918.             {
  919.                 // Set the number of coordinates
  920.                 pCurCmd->m_ulNumCoords = ulNumTmp;
  921.                 // Alloc space
  922.                 if (ulNumTmp)
  923.                 {
  924.                     pCurCmd->m_pdCoord = new double [ulNumTmp];
  925.                     if (pCurCmd)
  926.                     {
  927.                         // Copy the values and zero out the
  928.                         // tmp array
  929.                         for (UINT32 i = 0; i < ulNumTmp; i++)
  930.                         {
  931.                             pCurCmd->m_pdCoord[i] = pdTmp[i];
  932.                             pdTmp[i]              = 0.0;
  933.                         }
  934.                         // Reset the number of coordinates
  935.                         ulNumTmp = 0;
  936.                     }
  937.                     else
  938.                     {
  939.                         retVal = HXR_OUTOFMEMORY;
  940.                     }
  941.                 }
  942.                 if (SUCCEEDED(retVal))
  943.                 {
  944.                     // We already have a current PathCmd,
  945.                     // so add the current one to the array
  946.                     cTmpArr.SetAt(ulNumCmd++, (void*) pCurCmd);
  947.                 }
  948.             }
  949.             // Now we can delete the temporary array of coordinates
  950.             HX_VECTOR_DELETE(pdTmp);
  951.             // Copy from the temporary list to the CSmilAnimateElement
  952.             if (SUCCEEDED(retVal))
  953.             {
  954.                 HX_VECTOR_DELETE(pAnim->m_ppPathCmd);
  955.                 if (ulNumCmd)
  956.                 {
  957.                     pAnim->m_ppPathCmd = new PathCmd* [ulNumCmd];
  958.                     if (pAnim->m_ppPathCmd)
  959.                     {
  960.                         for (UINT32 i = 0; i < ulNumCmd; i++)
  961.                         {
  962.                             pAnim->m_ppPathCmd[i] = (PathCmd*) cTmpArr[i];
  963.                         }
  964.                     }
  965.                     else
  966.                     {
  967.                         retVal = HXR_OUTOFMEMORY;
  968.                     }
  969.                 }
  970.                 else
  971.                 {
  972.                     pAnim->m_ulNumPathCmds = 0;
  973.                 }
  974.             }
  975.             if (FAILED(retVal))
  976.             {
  977.                 for (UINT32 i = 0; i < ulNumCmd; i++)
  978.                 {
  979.                     PathCmd* pCmd = (PathCmd*) cTmpArr[i];
  980.                     HX_DELETE(pCmd);
  981.                 }
  982.             }
  983.         }
  984.         else
  985.         {
  986.             retVal = HXR_OUTOFMEMORY;
  987.         }
  988.         HX_VECTOR_DELETE(pTmp);
  989.     }
  990.     else
  991.     {
  992.         retVal = HXR_FAIL;
  993.     }
  994.     return retVal;
  995. }
  996. #endif // #if defined(XXXMEH_SPLINE_ANIMATION)
  997. BOOL CSmilParser::isDataURL(const char* pszURL)
  998. {
  999.     BOOL bRet = FALSE;
  1000.     if (pszURL)
  1001.     {
  1002.         // Get the string length
  1003.         UINT32 ulLen = strlen(pszURL);
  1004.         if (ulLen)
  1005.         {
  1006.             // Skip any leading whitespace char
  1007.             // Make sure we have at least 5 characters
  1008.             // past the whitespace for "data:"
  1009.             UINT32 ulNumWS = strspn(pszURL, " trn");
  1010.             if (ulNumWS + 5 < ulLen)
  1011.             {
  1012.                 // Advance to the beginning of non-whitespace
  1013.                 pszURL += ulNumWS;
  1014.                 // Check for "data:"
  1015.                 if (strncmp(pszURL, "data:", 5) == 0)
  1016.                 {
  1017.                     bRet = TRUE;
  1018.                 }
  1019.             }
  1020.         }
  1021.     }
  1022.     return bRet;
  1023. }
  1024. HX_RESULT CSmilParser::validateDataURL(const char* pszURL)
  1025. {
  1026.     HX_RESULT retVal = HXR_OK;
  1027.     if (pszURL)
  1028.     {
  1029.         if (isDataURL(pszURL))
  1030.         {
  1031.             // For complete syntax of data: URLs see:
  1032.             // data: URL RFC (http://www.cis.ohio-state.edu/cs/Services/rfc/rfc-text/rfc2397.txt)
  1033.             // URI syntax RFC (http://www.cis.ohio-state.edu/cgi-bin/rfc/rfc2396.html)
  1034.             //
  1035.             // Initialize the return value to fail
  1036.             retVal = HXR_FAIL;
  1037.             // Look for "data:"
  1038.             const char* pCh = strstr(pszURL, "data:");
  1039.             if (pCh)
  1040.             {
  1041.                 // Now find the ","
  1042.                 pCh = strchr(pCh, ',');
  1043.                 if (pCh)
  1044.                 {
  1045.                     // Skip past the ","
  1046.                     ++pCh;
  1047.                     // From now to the end of the string, enforce
  1048.                     // the BNF's allowed characters
  1049.                     BOOL   bIllegalChar = FALSE;
  1050.                     BOOL   bEscapeSeq   = FALSE;
  1051.                     UINT32 ulNumEscape  = 0;
  1052.                     while (pCh && *pCh)
  1053.                     {
  1054.                         char c = *pCh++;
  1055.                         if (bEscapeSeq)
  1056.                         {
  1057.                             if (isxdigit(c))
  1058.                             {
  1059.                                 ++ulNumEscape;
  1060.                             }
  1061.                             else
  1062.                             {
  1063.                                 bIllegalChar = TRUE;
  1064.                                 break;
  1065.                             }
  1066.                             if (ulNumEscape >= 2)
  1067.                             {
  1068.                                 bEscapeSeq  = FALSE;
  1069.                                 ulNumEscape = 0;
  1070.                             }
  1071.                         }
  1072.                         else if (c == '%')
  1073.                         {
  1074.                             // Make sure the next two characters are
  1075.                             // legally escaped
  1076.                             bEscapeSeq = TRUE;
  1077.                         }
  1078.                         else if (!isalnum(c))
  1079.                         {
  1080.                             if (!(c == ';'  ||
  1081.                                   c == '/'  ||
  1082.                                   c == '?'  ||
  1083.                                   c == ':'  ||
  1084.                                   c == '@'  ||
  1085.                                   c == '&'  ||
  1086.                                   c == '='  ||
  1087.                                   c == '+'  ||
  1088.                                   c == '$'  ||
  1089.                                   c == ','  ||
  1090.                                   c == '-'  ||
  1091.                                   c == '_'  ||
  1092.                                   c == '.'  ||
  1093.                                   c == '!'  ||
  1094.                                   c == '~'  ||
  1095.                                   c == '*'  ||
  1096.                                   c == 0x27 || // "'"
  1097.                                   c == '('  ||
  1098.                                   c == ')'))
  1099.                             {
  1100.                                 bIllegalChar = TRUE;
  1101.                                 break;
  1102.                             }
  1103.                         }
  1104.                     }
  1105.                     if (!bIllegalChar && !bEscapeSeq)
  1106.                     {
  1107.                         retVal = HXR_OK;
  1108.                     }
  1109.                 }
  1110.             }
  1111.         }
  1112.     }
  1113.     else
  1114.     {
  1115.         retVal = HXR_FAIL;
  1116.     }
  1117.     return retVal;
  1118. }
  1119. HX_RESULT
  1120. CSmilParser::addBeginEventElement(SmilTimeValue* pTimeVal)
  1121. {
  1122.     HX_RESULT rslt = HXR_OK;
  1123.     if (!m_pBeginEventList)
  1124.     {
  1125. m_pBeginEventList = new CHXSimpleList;
  1126. if (!m_pBeginEventList)
  1127. {
  1128.     return HXR_OUTOFMEMORY;
  1129. }
  1130.     }
  1131.     m_pBeginEventList->AddTail(pTimeVal);
  1132.     // Add it to the map
  1133.     addToBeginOrEndTimeMap(pTimeVal, SmilBeginTimeList);
  1134.     return rslt;
  1135. }
  1136. // /This function gets called on the fly whenever an event occurs, e.g.,
  1137. // when the user clicks on an element.
  1138. // ulEventTime is the time a click or other mouse event occured (which
  1139. // should be roughly the current playback time.  It is absolute, relative
  1140. // to the beginning of the presentation (i.e., current clip).  pEventElement
  1141. // is the element where the event occurred (e.g., clicked on) and is
  1142. // passed in here so that we can see if anyone in the beginEventList or
  1143. // endEventList has a begin event or end event, respectively, equal to this
  1144. // event on this pEventElement.
  1145. HX_RESULT
  1146. CSmilParser::tryToResolveBeginEndEvents(const char* pEventName,
  1147. const char* pEventElementId,
  1148. ULONG32 ulEventTime)
  1149. {
  1150.     HX_RESULT ret = HXR_OK;
  1151.     // /XXEH- make sure casting is OK here; what if event time
  1152.     // is greater than 24.855 days (i.e., is > 0x7fffffff)?
  1153.     HX_ASSERT(ulEventTime < 0x7fffffff);
  1154.     INT32 lEventTime = (INT32)ulEventTime;
  1155.     if (pEventName && strlen(pEventName) &&
  1156.     // /pEventElementId can't be NULL and it can't be empty:
  1157.     pEventElementId  &&  strlen(pEventElementId))
  1158.     {
  1159. BOOL bIsResumeEvent = (0 == strcmp(pEventName, "resumeEvent"));
  1160.         CHXSimpleList* pBeginEventList = NULL;
  1161.         if (isTimeValueListPresent(pEventName, pEventElementId,
  1162.                                    SmilBeginTimeList, pBeginEventList))
  1163.         {
  1164.             LISTPOSITION pos = pBeginEventList->GetHeadPosition();
  1165.             while (pos)
  1166.             {
  1167.                 BOOL bATimeWasResolved = FALSE;
  1168.                 SmilTimeValue* pValue = (SmilTimeValue*) pBeginEventList->GetNext(pos);
  1169.                 if (!pValue->m_pElement)
  1170.                 {
  1171.                     HX_ASSERT(pValue->m_pElement);
  1172.                     continue;
  1173.                 }
  1174.                 if (!pValue->getIdRef()  ||  !pValue->getEventName())
  1175.                 {
  1176.                     HX_ASSERT(pValue->getIdRef()  && pValue->getEventName());
  1177.                     continue;
  1178.                 }
  1179.                 // /Now go through all begin times that are awaiting this event
  1180.                 // from this id'd element and resolve them:
  1181.                 // /XXXEH- TODO: verify that SMIL Boston final spec still says to
  1182.                 // resolve & use begin times first before doing so for end times:
  1183.                 ret = pValue->m_pElement->resolveEventTimeValues(lEventTime,
  1184.                                     pEventName, pEventElementId,
  1185.                                     SmilBeginTimeList,
  1186.                                     bATimeWasResolved /*passed by ref*/);
  1187.                 // /XXXEH- TODO: verify algorithm in SMIL Boston final draft that
  1188.                 // says we should first resolve begin values awaiting this event
  1189.                 // and act on the result, e.g., start an element, and THEN resolve
  1190.                 // end values awaiting this event.  The order that this is done
  1191.                 // DOES affect playback in some cases (due to restart and other
  1192.                 // factors).
  1193.                 if (SUCCEEDED(ret)  &&  bATimeWasResolved)
  1194.                 {
  1195.                     ret = insertElementWithPendingBeginOrEnd(
  1196.                             pValue->m_pElement, lEventTime, SmilBeginTimeList);
  1197.     // /Found while fixing PR 79300 & PR 85885: an insert
  1198.     // failure is OK for resumeEvent:
  1199.     if (!SUCCEEDED(ret)  &&
  1200.     bIsResumeEvent)
  1201.     {
  1202. ret = HXR_OK;
  1203.     }
  1204.                 }
  1205.             }// /end walking begin event list.
  1206.         }
  1207.         // /XXXEH- TODO: move the "setDelay..() calls, above,
  1208.         // to below this if () block; we only want to start an element if
  1209.         // it's not currently playing and if it has a begin time that is
  1210.         // not the same as its end time.  All end times that are in the
  1211.         // past at the point of resolution of a begin time are ignored.
  1212.         // /XXXEH-  ---make sure I got the above right!  I think that
  1213.         //      ---the SMIL Boston spec says that begin="5s" end="4s"
  1214.         //      ---doesn't play because, at time 0, 4<5.  However, end isn't
  1215.         //      ---ignored if foo is clicked at 5s with the following timing:
  1216.         //      ---begin="foo.activateEvent" end="4s" because end is in the past
  1217.         //      ---at 5s and is thus ignored.  (RIGHT???).
  1218.         CHXSimpleList* pEndEventList = NULL;
  1219.         if (SUCCEEDED(ret) &&
  1220.     // /Again, don't bother with end values since resumeEvent should
  1221.     // only be in begin list (and had better not be in end list):
  1222.     !bIsResumeEvent  &&
  1223.             isTimeValueListPresent(pEventName, pEventElementId,
  1224.                                    SmilEndTimeList, pEndEventList))
  1225.         {
  1226.             LISTPOSITION pos = pEndEventList->GetHeadPosition();
  1227.             while (pos)
  1228.             {
  1229.                 BOOL bATimeWasResolved = FALSE;
  1230.                 SmilTimeValue* pValue = (SmilTimeValue*) pEndEventList->GetNext(pos);
  1231.                 if (!pValue->m_pElement)
  1232.                 {
  1233.                     HX_ASSERT(pValue->m_pElement);
  1234.                     continue;
  1235.                 }
  1236.                 if (!pValue->getIdRef()  ||  !pValue->getEventName())
  1237.                 {
  1238.                     HX_ASSERT(pValue->getIdRef()  && pValue->getEventName());
  1239.                     continue;
  1240.                 }
  1241.                 // /Now go through all begin times that are awaiting this event
  1242.                 // from this id'd element and resolve them:
  1243.                 // /XXXEH- TODO: verify that SMIL Boston final spec still says to
  1244.                 // resolve & use begin times first before doing so for end times:
  1245.                 ret = pValue->m_pElement->resolveEventTimeValues(lEventTime,
  1246.                                     pEventName, pEventElementId,
  1247.                                     SmilEndTimeList,
  1248.                                     bATimeWasResolved /*passed by ref*/);
  1249.                 // /XXXEH- TODO: verify algorithm in SMIL Boston final draft that
  1250.                 // says we should first resolve begin values awaiting this event
  1251.                 // and act on the result, e.g., start an element, and THEN resolve
  1252.                 // end values awaiting this event.  The order that this is done
  1253.                 // DOES affect playback in some cases (due to restart and other
  1254.                 // factors).  Note: we may be able to combine above begin-list
  1255.                 // for loop with this end-list for loop.
  1256.                 if (SUCCEEDED(ret)  &&  bATimeWasResolved)
  1257.                 {
  1258.                     ret = insertElementWithPendingBeginOrEnd(
  1259.                             pValue->m_pElement, lEventTime,
  1260.                             SmilEndTimeList);
  1261.                 }
  1262.             }// /end walking begin event list.
  1263.         }
  1264.     }
  1265.     else
  1266.     {
  1267.         ret = HXR_UNEXPECTED;
  1268.     }
  1269.     return ret;
  1270. }
  1271. HX_RESULT
  1272. CSmilParser::addEndEventElement(SmilTimeValue* pTimeVal)
  1273. {
  1274.     HX_RESULT rslt = HXR_OK;
  1275.     if (!m_pEndEventList)
  1276.     {
  1277. m_pEndEventList = new CHXSimpleList;
  1278. if (!m_pEndEventList)
  1279. {
  1280.     return HXR_OUTOFMEMORY;
  1281. }
  1282.     }
  1283.     m_pEndEventList->AddTail(pTimeVal);
  1284.     // Add it to the map
  1285.     addToBeginOrEndTimeMap(pTimeVal, SmilEndTimeList);
  1286.     return rslt;
  1287. }
  1288. HX_RESULT CSmilParser::addBeginMediaMarkerSyncElement(SmilTimeValue* pTmpVal)
  1289. {
  1290.     HX_RESULT retVal = HXR_FAIL;
  1291.     if (pTmpVal)
  1292.     {
  1293.         if (!m_pBeginMediaMarkerList)
  1294.         {
  1295.             m_pBeginMediaMarkerList = new CHXSimpleList();
  1296.         }
  1297.         if (m_pBeginMediaMarkerList)
  1298.         {
  1299.             m_pBeginMediaMarkerList->AddTail((void*) pTmpVal);
  1300.             retVal = HXR_OK;
  1301.         }
  1302.     }
  1303.     return retVal;
  1304. }
  1305. HX_RESULT CSmilParser::addEndMediaMarkerSyncElement(SmilTimeValue* pTmpVal)
  1306. {
  1307.     HX_RESULT retVal = HXR_FAIL;
  1308.     if (pTmpVal)
  1309.     {
  1310.         if (!m_pEndMediaMarkerList)
  1311.         {
  1312.             m_pEndMediaMarkerList = new CHXSimpleList();
  1313.         }
  1314.         if (m_pEndMediaMarkerList)
  1315.         {
  1316.             m_pEndMediaMarkerList->AddTail((void*) pTmpVal);
  1317.             retVal = HXR_OK;
  1318.         }
  1319.     }
  1320.     return retVal;
  1321. }
  1322. HX_RESULT CSmilParser::resolveMediaMarkerTime(const char* pszID,
  1323.                                               const char* pszMarkerName,
  1324.                                               UINT32      ulMarkerTime,
  1325.                                               REF(BOOL)   rbNeedHandleElements)
  1326. {
  1327.     HX_RESULT retVal = HXR_OK;
  1328.     if (pszID && pszMarkerName)
  1329.     {
  1330.         // Clear the handle elements flag
  1331.         rbNeedHandleElements = FALSE;
  1332.         // XXXMEH - TODO - linearly searching lists is not
  1333.         // a scalable solution - we should be looking up a
  1334.         // string in a map. Change how this is implemented
  1335.         //
  1336.         // First resolve the begin media marker list
  1337.         if (m_pBeginMediaMarkerList)
  1338.         {
  1339.             LISTPOSITION pos = m_pBeginMediaMarkerList->GetHeadPosition();
  1340.             while (pos)
  1341.             {
  1342.                 SmilTimeValue* pValue =
  1343.                     (SmilTimeValue*) m_pBeginMediaMarkerList->GetNext(pos);
  1344.                 if (pValue &&
  1345.                     pValue->getIdRef() &&
  1346.                     !strcmp(pszID, pValue->getIdRef()) &&
  1347.                     pValue->getMarkerName() &&
  1348.                     !strcmp(pszMarkerName, pValue->getMarkerName()))
  1349.                 {
  1350. //                    // Find out the scheduled start time for the element
  1351. //                    // we are based off of. We already know that this
  1352. //                    // element should be resolved since it is playing
  1353. //                    // and resolving markers.
  1354. //                    CSmilElement* pElement = findElement(pValue->getIdRef());
  1355. //                    if (pElement)
  1356. //                    {
  1357. //                        UINT32    ulStart = 0;
  1358. //                        HX_RESULT rv      = pElement->getCurrentScheduledStartTime(ulStart);
  1359. //                        if (SUCCEEDED(rv))
  1360. //                        {
  1361. //                            // Set this time as the "resolved" to time (this is
  1362. //                            // the time without the offset)
  1363. //                            pValue->setResolvedToTime((INT32) ulStart);
  1364. //                            pValue->setWhenTimeWasResolved((INT32) ulStart);
  1365. //                        }
  1366. //                    }
  1367.                     // Set the marker time
  1368.                     pValue->setMarkerTime(ulMarkerTime);
  1369.                     // XXXMEH - try this out - we want to now
  1370.                     // treat this timeval as a sync-arc.
  1371.                     addBeginTimeSyncElement(pValue->m_pElement);
  1372.                     pValue->m_pElement->m_BeginEventSourceID    = pValue->m_idRef;
  1373.                     pValue->m_pElement->m_nBeginEventSourceTag  = pValue->m_position;
  1374.                     pValue->m_pElement->m_lBeginEventClockValue = pValue->getTimeOffset();
  1375.                     m_pTimelineElementManager->addNotification(pValue->m_pElement->m_BeginEventSourceID,
  1376.                                                                pValue->m_pElement->m_pTimelineElement);
  1377.                     pValue->m_pElement->m_pTimelineElement->setDelayEventResolved(FALSE);
  1378. //                    HX_RESULT rv = insertElementWithPendingBeginOrEnd(pValue->m_pElement,
  1379. //                                                                      SMILTIME_NEGATIVE_INFINITY,
  1380. //                                                                      SmilBeginTimeList);
  1381.                     m_pTimelineElementManager->notify(pValue->m_idRef);
  1382.                     m_pTimelineElementManager->notify(pValue->m_pElement->m_pNode->m_id);
  1383.                     if (pValue->m_pElement->m_pTimelineElement->getParent())
  1384.                     {
  1385.                         pValue->m_pElement->m_pTimelineElement->getParent()->checkChildrenFillBehavior();
  1386.                     }
  1387.                     rbNeedHandleElements = TRUE;
  1388.                 }
  1389.             }
  1390.         }
  1391.         // Now resolve the end media marker list
  1392.         if (m_pEndMediaMarkerList)
  1393.         {
  1394.             LISTPOSITION pos = m_pEndMediaMarkerList->GetHeadPosition();
  1395.             while (pos)
  1396.             {
  1397.                 SmilTimeValue* pValue =
  1398.                     (SmilTimeValue*) m_pEndMediaMarkerList->GetNext(pos);
  1399.                 if (pValue &&
  1400.                     pValue->getIdRef() &&
  1401.                     !strcmp(pszID, pValue->getIdRef()) &&
  1402.                     pValue->getMarkerName() &&
  1403.                     !strcmp(pszMarkerName, pValue->getMarkerName()))
  1404.                 {
  1405. //                    // Find out the scheduled start time for the element
  1406. //                    // we are based off of. We already know that this
  1407. //                    // element should be resolved since it is playing
  1408. //                    // and resolving markers.
  1409. //                    CSmilElement* pElement = findElement(pValue->getIdRef());
  1410. //                    if (pElement)
  1411. //                    {
  1412. //                        UINT32    ulStart = 0;
  1413. //                        HX_RESULT rv      = pValue->m_pElement->getCurrentScheduledStartTime(ulStart);
  1414. //                        if (SUCCEEDED(rv))
  1415. //                        {
  1416. //                            // Set this time as the "resolved" to time (this is
  1417. //                            // the time without the offset)
  1418. //                            pValue->setResolvedToTime((INT32) ulStart);
  1419. //                            pValue->setWhenTimeWasResolved((INT32) ulStart);
  1420. //                        }
  1421. //                    }
  1422.                     // Set the time that the marker resolved to
  1423.                     pValue->setMarkerTime(ulMarkerTime);
  1424.                     // XXXMEH - try this out - we want to now
  1425.                     // treat this timeval as a sync-arc
  1426.                     addEndTimeSyncElement(pValue->m_pElement);
  1427.                     pValue->m_pElement->m_EndEventSourceID    = pValue->m_idRef;
  1428.                     pValue->m_pElement->m_nEndEventSourceTag  = pValue->m_position;
  1429.                     pValue->m_pElement->m_lEndEventClockValue = pValue->getTimeOffset();
  1430.                     m_pTimelineElementManager->addNotification(pValue->m_pElement->m_EndEventSourceID,
  1431.                                                                pValue->m_pElement->m_pTimelineElement);
  1432.                     pValue->m_pElement->m_pTimelineElement->setDelayEventResolved(FALSE);
  1433. //                    HX_RESULT rv = insertElementWithPendingBeginOrEnd(pValue->m_pElement,
  1434. //                                                                      SMILTIME_NEGATIVE_INFINITY,
  1435. //                                                                      SmilEndTimeList);
  1436.                     m_pTimelineElementManager->notify(pValue->m_idRef);
  1437.                     m_pTimelineElementManager->notify(pValue->m_pElement->m_pNode->m_id);
  1438.                     if (pValue->m_pElement->m_pTimelineElement->getParent())
  1439.                     {
  1440.                         pValue->m_pElement->m_pTimelineElement->getParent()->checkChildrenFillBehavior();
  1441.                     }
  1442.                     rbNeedHandleElements = TRUE;
  1443.                 }
  1444.             }
  1445.         }
  1446.         // Now resolve any clipBegin's which use this marker
  1447.         if (m_pClipBeginMarkerList)
  1448.         {
  1449.             LISTPOSITION pos = m_pClipBeginMarkerList->GetHeadPosition();
  1450.             while (pos)
  1451.             {
  1452.                 CSmilElement* pElement = (CSmilElement*) m_pClipBeginMarkerList->GetNext(pos);
  1453.                 if (pElement &&
  1454.                     pElement->m_pNode &&
  1455.                     !strcmp(pszID, pElement->m_pNode->m_id) &&
  1456.                     !strcmp(pszMarkerName, pElement->m_pszClipBeginMarkerName))
  1457.                 {
  1458.                     // Set the clipBegin time to the resolved time
  1459.                     pElement->m_ulClipBegin         = ulMarkerTime;
  1460.                     pElement->m_ulAuthoredClipBegin = ulMarkerTime;
  1461.                     // Set the flag saying we're resolved
  1462.                     pElement->m_bClipBeginMarkerResolved = TRUE;
  1463.                     // If the delay and duration have been resolved
  1464.                     // for this element, then we may have tried to
  1465.                     // schedule this element previously and could
  1466.                     // not because the clipBegin wasn't resolved.
  1467.                     // If we have NOT attempted to schedule this
  1468.                     // element, then don't try and schedule it now -
  1469.                     // wait on the normal process.
  1470.                     if (pElement->m_bWaitingOnClipBeginToResolve)
  1471.                     {
  1472.                         // Clear the flag
  1473.                         pElement->m_bWaitingOnClipBeginToResolve = FALSE;
  1474.                         // We DID try and schedule this element earlier,
  1475.                         // and could not due to not knowing the
  1476.                         // clipBegin. Therefore, now that we know the
  1477.                         // clipBegin, we will attempt to insert it again.
  1478.                         insertTimelineElement(pElement->m_pNode->m_id,
  1479.                                               pElement->m_ulDelay);
  1480.                         // Set the flag saying we need to
  1481.                         // call handleElements()
  1482.                         rbNeedHandleElements = TRUE;
  1483.                     }
  1484.                 }
  1485.             }
  1486.         }
  1487.         // Now resolve any clipEnd's which use this marker
  1488.         if (m_pClipEndMarkerList)
  1489.         {
  1490.             LISTPOSITION pos = m_pClipEndMarkerList->GetHeadPosition();
  1491.             while (pos)
  1492.             {
  1493.                 CSmilElement* pElement = (CSmilElement*) m_pClipEndMarkerList->GetNext(pos);
  1494.                 if (pElement &&
  1495.                     pElement->m_pNode &&
  1496.                     !strcmp(pszID, pElement->m_pNode->m_id) &&
  1497.                     !strcmp(pszMarkerName, pElement->m_pszClipEndMarkerName))
  1498.                 {
  1499.                     // Set the clipEnd time to the resolved time
  1500.                     pElement->m_ulClipEnd = ulMarkerTime;
  1501.                     // Set the flag saying we're resolved
  1502.                     pElement->m_bClipEndMarkerResolved = TRUE;
  1503.                     // If the delay and duration have been resolved
  1504.                     // for this element, then we may have tried to
  1505.                     // schedule this element previously and could
  1506.                     // not because the clipEnd wasn't resolved.
  1507.                     // If we have NOT attempted to schedule this
  1508.                     // element, then don't try and schedule it now -
  1509.                     // wait on the normal process.
  1510.                     if (pElement->m_bWaitingOnClipEndToResolve)
  1511.                     {
  1512.                         // Clear the flag
  1513.                         pElement->m_bWaitingOnClipEndToResolve = FALSE;
  1514.                         // We DID try and schedule this element earlier,
  1515.                         // and could not due to not knowing the
  1516.                         // clipBegin. Therefore, now that we know the
  1517.                         // clipBegin, we will attempt to insert it again.
  1518.                         insertTimelineElement(pElement->m_pNode->m_id,
  1519.                                               pElement->m_ulDelay);
  1520.                         // Set the flag saying we need to
  1521.                         // call handleElements()
  1522.                         rbNeedHandleElements = TRUE;
  1523.                     }
  1524.                 }
  1525.             }
  1526.         }
  1527.     }
  1528.     else
  1529.     {
  1530.         retVal = HXR_FAIL;
  1531.     }
  1532.     return retVal;
  1533. }
  1534. HX_RESULT
  1535. CSmilParser::addBeginTimeSyncElement(CSmilElement* pElement)
  1536. {
  1537.     if (!m_pBeginTimeSyncList)
  1538.     {
  1539. m_pBeginTimeSyncList = new CHXSimpleList;
  1540. if (!m_pBeginTimeSyncList)
  1541. {
  1542.     return HXR_OUTOFMEMORY;
  1543. }
  1544.     }
  1545.     m_pBeginTimeSyncList->AddTail(pElement);
  1546.     return HXR_OK;
  1547. }
  1548. HX_RESULT
  1549. CSmilParser::addEndTimeSyncElement(CSmilElement* pElement)
  1550. {
  1551.     if (!m_pEndTimeSyncList)
  1552.     {
  1553. m_pEndTimeSyncList = new CHXSimpleList;
  1554. if (!m_pEndTimeSyncList)
  1555. {
  1556.     return HXR_OUTOFMEMORY;
  1557. }
  1558.     }
  1559.     m_pEndTimeSyncList->AddTail(pElement);
  1560.     return HXR_OK;
  1561. }
  1562. HX_RESULT
  1563. CSmilParser::resolveSyncBaseElements()
  1564. {
  1565.     HX_RESULT ret = HXR_OK;
  1566.     if (m_pBeginTimeSyncList)
  1567.     {
  1568. CHXSimpleList::Iterator i;
  1569. for (i = m_pBeginTimeSyncList->Begin();
  1570.     i != m_pBeginTimeSyncList->End(); ++i)
  1571. {
  1572.     CSmilElement* pElement = (CSmilElement*)*i;
  1573.     LISTPOSITION lPos = NULL;
  1574.     if (NULL != pElement->m_pBeginTimeList)
  1575.     {
  1576. lPos = pElement->m_pBeginTimeList->GetHeadPosition();
  1577.     }
  1578.     if (NULL == lPos) // /list is empty.
  1579.     {
  1580. continue;
  1581.     }
  1582.     while (lPos  &&  HXR_OK == ret)
  1583.     {
  1584. SmilTimeValue* pValue =
  1585. (SmilTimeValue*)
  1586. (pElement->m_pBeginTimeList->GetNext(lPos));
  1587. if (SmilTimeSyncBase == pValue->m_type)
  1588. {
  1589.     INT32 offset = pValue->getTimeOffset();
  1590. #if defined(_DEBUG) // /XXXEH- testing!:
  1591.     LONG32 lEffectiveResolvedToTime = 0;
  1592.     pValue->getEffectiveResolvedTime(
  1593.     lEffectiveResolvedToTime);
  1594.     // /This will change so assert for now so when we
  1595.     // change how these vars are used we won't miss this code
  1596.     HX_ASSERT(pValue->isTimeResolved()?
  1597.     offset==lEffectiveResolvedToTime : TRUE);
  1598. #endif
  1599.     CSmilElement* pSyncElement =
  1600.     findElement((const char*)pValue->m_idRef);
  1601. #if defined(XXXEH_REPEAT_VALUE_TIMING_SHOULD_BE_EVENT_BASED)
  1602.     if (!pSyncElement)
  1603. #else
  1604.     // / "xxxx_repeat_copy_nnn" is OK since it's based on
  1605.     // xxxx.repeat(nnn) and is supposed to be treated as an
  1606.     // event and event id's don't have to exist:
  1607.     if (!pSyncElement  &&  !strstr(
  1608.     (const char*)pValue->m_idRef, "_repeat_copy_") )
  1609. #endif
  1610.     {
  1611. ret = HXR_FAIL;
  1612. CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  1613. errHandler.ReportError(SMILErrorNonexistentID,
  1614.     (const char*)pValue->m_idRef,
  1615.     pElement->m_pNode->m_ulTagStartLine);
  1616. break;
  1617.     }
  1618.     // /XXXEH- why don't we need to do this Josh?:
  1619.     //else
  1620.     //{
  1621.     //    pElement->m_BeginEventSourceID = pValue->m_idRef;
  1622.     //    pElement->m_lBeginEventClockValue = offset;
  1623.     //    pElement->m_nBeginEventSourceTag = pValue->m_position;
  1624.     //}
  1625. }
  1626.     } // /end while(lPos ...).
  1627. }
  1628.     }
  1629.     if (SUCCEEDED(ret) && m_pEndTimeSyncList)
  1630.     {
  1631. CHXSimpleList::Iterator i;
  1632. for (i = m_pEndTimeSyncList->Begin();
  1633.     i != m_pEndTimeSyncList->End(); ++i)
  1634. {
  1635.     CSmilElement* pElement = (CSmilElement*)*i;
  1636.     LISTPOSITION lPos = NULL;
  1637.     if (NULL != pElement->m_pBeginTimeList)
  1638.     {
  1639. lPos = pElement->m_pEndTimeList->GetHeadPosition();
  1640.     }
  1641.     if (NULL == lPos) // /list is empty.
  1642.     {
  1643. continue;
  1644.     }
  1645.     while (lPos  &&  HXR_OK == ret)
  1646.     {
  1647. SmilTimeValue* pValue =
  1648. (SmilTimeValue*)
  1649. (pElement->m_pEndTimeList->GetNext(lPos));
  1650. if (SmilTimeSyncBase == pValue->m_type)
  1651. {
  1652.     INT32 offset = pValue->getTimeOffset();
  1653. #if defined(_DEBUG) // /XXXEH- testing!:
  1654.     LONG32 lEffectiveResolvedToTime = 0;
  1655.     pValue->getEffectiveResolvedTime(
  1656.     lEffectiveResolvedToTime);
  1657.     // /This will change so assert for now so when we
  1658.     // change how these vars are used we won't miss this code
  1659.     HX_ASSERT(pValue->isTimeResolved()?
  1660.     offset==lEffectiveResolvedToTime : TRUE);
  1661. #endif
  1662.     CSmilElement* pSyncElement =
  1663.     findElement((const char*)pValue->m_idRef);
  1664. #if defined(XXXEH_REPEAT_VALUE_TIMING_SHOULD_BE_EVENT_BASED)
  1665.     if (!pSyncElement)
  1666. #else
  1667.     // / "xxxx_repeat_copy_nnn" is OK since it's based on
  1668.     // xxxx.repeat(nnn) and is supposed to be treated as an
  1669.     // event and event id's don't have to exist:
  1670.     if (!pSyncElement  &&  !strstr(
  1671.     (const char*)pValue->m_idRef, "_repeat_copy_") )
  1672. #endif
  1673.     {
  1674. ret = HXR_FAIL;
  1675. CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  1676. errHandler.ReportError(SMILErrorNonexistentID,
  1677.     (const char*)pValue->m_idRef,
  1678.     pElement->m_pNode->m_ulTagStartLine);
  1679. break;
  1680.     }
  1681.     // /XXXEH- why don't we need to do this Josh?:
  1682.     //else
  1683.     //{
  1684.     //    pElement->m_EndEventSourceID = pValue->m_idRef;
  1685.     //    pElement->m_lEndEventClockValue = offset;
  1686.     //    pElement->m_nEndEventSourceTag = pValue->m_position;
  1687.     //}
  1688. }
  1689.     } // /end while(lPos ...).
  1690. }
  1691.     }
  1692.     return ret;
  1693. }
  1694. // /None of the descendants have yet been added to the timeline because we
  1695. // needed to know what all of the descendants' begin times are resolved to
  1696. // before we can know which to insert before playback, which not to insert
  1697. // until during playback, and which never to insert.  In the following
  1698. // method (which is called before playback) we go ahead and insert the
  1699. // first one, timewise (and lexically first if there is a tie; in that
  1700. // case, we'll start the first and let the next interrupt the first during
  1701. // playback).  We also need to extend the duration of the excl to account
  1702. // for the latest of all its descendants' begins:
  1703. HX_RESULT
  1704. CSmilParser::handleExclDescendants()
  1705. {
  1706.     HX_RESULT ret = HXR_OK;
  1707.     // /XXXEH- see note in smlelem.cpp that starts with
  1708.     // "XXXEH- TODO: [optimization]: rather than inserting"...
  1709.     HX_RESULT retval = HXR_OK;
  1710.     BOOL bSomeScheduleWasChanged = FALSE;
  1711.     BOOL bDoHandleExclBeforePlaybackStarts = TRUE;
  1712.     retval = checkPendingBeginAndEndTimes(0, 0, // <-- use group 0 for all.
  1713.     bSomeScheduleWasChanged,
  1714.     0, // /Recursion count is 0 when called externally.
  1715.     NULL, NULL, bDoHandleExclBeforePlaybackStarts);
  1716. /*XXXEH: next, see if any excl has a child that has a resolved begin that is
  1717. beyond the dur of the presentation (group); maybe keep track of that
  1718. in setBeginTime() by keeping overall latest begin excl descendant
  1719. and then, here, add that element if it's beyond end of presentation
  1720. (or just extend dur of excl):
  1721. */
  1722.     // /If we are in an excl and we are beginning after our excl parent's
  1723.     // current child-derived end, then go ahead and insert into the timeline,
  1724.     LISTPOSITION lPos = NULL;
  1725.     CHXSimpleList* pPendList = GetPendingBeginTimeList();
  1726.     if (pPendList)
  1727.     {
  1728. lPos = pPendList->GetHeadPosition();
  1729.     }
  1730.     LONG32 lLatestGroup0BeginTimeSoFar = 0;
  1731.     LONG32 lLatestGroup0EndTimeSoFar = 0;
  1732.     SmilTimeValue* pTimeValOfGroup0LatestEndElem = NULL;
  1733.     while (lPos)
  1734.     {
  1735. SmilTimeValue* pCurTimeVal =
  1736. (SmilTimeValue*)pPendList->GetNext(lPos);
  1737. if (pCurTimeVal  &&  pCurTimeVal->m_pElement)
  1738. {
  1739.     ULONG32 ulParentEnd = (UINT32)-1;
  1740.     SMILNode* pSyncBaseNode = getSyncAncestor(
  1741.     pCurTimeVal->m_pElement->m_pNode);
  1742.     BOOL bIsInExcl = hasAncestor(SMILExcl,
  1743.     pCurTimeVal->m_pElement->m_pNode);
  1744.     if (bIsInExcl  &&  0==pSyncBaseNode->m_nGroup)
  1745.     {
  1746. if (pSyncBaseNode  &&  pSyncBaseNode->m_pElement  &&
  1747. pSyncBaseNode->m_pElement->m_pTimelineElement)
  1748. {
  1749.     // /XXXEH- TODO: handle case where endsync is
  1750.     // SMILEventSourceID and id matches m_pSourceElement->
  1751.     // m_pNode->m_id:
  1752.     // /XXXEH- TODO: also handle when sync parent has
  1753.     // indefinite end|dur:
  1754.     // /Now, see if we can extend our parent's duration and,
  1755.     // if so, see if we begin past that end time (if set) and,
  1756.     // if so, extend our parent's duration to our end time:
  1757.     if (!pSyncBaseNode->m_pElement->m_bHasExplicitEnd  &&
  1758.     !pSyncBaseNode->m_pElement->m_bHasExplicitDur  &&
  1759.     (SMILEventSourceFirst !=
  1760.     pSyncBaseNode->m_pElement->m_nEndsyncEventSourceTag  &&
  1761.     SMILEventSourceID !=
  1762.     pSyncBaseNode->m_pElement->m_nEndsyncEventSourceTag) )
  1763.     {
  1764. if ((UINT32)-1 != pSyncBaseNode->m_pElement->m_ulDuration  &&
  1765. (UINT32)-1 != pSyncBaseNode->m_pElement->m_ulDelay)
  1766. {
  1767.     ulParentEnd = pSyncBaseNode->m_pElement->m_ulDelay +
  1768.     pSyncBaseNode->m_pElement->m_ulDuration;
  1769. }
  1770. LONG32 lEffectiveResolvedToTime = 0;
  1771. HX_RESULT tmprslt =
  1772. pCurTimeVal->getEffectiveResolvedTime(
  1773. lEffectiveResolvedToTime);
  1774. if (HXR_OK==tmprslt  &&  lEffectiveResolvedToTime>0  &&
  1775. !pCurTimeVal->m_pElement->m_bHasBeenScheduled)
  1776. {
  1777.     // /We default to TRUE if it's MAX UINT32 because
  1778.     // duration of time containers hasn't neccessarily
  1779.     // been set by children yet:
  1780.     BOOL bDelayIsBeyondParentEnd = TRUE;
  1781.     if ((UINT32)-1 != ulParentEnd)
  1782.     {
  1783. bDelayIsBeyondParentEnd = (ulParentEnd <
  1784. pCurTimeVal->m_pElement->m_ulDelay);
  1785.     }
  1786.     if (bDelayIsBeyondParentEnd  &&
  1787.     lEffectiveResolvedToTime >
  1788.     lLatestGroup0BeginTimeSoFar)
  1789.     {
  1790. lLatestGroup0BeginTimeSoFar =
  1791. lEffectiveResolvedToTime;
  1792. lLatestGroup0EndTimeSoFar =
  1793. lEffectiveResolvedToTime +
  1794. ( (UINT32)-1 == pCurTimeVal->
  1795. m_pElement->m_ulDuration? 10 :
  1796. pCurTimeVal->m_pElement->m_ulDuration);
  1797. pTimeValOfGroup0LatestEndElem = pCurTimeVal;
  1798. // /Fix related to PR 56690: excl itself needs
  1799. // to know that it's got at least one child
  1800. // with a scheduled begin time(s):
  1801. HX_ASSERT(pSyncBaseNode->m_pElement->m_pTimelineElement);
  1802. if (pSyncBaseNode->m_pElement->m_pTimelineElement)
  1803. {
  1804.     pSyncBaseNode->m_pElement->m_pTimelineElement->
  1805.     setHasChildWithScheduledBegin(TRUE);
  1806. }
  1807.     }
  1808. }
  1809.     }
  1810. }
  1811.     }
  1812. }
  1813.     }
  1814.     if (lLatestGroup0EndTimeSoFar > 0  &&  pTimeValOfGroup0LatestEndElem)
  1815.     {
  1816. #if defined(XXXEH_THE_FOLLOWING_BREAKS_PAUSE_RESUME_IN_EXCL__NEEDS_REVISIT)
  1817. // /XXXEH- TODO: either remove from pendingBeginList or *don't*
  1818. // insert here but rather insert a dummy source (or *somehow* tell
  1819. // the timeline to stay open past lLatestGroup0BeginTimeSoFar):
  1820. // See "BUG-20010427_vidDoesntPause(IThinkDueToSecondOneBeing"...
  1821. // ..."AddedPriorToPlaybackIfParentDurIs0sAtTheTime...).smil"
  1822. insertTimelineElement(pTimeValOfGroup0LatestEndElem->m_pElement->
  1823. m_pTimelineElement->m_pID, lLatestGroup0BeginTimeSoFar);
  1824. #else
  1825. HX_ASSERT(1);  // /breakpoint-only code.
  1826. #endif
  1827.     }
  1828.     return ret;
  1829. }
  1830. HX_RESULT
  1831. CSmilParser::parseSmil1SyncbaseValue(const char* pCh,
  1832.      CSmilElement* pElement,
  1833.      SMILSyncAttributeTag nTag)
  1834. {
  1835.     HX_RESULT ret = HXR_OK;
  1836.     BOOL bParseError = FALSE;
  1837.     BOOL bHasEvent = TRUE;
  1838.     UINT32 clockValue = 0;
  1839.     char* pIdTag = new char[strlen(pCh)+1];
  1840.     char* pEvent = new char[strlen(pCh)+1];
  1841.     pIdTag[0] = 0;
  1842.     pEvent[0] = 0;
  1843.     BOOL bIsSMIL_1_0_idRef = TRUE;
  1844.     if (!strncmp(pCh, "id(", 3))
  1845.     {
  1846. pCh += 3; // skip over 'id('
  1847.     }
  1848.     else // /SMIL 2.0 id-ref can simply be the id val.
  1849.     {
  1850. bIsSMIL_1_0_idRef = FALSE;
  1851.     }
  1852.     int i = 0;
  1853.     while(*pCh && (*pCh != ')'))
  1854.     {
  1855. pIdTag[i++] = *pCh++;
  1856.     }
  1857.     if(*pCh == ')'  ||  !bIsSMIL_1_0_idRef)
  1858.     {
  1859. pIdTag[i] = 0;
  1860. // lookup ID to see if it references an existing entity,
  1861. // otherwise it is an error
  1862. void* pDummy = NULL;
  1863. // /XXXEH- TODO: make sure this is not only a valid ID,
  1864. // but is an immediate child of pElement (as per the SMIL 2.0 spec):
  1865. if(!m_pIDMap->Lookup(pIdTag, pDummy))
  1866. {
  1867.     ret = HXR_FAIL;
  1868.     CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  1869.     errHandler.ReportError(SMILErrorBadDuration, pCh,
  1870. pElement->m_pNode->m_ulTagStartLine);
  1871.     bParseError = TRUE;
  1872. }
  1873. else
  1874. {
  1875.     switch(nTag)
  1876.     {
  1877. case SMILSyncAttrBegin:
  1878. {
  1879.     pElement->m_BeginEventSourceID = pIdTag;
  1880. }
  1881. break;
  1882. case SMILSyncAttrEnd:
  1883. {
  1884.     pElement->m_EndEventSourceID = pIdTag;
  1885. }
  1886. break;
  1887. case SMILSyncAttrEndsync:
  1888. {
  1889.     pElement->m_EndsyncEventSourceID = pIdTag;
  1890. }
  1891. break;
  1892. default:
  1893. break;
  1894.     }
  1895. }
  1896. delete[] pIdTag;
  1897. if(strlen(pCh) > 2)
  1898. {
  1899.     if(nTag != SMILSyncAttrEndsync)
  1900.     {
  1901. pCh++; // skip over ')'
  1902. pCh++;  // skip over '('
  1903. i = 0;
  1904. while(*pCh && (*pCh != ')'))
  1905. {
  1906.     pEvent[i++] = *pCh++;
  1907. }
  1908. if(*pCh == ')')
  1909. {
  1910.     pEvent[i] = 0;
  1911. }
  1912. else
  1913. {
  1914.     bParseError = TRUE;
  1915. }
  1916.     }
  1917.     else
  1918.     {
  1919. bParseError = TRUE;
  1920.     }
  1921. }
  1922. else
  1923. {
  1924.     if(nTag == SMILSyncAttrEndsync)
  1925.     {
  1926. pElement->m_nEndsyncEventSourceTag = SMILEventSourceID;
  1927. bHasEvent = FALSE;
  1928.     }
  1929.     else
  1930.     {
  1931. bParseError = TRUE;
  1932.     }
  1933. }
  1934.     }
  1935.     else
  1936.     {
  1937. bParseError = TRUE;
  1938.     }
  1939.     if(bParseError)
  1940.     {
  1941. ret = HXR_FAIL;
  1942. CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  1943. errHandler.ReportError(SMILErrorBadDuration, pCh,
  1944.     pElement->m_pNode->m_ulTagStartLine);
  1945.     }
  1946.     else if(bHasEvent)
  1947.     {
  1948. SMILEventSourceTag eSourceTag = SMILEventSourceNone;
  1949. INT32 lEventClockValue = 0;
  1950. if(strcmp(pEvent, "begin") == 0)
  1951. {
  1952.     eSourceTag = SMILEventSourceBegin;
  1953. }
  1954. else if(strcmp(pEvent, "end") == 0)
  1955. {
  1956.     eSourceTag = SMILEventSourceEnd;
  1957. }
  1958. else
  1959. {
  1960.     // eat white space, and + or - if it is there..
  1961.     while (isspace(*pEvent))
  1962.     {
  1963. ++pEvent;
  1964.     }
  1965.     BOOL bPos = TRUE;
  1966.     if (*pEvent == '+')
  1967.     {
  1968. ++pEvent;
  1969.     }
  1970.     else if (*pEvent == '-')
  1971.     {
  1972. ++pEvent;
  1973. bPos = FALSE;
  1974.     }
  1975.     UINT32 clockValue;
  1976.     if(HXR_OK == parseClockValue(pEvent, clockValue))
  1977.     {
  1978. eSourceTag = SMILEventSourceClock;
  1979.     }
  1980.     else
  1981.     {
  1982. ret = HXR_FAIL;
  1983. CSmilSMILSyntaxErrorHandler errHandler(m_pContext);
  1984. errHandler.ReportError(SMILErrorBadDuration, pEvent,
  1985.     pElement->m_pNode->m_ulTagStartLine);
  1986.     }
  1987.     lEventClockValue =  (bPos ? clockValue:-1 * clockValue );
  1988. }
  1989. switch(nTag)
  1990. {
  1991.     case SMILSyncAttrBegin:
  1992.     {
  1993. pElement->m_nBeginEventSourceTag = eSourceTag;
  1994. pElement->m_lBeginEventClockValue = lEventClockValue;
  1995.     }
  1996.     break;
  1997.     case SMILSyncAttrEnd:
  1998.     {
  1999. pElement->m_nEndEventSourceTag = eSourceTag;
  2000. pElement->m_lEndEventClockValue = lEventClockValue;
  2001.     }
  2002.     break;
  2003.     case SMILSyncAttrEndsync:
  2004.     {
  2005. pElement->m_nEndsyncEventSourceTag = eSourceTag;
  2006.     }
  2007.     break;
  2008.     default:
  2009.     break;
  2010. }
  2011.     }
  2012.     delete[] pEvent;
  2013.     return ret;
  2014. }
  2015. BOOL
  2016. CSmilParser::EstablishBeginTimeList()
  2017. {
  2018.     BOOL bNotNull = TRUE;
  2019.     if (!m_pPendingBeginTimeList)
  2020.     {
  2021. m_pPendingBeginTimeList = new CHXSimpleList;
  2022. bNotNull = (NULL != m_pPendingBeginTimeList);
  2023.     }
  2024.     return bNotNull;
  2025. }
  2026. BOOL
  2027. CSmilParser::EstablishEndTimeList()
  2028. {
  2029.     BOOL bNotNull = TRUE;
  2030.     if (!m_pPendingEndTimeList)
  2031.     {
  2032. m_pPendingEndTimeList = new CHXSimpleList;
  2033. bNotNull = (NULL != m_pPendingEndTimeList);
  2034.     }
  2035.     return bNotNull;
  2036. }
  2037. BOOL
  2038. CSmilParser::EstablishBeginEventList()
  2039. {
  2040.     BOOL bNotNull = TRUE;
  2041.     if (!m_pBeginEventList)
  2042.     {
  2043. m_pBeginEventList = new CHXSimpleList;
  2044. bNotNull = (NULL != m_pBeginEventList);
  2045.     }
  2046.     return bNotNull;
  2047. }
  2048. BOOL
  2049. CSmilParser::EstablishEndEventList()
  2050. {
  2051.     BOOL bNotNull = TRUE;
  2052.     if (!m_pEndEventList)
  2053.     {
  2054. m_pEndEventList = new CHXSimpleList;
  2055. bNotNull = (NULL != m_pEndEventList);
  2056.     }
  2057.     return bNotNull;
  2058. }
  2059. HX_RESULT
  2060. CSmilParser::insertElementWithPendingBeginOrEnd(CSmilElement* pElement,
  2061.    INT32 lCurTimeInGroupTime,
  2062.    SmilTimingListType listType)
  2063. {
  2064.     HX_RESULT retval = HXR_OK;
  2065.     LISTPOSITION lPos = NULL;
  2066.     LISTPOSITION lPrev = NULL;
  2067.     LISTPOSITION lPosCurVal = NULL;
  2068.     SmilTimeValue* pNextResolvedValue = NULL;
  2069.     UINT32 ulSyncBaseTime = getSyncBaseTimeInGroupTimeCoords(pElement->m_pNode);
  2070.     INT32 lCurTimeInSyncBaseTime =  lCurTimeInGroupTime - (LONG32)ulSyncBaseTime;
  2071.     CHXSimpleList* pWhichList = NULL;
  2072.     if (SmilBeginTimeList == listType) // /insert begin time:
  2073.     {
  2074. if (!EstablishBeginTimeList())
  2075. {
  2076.     retval = HXR_OUTOFMEMORY;
  2077.     goto cleanup;
  2078. }
  2079. pWhichList = m_pPendingBeginTimeList;
  2080.     }
  2081.     else if (SmilEndTimeList == listType)// /insert end time:
  2082.     {
  2083. if (!EstablishEndTimeList())
  2084. {
  2085.     retval = HXR_OUTOFMEMORY;
  2086.     goto cleanup;
  2087. }
  2088. pWhichList = m_pPendingEndTimeList;
  2089.     }
  2090.     else
  2091.     {
  2092. HX_ASSERT(SmilBeginTimeList == listType  ||
  2093. SmilEndTimeList == listType);
  2094.     }
  2095.     if (NULL == pWhichList)
  2096.     {
  2097. retval = HXR_FAILED;
  2098. goto cleanup;
  2099.     }
  2100.     lPos = pWhichList->GetHeadPosition();
  2101.     // /First, we need to get the next resolved time of pElement
  2102.     // that is at or after lCurTimeInGroupTime:
  2103.     retval = pElement->getNextResolvedTimeValue(pNextResolvedValue,
  2104.     lCurTimeInGroupTime, lCurTimeInSyncBaseTime,
  2105.     listType, /* Don't need list of resolved times:*/ NULL);
  2106.     if (!SUCCEEDED(retval)  ||  NULL==pNextResolvedValue  ||
  2107.     !pNextResolvedValue->isTimeResolved())
  2108.     {
  2109. // /XXXEH- we shouldn't get here since we should never insert an
  2110. // element in this list that doesn't have a future resolved
  2111. // begin/end (depends on listType) time:
  2112. HX_ASSERT(0);
  2113. goto cleanup;
  2114.     }
  2115.     // /XXXEH- see "TODO: we ONLY want to..." comment below before believing
  2116.     // the following:
  2117.     // /Remove existing node in list if it's got same id and a later
  2118.     // resolved time; we only want each element once in the list and
  2119.     // list needs to be in order based on the next resolved begin time:
  2120.     // /XXXEH- TODO: we're searching the list twice; combine the following
  2121.     // with the subsequent while() loop:
  2122.     while (lPos)
  2123.     {
  2124. lPosCurVal = lPos;
  2125. SmilTimeValue* pCurNode =
  2126.     (SmilTimeValue*)pWhichList->GetNext(lPos);
  2127. if (pCurNode  &&  pCurNode->m_pElement  &&
  2128.     pCurNode->m_pElement->m_pNode  &&
  2129.     pCurNode->m_pElement->m_pNode->m_id == pElement->m_pNode->m_id)
  2130. {
  2131. /* /XXXEH- TODO: we ONLY want to remove duplicates of times that
  2132. are based on exactly the same event-base or sync-base reference,
  2133. e.g., begin="foo.activateEvent+5s; foo.activateEvent+8s" will
  2134. put two distinct begin times in this list when foo is clicked.
  2135. Modify the following so that it only removes this duplicate if it has
  2136. the same sync-base/event-base id and sync-type/event-type value (including
  2137. same offset):
  2138.     pWhichList->RemoveAt(lPosCurVal);
  2139. */
  2140. }
  2141. else
  2142. {
  2143.     // /(In)sanity check: no node should be NULL in this list and no
  2144.     // non-NULL node should have NULL m_pElement:
  2145.     HX_ASSERT(pCurNode  &&  pCurNode->m_pElement  &&
  2146.     pCurNode->m_pElement->m_pNode);
  2147. }
  2148.     }
  2149.     lPos = pWhichList->GetHeadPosition();
  2150.     lPrev = lPos;
  2151.     lPosCurVal = lPos;
  2152.     // /Now, find where in the list to insert this new one based on temporal
  2153.     // order:
  2154.     while(lPos)
  2155.     {
  2156. SmilTimeValue* pCurNode =
  2157.     (SmilTimeValue*)pWhichList->GetNext(lPos);
  2158. if (!pCurNode  ||  !pCurNode->m_pElement)
  2159. {
  2160.     HX_ASSERT(pCurNode  &&  pCurNode->m_pElement);
  2161.     continue;
  2162. }
  2163. // /To help fix one of the problems in PR 85885 & PR 79300, we need to
  2164. // make sure the curTime passed in is in syncBase time space, not group
  2165. // time, otherwise 2nd-or-later-in-seq children with scheduled begins
  2166. // will be treated as in the past or otherwise with wrong begin time:
  2167. UINT32 ulCurNodeSyncBaseTime = getSyncBaseTimeInGroupTimeCoords(
  2168. pCurNode->m_pElement->m_pNode);
  2169. INT32 lCurNodeCurTimeInSyncBaseTime = lCurTimeInGroupTime -
  2170. (LONG32)ulCurNodeSyncBaseTime;
  2171. // /This is the next resolved time of the current list node that
  2172. // we're comparing to pElement's next resolved time:
  2173. SmilTimeValue* pNextTimeValueOfCurElement = NULL;
  2174. retval = pCurNode->m_pElement->getNextResolvedTimeValue(
  2175. pNextTimeValueOfCurElement, lCurTimeInGroupTime,
  2176. lCurNodeCurTimeInSyncBaseTime, listType,
  2177. /* Don't need list of resolved times:*/ NULL);
  2178. if (!SUCCEEDED(retval)  ||  NULL==pNextTimeValueOfCurElement  ||
  2179. !pNextTimeValueOfCurElement->isTimeResolved())
  2180. {
  2181.     // /XXXEH- we shouldn't get here because we should never have
  2182.     // inserted an element in this list that doesn't have a future
  2183.     // resolved begin:
  2184. /// /XXXEH- not so sure about that...     HX_ASSERT(0);
  2185.     continue;
  2186. }
  2187. LONG32 lCurNodeEffectiveResolvedTime;
  2188. HX_RESULT rv1 = pNextTimeValueOfCurElement->getEffectiveResolvedTime(
  2189. lCurNodeEffectiveResolvedTime);
  2190. if (!SUCCEEDED(rv1))
  2191. {
  2192.     continue;
  2193. }
  2194. // /This is the next resolved time of pElement:
  2195. LONG32 lElementValueEffectiveResolvedTime;
  2196. HX_RESULT rv2 = pNextResolvedValue->getEffectiveResolvedTime(
  2197. lElementValueEffectiveResolvedTime);
  2198. if (!SUCCEEDED(rv2))
  2199. {
  2200.     retval = rv2;
  2201.     goto cleanup; // /error; we can't proceed.
  2202. }
  2203. // /See if pElement's next resolved time is less than the current
  2204. // list node's:
  2205. if (lCurNodeEffectiveResolvedTime>lElementValueEffectiveResolvedTime)
  2206. {
  2207.     pWhichList->InsertBefore(lPrev, pNextResolvedValue);
  2208.     retval = HXR_OK;
  2209.     goto cleanup;
  2210. }
  2211. lPrev = lPos;
  2212.     }
  2213.     // /Nothing was inserted in the above while(), so insert it at end:
  2214.     pWhichList->AddTail(pNextResolvedValue);
  2215. cleanup:
  2216.     return retval;
  2217. }
  2218. HX_RESULT
  2219. CSmilParser::handlePendingScheduling(INT32 lCurTimeInGroupTime,
  2220. INT16 iCurrentGroupIndex,
  2221. REF(BOOL) bSomeScheduleWasChanged,
  2222. /*OUT*/ CHXSimpleList* pPauseDisplayHideElementList,
  2223. /*OUT*/ CHXSimpleList* pPauseDisplayDisableElementList)
  2224. {
  2225.     HX_RESULT retval = HXR_OK;
  2226.     HX_RESULT tmpretval = HXR_OK;
  2227.     bSomeScheduleWasChanged = FALSE;
  2228.     retval = checkPendingBeginAndEndTimes(lCurTimeInGroupTime, iCurrentGroupIndex,
  2229.     // /This is set to TRUE if any element's begin and/or end time
  2230.     // gets updated to a new time:
  2231.     bSomeScheduleWasChanged,
  2232.     // /Recursion count is 0 when called externally:
  2233.     0,
  2234.     pPauseDisplayHideElementList,
  2235.     pPauseDisplayDisableElementList,
  2236.     FALSE);
  2237.     return retval;
  2238. }
  2239. typedef enum
  2240. {
  2241.       SMILTimelineStatusUnknown = 0
  2242.     , SMILTimelineStatusNeverScheduled
  2243.     , SMILTimelineStatusStartScheduledForLater
  2244.     , SMILTimelineStatusCurrentlyPlaying
  2245.     , SMILTimelineStatusFinishedPlaying
  2246.     , SMILTimelineStatusCurrentlyPaused
  2247.     , SMILTimelineStatusCurrentlyPausedAndRestarting // /For PR 62397 fix.
  2248. } SMILTimelineStatus;
  2249. /* This looks to see if any elements in the lists have a begin or end time
  2250.  * that is not yet accounted for in the timeline and that is now at or
  2251.  * earlier than lCurTime.  If any such begin times are found, then a track
  2252.  * that's playing that is associated with that element may get restarted
  2253.  * (depending on the element's restart value) and if any such end times are
  2254.  * found then the track that's playing that's associated with that element
  2255.  * will get stopped.  Note: Each list is sorted temporally so that the
  2256.  * first element is the earliest, and each element whose time is reached
  2257.  * gets removed.
  2258.  *
  2259.  * // /XXXEH- TODO: when a new begin time of an excl becomes scheduled
  2260.  * // within this function, be sure to schedule an end for all its siblings.
  2261.  *
  2262.  * Returns HXR_FAILED or HXR_UNEXPECTED on error, returns TRUE in
  2263.  * bREFSomeScheduleWasChanged if any begin and/or end time became used to
  2264.  * either start, restart, or end any element.
  2265.  */
  2266. HX_RESULT
  2267. CSmilParser::checkPendingBeginAndEndTimes(INT32 lCurTime,
  2268. INT16 iCurrentGroupIndex,
  2269. REF(BOOL) bREFSomeScheduleWasChanged, INT32 lRecursionCount,
  2270. /*OUT*/ CHXSimpleList* pPauseDisplayHideElementList,
  2271. /*OUT*/ CHXSimpleList* pPauseDisplayDisableElementList,
  2272. BOOL bDoHandleExclBeforePlaybackStarts)
  2273. {
  2274.     HX_RESULT retval = HXR_OK;
  2275.     bREFSomeScheduleWasChanged = FALSE;
  2276.     m_lLastCheckPendingTime = lCurTime;
  2277.     HX_ASSERT(lRecursionCount<=MAX_PENDING_CHECK_CALLDEPTH);
  2278.     // /Handle begin times that are ready to go:
  2279.     LISTPOSITION lPos = NULL;
  2280.     if (m_pPendingBeginTimeList)
  2281.     {
  2282. lPos = m_pPendingBeginTimeList->GetHeadPosition();
  2283.     }
  2284.     // /Keep track of this at the excl-element level to allow multiple excl's
  2285.     // to go through this loop as happens, for instance, when multiple groups
  2286.     // exist in the presentation and more than one has an excl in it, or when
  2287.     // multiple excl's begin at 0s in the same par:
  2288.     CHXMapStringToOb* pExclChildAddedBeforePlayback = new CHXMapStringToOb();
  2289.     SmilTimeValue* pTimeValEndToggleToBeIgnored = NULL;
  2290.     // /Go through and see if anybody has a begin time that's ready to become
  2291.     // their active begin time:
  2292.     while (lPos  &&  HXR_OK == retval)
  2293.     {
  2294. LISTPOSITION lPosOfCurTmpVal = lPos;
  2295. // /Gets val at lPos and then moves lPos to next node in list:
  2296. SmilTimeValue* pTmpVal =
  2297. (SmilTimeValue*)m_pPendingBeginTimeList->GetNext(lPos);
  2298. if (!pTmpVal  ||  !pTmpVal->m_pElement  ||
  2299. !pTmpVal->m_pElement->m_pNode)
  2300. {
  2301.     // /List shouldn't have an empty node or a node w/NULL element:
  2302.     HX_ASSERT(pTmpVal  &&  pTmpVal->m_pElement  &&
  2303.     pTmpVal->m_pElement->m_pNode);
  2304.     // /Get rid of it from the list:
  2305.     m_pPendingBeginTimeList->RemoveAt(lPosOfCurTmpVal);
  2306.     continue;
  2307. }
  2308. // /Fixes PR 54281 (final timing fix after core nested-meta fix):
  2309. // Don't use this timeValue if it's element is not in the current
  2310. // group, otherwise we'll start pending tracks based on prior group's
  2311. // onTimeSync times (each group has zero-based OnTimeSyncs()).
  2312. // NOTE: this can only happen in an excl which is the only place a
  2313. // resolved-begin-before-playback element will end up in the pending
  2314. // list:
  2315. if (pTmpVal->m_pElement->m_pNode->m_nGroup  != iCurrentGroupIndex  &&
  2316. // /If this is -1, then no source has ever been added to the
  2317. // core.  Helps fix cases where event-begun media is first
  2318. // media to play:
  2319. iCurrentGroupIndex != -1 &&
  2320. // /OK to do all time-0 ones prior to playback commencing
  2321. // because they're all OK to pre-schedule, anyway:
  2322. !bDoHandleExclBeforePlaybackStarts)
  2323. {
  2324.     continue;
  2325. }
  2326. LONG32 lEffectiveResolvedTime = 0;
  2327. LONG32 lSyncbaseDelayAddedToResolvedTime = 0;
  2328. HX_RESULT tmprslt =
  2329. pTmpVal->getEffectiveResolvedTime(lEffectiveResolvedTime);
  2330. if (HXR_OK!=tmprslt)
  2331. {
  2332.     // /No element should ever have been inserted in this list if it
  2333.     // didn't have a resolved time so we shouldn't get here!
  2334.     HX_ASSERT(HXR_OK==tmprslt);
  2335.     // /Get rid of it from the list:
  2336.     m_pPendingBeginTimeList->RemoveAt(lPosOfCurTmpVal);
  2337.     continue;
  2338. }
  2339. SMILNode* pExclAncestor = getSpecificAncestor(SMILExcl,
  2340. pTmpVal->m_pElement->m_pNode);
  2341. SMILNode* pSyncAncestor = getSyncAncestor(pTmpVal->m_pElement->m_pNode);
  2342. // /If we're in an excl and being handled prior to playback starting
  2343. // (or after playback starts but our excl parent has a begin offset),
  2344. // then we may not have our delay set yet by our parent in which
  2345. // case we need to add our parent delay to lEffectiveResolvedTime:
  2346. // This *only* applies to scheduled (non-event) begin times that
  2347. // resolved at time 0 before being able to adjust for parent delay
  2348. // offset:
  2349. if (0 == pTmpVal->getWhenTimeWasResolved()  &&
  2350. 0 == lEffectiveResolvedTime  &&
  2351. pExclAncestor  &&
  2352. pTmpVal->m_pElement  &&  pTmpVal->m_pElement->m_pNode  &&
  2353. (UINT32)-1 == pTmpVal->m_pElement->m_ulDelay  &&
  2354. (SmilTimeOffset == pTmpVal->m_type  ||
  2355. SmilTimeClockValue == pTmpVal->m_type  ||
  2356. SmilTimeWallclock == pTmpVal->m_type))
  2357. {
  2358.     if (pSyncAncestor  &&  pSyncAncestor->m_pElement  &&
  2359.     (UINT32)-1 != pSyncAncestor->m_pElement->m_ulDelay)
  2360.     {
  2361. if (bDoHandleExclBeforePlaybackStarts)
  2362. {
  2363.     pTmpVal->setResolvedToTime(pSyncAncestor->m_pElement->m_ulDelay);
  2364.     lEffectiveResolvedTime += pSyncAncestor->m_pElement->m_ulDelay;
  2365.     lSyncbaseDelayAddedToResolvedTime =
  2366.     pSyncAncestor->m_pElement->m_ulDelay;
  2367. }
  2368. else
  2369. {
  2370.     // /We'll get here if excl parent is not 1st child of a seq.
  2371.     HX_ASSERT(1  ||  "XXXEH- BUG-20010516_PR52110(simplifiedVersionMaybe)....smil");
  2372.     lEffectiveResolvedTime += pSyncAncestor->m_pElement->m_ulDelay;
  2373.     lSyncbaseDelayAddedToResolvedTime =
  2374.     pSyncAncestor->m_pElement->m_ulDelay;
  2375. }
  2376.     }
  2377.     else
  2378.     {
  2379. // /Parent has unresolved delay so we don't want to do
  2380. // anything with its children yet:
  2381. continue;
  2382.     }
  2383. }
  2384. // /If our effectiveResolvedTime is later than zero and we're in an
  2385. // excl and have a clock-type time, then our time is still in parent
  2386. // coordinates and not in overall timeline coordinates like lCurTime
  2387. // is.  We need to adjust the lEffectiveResolvedTime up by the delay
  2388. // of our parent for later comparison to lCurTime:
  2389. else if (pExclAncestor  &&
  2390. pTmpVal->m_pElement  &&  pTmpVal->m_pElement->m_pNode  &&
  2391. (UINT32)-1 == pTmpVal->m_pElement->m_ulDelay  &&
  2392. (SmilTimeOffset == pTmpVal->m_type  ||
  2393. SmilTimeClockValue == pTmpVal->m_type  ||
  2394. SmilTimeWallclock == pTmpVal->m_type))
  2395. {
  2396.     // /In an excl, we don't want to use clock value times; we want
  2397.     // use resolved-to times since we're treating these clock times
  2398.     // more like events.  getEffectiveResolvedTime(), above, just
  2399.     // returns the offset if it's a clock time, i.e., it is not in
  2400.     // player time but rather in local sync-base time because
  2401.     // clock times usually are used prior to playback as local times:
  2402.     INT32 lResolvedToTime = pTmpVal->getResolvedToTimeWithoutOffset();
  2403.     if (pSyncAncestor  &&  pSyncAncestor->m_pElement  &&
  2404.     (UINT32)-1 != pSyncAncestor->m_pElement->m_ulDelay)
  2405.     {
  2406. lEffectiveResolvedTime += pSyncAncestor->m_pElement->m_ulDelay;
  2407. // /If this is an excl-deferred track, then lResolvedToTime
  2408. // could be >0 and != lEffectiveResolvedTime (as in PR 55936).
  2409. pTmpVal->setResolvedToTime(lEffectiveResolvedTime);
  2410. pTmpVal->setWhenTimeWasResolved(lCurTime);
  2411.     }
  2412.     else
  2413.     {
  2414. // /Parent has unresolved delay so we don't want to do
  2415. // anything with its children yet:
  2416. continue;
  2417.     }
  2418. }
  2419. ULONG32 ulActualStartTime = 0;
  2420. ULONG32 ulActualStopTime = 0;
  2421. HX_RESULT pnrStart =
  2422. pTmpVal->m_pElement->getCurrentScheduledStartTime(
  2423. ulActualStartTime);
  2424. LONG32 lElementCurBeginTime = (LONG32)ulActualStartTime;
  2425. HX_RESULT pnrStop =
  2426. pTmpVal->m_pElement->getCurrentScheduledStopTime(
  2427. ulActualStopTime);
  2428. LONG32 lElementCurEndTime = (LONG32)ulActualStopTime;
  2429. SMILTimelineStatus curSMILTimelineStatus = SMILTimelineStatusUnknown;
  2430. BOOL bTrackIsFinishedAndFrozen = FALSE;
  2431. BOOL bCurElementIsTimeContainer =
  2432. isTimeContainerObject(pTmpVal->m_pElement->m_pNode);
  2433. if (!pTmpVal->m_pElement->m_bInsertedIntoTimeline)
  2434. {
  2435.     curSMILTimelineStatus = SMILTimelineStatusNeverScheduled;
  2436. }
  2437. else
  2438. {
  2439.     HX_ASSERT(HXR_OK == pnrStart  &&
  2440.     (UINT32)-1 != lElementCurBeginTime  &&
  2441.     SMILTIME_INFINITY != lElementCurBeginTime);
  2442.     if (lElementCurBeginTime > lCurTime)
  2443.     {
  2444. curSMILTimelineStatus =
  2445. SMILTimelineStatusStartScheduledForLater;
  2446.     }
  2447.     else
  2448.     {
  2449. // /We need to check if this is a paused track and, if so,
  2450. // extend its end time by how long it was paused:
  2451. if (lEffectiveResolvedTime <= lCurTime  &&
  2452. pTmpVal->isResumeEvent()  &&
  2453. pTmpVal->m_pElement->m_pHandler)
  2454. {
  2455.     CSmilTimelineElement* pParent = pTmpVal->m_pElement->
  2456.     m_pTimelineElement->getParent();
  2457.     pTmpVal->m_pElement->prepForResumeInExcl();
  2458.     // /First, let's check to see if it's got an explicit end
  2459.     // time that's already in the past (Interop Timing #25.8):
  2460.     BOOL bEndIsInThePast =
  2461.     (pTmpVal->m_pElement->m_bHasExplicitEnd  &&
  2462.     pTmpVal->m_pElement->m_bEndOffsetSet  &&
  2463.     pTmpVal->m_pElement->m_lEndOffset <= lCurTime);
  2464.     if (!bEndIsInThePast)
  2465.     {
  2466. curSMILTimelineStatus =
  2467. SMILTimelineStatusCurrentlyPaused;
  2468. LONG32 lPauseTime = pTmpVal->getPauseTime();
  2469. HX_ASSERT(lPauseTime < lCurTime);
  2470. LONG32 lPauseDuration = lCurTime>lPauseTime?
  2471. (lCurTime-lPauseTime) : 0;
  2472. ULONG32 ulDur = pTmpVal->m_pElement->m_ulDuration;
  2473. HX_ASSERT(pTmpVal->m_pElement->m_ulAnticipatedPauseDur <
  2474. WAY_IN_THE_FUTURE);
  2475. if (pTmpVal->m_pElement->m_ulAnticipatedPauseDur < ulDur)
  2476. {
  2477.     // /Helps fix PR 86107: reduce dur by what we thought
  2478.     // it was supposed to extend by (which may differ
  2479.     // from actual pause time) and then add actual pause
  2480.     // duration to the original value, below, to get
  2481.     // total actual duration including pause:
  2482.     ulDur -= pTmpVal->m_pElement->m_ulAnticipatedPauseDur;
  2483. }
  2484.                         // /Adding the conditional to this "else" re-fixes
  2485.                         // PR 85896 (& dup 79288) which were broken by PR 86107
  2486.                         // fix, and helps fix PR 100601.  This might be a valid
  2487.                         // case where the duration of the pausing element was
  2488.                         // not yet set at time of pause (i.e., it was still
  2489.                         // 0xFFFFFFFF) or it was indefinite; we shouldn't adjust
  2490.                         // "back" if we never adjusted forward:
  2491. else if (pTmpVal->m_pElement->m_ulAnticipatedPauseDur <
  2492. WAY_IN_THE_FUTURE)
  2493. {
  2494.     ulDur = 0;
  2495.     HX_ASSERT(ulDur);
  2496. }
  2497. // /Make sure this doesn't get used now that it's resuming:
  2498. pTmpVal->m_pElement->m_ulAnticipatedPauseDur = 0;
  2499. if (lPauseDuration > 0  &&  (UINT32)-1 != ulDur &&
  2500. SMILTIME_INFINITY != ulDur  &&
  2501. (!pTmpVal->m_pElement->m_bIndefiniteDuration  ||
  2502. pTmpVal->m_pElement->m_bIndefiniteEnd))
  2503. {
  2504.     // /Hleps Fix PR 85896: don't add pauseDur to
  2505.     // indefinite/unresolved duration:
  2506.     if (WAY_IN_THE_FUTURE != ulDur)
  2507.     {
  2508. ulDur += lPauseDuration;
  2509. #if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG_EXCL_TRACK_REMOVAL)
  2510. {
  2511.     FILE* f1 = ::fopen("c:\smil2excl.txt", bFirstExclTrackChangeDebugOut?"w":"a+");
  2512.     bFirstExclTrackChangeDebugOut = FALSE;
  2513.     ::fprintf(f1, "At %6ld: timeVal's id = %s;tresetting duration from %lu to %lu (delay=%lu, pauseDuration=%ld)n",
  2514. lCurTime, (const char*)pTmpVal->m_pElement->m_pNode->m_id,
  2515. pTmpVal->m_pElement->m_ulDuration, ulDur, pTmpVal->m_pElement->m_ulDelay, lPauseDuration);
  2516.     ::fclose(f1);
  2517. }
  2518. #endif
  2519. pTmpVal->m_pElement->m_pTimelineElement->
  2520. resetDuration(ulDur);
  2521. // /Helps fix PR 86106 (all 3 versions)
  2522. // /Force smildocrender to HandleElements():
  2523. bREFSomeScheduleWasChanged = TRUE;
  2524.     }
  2525.     else
  2526.     {
  2527. // /Fix for PR 85896: make sure core doesn't
  2528. // extend past the "indefinite/unresolved" time
  2529. // due to pause-extended track; tell core to
  2530. // reduce dur by curTime to keep the same end:
  2531. UINT32 ulCurTime =
  2532. lCurTime<0? 0 : (UINT32)lCurTime;
  2533. resetTimelineElementDuration(
  2534. pTmpVal->m_pElement->m_pNode->m_id,
  2535. ulDur - ulCurTime, ulDur);
  2536. // /Force smildocrender to HandleElements():
  2537. bREFSomeScheduleWasChanged = TRUE;
  2538.     }
  2539. }
  2540. retval = pTmpVal->m_pElement->m_pHandler->
  2541. handleTrackResuming(
  2542. (const char*)pTmpVal->m_pElement->m_pNode->m_id,
  2543. (INT32)pTmpVal->m_pElement->m_pNode->m_nGroup);
  2544. #if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG_EXCL_TRACK_REMOVAL)
  2545. {
  2546.     FILE* f1 = ::fopen("c:\smil2excl.txt", bFirstExclTrackChangeDebugOut?"w":"a+");
  2547.     bFirstExclTrackChangeDebugOut = FALSE;
  2548.     ::fprintf(f1, "At %6ld: timeVal's id = %s;thandleTrackResuming() returned 0x%08xn",
  2549.     lCurTime, (const char*)pTmpVal->m_pElement->m_pNode->m_id, retval);
  2550.     ::fclose(f1);
  2551. }
  2552. #endif
  2553. if (pParent)
  2554. {
  2555.     // /Helps fix PR 53175 (& 54540): resuming after
  2556.     // another ends should cause the one that ended to
  2557.     // disappear (if its fill="freeze" or "remove"):
  2558.     pParent->checkChildrenFillBehavior();
  2559. }
  2560.     }
  2561.     else
  2562.     {
  2563. if (pParent)
  2564. {
  2565. #if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG_EXCL_TRACK_REMOVAL)
  2566. {
  2567.     FILE* f1 = ::fopen("c:\smil2excl.txt", bFirstExclTrackChangeDebugOut?"w":"a+");
  2568.     bFirstExclTrackChangeDebugOut = FALSE;
  2569.     ::fprintf(f1, "At %6ld: timeVal's id = %s;tcalling checkChildrenFillBehavior() "
  2570.  "because someone's end has been surpassedn",
  2571.     lCurTime, (const char*)pTmpVal->m_pElement->m_pNode->m_id);
  2572.     ::fclose(f1);
  2573. }
  2574. #endif
  2575.     // /Make sure it has chance to be visibly removed:
  2576.     pParent->checkChildrenFillBehavior();
  2577. }
  2578. // /Get rid of it from the list:
  2579. m_pPendingBeginTimeList->RemoveAt(lPosOfCurTmpVal);
  2580. continue;
  2581.     }
  2582. }
  2583. else if (lElementCurEndTime > lCurTime)
  2584. {
  2585.     curSMILTimelineStatus =
  2586.     SMILTimelineStatusCurrentlyPlaying;
  2587.     // /Fixes PR 62397: need to check if it's a paused track
  2588.     // being restarted; if so, remove its resume event and
  2589.     // allow its currently-playing sibling to be removed:
  2590.     if (lEffectiveResolvedTime <= lCurTime  &&
  2591.     // /Make sure it's paused; PR 50588's par *was*
  2592.     // passing this if() test but was not paused; it
  2593.     // has a par with begin="0s;4s" and end > 4s:
  2594.     pTmpVal->m_pElement->m_bIsPausedInExcl  &&
  2595.     pTmpVal->m_pElement->m_pHandler)
  2596.     {
  2597. // /Resume events should have been handled above:
  2598. HX_ASSERT(!pTmpVal->isResumeEvent());
  2599. curSMILTimelineStatus =
  2600. SMILTimelineStatusCurrentlyPausedAndRestarting;
  2601. // /Next, remove the resume event from the event list
  2602. // since this track is restarting so its old, paused,
  2603. // track goes away:
  2604. // /Also, make sure that any paused sibling awaiting
  2605. // the current (restarting) one's end now points to
  2606. // the next-in-pause-queue element instead:
  2607. SmilTimeValue* pTmVlCurElementResumeEvent = NULL;
  2608. SmilTimeValue*
  2609.     pTmVlPausedSiblResumesWhenCurElementEnds = NULL;
  2610. LISTPOSITION listPos = NULL;
  2611. HX_ASSERT(m_pBeginEventList);
  2612. if (m_pBeginEventList)
  2613. {
  2614.     listPos = m_pBeginEventList->GetHeadPosition();
  2615.     while (listPos)
  2616.     {
  2617. LISTPOSITION lPosOfCurTmpTimeValue = listPos;
  2618. // /Gets val at lPos then moves lPos to next node:
  2619. SmilTimeValue* pTmpTimeValue = (SmilTimeValue*)
  2620. m_pBeginEventList->GetNext(listPos);
  2621. if (!pTmpTimeValue  ||
  2622. !pTmpTimeValue->m_pElement)
  2623. {
  2624.     // /List shouldn't have an empty or NULL node:
  2625.     HX_ASSERT(pTmpTimeValue  &&
  2626.     pTmpTimeValue->m_pElement);
  2627.     continue;
  2628. }
  2629. if (pTmpTimeValue->m_pElement ==
  2630. pTmpVal->m_pElement  &&
  2631. pTmpTimeValue->isResumeEvent())
  2632. {
  2633.     // /Get rid of it from the pending list:
  2634.     m_pBeginEventList->RemoveAt(lPosOfCurTmpTimeValue);
  2635.                                     // Get rid of it from the map
  2636.                                     removeFromBeginOrEndTimeMap(pTmpTimeValue, SmilBeginTimeList);
  2637.     pTmVlCurElementResumeEvent = pTmpTimeValue;
  2638.     if (pTmVlPausedSiblResumesWhenCurElementEnds)
  2639.     {
  2640. // /The one (if any) that was paused by
  2641. // the last play of this should instead
  2642. // await the resume event of the next-in-
  2643. // line element on the "pause queue":
  2644. pTmVlPausedSiblResumesWhenCurElementEnds->
  2645. m_idRef = pTmpTimeValue->m_idRef;
  2646. break; // /We found both so we're done.
  2647.     }
  2648. }
  2649. else if (pTmpTimeValue->m_idRef ==
  2650. pTmpVal->m_pElement->m_pNode->m_id  &&
  2651. pTmpTimeValue->isResumeEvent())
  2652. {
  2653.     pTmVlPausedSiblResumesWhenCurElementEnds =
  2654.     pTmpTimeValue;
  2655.     // /The one (if any) that was paused by
  2656.     // the last play of this should now
  2657.     // await the resume event of the next-in-
  2658.     // line element on the "pause queue":
  2659.     if (pTmVlCurElementResumeEvent)
  2660.     {
  2661. pTmVlPausedSiblResumesWhenCurElementEnds->
  2662. m_idRef =
  2663. pTmVlCurElementResumeEvent->m_idRef;
  2664. break; // /We found both so we're done.
  2665.     }
  2666. }
  2667.     }
  2668. }
  2669.     }
  2670. }
  2671. else
  2672. {
  2673.     curSMILTimelineStatus =
  2674.     SMILTimelineStatusFinishedPlaying;
  2675.     bTrackIsFinishedAndFrozen = FALSE;
  2676.     if (pTmpVal->m_pElement->m_ulRemoveTime > (ULONG32)lCurTime)
  2677.     {
  2678. bTrackIsFinishedAndFrozen = TRUE;
  2679.     }
  2680. }
  2681.     }
  2682. }
  2683. #if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG_EXCL_TRACK_REMOVAL)
  2684. {
  2685. const char* pCurStatus[7] =
  2686. { "SMILTimelineStatusUnknown",
  2687.     "SMILTimelineStatusNeverScheduled",
  2688.     "SMILTimelineStatusStartScheduledForLater",
  2689.     "SMILTimelineStatusCurrentlyPlaying",
  2690.     "SMILTimelineStatusFinishedPlaying",
  2691.     "SMILTimelineStatusCurrentlyPaused",
  2692.     "SMILTimelineStatusCurrentlyPausedAndRestarting"
  2693. };
  2694. FILE* f1 = ::fopen("c:\smil2excl.txt", bFirstExclTrackChangeDebugOut?"w":"a+");
  2695. bFirstExclTrackChangeDebugOut = FALSE;
  2696. ::fprintf(f1, "At %6ld: timeVal's id = %st "
  2697. "curSMILTimelineStatus==%s, ulActualStartTime=%lu, ulActualStopTime=%lu, "
  2698. "lElementCurBeginTime=%ld, lEffectiveResolvedTime=%ld, "
  2699. "lSyncbaseDelayAddedToResolvedTime=%ldn",
  2700. lCurTime, (const char*)pTmpVal->m_pElement->m_pNode->m_id,
  2701. pCurStatus[curSMILTimelineStatus],ulActualStartTime, ulActualStopTime,
  2702. lElementCurBeginTime, lEffectiveResolvedTime,
  2703. lSyncbaseDelayAddedToResolvedTime);
  2704. ::fclose(f1);
  2705. }
  2706. #endif
  2707. BOOL bIsInExcl = hasAncestor(SMILExcl, pTmpVal->m_pElement->m_pNode);
  2708. // /If this is prior to playback, all elements in the list shuold be
  2709. // descendants of an excl:
  2710. if (bDoHandleExclBeforePlaybackStarts  &&  !bIsInExcl)
  2711. {
  2712.     continue;
  2713. }
  2714. // /Prior to playback, only add the first excl child that has a
  2715. // begin time of 0s (or is the one with the earliest resolved begin):
  2716. if (bIsInExcl  &&  pExclChildAddedBeforePlayback  &&
  2717. pExclChildAddedBeforePlayback  &&  pExclAncestor  &&
  2718. (*pExclChildAddedBeforePlayback)[(const char*)
  2719. pExclAncestor->m_id])
  2720. {
  2721.     HX_ASSERT(bDoHandleExclBeforePlaybackStarts);
  2722.     continue;
  2723. }
  2724. // /We should be in one of these four states; anything else means
  2725. // there's an inconsistency somewhere:
  2726. HX_ASSERT (SMILTimelineStatusUnknown != curSMILTimelineStatus);
  2727. LONG32 lResolvedTimeToUse =
  2728. lEffectiveResolvedTime-lSyncbaseDelayAddedToResolvedTime;
  2729. // /Now, see if this pending time is ready to be used:
  2730. if (lResolvedTimeToUse <= lCurTime  ||
  2731. // /OPTIMIZATION:
  2732. // /If this element has never been scheduled, then go ahead
  2733. // and schedule it with this newly-resolved (and possibly
  2734. // future) time so core has greatest opportunity to pre-
  2735. // buffer the element prior to commencing its playback:
  2736. (!bIsInExcl  &&
  2737. SMILTimelineStatusNeverScheduled == curSMILTimelineStatus)  ||
  2738. // /OPTIMIZATION:
  2739. // /If element is scheduled to play later and this new
  2740. // begin time is prior to that, then use this new time
  2741. // and give core a chance to buffer it in advance:
  2742. (SMILTimelineStatusStartScheduledForLater ==
  2743. curSMILTimelineStatus  &&  lResolvedTimeToUse <
  2744. lElementCurBeginTime) )
  2745. {
  2746.     // Using the result, we need to decide what to do with
  2747.     // this element based on:
  2748.     //  (1) If it has ever been added to the timeline,
  2749.     //  (2) If it's currently playing, paused, or stopped,
  2750.     //  (3) If its restart value is "always", "never", or
  2751.     //      "whenNotActive"
  2752.     // Note: We don't want to just start the element based on a
  2753.     // newly-resolved begin time due to this event because
  2754.     // this element's begin list might be:
  2755.     //    begin="foo.activate+5s; 10s"
  2756.     // so a click at 8s means the 10s begin will be next, not
  2757.     // the click-based begin that resolves to 13s.
  2758.     // /Handle all these cases, where 't' is a time unit and
  2759.     // "0t" is now (ulEventTime), 'rE' is resolved event time,
  2760.     // i.e., event time plus any offset, "psB" and "psE" are
  2761.     // previously-scheduled Begin and End times, respectively:
  2762.     //
  2763.     // (1) Has never played and is not yet scheduled to,
  2764.     //  and resolved event time is negative, 0, or positive
  2765.     //  offset from now:
  2766.     //  -3t  -2t   -1t     0t    1t    2t    3t
  2767.     //   +-----+-----+-----+-----+-----+-----+
  2768.     //                    | /
  2769.     //                     rE
  2770.     //
  2771.     // (2) Has never played but is scheduled to later, and
  2772.     //  resolved event time is prior to previously-scheduled
  2773.     //  begin:
  2774.     //  -3t  -2t   -1t     0t    1t    2t    3t
  2775.     //   +-----+-----+-----+-----+-====+====-+
  2776.     //                    | /     |       |
  2777.     //                     rE     psB     psE
  2778.     //
  2779.     // (3) Has never played but is scheduled to later, and
  2780.     //  resolved event time is same as previously-scheduled
  2781.     //  begin:
  2782.     //  -3t  -2t   -1t     0t    1t    2t    3t
  2783.     //   +-----+-----+-----+--===+=====+==---+
  2784.     //                        |          |
  2785.     //                      rE,psB      psE
  2786.     //
  2787.     // (4) Has never played but is scheduled to later, and
  2788.     //  resolved event time is after previously-scheduled
  2789.     //  begin and prior to previously-scheduled end:
  2790.     //  -3t  -2t   -1t     0t    1t    2t    3t
  2791.     //   +-----+-----+-----+--===+=====+====-+
  2792.     //                        |     |      |
  2793.     //                       psB    rE    psE
  2794.     //
  2795.     // (5) Has never played but is scheduled to later, and
  2796.     //  resolved event time is same as previously-scheduled end:
  2797.     //  -3t  -2t   -1t     0t    1t    2t    3t
  2798.     //   +-----+-----+-----+--===+=====+==---+
  2799.     //                        |          |
  2800.     //                       psB      psE,rE
  2801.     //
  2802.     // (6) Has never played but is scheduled to later, and
  2803.     //  resolved event time is after previously-scheduled end:
  2804.     //  -3t  -2t   -1t     0t    1t    2t    3t
  2805.     //   +-----+-----+-----+--===+====-+-----+
  2806.     //                        |      |     |
  2807.     //                       psB    psE    rE
  2808.     //
  2809.     // (7a) Is done playing, and resolved event time is negative,
  2810.     //  0, or positive offset from now, but not less than prior end:
  2811.     //  -3t  -2t   -1t     0t    1t    2t    3t
  2812.     //   +-====+====-+-----+-----+-----+-----+
  2813.     //     |       |      | /
  2814.     //    psB     psE      rE
  2815.     //
  2816.     // (7b) Is done playing, and resolved event time is negative
  2817.     //  offset from now and earlier than prior end:
  2818.     //  -3t  -2t   -1t     0t    1t    2t    3t
  2819.     //   +-====+====-+-----+-----+-----+-----+
  2820.     //     |  |    |
  2821.     //    psB rE  psE
  2822.     //
  2823.     // (8) Is playing now, and resolved event time is prior to
  2824.     //  previously-scheduled end time:
  2825.     //  -3t  -2t   -1t     0t    1t    2t    3t
  2826.     //   +---==+=====+=====+=====+==---+-----+
  2827.     //       |            | /     |
  2828.     //      psB            rE     psE
  2829.     //
  2830.     // (9) Is playing now, and resolved event time is same as
  2831.     //  previously-scheduled end time:
  2832.     //  -3t  -2t   -1t     0t    1t    2t    3t
  2833.     //   +---==+=====+=====+=====+==---+-----+
  2834.     //       |                     |
  2835.     //      psB                 psE,rE
  2836.     //
  2837.     // (10) Is playing now, and resolved event time is after
  2838.     //  previously-scheduled end time:
  2839.     //  -3t  -2t   -1t     0t    1t    2t    3t
  2840.     //   +---==+=====+=====+=====+==---+-----+
  2841.     //       |                     |      |
  2842.     //      psB                   psE     rE
  2843.     //
  2844.     //
  2845.     // Algorithm:
  2846.     // - Whenever an element becomes active (i.e., begins
  2847.     //  playback), or whenever an element's begin time becomes
  2848.     //  resolved, search its begin-time list for next resolved
  2849.     //  time and, if restart != "never", add that to the
  2850.     //  "watched element" list (in order by begin time), removing
  2851.     //  any duplicate of that same element (with a later time).
  2852.     // - In every OnTimeSync(), check head of "watched element"
  2853.     //  list and see if its time has been reached.  If not,
  2854.     //  ignore and keep going.  If so, remove it and all other
  2855.     //  elements in that list whose begin times have been reached
  2856.     //  and decide whether or not to start/restart the element
  2857.     //  based on restart value for that element.
  2858.     // /Do a clip-begin for any negative offset that was "clipped"
  2859.     // due to being resolved too late.  We can calculate the
  2860.     // clip-begin offset as the difference between the effective
  2861.     // resolved time (when it actually begins) and the resolved-to
  2862.     // time (that includes the entire negative offset):
  2863.     INT32 lResolvedToTimeWithoutOffset =
  2864.     pTmpVal->getResolvedToTimeWithoutOffset();
  2865.     INT32 lEventTimeOffset = pTmpVal->getTimeOffset();
  2866.     INT32 lTimeWithFullOffset =
  2867.     lResolvedToTimeWithoutOffset + lEventTimeOffset;
  2868.     INT32 lClippedOffsetAmount =
  2869.     lTimeWithFullOffset - lEffectiveResolvedTime;
  2870.     INT32 lEffectiveEventTimeOffset =
  2871.     lEventTimeOffset - lClippedOffsetAmount;
  2872.     if (lEventTimeOffset < 0  &&  lClippedOffsetAmount < 0)
  2873.     {
  2874. // /If clip-begin is invalid, set it otherwise add to it:
  2875. pTmpVal->m_pElement->m_ulClipBegin = ((UINT32)-1 ==
  2876. pTmpVal->m_pElement->m_ulAuthoredClipBegin?
  2877. (ULONG32)(-lClippedOffsetAmount) :
  2878. (ULONG32)(-lClippedOffsetAmount) +
  2879. pTmpVal->m_pElement->m_ulAuthoredClipBegin);
  2880. // /Set lEventTimeOffset to zero for call to setDelay,
  2881. // below:
  2882. lEventTimeOffset = 0;
  2883.     }
  2884.     BOOL bOKToKillExclSibling = FALSE;
  2885.     BOOL bAddTrack = FALSE;
  2886.     BOOL bPrepForRestartNeeded = FALSE;
  2887. // /#define XXXEHODGE_DEBUG_CHECKPENDINGBEGINTIMES
  2888. #if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG_CHECKPENDINGBEGINTIMES)
  2889. { static BOOL bFirstTime = TRUE;
  2890. FILE* f1 = ::fopen("c:\smil2_checkPending.txt", bFirstTime?"w":"a+");
  2891. ::fprintf(f1, "npTmpVal->m_idRef= %s, LINE= %lu, "
  2892. "curSMILTimelineStatus==SMILTimelineStatusCurrentlyPlaying?%lu, "
  2893. "SmilRestartAlways==pTmpVal->m_pElement->m_restartBehavior%lu, "
  2894. "lTimeWithFullOffset=%ld, lElementCurBeginTime=%ld, lEffectiveResolvedTime=%ld, "
  2895. "lSyncbaseDelayAddedToResolvedTime=%ld, m_ulRemoveTime=%lun",
  2896. (const char*)pTmpVal->m_idRef, (UINT32)__LINE__,
  2897. curSMILTimelineStatus==SMILTimelineStatusCurrentlyPlaying,
  2898. SmilRestartAlways==pTmpVal->m_pElement->m_restartBehavior,
  2899. lTimeWithFullOffset, lElementCurBeginTime, lEffectiveResolvedTime,
  2900. lSyncbaseDelayAddedToResolvedTime, lCurTime, pTmpVal->m_pElement->m_ulRemoveTime);  ::fclose(f1);}
  2901. #endif
  2902.     if (SMILTimelineStatusNeverScheduled == curSMILTimelineStatus)
  2903.     {
  2904. bAddTrack = TRUE;
  2905. bPrepForRestartNeeded = FALSE;
  2906. bOKToKillExclSibling = TRUE;
  2907.     }
  2908.     // /Since we're starting earlier than when it's been scheduled,
  2909.     // restart doesn't come into play, but we have to insert that
  2910.     // future time into the pending begin time list:
  2911.     else if (SMILTimelineStatusStartScheduledForLater ==
  2912.     curSMILTimelineStatus)
  2913.     {
  2914. // /XXXEH- OPTIMIZATION TODO: instead of
  2915. // removeTrack+addTrack, just adjust time of
  2916. // already-scheduled one:
  2917. if (NULL == pTmpVal->m_pElement->m_pTimelineElement)
  2918. {
  2919.     retval = HXR_UNEXPECTED;
  2920.     HX_ASSERT(pTmpVal->m_pElement->m_pTimelineElement);
  2921.     goto cleanup;
  2922. }
  2923. else
  2924. {
  2925.     if (pTmpVal->m_pElement->m_pHandler  ||
  2926.     bCurElementIsTimeContainer)
  2927.     {
  2928. // /It's scheduled for later so it must have its
  2929. // delay set:
  2930. HX_ASSERT((UINT32)-1 !=
  2931. pTmpVal->m_pElement->m_ulDelay);
  2932. LONG32 lOldScheduledBegin =
  2933. lElementCurBeginTime;
  2934. // /XXXEH- OPTIMIZATION TODO: if
  2935. // (SMILTimelineStatusStartScheduledForLater ==
  2936. // curSMILTimelineStatus) then we should not remove
  2937. // and then add the track back, but rather should
  2938. // just call begin on the track now.  This requires,
  2939. // however, that all datatypes can handle having
  2940. // their time offsets adjusted on the fly:
  2941. // /See if pID is a time container; if so, call
  2942. // handleTrackRemoval() on all its descendant media:
  2943. if (bCurElementIsTimeContainer)
  2944. {
  2945.     retval = HXR_OK;
  2946.     SMILNode* pChild = pTmpVal->m_pElement->
  2947.     m_pNode->getFirstChild();
  2948.     while (pChild)
  2949.     {
  2950. CSmilElement* pElement = pChild->m_pElement;
  2951. if (pElement  &&  pElement->m_pHandler  &&
  2952. pElement->m_bInsertedIntoTimeline)
  2953. {
  2954.     HX_RESULT retval2 = pElement->m_pHandler->
  2955.     handleTrackRemoval((const char*)
  2956.     pElement->m_pNode->m_id,
  2957.     (INT32)pElement->m_pNode->m_nGroup);
  2958.     if (HXR_OK == retval2)
  2959.     {
  2960. // /The duration changed due to an
  2961. // event, not due to clipping by
  2962. // our sync-parent.  Set this to
  2963. // false so elementResolved() will
  2964. // allow sync-arcs to resolve on
  2965. // our new end:
  2966. pElement->m_bCurEndClippedByParent =
  2967. FALSE;
  2968. // /Fixes case where element has
  2969. // sync arc to this end time and
  2970. // we need to notify it that
  2971. // we've ended early:
  2972.                                         m_pTimelineElementManager->notify((const char*) pElement->m_pNode->m_id);
  2973.     }
  2974. }
  2975. pChild = pTmpVal->m_pElement->m_pNode->
  2976. getNextChild();
  2977.     }
  2978. }
  2979. else
  2980. {
  2981.     retval = pTmpVal->m_pElement->m_pHandler->
  2982.     handleTrackRemoval(
  2983.     (const char*)pTmpVal->
  2984.     m_pElement->m_pNode->m_id,
  2985.     (INT32)pTmpVal->
  2986.     m_pElement->m_pNode->m_nGroup);
  2987. }
  2988. if (HXR_OK == retval)
  2989. {
  2990.     // /The duration changed due to an event, not due
  2991.     // to clipping by our sync-parent.  Set this to
  2992.     // false so elementResolved() will allow
  2993.     // sync-arcs to resolve on our new end:
  2994.     pTmpVal->m_pElement->m_bCurEndClippedByParent =
  2995.     FALSE;
  2996.     // /Fixes case where element has a sync arc to
  2997.     // this end time and we need to notify it that
  2998.     //  we've ended early:
  2999.     m_pTimelineElementManager->notify((const char*) pTmpVal->m_pElement->m_pNode->m_id);
  3000.     // /Place previously-scheduled future time into
  3001.     // pending-time list since it's been superseded
  3002.     // by pTmpVal:
  3003.     retval = insertElementWithPendingBeginOrEnd(
  3004.     pTmpVal->m_pElement, lOldScheduledBegin,
  3005.     SmilBeginTimeList);
  3006. }
  3007.     }
  3008.     else
  3009.     {
  3010.                         // XXXMEH - removed since we sometimes get multiple
  3011.                         // char events, before the events have even been
  3012.                         // processed.
  3013. // HX_ASSERT(pTmpVal->m_pElement->m_pHandler);
  3014. retval = HXR_UNEXPECTED;
  3015.     }
  3016. }
  3017. bAddTrack = TRUE;
  3018. bPrepForRestartNeeded = TRUE;
  3019. bOKToKillExclSibling = TRUE;
  3020.     }
  3021.     // /If we're playing now and restart is "always" and our new
  3022.     // begin time is not in the future and is not so far in the
  3023.     // past that it was earlier than the currently-playing time,
  3024.     // OR if we're done playing and restart is not "never", then
  3025.     // remove the track and add it back with new begin/end time:
  3026.     else if (((SMILTimelineStatusCurrentlyPlaying ==
  3027.     curSMILTimelineStatus  ||
  3028.     // /Part of fix for PR 62397:
  3029.     SMILTimelineStatusCurrentlyPausedAndRestarting ==
  3030.     curSMILTimelineStatus)  &&
  3031.     SmilRestartAlways ==
  3032.     pTmpVal->m_pElement->m_restartBehavior  &&
  3033.     (lTimeWithFullOffset >=
  3034.     lElementCurBeginTime  &&
  3035.     lEffectiveResolvedTime <= lCurTime))  ||
  3036.     (SMILTimelineStatusFinishedPlaying ==
  3037.     curSMILTimelineStatus  &&  SmilRestartNever !=
  3038.     pTmpVal->m_pElement->m_restartBehavior) )
  3039.     {
  3040. #if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG)
  3041. {FILE* f1 = ::fopen("c:\smil2.txt", "a+"); ::fprintf(f1, "npTmpVal->m_idRef= %s, LINE= %lun", (const char*)pTmpVal->m_idRef, (UINT32)__LINE__);  ::fclose(f1);}
  3042. #endif
  3043. // /If we're finished playing, handle killing an excl
  3044. // sibling that's active, if any.  (Note: if we're not
  3045. // finished playing, then we are the active one so no
  3046. // need to shut anyone else down):
  3047. // (..but note: we're not the active one if we're paused)
  3048. if (SMILTimelineStatusFinishedPlaying ==
  3049. curSMILTimelineStatus)
  3050. {
  3051.     bOKToKillExclSibling = TRUE;
  3052. }
  3053. // /Last part of fix for PR 62397:
  3054. else if (SMILTimelineStatusCurrentlyPausedAndRestarting ==
  3055. curSMILTimelineStatus  &&
  3056. !pTmpVal->isResumeEvent())
  3057. {
  3058.     bOKToKillExclSibling = TRUE;
  3059. }
  3060. // /XXXEH- OPTIMIZATION TODO(?): instead of
  3061. // removeTrack+addTrack, just adjust time of
  3062. // already-playing one (?):
  3063. if (NULL == pTmpVal->m_pElement->m_pTimelineElement)
  3064. {
  3065.     retval = HXR_UNEXPECTED;
  3066.     HX_ASSERT(pTmpVal->m_pElement->m_pTimelineElement);
  3067.     goto cleanup;
  3068. }
  3069. else
  3070. {
  3071.     if ((pTmpVal->m_pElement->m_pHandler  ||
  3072.     bCurElementIsTimeContainer)  &&
  3073.     // /(for PR 62688 and others): don't remove
  3074.     // track(s) that are done playing:
  3075.     (SMILTimelineStatusFinishedPlaying !=
  3076.     curSMILTimelineStatus  ||
  3077.     // /Fixes PR 66212, which broke when PR 62688
  3078.     // fix, above, was added: we do need to remove a
  3079.     // track that is finished but *frozen* (and
  3080.     // thus track/renderer is still open):
  3081.     bTrackIsFinishedAndFrozen) )
  3082.     {
  3083. // /See if pID is a time container; if so, call
  3084. // handleTrackRemoval() on all its descendant media:
  3085. if (bCurElementIsTimeContainer)
  3086. {
  3087.     retval = HXR_OK;
  3088.     SMILNode* pChild = pTmpVal->m_pElement->
  3089.     m_pNode->getFirstChild();
  3090.     while (pChild)
  3091.     {
  3092. CSmilElement* pElement = pChild->m_pElement;
  3093. if (pElement  &&  pElement->m_pHandler  &&
  3094. pElement->m_bInsertedIntoTimeline)
  3095. {
  3096.     HX_RESULT retval2 = pElement->m_pHandler->
  3097.     handleTrackRemoval((const char*)
  3098.     pElement->m_pNode->m_id,
  3099.     (INT32)pElement->m_pNode->m_nGroup);
  3100.     if (HXR_OK == retval2)
  3101.     {
  3102. // /The duration changed due to an
  3103. // event, not due to clipping by
  3104. // our sync-parent.  Set this to
  3105. // false so elementResolved() will
  3106. // allow sync-arcs to resolve on
  3107. // our new end:
  3108. pElement->m_bCurEndClippedByParent =
  3109. FALSE;
  3110. // /Fixes case where element has
  3111. // sync arc to this end time and
  3112. // we need to notify it that
  3113. // we've ended early:
  3114. m_pTimelineElementManager->notify((const char*) pElement->m_pNode->m_id);
  3115.     }
  3116. }
  3117. pChild = pTmpVal->m_pElement->m_pNode->
  3118. getNextChild();
  3119.     }
  3120. }
  3121. else
  3122. {
  3123.     retval = pTmpVal->m_pElement->m_pHandler->
  3124.     handleTrackRemoval(
  3125.     (const char*)pTmpVal->
  3126.     m_pElement->m_pNode->m_id,
  3127.     (INT32)pTmpVal->
  3128.     m_pElement->m_pNode->m_nGroup);
  3129. }
  3130. // /Fixes case where element has a sync arc to this
  3131. // end time and we need to notify it that we've
  3132. // ended early:
  3133. if (HXR_OK == retval)
  3134. {
  3135.     // /The duration changed due to an event, not due
  3136.     // to clipping by our sync-parent.  Set this to
  3137.     // false so elementResolved() will allow
  3138.     // sync-arcs to resolve on our new end:
  3139.     pTmpVal->m_pElement->m_bCurEndClippedByParent =
  3140.     FALSE;
  3141.     m_pTimelineElementManager->notify((const char*) pTmpVal->m_pElement->m_pNode->m_id);
  3142. }
  3143.      retval = HXR_OK;
  3144. bAddTrack = TRUE;
  3145. bPrepForRestartNeeded = TRUE;
  3146.     }
  3147.     // /Fixes elements-won't-restart-in-excl bug introduced by
  3148.     // initial PR 62688 fix; if it's done playing, allow it to
  3149.     // restart even though we didn't (have to) remove it, above:
  3150.     else if (SMILTimelineStatusFinishedPlaying ==
  3151.     curSMILTimelineStatus)
  3152.     {
  3153.      retval = HXR_OK;
  3154. bAddTrack = TRUE;
  3155. bPrepForRestartNeeded = TRUE;
  3156.     }
  3157.     else
  3158.     {
  3159.                         // XXXMEH - removed since we sometimes get multiple
  3160.                         // char events, before the events have even been
  3161.                         // processed.
  3162. // HX_ASSERT(pTmpVal->m_pElement->m_pHandler);
  3163. retval = HXR_UNEXPECTED;
  3164.     }
  3165. }
  3166.     }
  3167.     BOOL bTimeValWasDeferred = FALSE;
  3168.     if (bOKToKillExclSibling)
  3169.     {
  3170. // /This finds the first actively-playing media element of
  3171. // the excl (if there even is an excl), noting that there may
  3172. // be more than one media element playing in the case where
  3173. // they are all children of a par descendant of the excl:
  3174. SMILNode* pActiveSibling = findActiveChildOfAncestorExcl(
  3175. pTmpVal->m_pElement->m_pNode, lCurTime);
  3176. #if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG_EXCL_TRACK_REMOVAL)
  3177. {
  3178.     FILE* f1 = ::fopen("c:\smil2excl.txt", bFirstExclTrackChangeDebugOut?"w":"a+");
  3179.     bFirstExclTrackChangeDebugOut = FALSE;
  3180.     ::fprintf(f1, "At %6ld: timeVal's id = %s, "
  3181. "findActiveChildOfAncestorExcl() found: pActiveSibling id=%s  n",
  3182. lCurTime, (const char*)pTmpVal->m_pElement->m_pNode->m_id, pActiveSibling?
  3183. (const char*)pActiveSibling->m_id:"NULL");
  3184.     ::fclose(f1);
  3185. }
  3186. #endif
  3187. if (pActiveSibling)
  3188. {
  3189.     // /Is currently playing (unless it was stopped
  3190.     // already by someone else) so kill it:
  3191.     if (NULL != pActiveSibling->m_pElement->m_pHandler)
  3192.     {
  3193. SMILPriorityClassPeersHigherLowerVal interruptAction=
  3194. SMILPriorityClassStop;
  3195. SMILPriorityClassPauseDisplay
  3196. activeSiblingPauseDisplay =
  3197. SMILPriorityClassPauseDisplayShow;
  3198. // /Decide based on priorityClass values what to do
  3199. // here; e.g., if this is a peer of the new media that
  3200. // wants to play, then the peers value will determine
  3201. // whether we stop, pause, or do nothing to it:
  3202. SMILNode* pPriorityClassOfActiveSibling =
  3203. getSpecificAncestor(SMILPriorityClass,
  3204. pActiveSibling);
  3205. if (pPriorityClassOfActiveSibling)
  3206. {
  3207.     // /Find priorityClass of interrupting media:
  3208.     SMILNode* pPriorityClassOfInterrupter =
  3209.     getSpecificAncestor(SMILPriorityClass,
  3210.     pTmpVal->m_pElement->m_pNode);
  3211.     HX_ASSERT(pPriorityClassOfInterrupter);
  3212.     if (!pPriorityClassOfInterrupter  ||
  3213.     !pPriorityClassOfInterrupter->m_pElement)
  3214.     {
  3215. // /XXXEH- fire off this error: all media in
  3216. // an excl must be inside a priorityClass if
  3217. // *any* other media in that excl is inside
  3218. // a priorityClass:
  3219. break;
  3220.     }
  3221.     CSmilPriorityClassElement* pPCActiveElem =
  3222.    (CSmilPriorityClassElement*)
  3223.    pPriorityClassOfActiveSibling->m_pElement;
  3224.     HX_ASSERT(pPCActiveElem);
  3225.     activeSiblingPauseDisplay =
  3226.     pPCActiveElem->m_pauseDisplay;
  3227.     // /If they have the same priorityClass, then
  3228.     // look at the peers behavior to see what to do:
  3229.     if (pPriorityClassOfInterrupter ==
  3230.     pPriorityClassOfActiveSibling)
  3231.     {
  3232. interruptAction = pPCActiveElem->m_peers;
  3233.     }
  3234.     // /Else, if interrupting p.c. is higher (i.e.,
  3235.     // declared (lexically) earlier in the excl),
  3236.     // look at active p.c.'s "higher" val:
  3237.     else if (pPriorityClassOfInterrupter->
  3238.     m_ulTagStartLine <
  3239.     pPriorityClassOfActiveSibling->
  3240.     m_ulTagStartLine  ||
  3241.     (pPriorityClassOfInterrupter->
  3242.     m_ulTagStartLine ==
  3243.     pPriorityClassOfActiveSibling->
  3244.     m_ulTagStartLine  &&
  3245.     pPriorityClassOfInterrupter->
  3246.     m_ulTagStartColumn <
  3247.     pPriorityClassOfActiveSibling->
  3248.     m_ulTagStartColumn) )
  3249.     {
  3250. interruptAction = pPCActiveElem->m_higher;
  3251.     }
  3252.     // /Else, if interrupting p.c. is lower (i.e.,
  3253.     // declared (lexically) later in the excl), look
  3254.     // at active p.c.'s "lower" val:
  3255.     else
  3256.     {
  3257. interruptAction = pPCActiveElem->m_lower;
  3258.     }
  3259. }
  3260. // /This is active node's "syncbase" element
  3261. // which may itself be a child of this excl:
  3262. SMILNode* pTimelineParentOfActiveSibling =
  3263. getSyncAncestor(pActiveSibling);
  3264. HX_ASSERT(pTimelineParentOfActiveSibling);
  3265. // /Is needed to fix PR 57120 (wrapping par version);
  3266. // in case of a deferral, it's the *interruptor* that
  3267. // defers, not the active sibling (unlike with pause):
  3268. SMILNode* pTimelineParentOfInterruptor =
  3269. getSyncAncestor(pTmpVal->m_pElement->m_pNode);
  3270. HX_ASSERT(pTimelineParentOfInterruptor);
  3271. // /Here's where we need to reset m_bIsDeferredInExcl
  3272. // to FALSE if a deferred element is now getting a
  3273. // chance to play (and not be further deferred):
  3274. if (pTmpVal->m_pElement->m_bIsDeferredInExcl  &&
  3275. interruptAction !=SMILPriorityClassDefer)
  3276. {
  3277.     pTmpVal->m_pElement->m_bIsDeferredInExcl = FALSE;
  3278.     pTmpVal->m_pElement->m_ulTimeDeferralOccurred = (UINT32)-1;
  3279. }
  3280. switch (interruptAction)
  3281. {
  3282.     case SMILPriorityClassPause:
  3283.     {
  3284. do
  3285. {
  3286.     if (SMILPriorityClassPauseDisplayHide ==
  3287.     activeSiblingPauseDisplay)
  3288.     {
  3289. // /There are some cases where this
  3290. // might be NULL, but we shouldn't
  3291. // get to this part of this function
  3292. // if it's NULL:
  3293. HX_ASSERT(pPauseDisplayHideElementList);
  3294. if (pPauseDisplayHideElementList)
  3295. {
  3296.     CHXString* pCStr = new CHXString;
  3297.     if (pCStr)
  3298.     {
  3299. // /copy it over:
  3300. *pCStr = (const char*)
  3301. pActiveSibling->m_id;
  3302. pPauseDisplayHideElementList->
  3303. AddTail(pCStr);
  3304.     }
  3305. }
  3306.     }
  3307.     else if (SMILPriorityClassPauseDisplayDisable ==
  3308.     activeSiblingPauseDisplay)
  3309.     {
  3310. // /There are some cases where this
  3311. // might be NULL, but we shouldn't
  3312. // get to this part of this function
  3313. // if it's NULL:
  3314. HX_ASSERT(pPauseDisplayDisableElementList);
  3315. if (pPauseDisplayDisableElementList)
  3316. {
  3317.     CHXString* pCStr = new CHXString;
  3318.     if (pCStr)
  3319.     {
  3320. // /copy it over:
  3321. *pCStr = (const char*)
  3322. pActiveSibling->m_id;
  3323. pPauseDisplayDisableElementList->
  3324. AddTail(pCStr);
  3325.     }
  3326. }
  3327.     }
  3328.     LONG32 lDiffBetwnNowAndBegin =
  3329.     lCurTime-lEffectiveResolvedTime;
  3330.     if (0==lEffectiveResolvedTime  &&
  3331.     lDiffBetwnNowAndBegin<=10)
  3332.     {
  3333. // /Fixes SMIL 2.0 Interop Timing #13.15:
  3334. // allow first track to draw once by
  3335. // interrupting in a subsequent call to
  3336. // checkPending...():
  3337. bTimeValWasDeferred = TRUE;
  3338. goto doneWithRestartCode;
  3339.     }
  3340.     HX_ASSERT(lDiffBetwnNowAndBegin>0);
  3341.     if (lDiffBetwnNowAndBegin > 0)
  3342.     {
  3343. // /XXXEH- TODO: if and when
  3344. // we stop treating scheduled
  3345. // interrupts as events, this
  3346. // will fire off and we'll need to
  3347. // delay the subsequent pause, below:
  3348. HX_ASSERT(lDiffBetwnNowAndBegin<500);
  3349.     }
  3350.     // /Adding this block helps fix PR 86107.
  3351.     // We need to adjust the duration of this
  3352.     // element to reflect the anticipated time
  3353.     // it will be paused.  That allows other
  3354.     // elements that play after it ends to
  3355.     // adjust accordingly before it's too late:
  3356.                                     // /Adding the if() around the block helps
  3357.                                     // fix PR 100601 & PR 85896 (=PR 79288):
  3358.                                     // /BUT, don't do this if duration of pauser
  3359.                                     // isn't resolved:
  3360.                                     // [XXXEH- we may need to set up a resolve-
  3361.                                     // this-when-trackDurationSet-callback-
  3362.                                     // happens construct (as is done in
  3363.                                     // elementResolved()) and do the following
  3364.                                     // then, when duration becomes resolved,
  3365.                                     // but I can't create content that breaks
  3366.                                     // without that]:
  3367.                                     if ((UINT32)-1 !=
  3368.                                             pTmpVal->m_pElement->m_ulDuration)
  3369.     {
  3370.      pActiveSibling->m_pElement->
  3371.     m_ulAnticipatedPauseDur =
  3372.     pTmpVal->m_pElement->m_ulDuration;
  3373.      ULONG32 ulAnticipatedDurInclPause =
  3374.     pActiveSibling->m_pElement->
  3375.     m_ulAnticipatedPauseDur +
  3376.     pActiveSibling->m_pElement->
  3377.     m_ulDuration;
  3378.      if (pActiveSibling->m_pElement->
  3379.     m_ulAnticipatedPauseDur >=
  3380.     WAY_IN_THE_FUTURE  ||
  3381.     pActiveSibling->m_pElement->
  3382.     m_ulDuration >=
  3383.     WAY_IN_THE_FUTURE)
  3384.      {
  3385. ulAnticipatedDurInclPause =
  3386. WAY_IN_THE_FUTURE -
  3387.                                                 // /Helps fix PR 100601 and
  3388.                                                 // PR 85896 (=PR 79288):
  3389. // /Subtract delay so total
  3390. // reported to core doesn't
  3391. // exceed indef "magic number":
  3392. pActiveSibling->m_pElement->m_ulDelay;
  3393.      }
  3394.      durationResolved((const char*)
  3395.     pActiveSibling->m_pElement->
  3396.      m_pNode->m_id,
  3397.     ulAnticipatedDurInclPause,
  3398.     FALSE /* not being set by parent */,
  3399.     TRUE /* dur is pause extending */);
  3400.      // /Force smildocrender to HandleElements():
  3401.      bREFSomeScheduleWasChanged = TRUE;
  3402.     } // /End block added to help fix PR 86107.
  3403.     // /This method not only pauses the
  3404.     // element but also creates a new
  3405.     // SmilTimeValue and inserts it in the
  3406.     // pending begin time list; this new
  3407.     // time value watches for the
  3408.     // iterrupting media to finish:
  3409.     SmilTimeValue* pReturnedTimeVal = NULL;
  3410.     retval = pActiveSibling->m_pElement->
  3411.     m_pHandler->handleTrackPausing(
  3412.     pActiveSibling,
  3413.     lEffectiveResolvedTime,
  3414.     activeSiblingPauseDisplay,
  3415.     pTmpVal->m_pElement->m_pNode->m_id);
  3416. #if defined(_DEBUG)  &&  defined(XXXEHODGE_DEBUG_EXCL_TRACK_REMOVAL)
  3417. {
  3418.     FILE* f1 = ::fopen("c:\smil2excl.txt", bFirstExclTrackChangeDebugOut?"w":"a+");
  3419.     bFirstExclTrackChangeDebugOut = FALSE;
  3420.     ::fprintf(f1, "At %6ld: timeVal's id = %s, "
  3421. "handleTrackPausing(%s) returned: 0x%08xn",
  3422. lCurTime, (const char*)pTmpVal->m_pElement->m_pNode->m_id,
  3423. (const char*)pActiveSibling->m_id, retval);
  3424.     ::fclose(f1);