📄 smltime.cpp
字号:
/* ***** BEGIN LICENSE BLOCK *****
* Version: RCSL 1.0/RPSL 1.0
*
* Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file, are
* subject to the current version of the RealNetworks Public Source License
* Version 1.0 (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the RealNetworks Community Source License Version 1.0
* (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
* in which case the RCSL will apply. You may also obtain the license terms
* directly from RealNetworks. You may not use this file except in
* compliance with the RPSL or, if you have a valid RCSL with RealNetworks
* applicable to this file, the RCSL. Please see the applicable RPSL or
* RCSL for the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the portions
* it created.
*
* This file, and the files included with this file, is distributed and made
* available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
// system
#include <time.h>
// include
#include "hxtypes.h"
#include "hxwintyp.h"
#include "hxcom.h"
#include "hxxml.h"
#include "smiltype.h"
// pncont
#include "hxslist.h"
#include "hxmap.h"
// pnmisc
#include "hxwinver.h"
// rnxmllib
#include "hxxmlprs.h"
// rmasmil
#include "smlelem.h"
#include "smlparse.h"
#include "smltime.h"
#include "smlprstime.h"
// pndebug
#include "debugout.h"
#include "hxassert.h"
#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE
static const char HX_THIS_FILE[] = __FILE__;
#endif
// /#define XXXEH_DEBUGOUT_ADDDURATION
#if defined(XXXEH_DEBUGOUT_ADDDURATION)
#define ADDDURATION_DEBUGOUT_STR_NEW_FILE "w"
#define ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE "a+"
static BOOL bFirstTimeAddDurDebugout = TRUE;
#endif
/*
* CSmilTimelineElementManager methods
*/
CSmilTimelineElementManager::CSmilTimelineElementManager():
m_pElementMap(NULL),
m_pNotifierMap(NULL)
{
}
CSmilTimelineElementManager::~CSmilTimelineElementManager()
{
HX_DELETE(m_pElementMap);
if(m_pNotifierMap)
{
CHXMapStringToOb::Iterator i = m_pNotifierMap->Begin();
for(; i != m_pNotifierMap->End(); ++i)
{
CHXSimpleList* pList = (CHXSimpleList*)(*i);
delete pList;
}
HX_DELETE(m_pNotifierMap);
}
}
void
CSmilTimelineElementManager::addTimelineElement(CSmilTimelineElement* pElement)
{
if(!m_pElementMap)
{
m_pElementMap = new CHXMapStringToOb;
}
(*m_pElementMap)[pElement->m_pID] = pElement;
}
CSmilTimelineElement*
CSmilTimelineElementManager::getTimelineElement(const char* pID)
{
CSmilTimelineElement* pElement = NULL;
if(m_pElementMap)
{
m_pElementMap->Lookup(pID, (void*&)pElement);
}
return pElement;
}
void
CSmilTimelineElementManager::addNotification(const char* pID,
CSmilTimelineElement* pElement)
{
if(!m_pNotifierMap)
{
m_pNotifierMap = new CHXMapStringToOb;
}
CHXSimpleList* pNotifyList = NULL;
if(!m_pNotifierMap->Lookup(pID, (void*&)pNotifyList))
{
pNotifyList = new CHXSimpleList;
(*m_pNotifierMap)[pID] = pNotifyList;
}
pNotifyList->AddTail(pElement);
}
void
CSmilTimelineElementManager::notify(const char* pID)
{
CHXSimpleList* pNotifyList = NULL;
if(m_pNotifierMap)
{
if(m_pNotifierMap->Lookup(pID, (void*&)pNotifyList))
{
CSmilTimelineElement* pDependentElement = NULL;
if(m_pElementMap->Lookup(pID, (void*&)pDependentElement))
{
CHXSimpleList::Iterator i = pNotifyList->Begin();
for(; i != pNotifyList->End(); ++i)
{
CSmilTimelineElement* pElement =
(CSmilTimelineElement*)(*i);
pElement->elementResolved(pDependentElement);
}
}
}
}
}
void
CSmilTimelineElementManager::resetTimeline()
{
if(m_pElementMap)
{
CHXMapStringToOb::Iterator i = m_pElementMap->Begin();
for(; i != m_pElementMap->End(); ++i)
{
CSmilTimelineElement* pElement =
(CSmilTimelineElement*)(*i);
pElement->reset();
}
}
}
/*
* CSmilTimelineElement methods
*/
CSmilTimelineElement::CSmilTimelineElement(CSmilElement* pSourceElement,
CSmilParser* pParser):
m_pSourceElement(pSourceElement),
m_pParser(pParser),
m_bDurationSet(FALSE),
m_bMaxDurationSet(FALSE),
m_bDelaySet(FALSE),
m_bDontResetDuration(FALSE),
m_bNonEventDelaySet(FALSE),
m_ulNonEventDelay((UINT32)-1),
m_bDelayEvent(FALSE),
m_bDurationEvent(FALSE),
m_pChildDurAddedMap(NULL),
m_bHasChildWithScheduledBegin(FALSE),
m_bInElementResolved(FALSE),
m_pParent(NULL),
m_pChildren(NULL),
m_pDependent(NULL)
{
m_pID = new char[pSourceElement->m_pNode->m_id.GetLength() + 1];
strcpy(m_pID, (const char*)m_pSourceElement->m_pNode->m_id); /* Flawfinder: ignore */
//[SMIL 1.0 Compliance] Helps fix PR 26471:
// /XXXEH- TODO: this is probably one of the places where
// endsync="media" is handled. We probably don't want to do the
// following if() statement if endsync is NOT media on the parent
// of an anchor|area element:
if (SMILAnchor != m_pSourceElement->m_pNode->m_tag &&
SMILArea != m_pSourceElement->m_pNode->m_tag)
{
m_pParser->m_pTimelineElementManager->addTimelineElement(this);
}
if(pSourceElement->m_nBeginEventSourceTag == SMILEventSourceBegin ||
pSourceElement->m_nBeginEventSourceTag == SMILEventSourceEnd ||
pSourceElement->m_nBeginEventSourceTag == SMILEventSourceClock)
{
m_pParser->m_pTimelineElementManager->addNotification(pSourceElement->m_BeginEventSourceID,
this);
// /If we've already got a resolved begin, then we don't want to claim
// that we're awaiting this sync-arc begin (as can happen if
// begin="0s; x.begin+4s")
if (!pSourceElement->m_bBeginOffsetSet)
{
m_bDelayEvent = TRUE;
}
}
if(pSourceElement->m_nEndEventSourceTag == SMILEventSourceBegin ||
pSourceElement->m_nEndEventSourceTag == SMILEventSourceEnd ||
pSourceElement->m_nEndEventSourceTag == SMILEventSourceClock)
{
m_pParser->m_pTimelineElementManager->addNotification(pSourceElement->m_EndEventSourceID,
this);
// /If we've already got a resolved end, then we don't want to claim
// that we're awaiting this sync-arc end (as can happen if
// end="10s; x.begin+14s")
if (!pSourceElement->m_bEndOffsetSet)
{
m_bDurationEvent = TRUE;
}
}
if(pSourceElement->m_nEndsyncEventSourceTag == SMILEventSourceID)
{
m_pParser->m_pTimelineElementManager->addNotification(pSourceElement->m_EndsyncEventSourceID,
this);
m_bDurationEvent = TRUE;
}
m_pChildDurAddedMap = new CHXMapStringToOb();
// /XXXEH- TODO: make sure this is what we want to do:
// /Get next resolved time, if any. If none are found in a non-empty
// begin-time list, then treat this as a delayed event:
if (NULL != pSourceElement->m_pBeginTimeList &&
!pSourceElement->m_pBeginTimeList->IsEmpty())
{
SmilTimeValue* pNextResolvedTimeValue = NULL;
HX_RESULT rettimeval = HXR_OK;
rettimeval = pSourceElement->getNextResolvedTimeValue(
pNextResolvedTimeValue,
// /XXXEH- TODO: make sure we don't want to input cur time here;
// is it possible that we'd get here after time 0 in the parent
// timeline??? I don't think so...:
SMILTIME_NEGATIVE_INFINITY,
SMILTIME_NEGATIVE_INFINITY,
SmilBeginTimeList,
/* Don't need list of resolved times:*/ NULL);
if (!SUCCEEDED(rettimeval) || NULL == pNextResolvedTimeValue)
{
// /Has no resolved time yet so must be awaiting an event:
m_bDelayEvent = TRUE;
}
}
}
CSmilTimelineElement::~CSmilTimelineElement()
{
delete m_pChildren;
delete[] m_pID;
HX_DELETE(m_pChildDurAddedMap);
}
void
CSmilTimelineElement::reset()
{
m_bDelaySet = FALSE;
m_bNonEventDelaySet = FALSE;
m_ulNonEventDelay = (UINT32)-1;
m_bDurationSet = FALSE;
m_bMaxDurationSet = FALSE;
// /XXXEH- do we really want to do this? Find a way to test this:
#if defined(XXXEH_NEEDS_TESTING)
HX_DELETE(m_pChildDurAddedMap); // /start fresh
#endif
}
void
CSmilTimelineElement::prepForRestart()
{
m_bDelaySet = FALSE;
m_bNonEventDelaySet = FALSE;
m_ulNonEventDelay = (UINT32)-1;
#if XXXEH_OLD_WAY_THAT_DIDNT_LET_SETDURATION_TAKE_CARE_OF_NEW_DUR
if (((UINT32)-1) != m_pSourceElement->m_ulOriginalDuration)
{
resetDuration(m_pSourceElement->m_ulOriginalDuration);
}
// /Note: leave m_bDurationSet & m_bMaxDurationSet alone for restart
#else
//...But if we're restarting, our duration may be different and this
// gets handled in CSmilTimelineElement::setDuration():
m_bDurationSet = FALSE;
// /Fixes PR 54704: if we don't reset this in concert with resetting
// m_bDurationSet, above, then ancestorEventsAreResolved() will fail
// when a re-insertTimelineElement() call on this occurs:
m_bDurationEvent = FALSE;
#endif
}
void
CSmilTimelineElement::setDelay(UINT32 ulDelay, BOOL bSetByParent)
{
ULONG32 ulPreviouslySetDelay = m_pSourceElement->m_ulDelay;
ULONG32 ulPreviouslySetPureDuration = m_pSourceElement->getPureDuration();
#if defined(_DEBUG) && defined(XXXEH_DEBUGOUT_ADDDURATION)
{
FILE* f1 = ::fopen("c:\\smil2AddDuration.txt", bFirstTimeAddDurDebugout?
ADDDURATION_DEBUGOUT_STR_NEW_FILE :
ADDDURATION_DEBUGOUT_STR_APPEND_TO_FILE );
::fprintf(f1, "CSmilTimelineElement{%s}::setDelay(delay=%lu, "
"bSetByParent=%sE), prior delay=%lu, m_bDelaySet=%sE\n",
(const char*)m_pID, ulDelay,
bSetByParent?"TRU":"FALS",
ulPreviouslySetDelay,
m_bDelaySet?"TRU":"FALS");
::fclose(f1);
bFirstTimeAddDurDebugout = FALSE;
}
#endif
if(!m_bDelaySet)
{
// /For PR 59584: if we're just resolving this to let the
// group duration "resolve" to unresolved, don't count begin:
if(WAY_IN_THE_FUTURE <= ulDelay)
{
HX_ASSERT(WAY_IN_THE_FUTURE >= ulDelay);
}
else if(!m_bDelayEvent)
{
BOOL bDelayClippedDueToNegOffset = FALSE;
if(m_pSourceElement->m_bBeginOffsetSet)
{
m_pSourceElement->m_ulDelay = ulDelay;
// /Handle all cases so that we don't overflow:
UINT32 ulPosOffset = m_pSourceElement->m_lBeginOffset > 0?
m_pSourceElement->m_lBeginOffset : 0;
UINT32 ulNegOffset = m_pSourceElement->m_lBeginOffset < 0?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -