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

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: animsand.cpp,v 1.2.12.1 2004/07/09 01:58:01 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. // system
  50. #include <time.h>
  51. #include <math.h>
  52. // include
  53. #include "hxtypes.h"
  54. #include "hxwintyp.h"
  55. #include "hxcom.h"
  56. #include "hxxml.h"
  57. #include "smiltype.h"
  58. // pnmisc
  59. #include "hxwinver.h"
  60. // pncont
  61. #include "hxslist.h"
  62. // rnxmllib
  63. #include "hxxmlprs.h"
  64. // rmasmil
  65. #include "smlelem.h"
  66. #include "smlparse.h"
  67. #include "animattr.h"
  68. // smlrendr
  69. #include "smlrmlog.h"
  70. #include "animsand.h"
  71. // pndebug
  72. #include "hxheap.h"
  73. #include "debugout.h"
  74. #ifdef _DEBUG
  75. #undef HX_THIS_FILE
  76. static const char HX_THIS_FILE[] = __FILE__;
  77. #endif
  78. CAnimationSandwichLayer::CAnimationSandwichLayer(CSmilAnimateElement* pElement,
  79.                                                  UINT32               ulAttrName,
  80.                                                  CSmilParser*         pParser)
  81. {
  82.     MLOG_LEAKCHECK("CON CAnimationSandwichLayer this=0x%08xn", this);
  83.     m_pElement         = NULL;
  84.     m_ulAttrName       = kAttrNameUnknown;
  85.     m_pdPacedDist      = NULL;
  86.     m_pdPacedTime      = NULL;
  87.     m_bRecomputePace   = FALSE;
  88.     m_bFirstTime       = TRUE;
  89.     m_pSmilParser      = pParser;
  90.     m_ulLastTime       = 0;
  91.     m_ulDelay          = 0;
  92.     m_ulActiveDuration = 0;
  93.     if (pElement && pElement->m_pNode)
  94.     {
  95.         // Make sure the attribute name makes sense
  96.         // with this element. If this element
  97.         // is NOT an <animateMotion>, then we expect
  98.         // the attribute name in the element to match
  99.         // the passed-in attribute name. If this 
  100.         // element IS <animateMotion>, then the passed-in
  101.         // attribute should be either "left" or "top".
  102.         if ((pElement->m_pNode->m_tag == SMILAnimateMotion &&
  103.              (ulAttrName == kAttrNameLeft || ulAttrName == kAttrNameTop)) ||
  104.             (pElement->m_pNode->m_tag != SMILAnimateMotion &&
  105.              ulAttrName == (UINT32) pElement->m_ucAttributeName))
  106.         {
  107.             // Assign the members
  108.             m_pElement         = pElement;
  109.             m_ulAttrName       = ulAttrName;
  110.             m_ulDelay          = pElement->m_ulDelay;
  111.             m_ulActiveDuration = pElement->m_ulActiveDuration;
  112.             // Check if the "end" attribute constrains
  113.             // the active duration.
  114.             if (pElement->m_bEndOffsetSet)
  115.             {
  116.                 UINT32 ulEndMinusBegin = ((UINT32) pElement->m_lEndOffset) - m_ulDelay;
  117.                 if (ulEndMinusBegin < m_ulActiveDuration)
  118.                 {
  119.                     m_ulActiveDuration = ulEndMinusBegin;
  120.                 }
  121.             }
  122.             // If we are a paced animation, then we need to
  123.             // decide how we are going to compute the D()
  124.             // and T() functions.
  125.             if (pElement->m_ucCalcMode == kCalcModePaced)
  126.             {
  127.                 // Now we need to determine if these functions should be
  128.                 // re-computed every time. We need to do this IF any
  129.                 // attributes are relative.
  130.                 BOOL bSomeRelative = FALSE;
  131.                 for (UINT32 i = 0; i < pElement->m_ulNumValues; i++)
  132.                 {
  133.                     if (pElement->m_ppValue[i])
  134.                     {
  135.                         for (UINT32 j = 0; j < CAttr::kVectorSize; j++)
  136.                         {
  137.                             if (pElement->m_ppValue[i]->IsRelative(j))
  138.                             {
  139.                                 bSomeRelative = TRUE;
  140.                             }
  141.                         }
  142.                     }
  143.                 }
  144.                 if (bSomeRelative)
  145.                 {
  146.                     // We will have to recompute the functions
  147.                     // every time we evaluate
  148.                     m_bRecomputePace = TRUE;
  149.                 }
  150.             }
  151.         }
  152.     }
  153. }
  154. CAnimationSandwichLayer::~CAnimationSandwichLayer()
  155. {
  156.     MLOG_LEAKCHECK("DES CAnimationSandwichLayer this=0x%08xn", this);
  157.     HX_VECTOR_DELETE(m_pdPacedDist);
  158.     HX_VECTOR_DELETE(m_pdPacedTime);
  159. }
  160. const char* CAnimationSandwichLayer::GetAnimationElementID() const
  161. {
  162.     const char* pRet = NULL;
  163.     if (m_pElement &&
  164.         m_pElement->m_pNode)
  165.     {
  166.         pRet = (const char*) m_pElement->m_pNode->m_id;
  167.     }
  168.     return pRet;
  169. }
  170. const char* CAnimationSandwichLayer::GetTargetElementID() const
  171. {
  172.     const char* pRet = NULL;
  173.     if (m_pElement && m_pElement->m_pTargetElementID)
  174.     {
  175.         pRet = (const char*) *m_pElement->m_pTargetElementID;
  176.     }
  177.     return pRet;
  178. }
  179. SMILNodeTag CAnimationSandwichLayer::GetTargetElementTag() const
  180. {
  181.     SMILNodeTag eRet = SMILUnknown;
  182.     if (m_pElement)
  183.     {
  184.         eRet = m_pElement->m_eTargetElementTag;
  185.     }
  186.     return eRet;
  187. }
  188. SMILNodeTag CAnimationSandwichLayer::GetAnimationElementTag() const
  189. {
  190.     SMILNodeTag eRet = SMILUnknown;
  191.     if (m_pElement && m_pElement->m_pNode)
  192.     {
  193.         eRet = m_pElement->m_pNode->m_tag;
  194.     }
  195.     return eRet;
  196. }
  197. BOOL CAnimationSandwichLayer::IsActive(UINT32 ulTime) const
  198. {
  199.     BOOL bRet = FALSE;
  200.     if (m_pElement && ulTime >= m_ulDelay)
  201.     {
  202.         if (m_pElement->m_bIndefiniteActiveDuration ||
  203.             ulTime < m_ulDelay + m_ulActiveDuration)
  204.         {
  205.             // During the active duration - it's active
  206.             bRet = TRUE;
  207.         }
  208.     }
  209.     return bRet;
  210. }
  211. BOOL CAnimationSandwichLayer::IsFrozen(UINT32 ulTime) const
  212. {
  213.     BOOL bRet = FALSE;
  214.     if (m_pElement &&
  215.         (m_pElement->m_eActualFill == FillFreeze ||
  216.          m_pElement->m_eActualFill == FillHold))
  217.     {
  218.         if (!m_pElement->m_bIndefiniteActiveDuration)
  219.         {
  220.             if (ulTime >= m_ulDelay + m_ulActiveDuration)
  221.             {
  222.                 // XXXMEH - now that we are calculating a remove
  223.                 // time for every timed element, we should be able
  224.                 // to use the m_ulRemoveTime. However, let's keep
  225.                 // the old code around "just in case".
  226.                 if (m_pElement->m_ulRemoveTime == ((UINT32) -1))
  227.                 {
  228.                     UINT32 ulRemoveTime = 0;
  229.                     HX_RESULT rv = m_pSmilParser->computeRemoveTime(m_pElement->m_pNode->m_id,
  230.                                                                     ulRemoveTime);
  231.                     if (SUCCEEDED(rv))
  232.                     {
  233.                         m_pElement->m_ulRemoveTime = ulRemoveTime;
  234.                     }
  235.                 }
  236.                 if (ulTime <= m_pElement->m_ulRemoveTime)
  237.                 {
  238.                     bRet = TRUE;
  239.                 }
  240.             }
  241.         }
  242.     }
  243.     return bRet;
  244. }
  245. BOOL CAnimationSandwichLayer::IsActiveZeroBased(UINT32 ulTime) const
  246. {
  247.     BOOL bRet = FALSE;
  248.     if (m_pElement &&
  249.         (m_pElement->m_bIndefiniteActiveDuration ||
  250.          ulTime < m_ulActiveDuration))
  251.     {
  252.         // During the active duration - it's active
  253.         bRet = TRUE;
  254.     }
  255.     return bRet;
  256. }
  257. BOOL CAnimationSandwichLayer::IsFrozenZeroBased(UINT32 ulTime) const
  258. {
  259.     BOOL bRet = FALSE;
  260.     if (m_pElement &&
  261.         (m_pElement->m_eActualFill == FillFreeze ||
  262.          m_pElement->m_eActualFill == FillHold))
  263.     {
  264.         if (!m_pElement->m_bIndefiniteActiveDuration)
  265.         {
  266.             if (ulTime >= m_ulActiveDuration)
  267.             {
  268.                 if (ulTime <= (m_pElement->m_ulRemoveTime - m_ulDelay))
  269.                 {
  270.                     bRet = TRUE;
  271.                 }
  272.             }
  273.         }
  274.     }
  275.     return bRet;
  276. }
  277. BOOL CAnimationSandwichLayer::IsAdditive() const
  278. {
  279.     BOOL bRet = FALSE;
  280.     if (m_pElement)
  281.     {
  282.         if (m_pElement->m_ucAdditive == kAdditiveSum)
  283.         {
  284.             bRet = TRUE;
  285.         }
  286.     }
  287.     return bRet;
  288. }
  289. BOOL CAnimationSandwichLayer::IsToAnimation() const
  290. {
  291.     BOOL bRet = FALSE;
  292.     if (m_pElement &&
  293.         m_pElement->m_ucAnimationType == kAnimTypeTo)
  294.     {
  295.         bRet = TRUE;
  296.     }
  297.     return bRet;
  298. }
  299. CAttr CAnimationSandwichLayer::AnimationEffectFunction(UINT32 ulTime,
  300.                                                        CAttr* pUnder,
  301.                                                        CAttr* pDepend)
  302. {
  303.     CAttr cRet;
  304.     if (pUnder)
  305.     {
  306.         // Initialize to the underlying value
  307.         cRet = *pUnder;
  308.         // Compute the zero-based time
  309.         UINT32 ulT = ulTime - m_ulDelay; // XXXMEH - is this right?
  310.         // Compute the time after time manipulations
  311.         UINT32 ulTM = ComputeFilteredSimpleTime(ulT);
  312.         // Decide if we're active or frozen
  313.         if (IsActiveZeroBased(ulT))
  314.         {
  315.             // Evaluate the cumulative animation function at this time
  316.             cRet = CumulativeAnimationFunction(ulTM, pUnder, pDepend);
  317.             // Now we need to check if we need to fire a repeatEvent.
  318.             //
  319.             // Compute which iteration the last time was in
  320.             UINT32 ulLastIter = 0;
  321.             if (m_pElement->m_ulSimpleDuration)
  322.             {
  323.                 ulLastIter = m_ulLastTime / m_pElement->m_ulSimpleDuration;
  324.             }
  325.             // Compute which iteration we are currently in
  326.             UINT32 ulThisIter = 0;
  327.             if (m_pElement->m_ulSimpleDuration)
  328.             {
  329.                 ulThisIter = ulTM / m_pElement->m_ulSimpleDuration;
  330.             }
  331.             // If we are in different iterations, then we will
  332.             // assume that this is the first time in the new iteration
  333.             // and we will fire a "repeatEvent"
  334.             if (ulLastIter != ulThisIter &&
  335.                 m_pSmilParser)
  336.             {
  337.                 m_pSmilParser->tryToResolveBeginEndEvents("repeatEvent",
  338.                                                           m_pElement->m_pNode->m_id,
  339.                                                           ulTime);
  340.                 // XXXMEH - temporarily, we will also fire a "repeat(x)" event
  341.                 char szTmp[32]; /* Flawfinder: ignore */
  342.                 sprintf(szTmp, "repeat(%lu)", ulThisIter); /* Flawfinder: ignore */
  343.                 m_pSmilParser->tryToResolveBeginEndEvents((const char*) szTmp,
  344.                                                           m_pElement->m_pNode->m_id,
  345.                                                           ulTime);
  346.             }
  347.             // Save the last time
  348.             m_ulLastTime = ulTM;
  349.         }
  350.         else if (IsFrozenZeroBased(ulT))
  351.         {
  352.             // We are in the frozen period after the active duration
  353.             //
  354.             // Compute the remainder time
  355.             // XXXMEH - TODO - most of the time this "frozen time"
  356.             // calculation can be done once up front.
  357.             UINT32 ulModTime = 0;
  358.             // m_ulActiveDuration takes into speed modifications. We
  359.             // need to undo this before we compute the remainder time.
  360.             UINT32 ulNewAD = m_ulActiveDuration;
  361.             if (m_pElement->m_dSpeed != 1.0)
  362.             {
  363.                 double dNewAD = (double) ulNewAD * fabs(m_pElement->m_dSpeed);
  364.                 ulNewAD       = (UINT32) floor(dNewAD + 0.5);
  365.             }
  366.             // m_ulSimpleDuration does NOT take into account autoReverse,
  367.             // but m_ulActiveDuration does. So we need to add in the
  368.             // effect of autoReverse to m_ulSimpleDuration
  369.             UINT32 ulNewSD = m_pElement->m_ulSimpleDuration;
  370.             if (m_pElement->m_bAutoReverse)
  371.             {
  372.                 ulNewSD *= 2;
  373.             }
  374.             // Now we can compute the remainder time
  375.             if (ulNewSD)
  376.             {
  377.                 ulModTime = ulNewAD % ulNewSD;
  378.             }
  379.             // Now, our active duration an even multiple of simple duration?
  380.             if (ulModTime)
  381.             {
  382.                 // Active duration is NOT an even multiple of simple duration,
  383.                 // so we just evaluate the cumulative animation function
  384.                 // at the end of the active duration. Make sure
  385.                 // and pass the time through time manipulations.
  386.                 UINT32 ulADTM = ComputeFilteredSimpleTime(m_ulActiveDuration);
  387.                 cRet = CumulativeAnimationFunction(ulADTM, pUnder, pDepend);
  388.             }
  389.             else
  390.             {
  391.                 // Active duration IS an even multiple of simple duration
  392.                 //
  393.                 // Are we cumulative or not?
  394.                 if (m_pElement->m_ucAccumulate == kAccumulateNone)
  395.                 {
  396.                     // We are non-cumulative - simply evaluate at the
  397.                     // simple duration. First pass the simple duration
  398.                     // through time manipulations
  399.                     UINT32 ulSD = m_pElement->m_ulSimpleDuration;
  400.                     if (m_pElement->m_bAutoReverse)
  401.                     {
  402.                         ulSD *= 2;
  403.                     }
  404.                     if (m_pElement->m_dSpeed != 1.0 &&
  405.                         m_pElement->m_dSpeed != 0.0)
  406.                     {
  407.                         double dSDSpeed = (double) ulSD / fabs(m_pElement->m_dSpeed);
  408.                         ulSD = (UINT32) floor(dSDSpeed + 0.5);
  409.                     }
  410.                     UINT32 ulSDTM = ComputeFilteredSimpleTime(ulSD);
  411.                     cRet = SimpleAnimationFunction(ulSDTM, pUnder, pDepend);
  412.                 }
  413.                 else
  414.                 {
  415.                     // We ARE cumulative
  416.                     //
  417.                     // Compute the multiple
  418.                     UINT32 ulMult    = 1;
  419.                     UINT32 ulCumTime = 0;
  420.                     if (m_pElement->m_ulSimpleDuration)
  421.                     {
  422.                         if (m_pElement->m_bAutoReverse)
  423.                         {
  424.                             ulMult    = m_ulActiveDuration / (2 * m_pElement->m_ulSimpleDuration);
  425.                             ulCumTime = 2 * m_pElement->m_ulSimpleDuration * (ulMult - 1);
  426.                         }
  427.                         else
  428.                         {
  429.                             ulMult    = m_ulActiveDuration / m_pElement->m_ulSimpleDuration;
  430.                             ulCumTime = m_pElement->m_ulSimpleDuration * (ulMult - 1);
  431.                         }
  432.                     }
  433.                     // Compute the frozen value
  434.                     UINT32 ulCumTimeTM = ComputeFilteredSimpleTime(ulCumTime);
  435.                     CAttr cCum  = CumulativeAnimationFunction(ulCumTimeTM, pUnder, pDepend);
  436.                     UINT32 ulSDTM = 0;
  437.                     if (m_pElement->m_bAutoReverse)
  438.                     {
  439.                         ulSDTM = ComputeFilteredSimpleTime(2 * m_pElement->m_ulSimpleDuration);
  440.                     }
  441.                     else
  442.                     {
  443.                         ulSDTM = ComputeFilteredSimpleTime(m_pElement->m_ulSimpleDuration);
  444.                     }
  445.                     cRet = SimpleAnimationFunction(ulSDTM, pUnder, pDepend);
  446.                     cRet.Add(&cCum, pDepend);
  447.                 }
  448.             }
  449.             // Save the last time
  450.             m_ulLastTime = ulTM;
  451.         }
  452.     }
  453.     return cRet;
  454. }
  455. BOOL CAnimationSandwichLayer::HigherPriority(CAnimationSandwichLayer* pLayer)
  456. {
  457.     BOOL bRet = TRUE;
  458.     if (pLayer)
  459.     {
  460.         if (m_ulDelay > pLayer->m_ulDelay)
  461.         {
  462.             // We start later than pLayer, so we're higher priority
  463.             bRet = TRUE;
  464.         }
  465.         else if (m_ulDelay == pLayer->m_ulDelay)
  466.         {
  467.             // We start at the same time as pLayer, so the spec
  468.             // says we first have to look at sync relationships
  469.             if (m_pElement->m_BeginEventSourceID == pLayer->m_pElement->m_pNode->m_id)
  470.             {
  471.                 // pLayer is our syncbase, so we are higher priority
  472.                 bRet = TRUE;
  473.             }
  474.             else if (pLayer->m_pElement->m_BeginEventSourceID == m_pElement->m_pNode->m_id)
  475.             {
  476.                 // We are pLayer's syncbase, so pLayer is higher priority
  477.                 bRet = FALSE;
  478.             }
  479.             else
  480.             {
  481.                 // There is no sync relationship between us and pLayer,
  482.                 // so we have to look at lexical order. First look at
  483.                 // the line the tag starts
  484.                 if (m_pElement->m_pNode->m_ulTagStartLine >
  485.                     pLayer->m_pElement->m_pNode->m_ulTagStartLine)
  486.                 {
  487.                     // We start lexically later, so we are 
  488.                     // higher priority
  489.                     bRet = TRUE;
  490.                 }
  491.                 else if (m_pElement->m_pNode->m_ulTagStartLine ==
  492.                          pLayer->m_pElement->m_pNode->m_ulTagStartLine)
  493.                 {
  494.                     // We start on the same line, so look
  495.                     // at the starting column
  496.                     if (m_pElement->m_pNode->m_ulTagStartColumn >
  497.                         pLayer->m_pElement->m_pNode->m_ulTagStartColumn)
  498.                     {
  499.                         // We start lexically later, so we are 
  500.                         // higher priority
  501.                         bRet = TRUE;
  502.                     }
  503.                     else if (m_pElement->m_pNode->m_ulTagStartColumn ==
  504.                              pLayer->m_pElement->m_pNode->m_ulTagStartColumn)
  505.                     {
  506.                         // Huh? How can a different element start at
  507.                         // the same line and column that we do? Probably
  508.                         // bogus, so make an arbitrary choice
  509.                         bRet = TRUE;
  510.                     }
  511.                     else
  512.                     {
  513.                         // We start lexically earlier, so we are NOT
  514.                         // higher priority
  515.                         bRet = FALSE;
  516.                     }
  517.                 }
  518.                 else
  519.                 {
  520.                     // We start lexically earlier, so we are NOT
  521.                     // higher priority
  522.                     bRet = FALSE;
  523.                 }
  524.             }
  525.         }
  526.         else
  527.         {
  528.             // pLayer starts later than us, so it's higher priority
  529.             bRet = FALSE;
  530.         }
  531.     }
  532.     return bRet;
  533. }
  534. void CAnimationSandwichLayer::AdjustActiveDuration(UINT32 ulTime)
  535. {
  536.     if (ulTime >= m_ulDelay)
  537.     {
  538.         m_ulActiveDuration = ulTime - m_ulDelay;
  539.     }
  540. }
  541. CAttr CAnimationSandwichLayer::SimpleAnimationFunction(UINT32 ulTime,
  542.                                                        CAttr* pUnder,
  543.                                                        CAttr* pDepend)
  544. {
  545.     CAttr cRet;
  546.     if (pUnder)
  547.     {
  548.         // Initialize the return to the underlying value
  549.         cRet = *pUnder;
  550.         // Do we have an indefinite simple duration?
  551.         if (m_pElement->m_bIndefiniteSimpleDuration)
  552.         {
  553.             // Our simple duration is indefinite, so interpolation
  554.             // is not defined. We should set ourselves to value(0).
  555.             //
  556.             // What kind of animation are we?
  557.             if (m_pElement->m_pNode->m_tag == SMILSet)
  558.             {
  559.                 // If this is a set, then we know there is
  560.                 // only one values, so we need to just
  561.                 // set the value to m_ppValue[1]
  562.                 if (m_pElement->m_ppValue[1])
  563.                 {
  564.                     cRet = *m_pElement->m_ppValue[1];
  565.                 }
  566.             }
  567.             else if (m_pElement->m_ucAnimationType == kAnimTypeTo)
  568.             {
  569.                 // If this is a to-animation, then value(0)
  570.                 // is the underlying value.
  571.                 cRet = *pUnder;
  572.             }
  573.             else
  574.             {
  575.                 // Assign the value(0) if we have one
  576.                 if (m_pElement->m_ppValue[0])
  577.                 {
  578.                     cRet = *m_pElement->m_ppValue[0];
  579.                 }
  580.             }
  581.         }
  582.         else
  583.         {
  584.             // Our simple duration is not indefinite
  585.             //
  586.             // We are just defined over the simple duration
  587.             if (ulTime <= m_pElement->m_ulSimpleDuration)
  588.             {
  589.                 if (m_pElement->m_pNode->m_tag == SMILSet)
  590.                 {
  591.                     // If this is a set, then we know there is
  592.                     // only two values, so we need to just
  593.                     // set the value to m_ppValue[1]
  594.                     if (m_pElement->m_ppValue[1])
  595.                     {
  596.                         cRet = *m_pElement->m_ppValue[1];
  597.                     }
  598.                 }
  599.                 else
  600.                 {
  601.                     // What is our calcmode?
  602.                     if (m_pElement->m_ucCalcMode == kCalcModeDiscrete)
  603.                     {
  604.                         // Divide the interval into m_ulNumValues segments
  605.                         UINT32 ulIndex = m_pElement->m_ulNumValues;
  606.                         if (m_pElement->m_ulSimpleDuration)
  607.                         {
  608.                             ulIndex = m_pElement->m_ulNumValues * ulTime / m_pElement->m_ulSimpleDuration;
  609.                         }
  610.                         // Make sure that m_pElement->m_ulSimpleDuration maps
  611.                         // to index m_ulNumValues - 1 and not m_ulNumValues
  612.                         if (ulIndex >= m_pElement->m_ulNumValues)
  613.                         {
  614.                             ulIndex = m_pElement->m_ulNumValues - 1;
  615.                         }
  616.                         // If we are a "to" animation, then m_ppValue[0] is
  617.                         // a placeholder for the underlying value. Therefore,
  618.                         // if we are a "to" animation and have selected index 0,
  619.                         // then we need to replace it by the underlying value
  620.                         if (m_pElement->m_ucAnimationType == kAnimTypeTo &&
  621.                             ulIndex == 0)
  622.                         {
  623.                             cRet = *pUnder;
  624.                         }
  625.                         else if (m_pElement->m_ucAnimationType == kAnimTypeFromBy &&
  626.                                  ulIndex == 1)
  627.                         {
  628.                             // On a from-by animation, you are interpolating
  629.                             // between the from value and the sum of the from
  630.                             // and by values. m_ppValue[0] is the from value.
  631.                             // However, m_ppValue[1] is the by value, not the
  632.                             // sum of the from and by values. So if we have
  633.                             // chosen index 1, then we need to compute the sum
  634.                             // of the from and by values
  635.                             //
  636.                             if (m_pElement->m_ppValue[0] &&
  637.                                 m_pElement->m_ppValue[1])
  638.                             {
  639.                                 // First assign the from value
  640.                                 cRet = *m_pElement->m_ppValue[0];
  641.                                 // Then add the by value
  642.                                 cRet.Add(m_pElement->m_ppValue[1], pDepend);
  643.                             }
  644.                         }
  645.                         else
  646.                         {
  647.                             // Simply return the proper value
  648.                             if (m_pElement->m_ppValue[ulIndex])
  649.                             {
  650.                                 cRet = *m_pElement->m_ppValue[ulIndex];
  651.                             }
  652.                         }
  653.                     }
  654.                     else if (m_pElement->m_ucCalcMode == kCalcModeLinear ||
  655.                              (m_pElement->m_ucCalcMode == kCalcModePaced &&
  656.                               m_pElement->m_ulNumValues == 2))
  657.                     {
  658.                         // Is this a "to" animation?
  659.                         if (m_pElement->m_ucAnimationType == kAnimTypeTo)
  660.                         {
  661.                             // If we are a "to" animation, then we interpolate
  662.                             // between the underlying value and the "to" value,
  663.                             // which is (m_ppValue[1]).
  664.                             if (m_pElement->m_ppValue[1])
  665.                             {
  666.                                 // Do the interpolation
  667.                                 double t1 = 0.0;
  668.                                 double t2 = (double) m_pElement->m_ulSimpleDuration;
  669.                                 double t  = ulTime;
  670.                                 cRet.Interp(pUnder, t1, m_pElement->m_ppValue[1], t2, t, pDepend);
  671.                             }
  672.                         }
  673.                         else if (m_pElement->m_ucAnimationType == kAnimTypeFromBy)
  674.                         {
  675.                             // On a from-by animation, you are interpolating
  676.                             // between the from value and the sum of the from
  677.                             // and by values. m_ppValue[0] is the from value.
  678.                             // However, m_ppValue[1] is the by value, not the
  679.                             // sum of the from and by values. So we need to
  680.                             // compute the sum of the from and by values
  681.                             if (m_pElement->m_ppValue[0] &&
  682.                                 m_pElement->m_ppValue[1])
  683.                             {
  684.                                 CAttr cSum = *m_pElement->m_ppValue[0];
  685.                                 cSum.Add(m_pElement->m_ppValue[1], pDepend);
  686.                                 // Then we interpolate between m_ppValue[0] (the
  687.                                 // "from" value) and cSum (the sum of the "from"
  688.                                 // and "by" values).
  689.                                 double t1 = 0.0;
  690.                                 double t2 = (double) m_pElement->m_ulSimpleDuration;
  691.                                 double t  = (double) ulTime;
  692.                                 cRet.Interp(m_pElement->m_ppValue[0], t1, &cSum, t2, t, pDepend);
  693.                             }
  694.                         }
  695.                         else
  696.                         {
  697.                             // Divide the interval into m_ulNumValues-1 segments
  698.                             UINT32 ulIndex = m_pElement->m_ulNumValues - 1;
  699.                             if (m_pElement->m_ulSimpleDuration)
  700.                             {
  701.                                 ulIndex = (m_pElement->m_ulNumValues - 1) * ulTime / m_pElement->m_ulSimpleDuration;
  702.                             }
  703.                             // Now interpolate between this value and the next
  704.                             if (ulIndex + 1 < m_pElement->m_ulNumValues &&
  705.                                 m_pElement->m_ppValue[ulIndex] &&
  706.                                 m_pElement->m_ppValue[ulIndex + 1])
  707.                             {
  708.                                 // Do the interpolation
  709.                                 double t1 = ulIndex * m_pElement->m_ulSimpleDuration /
  710.                                             (m_pElement->m_ulNumValues - 1);
  711.                                 double t2 = (ulIndex + 1) * m_pElement->m_ulSimpleDuration /
  712.                                             (m_pElement->m_ulNumValues - 1);
  713.                                 double t  = ulTime;
  714.                                 cRet.Interp(m_pElement->m_ppValue[ulIndex],     t1,
  715.                                             m_pElement->m_ppValue[ulIndex + 1], t2,
  716.                                             t, pDepend);
  717.                             }
  718.                             else
  719.                             {
  720.                                 // The only way this can happen is if
  721.                                 // ulTime == m_pElement->m_ulSimpleDuration, so if this
  722.                                 // if the case, we need to return the un-interpolated
  723.                                 // value of m_ppValue[m_pElement->m_ulNumValues - 1]
  724.                                 if (m_pElement->m_ppValue[m_pElement->m_ulNumValues - 1])
  725.                                 {
  726.                                     cRet = *m_pElement->m_ppValue[m_pElement->m_ulNumValues - 1];
  727.                                 }
  728.                             }
  729.                         }
  730.                     }
  731.                     else if (m_pElement->m_ucCalcMode == kCalcModePaced)
  732.                     {
  733.                         // If we need to recompute the paced tables,
  734.                         // then do it now
  735.                         if (m_bRecomputePace ||
  736.                             (!m_bRecomputePace && m_bFirstTime))
  737.                         {
  738.                             RecomputePace(pDepend);
  739.                         }
  740.                         // Find out what index we're at
  741.                         double t = (double) ulTime;
  742.                         UINT32 i = 0;
  743.                         for (i = 0; i < m_pElement->m_ulNumValues - 1; i++)
  744.                         {
  745.                             if (t >= m_pdPacedTime[i] && t <= m_pdPacedTime[i + 1])
  746.                             {
  747.                                 break;
  748.                             }
  749.                         }
  750.                         if (i + 1 < m_pElement->m_ulNumValues)
  751.                         {
  752.                             // Do the interpolation
  753.                             cRet.Interp(m_pElement->m_ppValue[i],     m_pdPacedTime[i],
  754.                                         m_pElement->m_ppValue[i + 1], m_pdPacedTime[i + 1],
  755.                                         (double) ulTime, pDepend);
  756.                         }
  757.                     }
  758.                 }
  759.                 // Now we can clear the first time flag
  760.                 m_bFirstTime = FALSE;
  761.             }
  762.         }
  763.     }
  764.     return cRet;
  765. }
  766. CAttr CAnimationSandwichLayer::CumulativeAnimationFunction(UINT32 ulTime,
  767.                                                            CAttr* pUnder,
  768.                                                            CAttr* pDepend)
  769. {
  770.     CAttr cRet;
  771.     if (pUnder)
  772.     {
  773.         // Initialize to the underlying value
  774.         cRet = *pUnder;
  775.         // Are we cumulative or not?
  776.         if (m_pElement->m_ucAccumulate == kAccumulateSum)
  777.         {
  778.             // We are a cumulative animation
  779.             //
  780.             // Modulo the time by the simple duration
  781.             UINT32 ulModTime = 0;
  782.             if (m_pElement->m_ulSimpleDuration)
  783.             {
  784.                 ulModTime = ulTime % m_pElement->m_ulSimpleDuration;
  785.             }
  786.             // Evaluate the simple animation function at this time
  787.             CAttr cMod = SimpleAnimationFunction(ulModTime, pUnder, pDepend);
  788.             // Find the iteration
  789.             UINT32 ulIter = 0;
  790.             if (m_pElement->m_ulSimpleDuration)
  791.             {
  792.                 ulIter = ulTime / m_pElement->m_ulSimpleDuration;
  793.             }
  794.             if (ulIter)
  795.             {
  796.                 // Evaluate the animation at the simple duration
  797.                 cRet = SimpleAnimationFunction(m_pElement->m_ulSimpleDuration,
  798.                                                pUnder, pDepend);
  799.                 // Multiply by iteration value
  800.                 cRet.Mult((double) ulIter);
  801.                 // Add the simple animation result
  802.                 cRet.Add(&cMod, pDepend);
  803.             }
  804.             else
  805.             {
  806.                 // We're on the first iteration
  807.                 cRet = cMod;
  808.             }
  809.         }
  810.         else
  811.         {
  812.             // We are a non-cumulative animation
  813.             //
  814.             // Modulo the time by the simple duration
  815.             UINT32 ulModTime = 0;
  816.             if (m_pElement->m_ulSimpleDuration)
  817.             {
  818.                 ulModTime = ulTime % m_pElement->m_ulSimpleDuration;
  819.             }
  820.             // Evaluate the simple animation function at this time
  821.             cRet = SimpleAnimationFunction(ulModTime, pUnder, pDepend);
  822.         }
  823.     }
  824.     return cRet;
  825. }
  826. void CAnimationSandwichLayer::RecomputePace(CAttr* pDepend)
  827. {
  828.     if (!m_pdPacedDist)
  829.     {
  830.         m_pdPacedDist = new double [m_pElement->m_ulNumValues];
  831.         if (m_pdPacedDist)
  832.         {
  833.             memset((void*) m_pdPacedDist, 0, sizeof(double) *
  834.                    m_pElement->m_ulNumValues);
  835.         }
  836.     }
  837.     if (!m_pdPacedTime)
  838.     {
  839.         m_pdPacedTime = new double [m_pElement->m_ulNumValues];
  840.         if (m_pdPacedTime)
  841.         {
  842.             memset((void*) m_pdPacedTime, 0, sizeof(double) *
  843.                    m_pElement->m_ulNumValues);
  844.         }
  845.     }
  846.     if (m_pdPacedDist && m_pdPacedTime)
  847.     {
  848.         UINT32 i = 0;
  849.         // Compute D()
  850.         m_pdPacedDist[0] = 0.0;
  851.         for (i = 1; i < m_pElement->m_ulNumValues; i++)
  852.         {
  853.             m_pdPacedDist[i] = m_pdPacedDist[i - 1] +
  854.                                CAttr::Dist(m_pElement->m_ppValue[i - 1],
  855.                                            m_pElement->m_ppValue[i],
  856.                                            pDepend);
  857.         }
  858.         // Compute T()
  859.         double dTotal = m_pdPacedDist[m_pElement->m_ulNumValues - 1];
  860.         for (i = 0; i < m_pElement->m_ulNumValues; i++)
  861.         {
  862.             m_pdPacedTime[i] = m_pdPacedDist[i] * m_pElement->m_ulSimpleDuration / dTotal;
  863.         }
  864.     }
  865. }
  866. UINT32 CAnimationSandwichLayer::ComputeFilteredSimpleTime(UINT32 ulUnfilteredActiveTime)
  867. {
  868.     UINT32 ulRet = ulUnfilteredActiveTime;
  869.     if (m_pElement &&
  870.         (m_pElement->m_bAutoReverse       ||
  871.          m_pElement->m_dSpeed      != 1.0 ||
  872.          m_pElement->m_dAccelerate != 0.0 ||
  873.          m_pElement->m_dDecelerate != 0.0))
  874.     {
  875.         // Compute the duration of the acceleration phase
  876.         double dacc = ((double) m_pElement->m_ulSimpleDuration) *
  877.                       m_pElement->m_dAccelerate;
  878.         // Compute the duration of the deceleration phase
  879.         double ddec = ((double) m_pElement->m_ulSimpleDuration) *
  880.                       m_pElement->m_dDecelerate;
  881.         // Compute the active filtered time (which takes
  882.         // into account the speed attribute)
  883.         double dActiveFilteredTime = 0.0;
  884.         if (m_pElement->m_dSpeed > 0.0)
  885.         {
  886.             dActiveFilteredTime = ((double) ulUnfilteredActiveTime) *
  887.                                   m_pElement->m_dSpeed;
  888.         }
  889.         else
  890.         {
  891.             dActiveFilteredTime = ((double) m_pElement->m_ulADNoSpeed) -
  892.                                   (((double) ulUnfilteredActiveTime) *
  893.                                    fabs(m_pElement->m_dSpeed));
  894.         }
  895.         // Compute the unfiltered simple time
  896.         double dUnfilteredSimpleTime = dActiveFilteredTime;
  897.         double dDur                  = (double) m_pElement->m_ulSimpleDuration;
  898.         double dDurPrime             = dDur;
  899.         if (m_pElement->m_bAutoReverse)
  900.         {
  901.             dDurPrime *= 2.0;
  902.         }
  903.         // Is there any repeating behavior?
  904.         if (m_pElement->m_dRepeatCount == 1.0 &&
  905.             (m_pElement->m_ulRepeatDur  == ((UINT32) -1) ||
  906.              m_pElement->m_bRepeatDurIsIndefinite))
  907.         {
  908.             // No repeating behavior here, so unfiltered simple
  909.             // time is equal to active filtered time
  910.             dUnfilteredSimpleTime = dActiveFilteredTime;
  911.         }
  912.         else
  913.         {
  914.             // This animation repeats, so calcuate the
  915.             // remainder
  916.             if (dDurPrime != 0.0)
  917.             {
  918.                 dUnfilteredSimpleTime =
  919.                     dActiveFilteredTime -
  920.                     dDurPrime * floor(dActiveFilteredTime / dDurPrime);
  921.             }
  922.         }
  923.         // Account for autoReverse behavior
  924.         double dUnfilteredSimpleTimePrime = dUnfilteredSimpleTime;
  925.         if (m_pElement->m_bAutoReverse &&
  926.             dUnfilteredSimpleTime >= dDur)
  927.         {
  928.             dUnfilteredSimpleTimePrime = (2.0 * dDur) - dUnfilteredSimpleTime;
  929.         }
  930.         // Compute the decel begin time
  931.         double dDecelBegin = dDur - ddec;
  932.         // Compute the filtered simple time
  933.         double dFilteredSimpleTime = (double) dUnfilteredSimpleTimePrime;
  934.         double dRDenom             = 1.0 -
  935.                                      (m_pElement->m_dAccelerate / 2.0) - 
  936.                                      (m_pElement->m_dDecelerate / 2.0);
  937.         double dR = 1.0;
  938.         if (dRDenom != 0.0)
  939.         {
  940.             dR = 1.0 / dRDenom;
  941.         }
  942.         if (dUnfilteredSimpleTimePrime >= 0.0 &&
  943.             dUnfilteredSimpleTimePrime < dacc)
  944.         {
  945.             dFilteredSimpleTime = dUnfilteredSimpleTimePrime *
  946.                                   ComputeRunRate(dUnfilteredSimpleTimePrime,
  947.                                                  m_pElement->m_dAccelerate,
  948.                                                  m_pElement->m_dDecelerate,
  949.                                                  dDur) / 2.0;
  950.         }
  951.         else if (dUnfilteredSimpleTimePrime >= dacc &&
  952.                  dUnfilteredSimpleTimePrime <= dDecelBegin)
  953.         {
  954.             dFilteredSimpleTime = dR * (dUnfilteredSimpleTimePrime - (dacc / 2.0));
  955.         }
  956.         else if (dUnfilteredSimpleTimePrime > dDecelBegin &&
  957.                  dUnfilteredSimpleTimePrime <= dDur)
  958.         {
  959.             double tdec = dUnfilteredSimpleTime - dDecelBegin;
  960.             double pd   = 1.0;
  961.             if (ddec != 0.0)
  962.             {
  963.                 pd = tdec / ddec;
  964.             }
  965.             dFilteredSimpleTime = dR * (dDur - (dacc / 2.0) - ddec +
  966.                                         (tdec * (2.0 - pd) / 2.0));
  967.             // Make sure we don't ever round up to dDur if
  968.             // our input is less than dDur
  969.             if (dUnfilteredSimpleTimePrime < dDur &&
  970.                 dFilteredSimpleTime >= dDur - 0.5)
  971.             {
  972.                 dFilteredSimpleTime = dDur - 0.50000000001;
  973.             }
  974.         }
  975.         // Now round to nearest integer
  976.         ulRet = (UINT32) floor(dFilteredSimpleTime + 0.5);
  977.     }
  978.     return ulRet;
  979. }
  980. double CAnimationSandwichLayer::ComputeRunRate(double dT, double dAccel,
  981.                                                double dDecel, double dDur)
  982. {
  983.     double dRet = 1.0;
  984.     double dacc    = dDur * dAccel;
  985.     double ddec    = dDur * dDecel;
  986.     double dRDenom = 1.0 - (dAccel / 2.0) - (dDecel / 2.0);
  987.     if (dRDenom != 0.0)
  988.     {
  989.         double dR = 1.0 / dRDenom;
  990.         // Compute the decel begin time
  991.         double dDecBegin = dDur - ddec;
  992.         // Now compute the run rate
  993.         if (dT >= 0.0 && dT < dacc)
  994.         {
  995.             if (dacc != 0.0)
  996.             {
  997.                 dRet = dR * dT / dacc;
  998.             }
  999.         }
  1000.         else if (dT >= dacc && dT <= dDecBegin)
  1001.         {
  1002.             dRet = dR;
  1003.         }
  1004.         else if (dT > dDecBegin && dT <= dDur)
  1005.         {
  1006.             if (ddec != 0.0)
  1007.             {
  1008.                 dRet = dR * (dDur - dT) / ddec;
  1009.             }
  1010.         }
  1011.     }
  1012.     return dRet;
  1013. }
  1014. #if defined(XXXMEH_SPLINE_ANIMATION)
  1015. double CAnimationSandwichLayer::ComputeSpline(double t,  double t1, double t2,
  1016.                                               double v1, double v2, double x1,
  1017.                                               double y1, double x2, double y2)
  1018. {
  1019.     double dRet = 0.0;
  1020.     if (x1 >= 0.0 && x1 <= 1.0 &&
  1021.         y1 >= 0.0 && y1 <= 1.0 &&
  1022.         x2 >= 0.0 && x2 <= 1.0 &&
  1023.         y2 >= 0.0 && y2 <= 1.0)
  1024.     {
  1025.         if (t2 >= t1)
  1026.         {
  1027.             if (t >= t1)
  1028.             {
  1029.                 if (t <= t2)
  1030.                 {
  1031.                     if (t2 > t1)
  1032.                     {
  1033.                         // We compute the spline interpolation
  1034.                         // in the following steps:
  1035.                         // a) Scale the time down to unit time
  1036.                         // b) Get the output bezier time (still in unit time)
  1037.                         // c) Use this output time as the 
  1038.                         //    input time for linear interpolation.
  1039.                         //
  1040.                         // Scale the time to unit time
  1041.                         double dInUnitT = (t - t1) / (t2 - t1);
  1042.                         // Get the output bezier time
  1043.                         double dOutUnitT = ComputeBezierOutputTime(dUnitT, x1, y1, x2, y2);
  1044.                         // Do a sanity check on the output time
  1045.                         if (dOutUnitT < 0.0)
  1046.                         {
  1047.                             dOutUnitT = 0.0;
  1048.                             HX_ASSERT(FALSE && "Bad value returned from ComputeBezierOutputTime()");
  1049.                         }
  1050.                         else if (dOutUnitT > 1.0)
  1051.                         {
  1052.                             dOutUnitT = 1.0;
  1053.                             HX_ASSERT(FALSE && "Bad value returned from ComputeBezierOutputTime()");
  1054.                         }
  1055.                         // Use this time to linearly interpolate
  1056.                         dRet = v1 + (v2 - v1) * dOutUnitT;
  1057.                     }
  1058.                     else
  1059.                     {
  1060.                         // t1 is equal to t2. So this is a discontinuous
  1061.                         // interval, so by endpoint-exclusive logic [a,b),
  1062.                         // we choose v2 for the output value. This is not
  1063.                         // an input error, so we don't assert.
  1064.                         dRet = v2;
  1065.                     }
  1066.                 }
  1067.                 else
  1068.                 {
  1069.                     dRet = v2;
  1070.                     HX_ASSERT(FALSE && "ComputeSpline(): t is greater than t2 - v2 assigned");
  1071.                 }
  1072.             }
  1073.             else
  1074.             {
  1075.                 dRet = v1;
  1076.                 HX_ASSERT(FALSE && "ComputeSpline(): t is less than t1 - v1 assigned");
  1077.             }
  1078.         }
  1079.         else
  1080.         {
  1081.             HX_ASSERT(FALSE && "ComputeSpline(): t2 cannot be less than t1");
  1082.         }
  1083.     }
  1084.     else
  1085.     {
  1086.         HX_ASSERT(FALSE && "Illegal bezier control parameters in ComputeSpline()");
  1087.     }
  1088.     return dRet;
  1089. }
  1090. double CAnimationSandwichLayer::ComputeBezierOutputTime(double t,
  1091.                                                         double x1, double y1,
  1092.                                                         double x2, double y2)
  1093. {
  1094.     double dRet = 0.0;
  1095.     if (t  >= 0.0 && t  <= 1.0 &&
  1096.         x1 >= 0.0 && x1 <= 1.0 &&
  1097.         y1 >= 0.0 && y1 <= 1.0 &&
  1098.         x2 >= 0.0 && x2 <= 1.0 &&
  1099.         y2 >= 0.0 && y2 <= 1.0)
  1100.     {
  1101.         // We get the output bezier-curve-warped time
  1102.         // by doing the following:
  1103.         //
  1104.         // a) Find q where x(q) = t
  1105.         // b) Compute y(q)
  1106.         //
  1107.         // Find the q where x(q) = t
  1108.         double dQ = SolveForBezierT(t, x1, x2, BEZIER_TOLERANCE);
  1109.         // Do a sanity check on this value
  1110.         if (dQ < 0.0)
  1111.         {
  1112.             dQ = 0.0;
  1113.             HX_ASSERT(FALSE && "Bad value returned from SolveForBezierT()");
  1114.         }
  1115.         else if (dQ > 1.0)
  1116.         {
  1117.             dQ = 1.0;
  1118.             HX_ASSERT(FALSE && "Bad value returned from SolveForBezierT()");
  1119.         }
  1120.         // Compute y(q)
  1121.         dRet = ComputeBezier(dQ, y1, y2);
  1122.     }
  1123.     else
  1124.     {
  1125.         HX_ASSERT(FALSE && "Illegal input parameters in ComputeBezierOutputTime()");
  1126.     }
  1127.     return dRet;
  1128. }
  1129. double CAnimationSandwichLayer::SolveForBezierT(double x,  double x1,
  1130.                                                 double x2, double tol)
  1131. {
  1132.     double dRet = 0.0;
  1133.     if (x   >= 0.0 && x   <= 1.0 &&
  1134.         x1  >= 0.0 && x1  <= 1.0 &&
  1135.         x2  >= 0.0 && x2  <= 1.0 &&
  1136.         tol >  0.0 && tol <= 1.0)
  1137.     {
  1138.         double tL = 0.0;
  1139.         double xL = 0.0;
  1140.         double tR = 1.0;
  1141.         double xR = 1.0;
  1142.         double tM = 0.5;
  1143.         double xM = ComputeBezier(tM, x1, x2);
  1144.         UINT32 i  = 0;
  1145.         while (fabs(xM - x) > tol &&
  1146.                i < BEZIER_MAX_ITERATIONS)
  1147.         {
  1148.             // Is our computed mid-point smaller or
  1149.             // larger than our desired value?
  1150.             if (xM > x)
  1151.             {
  1152.                 // Take the left-hand interval
  1153.                 tR = tM;
  1154.             }
  1155.             else
  1156.             {
  1157.                 // Take the right-hand interval
  1158.                 tL = tM;
  1159.             }
  1160.             // Compute new mid-point
  1161.             tM = (tL + tR) / 2.0;
  1162.             // Compute new value
  1163.             xM = ComputeBezier(tM, x1, x2);
  1164.             // Increment the iteration count
  1165.             ++i;
  1166.         }
  1167.         // Set the return value
  1168.         dRet = tM;
  1169.         // Check if we blew our max iteration count
  1170.         if (i >= BEZIER_MAX_ITERATIONS)
  1171.         {
  1172.             HX_ASSERT(FALSE && "SolveForBezierT(): Could not get within tolerance in max iterations");
  1173.         }
  1174.     }
  1175.     else
  1176.     {
  1177.         HX_ASSERT(FALSE && "Illegal input parameters in SolveForBezierT()");
  1178.     }
  1179.     return dRet;
  1180. }
  1181. double CAnimationSandwichLayer::ComputeBezier(double t, double a1, double a2)
  1182. {
  1183.     double dRet = 0.0;
  1184.     if (t  >= 0.0 && t  <= 1.0 &&
  1185.         a1 >= 0.0 && a1 <= 1.0 &&
  1186.         a2 >= 0.0 && a2 <= 1.0)
  1187.     {
  1188.         double t2  = t * t;
  1189.         double t3  = t2 * t;
  1190.         double ti  = 1.0 - t;
  1191.         double ti2 = ti * ti;
  1192.         dRet       = 3.0 * t  * ti2 * a1 +
  1193.                      3.0 * t2 * ti  * a2 +
  1194.                      t3;
  1195.     }
  1196.     else
  1197.     {
  1198.         HX_ASSERT(FALSE && "Illegal input parameters in ComputeBezier()");
  1199.     }
  1200.     return dRet;
  1201. }
  1202. #endif // #if defined(XXXMEH_SPLINE_ANIMATION)
  1203. CAnimationSandwich::CAnimationSandwich(const char* pszTargetElementID,
  1204.                                        SMILNodeTag eTargetElementTag,
  1205.                                        UINT32      ulAttrName)
  1206. {
  1207.     MLOG_LEAKCHECK("CON CAnimationSandwich this=0x%08xn", this);
  1208.     m_pTargetElementID  = new CHXString(pszTargetElementID);
  1209.     m_eTargetElementTag = eTargetElementTag;
  1210.     m_ulAttrName        = ulAttrName;
  1211.     m_pLayerList        = NULL;
  1212. }
  1213. CAnimationSandwich::~CAnimationSandwich()
  1214. {
  1215.     MLOG_LEAKCHECK("DES CAnimationSandwich this=0x%08xn", this);
  1216.     ClearAllLayers();
  1217.     HX_DELETE(m_pTargetElementID);
  1218.     HX_DELETE(m_pLayerList);
  1219. }
  1220. void CAnimationSandwich::ClearAllLayers()
  1221. {
  1222.     if (m_pLayerList)
  1223.     {
  1224.         LISTPOSITION pos = m_pLayerList->GetHeadPosition();
  1225.         while (pos)
  1226.         {
  1227.             CAnimationSandwichLayer* pLayer = (CAnimationSandwichLayer*) m_pLayerList->GetNext(pos);
  1228.             HX_DELETE(pLayer);
  1229.         }
  1230.         m_pLayerList->RemoveAll();
  1231.     }
  1232. }
  1233. const char* CAnimationSandwich::GetTargetElementID() const
  1234. {
  1235.     const char* pRet = NULL;
  1236.     if (m_pTargetElementID)
  1237.     {
  1238.         pRet = (const char*) *m_pTargetElementID;
  1239.     }
  1240.     return pRet;
  1241. }
  1242. HX_RESULT CAnimationSandwich::AddLayer(CAnimationSandwichLayer* pLayer)
  1243. {
  1244.     HX_RESULT retVal = HXR_OK;
  1245.     if (pLayer)
  1246.     {
  1247.         if (!m_pLayerList)
  1248.         {
  1249.             m_pLayerList = new CHXSimpleList();
  1250.         }
  1251.         if (m_pLayerList)
  1252.         {
  1253.             BOOL         bAdded = FALSE;
  1254.             LISTPOSITION pos    = m_pLayerList->GetHeadPosition();
  1255.             while (pos)
  1256.             {
  1257.                 CAnimationSandwichLayer* pListLayer = (CAnimationSandwichLayer*) m_pLayerList->GetAt(pos);
  1258.                 if (pListLayer->HigherPriority(pLayer))
  1259.                 {
  1260.                     // The current layer in the list is higher priority
  1261.                     // than the layer we want to add, so we must insert
  1262.                     // ourselves BEFORE this layer
  1263.                     m_pLayerList->InsertBefore(pos, (void*) pLayer);
  1264.                     // Set the flag
  1265.                     bAdded = TRUE;
  1266.                     // Now jump out of the loop
  1267.                     break;
  1268.                 }
  1269.                 m_pLayerList->GetNext(pos);
  1270.             }
  1271.             // If we didn't add ourselves, then that
  1272.             // means we are the highest priority, so 
  1273.             // add ourselves to the tail of the list
  1274.             if (!bAdded)
  1275.             {
  1276.                 m_pLayerList->AddTail((void*) pLayer);
  1277.             }
  1278.         }
  1279.         else
  1280.         {
  1281.             retVal = HXR_OUTOFMEMORY;
  1282.         }
  1283.     }
  1284.     return retVal;
  1285. }
  1286. void CAnimationSandwich::RemoveLayer(const char* pszAnimID)
  1287. {
  1288.     if (pszAnimID && m_pLayerList)
  1289.     {
  1290.         LISTPOSITION pos = m_pLayerList->GetHeadPosition();
  1291.         while (pos)
  1292.         {
  1293.             CAnimationSandwichLayer* pLayer =
  1294.                 (CAnimationSandwichLayer*) m_pLayerList->GetAt(pos);
  1295.             if (pLayer &&
  1296.                 pLayer->GetAnimationElementID() &&
  1297.                 !strcmp(pszAnimID, pLayer->GetAnimationElementID()))
  1298.             {
  1299.                 // We need to remove this layer
  1300.                 //
  1301.                 // First remove it from the list
  1302.                 pos = m_pLayerList->RemoveAt(pos);
  1303.                 // Next delete the object itself
  1304.                 HX_DELETE(pLayer);
  1305.             }
  1306.             else
  1307.             {
  1308.                 m_pLayerList->GetNext(pos);
  1309.             }
  1310.         }
  1311.     }
  1312. }
  1313. void CAnimationSandwich::FreezeLayers(const char* pszAnimID, UINT32 ulCurTime)
  1314. {
  1315.     if (pszAnimID && m_pLayerList)
  1316.     {
  1317.         LISTPOSITION pos = m_pLayerList->GetHeadPosition();
  1318.         while (pos)
  1319.         {
  1320.             CAnimationSandwichLayer* pLayer =
  1321.                 (CAnimationSandwichLayer*) m_pLayerList->GetNext(pos);
  1322.             if (pLayer &&
  1323.                 pLayer->GetAnimationElementID() &&
  1324.                 !strcmp(pszAnimID, pLayer->GetAnimationElementID()) &&
  1325.                 pLayer->IsActive(ulCurTime))
  1326.             {
  1327.                 // We need to freeze this layer. We do this
  1328.                 // by adjusting the layer's m_ulActiveDuration
  1329.                 // such that pLayer->m_ulDelay + pLayer->m_ulActiveDuration
  1330.                 // is equal to the current time.
  1331.                 pLayer->AdjustActiveDuration(ulCurTime);
  1332.             }
  1333.         }
  1334.     }
  1335. }
  1336. CAttr CAnimationSandwich::GetValue(UINT32 ulTime, CAttr* pUnder, CAttr* pDepend)
  1337. {
  1338.     CAttr cRet;
  1339.     if (pUnder)
  1340.     {
  1341.         // Initialize the running value
  1342.         CAttr cUnder(*pUnder);
  1343.         // Now run through the layers
  1344.         if (m_pLayerList)
  1345.         {
  1346.             LISTPOSITION pos = m_pLayerList->GetHeadPosition();
  1347.             while (pos)
  1348.             {
  1349.                 CAnimationSandwichLayer* pLayer =
  1350.                     (CAnimationSandwichLayer*) m_pLayerList->GetNext(pos);
  1351.                 if (pLayer &&
  1352.                     (pLayer->IsActive(ulTime) ||
  1353.                      pLayer->IsFrozen(ulTime)))
  1354.                 {
  1355.                     // Evaluate this layer
  1356.                     CAttr cRes = pLayer->AnimationEffectFunction(ulTime, &cUnder, pDepend);
  1357.                     // Now we either have to replace OR add
  1358.                     if (pLayer->IsAdditive() &&
  1359.                         !pLayer->IsToAnimation())
  1360.                     {
  1361.                         cUnder.Add(&cRes, pDepend);
  1362.                     }
  1363.                     else
  1364.                     {
  1365.                         cUnder = cRes;
  1366.                     }
  1367.                 }
  1368.             }
  1369.         }
  1370.         // Now set the return value
  1371.         cRet = cUnder;
  1372.     }
  1373.     return cRet;
  1374. }
  1375. UINT32 CAnimationSandwich::GetNumLayers() const
  1376. {
  1377.     UINT32 ulRet = 0;
  1378.     if (m_pLayerList)
  1379.     {
  1380.         ulRet = m_pLayerList->GetCount();
  1381.     }
  1382.     return ulRet;
  1383. }
  1384. void CAnimationSandwich::AdjustLayers(UINT32 ulTime)
  1385. {
  1386.     if (m_pLayerList)
  1387.     {
  1388.         LISTPOSITION pos = m_pLayerList->GetHeadPosition();
  1389.         while (pos)
  1390.         {
  1391.             CAnimationSandwichLayer* pLayer = (CAnimationSandwichLayer*) m_pLayerList->GetAt(pos);
  1392.             if (!pLayer->IsActive(ulTime) &&
  1393.                 !pLayer->IsFrozen(ulTime))
  1394.             {
  1395.                 // We need to remove this layer
  1396.                 //
  1397.                 // First remove it from the list
  1398.                 pos = m_pLayerList->RemoveAt(pos);
  1399.                 // Next delete the object itself
  1400.                 HX_DELETE(pLayer);
  1401.             }
  1402.             else
  1403.             {
  1404.                 m_pLayerList->GetNext(pos);
  1405.             }
  1406.         }
  1407.     }
  1408. }
  1409. BOOL CAnimationSandwich::MatchingSandwich(CSmilAnimateElement* pAnim)
  1410. {
  1411.     BOOL bRet = FALSE;
  1412.     if (pAnim &&
  1413.         pAnim->m_pTargetElementID &&
  1414.         m_pTargetElementID &&
  1415.         *pAnim->m_pTargetElementID == *m_pTargetElementID)
  1416.     {
  1417.         // We know that this animate element has the
  1418.         // same target element ID as we do. Now we 
  1419.         // need to check if it has the same attributeName.
  1420.         // If the animate element is an <animateMotion>, then
  1421.         // our sandwich could be either left or top. If the
  1422.         // animate element is not <animateMotion>, then the
  1423.         // attributeName has to match exactly.
  1424.         if (pAnim->m_pNode &&
  1425.             pAnim->m_pNode->m_tag == SMILAnimateMotion)
  1426.         {
  1427.             if (m_ulAttrName == kAttrNameLeft ||
  1428.                 m_ulAttrName == kAttrNameTop)
  1429.             {
  1430.                 bRet = TRUE;
  1431.             }
  1432.         }
  1433.         else
  1434.         {
  1435.             UINT32 ulAttrName = pAnim->m_ucAttributeName;
  1436.             if (ulAttrName == m_ulAttrName)
  1437.             {
  1438.                 bRet = TRUE;
  1439.             }
  1440.         }
  1441.     }
  1442.     return bRet;
  1443. }
  1444. BOOL CAnimationSandwich::AtLeastOneActiveLayer(UINT32 ulTime)
  1445. {
  1446.     BOOL bRet = FALSE;
  1447.     if (m_pLayerList &&
  1448.         m_pLayerList->GetCount() > 0)
  1449.     {
  1450.         LISTPOSITION pos = m_pLayerList->GetHeadPosition();
  1451.         while (pos)
  1452.         {
  1453.             CAnimationSandwichLayer* pLayer =
  1454.                 (CAnimationSandwichLayer*) m_pLayerList->GetNext(pos);
  1455.             if (pLayer && pLayer->IsActive(ulTime))
  1456.             {
  1457.                 bRet = TRUE;
  1458.                 break;
  1459.             }
  1460.         }
  1461.     }
  1462.     return bRet;
  1463. }
  1464. CSmilAnimateInfo::CSmilAnimateInfo()
  1465. {
  1466.     m_pSandwich = NULL;
  1467.     m_pUnder    = NULL;
  1468.     m_pDepend   = NULL;
  1469. }
  1470. CSmilAnimateInfo::~CSmilAnimateInfo()
  1471. {
  1472.     HX_DELETE(m_pSandwich);
  1473.     HX_DELETE(m_pUnder);
  1474.     HX_DELETE(m_pDepend);
  1475. }