📄 smlparse.cpp
字号:
m_bFirstPacket = TRUE;
// Clear the begin time map
clearTimeValueMap(SmilBeginTimeList);
// Clear the end time map
clearTimeValueMap(SmilEndTimeList);
// Clear and delete the custom event list
clearExternalEventList();
HX_DELETE(m_pExternalEventList);
// Clear the handler list
HX_DELETE(m_pElementsWithHandlerList);
}
HX_RESULT
CSmilParser::init(BOOL bStoreErrors)
{
HX_RESULT rc = HXR_OK;
close();
m_pNodeListStack = new CHXStack;
m_pPacketQueue = new CHXSimpleList;
m_pIDMap = new CHXMapStringToOb;
m_pAddGroupMap = new CHXMapLongToObj;
m_bStoreErrors = bStoreErrors;
if (m_bStoreErrors)
{
// XXXJHUG error stuff.
// In the future if there was any reason, we could
// store the errors in the nodes that the errors occurred in.
// for now when we get an error notification, we will
// just call the storeError function which will add
// a new IHXBuffer to this array.. This will also be
// called when problems are found with tags...
// this will save having to walk the tree when it
// is time to dump the errors.
m_pErrors = new CHXPtrArray;
}
SMILNode* pRootNode = new SMILNode;
pRootNode->m_id = "root";
pRootNode->m_name = "root";
m_pNodeList = new SMILNodeList;
pRootNode->m_pNodeList = m_pNodeList;
m_pNodeList->m_pParentNode = pRootNode;
m_pNodeListStack->Push(pRootNode);
#if !defined(USE_EXPAT_FOR_SMIL)
//#define USE_EXPAT_FOR_SMIL
#endif
#ifdef USE_EXPAT_FOR_SMIL
rc = m_pClassFactory->CreateInstance(CLSID_IHXXMLParser, (void**)&m_pParser);
if (FAILED(rc))
{
// they don't have the parser... use old one?
// Don't QI core for IID_IHXXMLParser; use our own instance.
m_pParser = new HXXMLParser;
if (m_pParser)
{
rc = HXR_OK;
m_pParser->AddRef();
}
else
{
rc = HXR_OUTOFMEMORY;
}
}
if (SUCCEEDED(rc))
{
m_pResponse = new CSmilParserResponse(this);
m_pResponse->AddRef();
// Expat is created off the CCF.
// In strict mode it requires 100% compliant XML.
rc = m_pParser->Init(m_pResponse, "iso-8859-1", TRUE);
}
#else
// Don't QI core for IID_IHXXMLParser; use our own instance.
HXXMLParser* parser = new HXXMLParser();
if (parser)
{
parser->AddRef();
}
else
{
rc = HXR_OUTOFMEMORY;
}
if (SUCCEEDED(rc))
{
m_pResponse = new CSmilParserResponse(this);
m_pResponse->AddRef();
rc = parser->Init(m_pResponse, NULL, TRUE); // strict parser
}
if (m_bStoreErrors && parser)
{
parser->InitErrorNotifier(m_pResponse);
}
m_pParser = (IHXXMLParser*)parser;
#endif
return rc;
}
HX_RESULT
CSmilParser::parse(IHXBuffer* pBuffer, BOOL bIsFinal)
{
HX_RESULT rc = HXR_OK;
if (m_bFirstPacket)
{
m_bFirstPacket = FALSE;
time(&m_tRefTime);
}
rc = m_pParser->Parse(pBuffer, bIsFinal);
if (SUCCEEDED(rc) && FAILED(m_lParseError))
{
rc = m_lParseError;
}
if(HXR_OK != rc)
{
m_pParser->GetCurrentLineNumber(m_ulErrorLineNumber);
m_pParser->GetCurrentColumnNumber(m_ulErrorColumnNumber);
HX_RELEASE(m_pErrorText);
m_pParser->GetCurrentErrorText(m_pErrorText);
}
return rc;
}
HX_RESULT
CSmilParser::durationResolved(const char* pID, UINT32 ulDuration,
// /Defaults to FALSE:
BOOL bSetByParent,
BOOL bDurationExtendingDueToPause)
{
HX_RESULT rc = HXR_OK;
SMILNode* pNode = NULL;
if(m_pIDMap->Lookup(pID, (void*&)pNode))
{
if (pNode->m_pElement->m_bIndefiniteDuration)
{
#if defined(XXXEH_OLD_SPECIAL_CASE_HANDLING_OF_INDEF_DUR)
goto cleanup;
#endif
}
// add duration to parent element
if(pNode &&
pNode->m_pElement &&
pNode->m_pElement->m_pTimelineElement)
{
pNode->m_pElement->m_pTimelineElement->setDuration(ulDuration,
bSetByParent, bDurationExtendingDueToPause);
}
}
#if defined(XXXEH_OLD_SPECIAL_CASE_HANDLING_OF_INDEF_DUR)
cleanup:
#endif
return rc;
}
BOOL AncestorEventsAreResolved(SMILNode* pNode, SMILNode* pOriginalChildNode)
{
if (!pNode || !pNode->m_pElement ||
!pNode->m_pParent || pNode->m_tag == SMILBody)
{
return TRUE;
}
// /For any parent that's not a timeline element, e.g., priorityClass,
// just ignore and return its parent's results:
else if (!pNode->m_pElement->m_pTimelineElement)
{
return AncestorEventsAreResolved(pNode->m_pParent, pOriginalChildNode);
}
//Now, look to see if its duration and delay events, if any, are
// resolved:
if ( ( (pNode->m_pElement->m_pTimelineElement->durationEvent() &&
!pNode->m_pElement->m_pTimelineElement->durationSet() &&
// /Fixes 1/2 of PR 50535: don't care about duration event for child
// itself; it's OK to add a timeline element that has an unresolved
// end; (but if parent has unresolved end, we may need to wait):
pNode != pOriginalChildNode) ||
(pNode->m_pElement->m_pTimelineElement->delayEvent() &&
!pNode->m_pElement->m_pTimelineElement->initialDelaySet()) ) &&
//[SMIL 1.0 compliance] Helps fix PR 32578:
//However, if we have a duration event and it's based on a child's
// timing (as can happen via endsync="id(child)", then we want to
// avoid this element waiting for its parent to be resolved while
// the parent is waiting for this element to be resolved:
(!pNode->m_pElement->m_pTimelineElement->durationEvent() ||
SMILEventSourceID != pNode->m_pElement->m_nEndsyncEventSourceTag) )
{
return FALSE; //We still need to await event resolution.
}
//pNode is ok but its dependency ancestors may still be unresolved and
// thus pNode may still have timing constraints from its dependency
// ancestors due to their unresolved event(s):
return AncestorEventsAreResolved(pNode->m_pParent, pOriginalChildNode);
}
HX_RESULT
CSmilParser::adjustForNegativeOffset(const char* pID)
{
HX_RESULT pnresult = HXR_OK;
SMILNode* pNode = 0;
if(!m_pIDMap->Lookup(pID, (void*&)pNode))
{
pnresult = HXR_FAILED;
}
else if (pNode && pNode->m_pElement &&
!pNode->m_pElement->m_bInsertedIntoTimeline &&
pNode->m_pParent && pNode->m_pParent->m_pElement)
{
// /Use syncBase, not parent here (in case parent is <a>, <switch>,
// or <priorityClass> element); this fixes bug (PR 56233 repro case)
// where clipBegin was calculted wrong, below, because priorityClass
// was being used as syncbase and it had a begin time later than this:
SMILNode* pSyncBaseNode = getSyncAncestor(pNode);
if (!pSyncBaseNode || !pSyncBaseNode->m_pElement)
{
pnresult = HXR_FAILED;
goto cleanup;
}
// /If we have a negative begin offset or delay which starts us
// earlier than the begin offset or delay of our syncbase, we need
// to do a clip-begin equal to the difference, and we need to
// update our duration as well:
LONG32 lParentBegin =
// /If delay is valid, use it otherwise use valid beginOffset
pSyncBaseNode->m_pElement->m_ulDelay != ((UINT32)-1) ?
(LONG32)pSyncBaseNode->m_pElement->m_ulDelay :
pSyncBaseNode->m_pElement->m_bBeginOffsetSet?
pSyncBaseNode->m_pElement->m_lBeginOffset : 0;
LONG32 lCurElementBegin =
pNode->m_pElement->m_ulDelay != ((UINT32)-1) ?
(LONG32)pNode->m_pElement->m_ulDelay :
pNode->m_pElement->m_bBeginOffsetSet?
pNode->m_pElement->m_lBeginOffset :
// /In adjustForNegativeOffset():
// /Fixes case where parent has explicit dur, explicit
// begin offset, and pNode's element begins on an event;
// this used to set lCurElementBegin to 0 and erroneous
// clip-begin equal to parent's begin offset would ensue:
MAX_LONG32;
// /First, we need to see if this is happening during playback; if
// so, our begin may have resolved to a time in the past that is
// later than our sync-parent's begin; in that case, we need to
// adjust the clip-begin and delay to account for the diff between
// now and lCurElementBegin:
if (m_lLastCheckPendingTime > (lCurElementBegin +
// /(re)Fixes broken long-sync-arc test file
// BUG-20001110_BeginOffsetInPar...BeginningOnClickAllowsSync.smi
// where the clipBegin was being *re*-computed here, after
// having already been adjusted in setDelay() for a long-sync-
// arc negative offset. We shouldn't do any adjustment here
// if the difference is very small (which is not due to
// user or authored delay clipping, but is due to processor
// time between when our parent resolved and when the last
// check pending time):
CHECKPENDING_TIME_VS_CURTIME_FUDGE_FACTOR))
{
lParentBegin = m_lLastCheckPendingTime;
}
if (lCurElementBegin < lParentBegin)
{
LONG32 lDiff = lParentBegin - lCurElementBegin;
HX_ASSERT(lDiff >= 0);
if (lDiff > 0)
{
ULONG32 ulPriorPureDuration = pNode->m_pElement->getPureDuration();
ULONG32 ulDiff = (ULONG32)lDiff;
// /If clip-begin is invalid, set it otherwise add to it:
pNode->m_pElement->m_ulClipBegin = ((UINT32)-1 ==
pNode->m_pElement->m_ulAuthoredClipBegin? ulDiff :
ulDiff+pNode->m_pElement->m_ulAuthoredClipBegin);
if ((UINT32)-1 != pNode->m_pElement->m_ulDuration)
{
if (pNode->m_pElement->m_ulDuration > ulDiff)
{
pNode->m_pElement->m_ulDuration -= ulDiff;
}
// /else duration is negative; it can't ever play:
else
{
pNode->m_pElement->m_ulDuration = 0;
}
}
// /And, we should now begin when our parent does:
pNode->m_pElement->m_ulDelay = lParentBegin;
// /Only reset duration if it's not 0xFFFFFFFF and
// if it's not the same as it was before:
if ((UINT32)-1 != pNode->m_pElement->m_ulDuration &&
ulPriorPureDuration != pNode->m_pElement->getPureDuration())
{
resetTimelineElementDuration(pID,
pNode->m_pElement->getPureDuration(),
ulPriorPureDuration);
}
if (m_pTimelineElementManager) m_pTimelineElementManager->notify(pID);
}
}
}
cleanup:
return pnresult;
}
void
CSmilParser::insertTimelineElement(const char* pID, UINT32 ulDelay)
{
#if defined(_DEBUG) && defined(XXXEH_DEBUGOUT_ADDDURATION)
{
FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", "a+");
::fprintf(f1, "CSmilParser::insertTimelineElement(%s, delay=%lu) _-_-_-_-_-_-_-_-_\n",
(const char*)pID, ulDelay);
::fclose(f1);
}
#endif
SMILNode* pNode = 0;
if(m_pIDMap->Lookup(pID, (void*&)pNode))
{
if(pNode &&
pNode->m_pElement &&
// /XXXEH- TODO: we need to handle restart!="never" which
// means that the following if condition should take this
// into account:
!pNode->m_pElement->m_bInsertedIntoTimeline &&
//[SMIL 1.0 compliance] Helps fix PR 16629:
// We don't want to insert a node into the timeline if
// its begin is dependent on another (not-yet-
// resolved) element:
((!pNode->m_pElement->m_pTimelineElement->delayEvent() ||
pNode->m_pElement->m_pTimelineElement->initialDelaySet()) )
//[SMIL 1.0 compliance] Helps fix 14420:
// First, we need to look all the way up the tree of ancestors
// to see if any of them have event-based delays or durations
// and to make sure the appropriate time(s) are resolved. If
// not, we'll have to await those event resolutions before
// inserting this element into the timeline:
&& AncestorEventsAreResolved(pNode, pNode)
// /For SMIL 2.0, we can have begin="indefinite" which should
// be treated as un unresolved event (but only if that's the
// sole begin time specified; begin="indefinite; 5s" should be
// treated as begin="5s"):
&& !pNode->m_pElement->m_bIndefiniteBegin
)
{
ULONG32 ulDelayBeyondParentDelay = 0;
ULONG32 ulSyncBaseDelay = 0;
SMILNode* pSyncAncestor = getSyncAncestor(pNode);
HX_ASSERT((UINT32)-1 != pSyncAncestor->m_pElement->m_ulDelay);
// /Check hard time boundaries set by parent:
if (pSyncAncestor && pSyncAncestor->m_pElement &&
(UINT32)-1 != pSyncAncestor->m_pElement->m_ulDelay)
{
ulSyncBaseDelay = pSyncAncestor->m_pElement->m_ulDelay;
ulDelayBeyondParentDelay = ulDelay - ulSyncBaseDelay;
HX_ASSERT(ulDelay >= ulSyncBaseDelay);
if (ulDelay < ulSyncBaseDelay)
{
ulDelayBeyondParentDelay = 0;
}
// /If child has delay beyond parent's delay+duration, i.e.,
// begin resolved on an event or sync arc, then don't insert it:
else
{
if (pSyncAncestor->m_pElement->m_bHasExplicitDur &&
!pSyncAncestor->m_pElement->m_bIndefiniteDuration &&
!pSyncAncestor->m_pElement->m_bIndefiniteEnd &&
(ulDelayBeyondParentDelay >=
pSyncAncestor->m_pElement->m_ulDuration) )
{
goto cleanup; //It can't ever play.
}
else if (pSyncAncestor->m_pElement->m_bEndOffsetSet &&
!pSyncAncestor->m_pElement->m_bIndefiniteDuration &&
!pSyncAncestor->m_pElement->m_bIndefiniteEnd)
{
if (ulDelayBeyondParentDelay >=
pSyncAncestor->m_pElement->m_ulDuration)
{
goto cleanup; //It can't ever play.
}
}
}
}
else
{
// /Fixes PR 50411: long sync-arc begin resolved before parent
// begin resolved and is thus not adjusted for any offset
// from parent begin; dur:=0 if it ends before parent begin:
if (pSyncAncestor)
{
pNode->m_pElement->m_bAwaitingSyncAncestorBeginNotification=
TRUE;
}
goto cleanup; // /Wait to insert this until parent is resolved.
}
#define XXXEH_ABOVE_SHOULD_HANDLE_THIS__REMOVE_IF_NO_ASSERT0_BY_20010530
#if defined(XXXEH_ABOVE_SHOULD_HANDLE_THIS__REMOVE_IF_NO_ASSERT0_BY_20010530)
// /[SMIL 1.0 Compliance] Fixes PR 27644:
// if our begin offset is same or greater than our parent's
// end offset, then we should be ignored:
if ( pNode->m_pParent && pNode->m_pParent->m_pElement &&
pNode->m_pElement->m_bBeginOffsetSet &&
pNode->m_pParent->m_pElement->m_bEndOffsetSet &&
(pNode->m_pElement->m_lBeginOffset >
pNode->m_pParent->m_pElement->m_lEndOffset) )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -