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

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. // include
  36. #include "hxtypes.h"
  37. #include "hxwintyp.h"
  38. #include "hxcom.h"
  39. #include "hxassert.h"
  40. #include <stdio.h>
  41. #ifdef _WINDOWS
  42. #include <windows.h>
  43. #include "platform/win/resource.h"
  44. #endif
  45. #if defined(_UNIX) && defined(USE_XWINDOWS)
  46. #include <X11/cursorfont.h>
  47. #include <X11/Intrinsic.h>
  48. #endif
  49. #ifdef _MACINTOSH
  50. #include <ctype.h>
  51. #include "platform/mac/cresload.h"
  52. extern FSSpec g_DLLFSpec;
  53. //CResourceLoader* CResourceLoader::zm_theResourceLoader = NULL;
  54. #endif
  55. //Mini sites don't support ARGB blt'ing.
  56. //Should break this out into a ALPHA_SUPPORTED feature.
  57. #if !defined(HELIX_FEATURE_MINI_SITE)
  58. #  define ARGB_CID HX_ARGB
  59. #else
  60. #  define ARGB_CID HX_RGB
  61. #endif
  62. #include "hxcomm.h"
  63. #include "ihxpckts.h"
  64. #include "hxfiles.h"
  65. #include "hxcore.h"
  66. #include "hxrendr.h"
  67. #include "hxhyper.h"
  68. #include "hxplugn.h"
  69. #include "hxwin.h"
  70. #include "hxasm.h"
  71. #include "hxevent.h"
  72. #include "hxvsurf.h"
  73. #include "hxver.h"
  74. #include "hxupgrd.h"
  75. #include "hxengin.h"
  76. #include "hxmon.h"
  77. #include "hxerror.h"
  78. #include "hxclsnk.h"
  79. #include "hxprefs.h"
  80. #include "addupcol.h"
  81. #include "hxstrutl.h"
  82. #include "netbyte.h"
  83. #include "unkimp.h"
  84. #include "baseobj.h"
  85. #include "hxparse.h"
  86. #include "hxtick.h"
  87. #include "hxbuffer.h"
  88. #include "hxstring.h"
  89. #include "gstring.h"
  90. #include "glist.h"
  91. #include "pxutil.h"
  92. #include "pxrect.h"
  93. #include "pxcolor.h"
  94. #include "pxeffect.h"
  95. #include "parseurl.h"
  96. #include "pxcallbk.h"
  97. #include "pximage.h"
  98. #include "makebomb.h"
  99. #include "pxtransp.h"
  100. #include "cladvsnk.h"
  101. #include "baseobj.h"
  102. #include "unkimp.h"
  103. #include "lzw.h"
  104. #include "gifimage.h"
  105. #include "gifcodec.h"
  106. #include "gifrmlog.h"
  107. #include "pxgifrnd.h"
  108. #include "gifrdll.ver"
  109. #include "debugout.h"
  110. #include "hxheap.h"
  111. #ifdef _DEBUG
  112. #undef HX_THIS_FILE     
  113. static const char HX_THIS_FILE[] = __FILE__;
  114. #endif
  115. #include "errdbg.h"
  116. #ifdef _AIX
  117. #include "dllpath.h"
  118. ENABLE_MULTILOAD_DLLACCESS_PATHS(Pxgifrnd);
  119. #endif
  120. const char * const CGIFRenderer::m_pszName                          = "GIF";
  121. const char * const CGIFRenderer::m_pszDescription                   = "Helix GIF Renderer Plugin";
  122. const char * const CGIFRenderer::m_pszCopyright                     = HXVER_COPYRIGHT;
  123. const char * const CGIFRenderer::m_pszMoreInfoURL                   = HXVER_MOREINFO;
  124. const char * const CGIFRenderer::m_ppszStreamMimeType[]             = {"application/vnd.rn-gifstream", 
  125.                                                                  "application/vnd.rn-gifstream2",
  126.                                                                  "application/vnd.rn-gifstream3",
  127.                                                                  NULL};
  128. const UINT32 CGIFRenderer::m_ulHighestSupportedContentVersion = HX_ENCODE_PROD_VERSION(0, 0, 0, 0);
  129. const UINT32 CGIFRenderer::m_ulHighestSupportedStreamVersion  = HX_ENCODE_PROD_VERSION(0, 1, 0, 0);
  130. #ifdef _WINDOWS
  131. extern HINSTANCE g_hInstance;
  132. #endif
  133. CGIFRenderer::CGIFRenderer()
  134. {
  135.     MLOG_LEAK("CON CGIFRenderer this=0x%08xn", this);
  136.     m_lRefCount            = 0;
  137.     m_pContext             = NULL;
  138.     m_pStream              = NULL;
  139.     m_cSize.cx             = 0;
  140.     m_cSize.cy             = 0;
  141.     m_pMISUS               = NULL;
  142.     m_pMISUSSite           = NULL;
  143.     m_pCommonClassFactory  = NULL;
  144.     m_pHyperNavigate       = NULL;
  145.     m_pStatusMessage       = NULL;
  146.     m_pGIFCodec            = NULL;
  147.     m_ulPadWidth           = 0;
  148.     m_bDecompressFinished  = FALSE;
  149.     m_ulCurImg             = 0;
  150.     m_ulCurImgRenderTime   = 0;
  151.     m_pOutputBuffer        = NULL;
  152.     m_ucTarget             = kTargetBrowser;
  153.     m_cURL                 = "";
  154.     m_ulBackgroundColor    = 0x00FFFFFF;
  155.     m_pScheduler           = NULL;
  156.     m_ulDataWidth          = 0;
  157.     m_ulLoopsDone          = 0;
  158.     m_ulBitsPerPixel       = 32;
  159.     m_ulBytesPerPixel      = 4;
  160.     m_bRGBOrdering         = TestBigEndian();
  161.     m_bFirstTimeSync       = TRUE;
  162.     m_bFirstDraw           = TRUE;
  163.     m_lLastImg             = -1;
  164.     m_bSiteAttached        = FALSE;
  165.     m_ulCurDelayTime       = 0;
  166.     m_pErrorMessages       = NULL;
  167. #if defined(_WINDOWS)
  168.     m_bRowsInverted        = TRUE;
  169. #elif defined(_MACINTOSH)
  170.     m_bRowsInverted        = FALSE;
  171. #elif defined(_UNIX)
  172.     m_bRowsInverted        = FALSE;
  173. #endif
  174.     m_bStatusMsgWillNeedErasing = FALSE;
  175.     m_bSetHyperlinkCursor    = FALSE;
  176.     m_sOldMouseX             = -1;
  177.     m_sOldMouseY             = -1;
  178. #if defined(_WINDOWS)
  179.     m_hPreHyperlinkCursor    = NULL;
  180.     m_hHyperlinkCursor       = NULL;
  181. #elif defined(_MACINTOSH)
  182.     const short HAND_CURSOR  = 1313;
  183.     m_pResourceLoader = CResourceLoader::CreateInstance(g_DLLFSpec);
  184.     m_hHyperlinkCursor = (CursHandle)m_pResourceLoader->LoadResource('CURS', HAND_CURSOR);
  185.     m_eCurrentCursor         = CURSOR_ARROW;
  186. #elif defined(_UNIX) && defined(USE_XWINDOWS)
  187.     m_pDisplay             = 0;
  188.     m_Window               = 0;
  189.     m_hHyperlinkCursor     = -1;
  190.     m_hCurrentCursor       = -1;
  191. #endif
  192.     m_pStreamHeaderBuffer  = NULL;
  193.     m_ulStreamHeaderOffset = 0;
  194.     m_bIgnorePackets       = FALSE;
  195.     m_pCallback            = NULL;
  196.     m_bImageBombed         = FALSE;
  197.     m_ulRendererFlags      = 0;
  198.     m_ulWidth              = 0;
  199.     m_ulHeight             = 0;
  200.     m_pValues              = NULL;
  201.     m_ulBackgroundOpacity         = 255;
  202.     m_ulMediaOpacity              = 255;
  203.     m_ulMediaChromaKey            = 0;
  204.     m_bMediaChromaKeySpecified    = FALSE;
  205.     m_ulMediaChromaKeyTolerance   = 0;
  206.     m_ulMediaChromaKeyOpacity     = 0;
  207.     m_bUsesAlphaChannel           = FALSE;
  208.     m_bPreserveMediaRepeat        = TRUE;
  209.     m_bPaused                     = FALSE;
  210.     m_lTimeOffset                 = 0;
  211.     m_tSchedulerTimeBase.tv_sec   = 0;
  212.     m_tSchedulerTimeBase.tv_usec  = 0;
  213.     m_ulTimeAtSchedulerTimeBase   = 0;
  214.     m_ulCurFrameIndex             = 0xFFFFFFFF;
  215.     m_pClientAdviseSink           = NULL;
  216.     m_ulEndTime                   = 0;
  217.     m_bNoNativeSize               = FALSE;
  218.     m_bCanBltSubRects             = FALSE;
  219. }
  220. CGIFRenderer::~CGIFRenderer()
  221. {
  222.     MLOG_LEAK("DES CGIFRenderer this=0x%08xn", this);
  223.     if (m_pCallback)
  224.     {
  225.         if (m_pCallback->IsCallbackPending())
  226.         {
  227.             m_pCallback->RemovePendingCallback();
  228.         }
  229.     }
  230.     if (m_pClientAdviseSink)
  231.     {
  232.         m_pClientAdviseSink->Close();
  233.     }
  234.     HX_RELEASE(m_pStatusMessage);
  235.     HX_RELEASE(m_pOutputBuffer);
  236.     HX_RELEASE(m_pContext);
  237.     HX_RELEASE(m_pCommonClassFactory);
  238.     HX_RELEASE(m_pHyperNavigate);
  239.     HX_DELETE(m_pGIFCodec);
  240.     HX_RELEASE(m_pScheduler);
  241.     HX_RELEASE(m_pErrorMessages);
  242.     
  243. #if defined(_MACINTOSH)
  244.     if (m_hHyperlinkCursor)
  245.     {
  246.         m_pResourceLoader->UnloadResource((Handle)m_hHyperlinkCursor);
  247.         m_hHyperlinkCursor = NULL;
  248.         
  249.         HX_RELEASE(m_pResourceLoader);
  250.     }
  251. #endif
  252. #if defined(_UNIX) && defined(USE_XWINDOWS)
  253.     if ((m_hHyperlinkCursor != -1) && m_pDisplay)
  254.     {
  255.     XFreeCursor(m_pDisplay, m_hHyperlinkCursor);
  256.     m_hHyperlinkCursor = -1;
  257.     }
  258. #endif
  259.     HX_RELEASE(m_pStreamHeaderBuffer);
  260.     HX_RELEASE(m_pCallback);
  261.     HX_RELEASE(m_pValues);
  262.     HX_RELEASE(m_pClientAdviseSink);
  263. }
  264. STDMETHODIMP CGIFRenderer::QueryInterface(REFIID riid, void** ppvObj)
  265. {
  266.     HX_RESULT retVal = HXR_OK;
  267.     if (ppvObj)
  268.     {
  269.         // Set default
  270.         *ppvObj = NULL;
  271.         // Check for IID type
  272.         if (IsEqualIID(riid, IID_IUnknown))
  273.         {
  274.             AddRef();
  275.             *ppvObj = (IUnknown*) (IHXPlugin*) this;
  276.         }
  277.         else if (IsEqualIID(riid, IID_IHXPlugin))
  278.         {
  279.             AddRef();
  280.             *ppvObj = (IHXPlugin*) this;
  281.         }
  282.         else if (IsEqualIID(riid, IID_IHXRenderer))
  283.         {
  284.             AddRef();
  285.             *ppvObj = (IHXRenderer*) this;
  286.         }
  287.         else if (IsEqualIID(riid, IID_IHXSiteUser))
  288.         {
  289.             AddRef();
  290.             *ppvObj = (IHXSiteUser*) this;
  291.         }
  292.         else if (IsEqualIID(riid, IID_IHXSiteUserSupplier))
  293.         {
  294.             if (m_pMISUS)
  295.             {
  296.                 return m_pMISUS->QueryInterface(IID_IHXSiteUserSupplier, ppvObj);
  297.             }
  298.             else
  299.             {
  300.                 retVal = HXR_UNEXPECTED;
  301.             }
  302.         }
  303.         else if (IsEqualIID(riid, IID_IHXStatistics))
  304.         {
  305.             AddRef();
  306.             *ppvObj = (IHXStatistics*) this;
  307.         }
  308.         else if (IsEqualIID(riid, IID_IHXValues))
  309.         {
  310.             AddRef();
  311.             *ppvObj = (IHXValues*) this;
  312.         }
  313.         else if (IsEqualIID(riid, IID_IHXUpdateProperties))
  314.         {
  315.             AddRef();
  316.             *ppvObj = (IHXUpdateProperties*) this;
  317.         }
  318.         else
  319.         {
  320.             retVal = HXR_NOINTERFACE;
  321.         }
  322.     }
  323.     else
  324.     {
  325.         retVal = HXR_FAIL;
  326.     }
  327.     return retVal;
  328. }
  329. STDMETHODIMP_(UINT32) CGIFRenderer::AddRef()
  330. {
  331.     return InterlockedIncrement(&m_lRefCount);
  332. }
  333. STDMETHODIMP_(UINT32) CGIFRenderer::Release()
  334. {
  335.     if (InterlockedDecrement(&m_lRefCount) > 0)
  336.     {
  337.         return m_lRefCount;
  338.     }
  339.     delete this;
  340.     return 0;
  341. }
  342. STDMETHODIMP CGIFRenderer::GetPluginInfo(REF(BOOL)         rbLoadMultiple,
  343.                                          REF(const char *) rpszDescription,
  344.                                          REF(const char *) rpszCopyright,
  345.                                          REF(const char *) rpszMoreInfoURL,
  346.                                          REF(UINT32)       rulVersionNumber)
  347. {
  348.     rbLoadMultiple   = TRUE;
  349.     rpszDescription  = (const char*) m_pszDescription;
  350.     rpszCopyright    = (const char*) m_pszCopyright;
  351.     rpszMoreInfoURL  = (const char*) m_pszMoreInfoURL;
  352.     rulVersionNumber = TARVER_ULONG32_VERSION;
  353.     return HXR_OK;
  354. }
  355. STDMETHODIMP CGIFRenderer::InitPlugin(IUnknown* pContext)
  356. {
  357.     HX_RESULT retVal = HXR_FAIL;
  358.     if (pContext)
  359.     {
  360.         // Save a copy of the calling context
  361.         HX_RELEASE(m_pContext);
  362.         m_pContext = pContext;
  363.         m_pContext->AddRef();
  364.         // Get a IHXCommonClassFactory interface
  365.         HX_RELEASE(m_pCommonClassFactory);
  366.         retVal = m_pContext->QueryInterface(IID_IHXCommonClassFactory,
  367.                                             (void**) &m_pCommonClassFactory);
  368.         if (SUCCEEDED(retVal))
  369.         {
  370. #if defined(HELIX_FEATURE_HYPER_NAVIGATE)
  371.             // Get an IHXHyperNavigate interface
  372.             HX_RELEASE(m_pHyperNavigate);
  373.             m_pContext->QueryInterface(IID_IHXHyperNavigate,
  374.                                        (void**) &m_pHyperNavigate);
  375. #endif /* #if defined(HELIX_FEATURE_HYPER_NAVIGATE) */
  376.             // Get the IHXStatusMessage interface - it's OK if TLC doesn't support
  377.             // this, so we won't check error return.
  378.             HX_RELEASE(m_pStatusMessage);
  379.             m_pContext->QueryInterface(IID_IHXStatusMessage,
  380.                                        (void**) &m_pStatusMessage);
  381.             // Get an IHXScheduler interface
  382.             HX_RELEASE(m_pScheduler);
  383.             retVal = m_pContext->QueryInterface(IID_IHXScheduler,
  384.                                                 (void**) &m_pScheduler);
  385.             if (SUCCEEDED(retVal))
  386.             {
  387.                 // Get the IHXErrorMessages interface - OK if
  388.                 // TLC doesn't support it
  389.                 HX_RELEASE(m_pErrorMessages);
  390.                 m_pContext->QueryInterface(IID_IHXErrorMessages,
  391.                                            (void**) &m_pErrorMessages);
  392.                 // Create a PXCallback object
  393.                 HX_RELEASE(m_pCallback);
  394.                 m_pCallback = new PXCallback();
  395.                 if (m_pCallback)
  396.                 {
  397.                     // AddRef the object
  398.                     m_pCallback->AddRef();
  399.                     // Init the callback object
  400.                     retVal = m_pCallback->Init(m_pContext, this);
  401.                     if (SUCCEEDED(retVal))
  402.                     {
  403.                         // Create the IHXValues object
  404.                         HX_RELEASE(m_pValues);
  405.                         m_pCommonClassFactory->CreateInstance(CLSID_IHXValues,
  406.                                                               (void**) &m_pValues);
  407.                     }
  408.                 }
  409.                 else
  410.                 {
  411.                     retVal = HXR_OUTOFMEMORY;
  412.                 }
  413.             }
  414.         }
  415.     }
  416.     return retVal;
  417. }
  418. STDMETHODIMP CGIFRenderer::GetRendererInfo(REF(const char **) rppszStreamMimeType,
  419.                                            REF(UINT32)        rulInitialGranularity)
  420. {
  421.     rppszStreamMimeType   = (const char**) m_ppszStreamMimeType;
  422.     rulInitialGranularity = 1000;
  423.     return HXR_OK;
  424. }
  425. STDMETHODIMP CGIFRenderer::StartStream(IHXStream* pStream, IHXPlayer* pPlayer)
  426. {
  427.     HX_RESULT retVal = HXR_OK;
  428.     if (pStream && pPlayer)
  429.     {
  430.         // Save a copy of the stream
  431.         HX_RELEASE(m_pStream);
  432.         m_pStream = pStream;
  433.         m_pStream->AddRef();
  434.         // Create a PXClientAdviseSink object
  435.         HX_RELEASE(m_pClientAdviseSink);
  436.         m_pClientAdviseSink = new PXClientAdviseSink();
  437.         if (m_pClientAdviseSink)
  438.         {
  439.             // AddRef the object
  440.             m_pClientAdviseSink->AddRef();
  441.             // Init the object - this registers this renderer
  442.             // as a client advise sink
  443.             retVal = m_pClientAdviseSink->Init(pPlayer,
  444.                                                (PXClientAdviseSinkResponse*) this);
  445.         }
  446.         else
  447.         {
  448.             retVal = HXR_OUTOFMEMORY;
  449.         }
  450. #if defined(HELIX_FEATURE_MISU)
  451.         if (SUCCEEDED(retVal))
  452.         {
  453.             // Create a IHXMultiInstanceSiteUserSupplier interface
  454.             HX_RELEASE(m_pMISUS);
  455.             retVal = m_pCommonClassFactory->CreateInstance(CLSID_IHXMultiInstanceSiteUserSupplier,
  456.                                                            (void**) &m_pMISUS);
  457.             if (SUCCEEDED(retVal))
  458.             {
  459.                 // Register ourselves as a site user
  460.                 retVal = m_pMISUS->SetSingleSiteUser((IUnknown*) (IHXSiteUser*) this);
  461.             }
  462.         }
  463. #endif
  464.     }
  465.     else
  466.     {
  467.         retVal = HXR_FAIL;
  468.     }
  469.     return retVal;
  470. }
  471. STDMETHODIMP CGIFRenderer::OnHeader(IHXValues *pStreamHeaderObj)
  472. {
  473.     // Check for input error
  474.     if (pStreamHeaderObj == NULL)
  475.     {
  476.         return HXR_FAIL;
  477.     }
  478.     // Get content version from header
  479.     UINT32    ulIncomingContentVersion;
  480.     HX_RESULT retVal = pStreamHeaderObj->GetPropertyULONG32("ContentVersion", ulIncomingContentVersion);
  481.     if (retVal != HXR_OK)
  482.     {
  483.         return HXR_FAIL;
  484.     }
  485.     // Get stream version from header
  486.     UINT32 ulIncomingStreamVersion;
  487.     retVal = pStreamHeaderObj->GetPropertyULONG32("StreamVersion", ulIncomingStreamVersion);
  488.     if (retVal != HXR_OK)
  489.     {
  490.         return HXR_FAIL;
  491.     }
  492.     // Check the versions
  493.     if (ulIncomingContentVersion > m_ulHighestSupportedContentVersion ||
  494.         ulIncomingStreamVersion  > m_ulHighestSupportedStreamVersion)
  495.     {
  496.         // Add to AU collection
  497.         AddToAutoUpgradeCollection(m_ppszStreamMimeType[2], m_pContext);
  498.         // Now we return an error, any error actually
  499.         return HXR_NO_RENDERER;
  500.     }
  501.     // Get the opaque data from the stream header
  502.     IHXBuffer *pBuffer = NULL;
  503.     retVal = pStreamHeaderObj->GetPropertyBuffer("OpaqueData", pBuffer);
  504.     if (retVal != HXR_OK)
  505.     {
  506.         return retVal;
  507.     }
  508.     // Unpack some info
  509.     BYTE *pData = pBuffer->GetBuffer();
  510.     UnPack8(pData,      m_ucTarget);
  511.     // These are no longer used by the renderer they are parsed in the new hypernavigate object in the core so all renderer
  512.     // commands are consistent and parsed in one place.  We do have to skip over them since the file format still puts them in.
  513. //  UnPack8(pData,      m_ucURLType);
  514. //  UnPack32(pData,     m_ulSeekTime);
  515.     pData += 5;     // Even though the 2 above members were removed we still need to increment the data pointer
  516.     // Note that we don't get the alpha from the background color
  517.     // in the opaque part of the stream header - we get that from
  518.     // the "bgOpacity" CString property in the stream header
  519.     BYTE ucBgRed   = pData[0];
  520.     BYTE ucBgGreen = pData[1];
  521.     BYTE ucBgBlue  = pData[2];
  522.     m_ulBackgroundColor = (ucBgRed << 16) | (ucBgGreen << 8) | ucBgBlue;
  523.     pData += 4;
  524.     UnPackString(pData, m_cURL);
  525.     // Get the current URL
  526.     IHXStreamSource* pStreamSource = NULL;
  527.     retVal = m_pStream->GetSource(pStreamSource);
  528.     if (retVal != HXR_OK || !pStreamSource)
  529.     {
  530.         HX_RELEASE(pBuffer);
  531.         return HXR_FAIL;
  532.     }
  533.     const char* pszURL = pStreamSource->GetURL();
  534.     if (!pszURL)
  535.     {
  536.         HX_RELEASE(pBuffer);
  537.         HX_RELEASE(pStreamSource);
  538.         return HXR_FAIL;
  539.     }
  540.     CHXString cOriginalURL = pszURL;
  541.     HX_RELEASE(pStreamSource);
  542.     // Check the URL to see if it's relative
  543.     if (m_cURL.length() > 0)
  544.     {
  545.         if (m_ucTarget == kTargetPlayer)
  546.         {
  547.             if (IsURLRelative(m_cURL.c_str()) &&
  548.                 !strstr(m_cURL.c_str(), "command:"))
  549.             {
  550.                 CHXString cRelURL(m_cURL.c_str());
  551.                 CHXString cAbsURL;
  552.                 retVal = MakeAbsoluteURL(cOriginalURL, cRelURL, cAbsURL);
  553.                 if (retVal == HXR_OK)
  554.                 {
  555.                     m_cURL = (const char *) cAbsURL;
  556.                 }
  557.             }
  558.         }
  559.     }
  560.     // Get the renderer flags property
  561.     m_ulRendererFlags = 0;
  562.     pStreamHeaderObj->GetPropertyULONG32("RendererFlags", m_ulRendererFlags);
  563.     // Check bit 0 to see if parsing failed
  564.     m_ulWidth          = 0;
  565.     m_ulHeight         = 0;
  566.     UINT32 ulBytesUsed = 0;
  567.     if (m_ulRendererFlags & GIF_RENDERER_FLAG_PARSEFAILED)
  568.     {
  569.         // Get the width and height from the stream header
  570.         pStreamHeaderObj->GetPropertyULONG32("Width",  m_ulWidth);
  571.         pStreamHeaderObj->GetPropertyULONG32("Height", m_ulHeight);
  572.         if (!m_ulWidth || !m_ulHeight)
  573.         {
  574.             m_ulWidth       = 48;
  575.             m_ulHeight      = 48;
  576.             m_bNoNativeSize = TRUE;
  577.         }
  578.     }
  579.     else
  580.     {
  581.         // Create a CGIFCodec
  582.         HX_DELETE(m_pGIFCodec);
  583.         m_pGIFCodec = new CGIFCodec();
  584.         if (!m_pGIFCodec)
  585.         {
  586.             HX_RELEASE(pBuffer);
  587.             return HXR_OUTOFMEMORY;
  588.         }
  589.         // Initialize the CGIFCodec for decompression
  590.         ulBytesUsed = pData - pBuffer->GetBuffer();
  591.         retVal = m_pGIFCodec->InitDecompress(pData, pBuffer->GetSize() - ulBytesUsed);
  592.         if (retVal != HXR_OK)
  593.         {
  594.             HX_RELEASE(pBuffer);
  595.             HX_DELETE(m_pGIFCodec);
  596.             return retVal;
  597.         }
  598.         // Set the width and height
  599.         m_ulWidth  = m_pGIFCodec->GetLogicalScreenWidth();
  600.         m_ulHeight = m_pGIFCodec->GetLogicalScreenHeight();
  601.     }
  602.     // Get the mediaRepeat string
  603.     IHXBuffer* pMediaRepeatStr = NULL;
  604.     pStreamHeaderObj->GetPropertyCString("mediaRepeat",
  605.                                          pMediaRepeatStr);
  606.     if (pMediaRepeatStr)
  607.     {
  608.         if (!strcmp((const char*) pMediaRepeatStr->GetBuffer(), "strip"))
  609.         {
  610.             m_bPreserveMediaRepeat = FALSE;
  611.         }
  612.     }
  613.     HX_RELEASE(pMediaRepeatStr);
  614.     // Save the stream header's opaque buffer
  615.     HX_RELEASE(m_pStreamHeaderBuffer);
  616.     m_pStreamHeaderBuffer = pBuffer;
  617.     m_pStreamHeaderBuffer->AddRef();
  618.     // Init the stream header buffer offset
  619.     m_ulStreamHeaderOffset = ulBytesUsed;
  620.     // Now we can release the IHXBuffer
  621.     HX_RELEASE(pBuffer);
  622.      // Create an output buffer
  623.     HX_RELEASE(m_pOutputBuffer);
  624.     retVal = m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer, (void **) &m_pOutputBuffer);
  625.     if (retVal != HXR_OK)
  626.     {
  627.         HX_DELETE(m_pGIFCodec);
  628.         return retVal;
  629.     }
  630.     
  631.     // Compute the size of the output buffer
  632.     m_ulDataWidth      = m_ulWidth * m_ulBytesPerPixel;
  633.     m_ulPadWidth       = (m_ulDataWidth + 3) & ~3; // This rounds up to nearest multiple of 4
  634.     UINT32 ulNumBytes  = m_ulPadWidth * m_ulHeight;
  635.     
  636.     // Set the size of the output buffer
  637.     retVal = m_pOutputBuffer->SetSize(ulNumBytes);
  638.     if (retVal != HXR_OK)
  639.     {
  640.         HX_DELETE(m_pGIFCodec);
  641.         HX_RELEASE(m_pOutputBuffer);
  642.         return retVal;
  643.     }
  644.     // Initially draw the background color into the display buffer
  645.     DrawBackgroundColor();
  646.     // Initialize the rendering members
  647.     m_ulCurImg           = 0;
  648.     m_ulCurImgRenderTime = 0;
  649.     m_ulCurDelayTime     = 0;
  650.     m_lLastImg           = -1;
  651.     // Initialize the loop done count
  652.     m_ulLoopsDone        = 0;
  653.     // Clear the ignore packets flag
  654.     m_bIgnorePackets     = FALSE;
  655.     // Set the first time sync flag
  656.     m_bFirstTimeSync     = TRUE;
  657.     // If the parsing failed, then fill in the image with a bomb image
  658.     if (m_ulRendererFlags & GIF_RENDERER_FLAG_PARSEFAILED)
  659.     {
  660.         CopyBombImage();
  661.     }
  662.     else
  663.     {
  664.         // Send some debug info
  665.         MLOG_MISC(m_pErrorMessages,
  666.                   "0x%08x::OnHeader() w=%lu h=%lu loopcount=%lun",
  667.                    this, m_pGIFCodec->GetLogicalScreenWidth(),
  668.                    m_pGIFCodec->GetLogicalScreenHeight(), m_pGIFCodec->GetLoopCount());
  669.     }
  670.     // Get the duration
  671.     pStreamHeaderObj->GetPropertyULONG32("Duration", m_ulEndTime);
  672.     return HXR_OK;
  673. }
  674. STDMETHODIMP CGIFRenderer::OnBegin(UINT32 ulTimeAfterBegin)
  675. {
  676.     MLOG_MISC(m_pErrorMessages,
  677.               "%lu OnBegin(%lu) this=0x%08xn",
  678.               HX_GET_BETTERTICKCOUNT(), ulTimeAfterBegin, this);
  679.     return HXR_OK;
  680. }
  681. STDMETHODIMP CGIFRenderer::GetDisplayType(REF(HX_DISPLAY_TYPE) rDisplayType,
  682.                                           REF(IHXBuffer *)     rpDisplayInfo)
  683. {
  684.     rDisplayType = HX_DISPLAY_WINDOW          |
  685.                    HX_DISPLAY_SUPPORTS_RESIZE |
  686.                    HX_DISPLAY_SUPPORTS_FULLSCREEN;
  687.     return HXR_OK;
  688. }
  689. STDMETHODIMP CGIFRenderer::OnPacket(IHXPacket *pPacket, INT32 lTimeOffset)
  690. {
  691.     MLOG_MISC(m_pErrorMessages,
  692.               "%lu OnPacket(,%ld) this=0x%08xn",
  693.               HX_GET_BETTERTICKCOUNT(), lTimeOffset, this);
  694.     // Check for input error
  695.     if (pPacket == NULL)
  696.     {
  697.         return HXR_INVALID_PARAMETER;
  698.     }
  699.     // Save the time offset
  700.     m_lTimeOffset = lTimeOffset;
  701.     // If we are in between OnPreSeek() and OnPostSeek(), we will ignore 
  702.     // packets
  703.     if (m_bIgnorePackets || m_bImageBombed)
  704.     {
  705.         return HXR_OK;
  706.     }
  707.     // Check if the packet is lost
  708.     if (pPacket->IsLost())
  709.     {
  710.         m_pGIFCodec->PacketLost();
  711.         return HXR_OK;
  712.     }
  713.     // Get the IHXBuffer from the packet
  714.     IHXBuffer *pBuffer = pPacket->GetBuffer();
  715.     if (pBuffer == NULL)
  716.     {
  717.         return HXR_INVALID_PARAMETER;
  718.     }
  719.     BYTE*  pData      = pBuffer->GetBuffer();
  720.     UINT32 ulDataSize = pBuffer->GetSize();
  721.     // Retrieve the flags
  722.     UINT32 ulFlags = 0;
  723.     UnPack32(pData, ulFlags);
  724.     // Is this packet the beginning of a new image?
  725.     BOOL bFirstInImage = FALSE;
  726.     if (ulFlags & 0x01)
  727.     {
  728.         bFirstInImage = TRUE;
  729.     }
  730.     // Comment extensions at the end of the file could mean we receive packets
  731.     // after we are finished decoding. In this case, we just return
  732.     if (m_pGIFCodec->DecompressFinished())
  733.     {
  734.         HX_RELEASE(pBuffer);
  735.         return HXR_OK;
  736.     }
  737.     // Pass the data on to the CGIFCodec
  738.     HX_RESULT retVal = m_pGIFCodec->Decompress(pBuffer->GetBuffer() + 4,
  739.                                                pBuffer->GetSize()   - 4,
  740.                                                bFirstInImage);
  741.     if (retVal != HXR_OK)
  742.     {
  743.         CopyBombImage();
  744.     }
  745.     // Release our reference to the IHXBuffer
  746.     HX_RELEASE(pBuffer);
  747.     return HXR_OK;
  748. }
  749. STDMETHODIMP CGIFRenderer::OnTimeSync(UINT32 ulTime)
  750. {
  751.     MLOG_TIMING(m_pErrorMessages,
  752.               "0x%08x::OnTimeSync(%lu)n",
  753.               this, ulTime);
  754.     HX_RESULT retVal = HXR_OK;
  755.     if (m_bFirstTimeSync || m_bPaused)
  756.     {
  757.         // Clear the first timesync flag
  758.         m_bFirstTimeSync = FALSE;
  759.         // Clear the paused flag
  760.         m_bPaused = FALSE;
  761.         // Adjust the time according to the
  762.         // offset passed in through OnPacket()
  763.         INT32  lAdjustedTime  = ((INT32) ulTime) + m_lTimeOffset;
  764.         UINT32 ulAdjustedTime = (UINT32) (lAdjustedTime >= 0 ? lAdjustedTime : 0);
  765.         // Set the current scheduler time base
  766.         if (m_pScheduler)
  767.         {
  768.             // Compute time in milliseconds
  769.             m_tSchedulerTimeBase = m_pScheduler->GetCurrentSchedulerTime();
  770. //            m_ulSchedulerTimeBase = (cTime.tv_sec * 1000) + ((cTime.tv_usec + 500) / 1000);
  771.             m_ulTimeAtSchedulerTimeBase = ulAdjustedTime;
  772.         }
  773.         // Update the display
  774.         UpdateDisplay(ulAdjustedTime);
  775.     }
  776.     return retVal;
  777. }
  778. HX_RESULT CGIFRenderer::UpdateDisplay(UINT32 ulTime)
  779. {
  780.     MLOG_MISC(m_pErrorMessages,
  781.               "%lu UpdateDisplay(%lu) this=0x%08xn",
  782.               HX_GET_BETTERTICKCOUNT(), ulTime, this);
  783.     HX_RESULT retVal = HXR_OK;
  784.     // Do we have a valid CGIFCodec?
  785.     if (m_pGIFCodec && !m_bImageBombed)
  786.     {
  787.         // Reset the damage flag
  788.         BOOL bDoDamage = FALSE;
  789.         // Compute which frame we should be on at this time
  790.         UINT32 ulFrameIndex = 0;
  791.         if (m_pGIFCodec->GetNumImages() > 1)
  792.         {
  793.             // Get the modulo time
  794.             UINT32 ulModTime   = 0;
  795.             UINT32 ulCycleTime = GetCycleTime();
  796.             if (ulCycleTime)
  797.             {
  798.                 UINT32 ulIter      = ulTime / ulCycleTime;
  799.                 UINT32 ulIterStart = ulIter * ulCycleTime;
  800.                 ulModTime          = ulTime - ulIterStart;
  801.             }
  802.             UINT32 ulRunSum    = 0;
  803.             UINT32 ulNumFrames = m_pGIFCodec->GetNumImages();
  804.             for (UINT32 i = 0; i < ulNumFrames; i++)
  805.             {
  806.                 // Get the delay for this frame
  807.                 UINT32     ulFrameDelay = 0;
  808.                 CGIFImage* pImage       = m_pGIFCodec->GetImage(i);
  809.                 if (pImage)
  810.                 {
  811.                     ulFrameDelay = pImage->GetDelayTime() * 10;
  812.                 }
  813.                 // Check if our time is in this frame
  814.                 if (ulModTime >= ulRunSum &&
  815.                     ulModTime <  ulRunSum + ulFrameDelay)
  816.                 {
  817.                     ulFrameIndex = i;
  818.                     break;
  819.                 }
  820.                 // Add the delay for this frame to the running sum
  821.                 ulRunSum += ulFrameDelay;
  822.             }
  823.         }
  824.         // Is the frame currently in the buffer the same
  825.         // as our computed frame? If it is, then we don't
  826.         // need to update our buffer
  827.         BOOL bFinished         = FALSE;
  828.         BOOL bWouldHaveSkipped = FALSE;
  829.         if (ulFrameIndex != m_ulCurFrameIndex)
  830.         {
  831.             // Make sure we don't skip frames
  832.             UINT32 ulFrameIndexNoSkip = ulFrameIndex;
  833.             if (m_ulCurFrameIndex != 0xFFFFFFFF)
  834.             {
  835.                 UINT32 ulFrameDiff = 0;
  836.                 if (ulFrameIndex >= m_ulCurFrameIndex)
  837.                 {
  838.                     ulFrameDiff = ulFrameIndex - m_ulCurFrameIndex;
  839.                 }
  840.                 else
  841.                 {
  842.                     ulFrameDiff = m_pGIFCodec->GetNumImages() -
  843.                                   m_ulCurFrameIndex + ulFrameIndex;
  844.                 }
  845.                 if (ulFrameDiff > 1)
  846.                 {
  847.                     ulFrameIndexNoSkip = m_ulCurFrameIndex + 1;
  848.                     if (ulFrameIndexNoSkip >= m_pGIFCodec->GetNumImages())
  849.                     {
  850.                         ulFrameIndexNoSkip = 0;
  851.                     }
  852.                 }
  853.             }
  854.             // Enforce no skipping of frames, but set a flag if
  855.             // we did have to change the frame, so that we can
  856.             // use that to update our callback interval
  857.             if (ulFrameIndexNoSkip != ulFrameIndex)
  858.             {
  859.                 // Yes, we are having to force not to skip a frame
  860.                 bWouldHaveSkipped = TRUE;
  861.                 ulFrameIndex      = ulFrameIndexNoSkip;
  862.             }
  863.             // Is the image we want to draw done? If it's not finished,
  864.             // we DON'T want to draw but we DO want another callback
  865.             CGIFImage* pCurImage = m_pGIFCodec->GetImage(ulFrameIndex);
  866.             if (pCurImage)
  867.             {
  868.                 bFinished = pCurImage->Finished();
  869.             }
  870.             // Do we need to update?
  871.             if (bFinished)
  872.             {
  873.                 // Yes, we need to update, so first we get the image
  874.                 m_pGIFCodec->GetRGBImageEx((m_ulCurFrameIndex == 0xFFFFFFFF ? -1 : (INT32) m_ulCurFrameIndex),
  875.                                            ulFrameIndex,
  876.                                            m_pOutputBuffer->GetBuffer(),
  877.                                            m_pGIFCodec->GetLogicalScreenWidth(),
  878.                                            m_pGIFCodec->GetLogicalScreenHeight(),
  879.                                            m_ulPadWidth,
  880.                                            m_ulBytesPerPixel,
  881.                                            m_bRowsInverted,
  882.                                            m_bRGBOrdering,
  883.                                            m_ulBackgroundColor,
  884.                                            (m_ulMediaOpacity == 255 ? FALSE : TRUE),
  885.                                            m_ulMediaOpacity,
  886.                                            m_bMediaChromaKeySpecified,
  887.                                            m_ulMediaChromaKey,
  888.                                            m_ulMediaChromaKeyTolerance,
  889.                                            m_ulMediaChromaKeyOpacity);
  890.                 // XXXMEH - do dumb assignment for now. We should later check
  891.                 // chroma key to find if any colors were actually encountered.
  892.                 if (m_ulBackgroundOpacity < 255 ||
  893.                     m_ulMediaOpacity < 255      ||
  894.                     m_bMediaChromaKeySpecified)
  895.                 {
  896.                     m_bUsesAlphaChannel = TRUE;
  897.                 }
  898.                 // Set the damage flag
  899.                 bDoDamage = TRUE;
  900.                 // We need to damage the rect. If we are bltting off
  901.                 // of HX_SURFACE_UPDATE2, then we should damage the
  902.                 // rect of both the current frame and the previous frame.
  903.                 // If we are still bltting off of HX_SURFACE_UPDATE, then
  904.                 // we need to damage the whole logical screen area.
  905.                 if (m_bCanBltSubRects)
  906.                 {
  907.                     // Damage the rect of the previous frame
  908.                     DamageFrameRect(m_ulCurFrameIndex);
  909.                     // Damage the rect of the current frame
  910.                     DamageFrameRect(ulFrameIndex);
  911.                     // Force a redraw
  912.                     if (m_pMISUSSite)
  913.                     {
  914.                         m_pMISUSSite->ForceRedraw();
  915.                     }
  916.                 }
  917.                 else
  918.                 {
  919.                     // Damage entire site area
  920.                     if (m_pMISUSSite)
  921.                     {
  922.                         // Get the size of the site
  923.                         HXxSize cSize = {0, 0};
  924.                         m_pMISUSSite->GetSize(cSize);
  925.                         // Get the damage rect
  926.                         HXxRect cRect = {0, 0, cSize.cx, cSize.cy};
  927.                         MLOG_MISC(m_pErrorMessages,
  928.                                   "%lu     Damaging entire logical screen: "
  929.                                   "(%ld,%ld,%ld,%ld) (%ld x %ld)n",
  930.                                   HX_GET_BETTERTICKCOUNT(),
  931.                                   cRect.left,  cRect.top,
  932.                                   cRect.right, cRect.bottom,
  933.                                   HXxRECT_WIDTH(cRect),
  934.                                   HXxRECT_HEIGHT(cRect));
  935.                         m_pMISUSSite->DamageRect(cRect);
  936.                         m_pMISUSSite->ForceRedraw();
  937.                     }
  938.                 }
  939.                 // Check if we just completed a loop. If the frame
  940.                 // index that we just drew into the buffer is LOWER
  941.                 // than the frame index that USED to be there, then
  942.                 // we will assume we just wrapped around
  943.                 if ((m_ulCurFrameIndex           == 0xFFFFFFFF &&
  944.                      m_pGIFCodec->GetNumImages() == 1) ||
  945.                     (m_ulCurFrameIndex           != 0xFFFFFFFF &&
  946.                      ulFrameIndex                <  m_ulCurFrameIndex))
  947.                 {
  948.                     m_ulLoopsDone++;
  949.                 }
  950.                 // Update the current frame index
  951.                 m_ulCurFrameIndex = ulFrameIndex;
  952.             }
  953.         }
  954.         // Do we need to schedule another callback?
  955.         if (m_bSiteAttached &&                                        // only schedule another callback if site is attached
  956.             m_pCallback    &&                                         // can't do it without a callback object
  957.             (m_bPreserveMediaRepeat ||
  958.              (!m_bPreserveMediaRepeat && m_ulLoopsDone == 0)) &&
  959.             ((bFinished == FALSE)               ||                    // GIF isn't finished yet
  960.             (m_pGIFCodec->GetLoopCount() == 0) ||                     // GIF says to loop infinitely
  961.              (m_pGIFCodec->GetLoopCount() > 0 &&                      // GIF says to loop a finite number of
  962.               m_ulLoopsDone < m_pGIFCodec->GetLoopCount())))          //   times and we're not finished
  963.         {
  964.             // If we just drew the image, then don't schedule a callback until
  965.             // the delay time from now. If we didn't draw, then schedule one
  966.             // kCallbackInterval milliseconds from now
  967.             BOOL       bRelative     = TRUE;
  968.             UINT32     ulTimeFromNow = kCallbackInterval;
  969.             HXTimeval cTime         = {0, 0};
  970.             // Was the frame finished?
  971.             if (bFinished)
  972.             {
  973.                 // Did we draw and would have skipped a frame?
  974.                 if (bDoDamage && bWouldHaveSkipped)
  975.                 {
  976.                     // Schedule a short relative callback
  977.                     bRelative     = TRUE;
  978.                     ulTimeFromNow = kMinCallbackInterval;
  979.                 }
  980.                 else
  981.                 {
  982.                     // Get the time that the next frame would display
  983.                     UINT32 ulNextFrameTime = GetNextFrameTime(ulTime);
  984.                     // If the difference is small enough, then schedule
  985.                     // a short relative callback. Otherwise schedule
  986.                     // an absolute callback
  987.                     if (ulNextFrameTime - ulTime > kMinCallbackInterval)
  988.                     {
  989.                         // Get the time difference between the next frame
  990.                         // time and the time at the scheduler time base
  991.                         UINT32 ulDiff = 0;
  992.                         if (ulNextFrameTime >= m_ulTimeAtSchedulerTimeBase)
  993.                         {
  994.                             ulDiff = ulNextFrameTime - m_ulTimeAtSchedulerTimeBase;
  995.                         }
  996.                         else
  997.                         {
  998.                             ulDiff = 0xFFFFFFFF - m_ulTimeAtSchedulerTimeBase + ulNextFrameTime;
  999.                         }
  1000.                         // Compute the difference in seconds and microseconds
  1001.                         HXTimeval cDiff = {0, 0};
  1002.                         cDiff.tv_sec  = ulDiff / 1000;
  1003.                         cDiff.tv_usec = (ulDiff - (cDiff.tv_sec * 1000)) * 1000;
  1004.                         // Add this difference to the scheduler time base
  1005.                         cTime.tv_sec  = m_tSchedulerTimeBase.tv_sec  + cDiff.tv_sec;
  1006.                         cTime.tv_usec = m_tSchedulerTimeBase.tv_usec + cDiff.tv_usec;
  1007.                         // Wrap the usec if necessary
  1008.                         if (cTime.tv_usec >= 1000000)
  1009.                         {
  1010.                             cTime.tv_usec -= 1000000;
  1011.                             cTime.tv_sec  += 1;
  1012.                         }
  1013.                         // Clear the relative flag
  1014.                         bRelative = FALSE;
  1015.                     }
  1016.                     else
  1017.                     {
  1018.                         bRelative     = TRUE;
  1019.                         ulTimeFromNow = kMinCallbackInterval;
  1020.                     }
  1021.                 }
  1022.             }
  1023.             else
  1024.             {
  1025.                 // Frame had not completed decoding - schedule a
  1026.                 // relative callback
  1027.                 bRelative     = TRUE;
  1028.                 ulTimeFromNow = kNotFinishedInterval;
  1029.             }
  1030.             // Schedule the next callback
  1031.             if (bRelative)
  1032.             {
  1033.                 m_pCallback->ScheduleRelativeCallback(ulTimeFromNow);
  1034.             }
  1035.             else
  1036.             {
  1037.                 m_pCallback->ScheduleAbsoluteCallback(cTime);
  1038.             }
  1039.         }
  1040.     }
  1041.     return retVal;
  1042. }
  1043. STDMETHODIMP CGIFRenderer::OnPreSeek(UINT32 ulTimeBefore, UINT32 ulTimeAfter)
  1044. {
  1045.     MLOG_MISC(m_pErrorMessages,
  1046.               "0x%08x::OnPreSeek(%lu,%lu)n",
  1047.               this, ulTimeBefore, ulTimeAfter);
  1048.     // Set the ignore packets flag
  1049.     m_bIgnorePackets = TRUE;
  1050.     return HXR_OK;
  1051. }
  1052. STDMETHODIMP CGIFRenderer::OnPostSeek(UINT32 ulTimeBefore, UINT32 ulTimeAfter)
  1053. {
  1054.     MLOG_MISC(m_pErrorMessages,
  1055.               "0x%08x::OnPostSeek(%lu,%lu)n",
  1056.               this, ulTimeBefore, ulTimeAfter);
  1057.     HX_RESULT retVal = HXR_OK;
  1058.     if (m_pStreamHeaderBuffer && !m_bImageBombed)
  1059.     {
  1060.         // Determine if the seek-to time is past our ending time.
  1061.         // We only need to blow away everything if we are going to
  1062.         // be getting packets all over again. That will happen only
  1063.         // if the seek-to time is < our end time.
  1064.         if (ulTimeAfter < m_ulEndTime)
  1065.         {
  1066.             // We are going to start receiving packets all over again, so
  1067.             // we need to blow away the CGIFCodec class and start over
  1068.             // again. We will need to reinit it with the stream header
  1069.             // buffer.
  1070.             //
  1071.             // Delete the old CGIFCodec
  1072.             HX_DELETE(m_pGIFCodec);
  1073.             // Create a new one
  1074.             m_pGIFCodec = new CGIFCodec();
  1075.             if (m_pGIFCodec)
  1076.             {
  1077.                 // Get the stream header pointer
  1078.                 BYTE* pData = m_pStreamHeaderBuffer->GetBuffer() + m_ulStreamHeaderOffset;
  1079.                 // Initialize the CGIFCodec for decompression
  1080.                 retVal = m_pGIFCodec->InitDecompress(m_pStreamHeaderBuffer->GetBuffer() + m_ulStreamHeaderOffset,
  1081.                                                      m_pStreamHeaderBuffer->GetSize()   - m_ulStreamHeaderOffset);
  1082.                 if (SUCCEEDED(retVal))
  1083.                 {
  1084.                     // Initialize the rendering members
  1085.                     m_ulCurImg           = 0;
  1086.                     m_ulCurImgRenderTime = 0;
  1087.                     m_ulCurDelayTime     = 0;
  1088.                     m_lLastImg           = -1;
  1089.                     // Initialize the loop done count
  1090.                     m_ulLoopsDone        = 0;
  1091.                     // Clear the ignore packets flag
  1092.                     m_bIgnorePackets     = FALSE;
  1093.                 }
  1094.             }
  1095.             else
  1096.             {
  1097.                 retVal = HXR_OUTOFMEMORY;
  1098.             }
  1099.         }
  1100.     }
  1101.     else
  1102.     {
  1103.         retVal = HXR_UNEXPECTED;
  1104.     }
  1105.     
  1106.     return retVal;
  1107. }
  1108. STDMETHODIMP CGIFRenderer::OnPause(UINT32 ulTimeBeforePause)
  1109. {
  1110.     MLOG_MISC(m_pErrorMessages,
  1111.               "0x%08x::OnPause(%lu)n",
  1112.               this, ulTimeBeforePause);
  1113.     // Set the paused flag
  1114.     m_bPaused = TRUE;
  1115.     return HXR_OK;
  1116. }
  1117. STDMETHODIMP CGIFRenderer::OnBuffering(UINT32 ulReason, UINT16 usPercentComplete)
  1118. {
  1119.     MLOG_MISC(m_pErrorMessages,
  1120.               "0x%08x::OnBuffering(%lu,%u)n",
  1121.               this, ulReason, usPercentComplete);
  1122.     return HXR_OK;
  1123. }
  1124. STDMETHODIMP CGIFRenderer::OnEndofPackets()
  1125. {
  1126.     MLOG_MISC(m_pErrorMessages,
  1127.               "0x%08x::OnEndofPackets()n",
  1128.               this);
  1129.     return HXR_OK;
  1130. }
  1131. STDMETHODIMP CGIFRenderer::EndStream()
  1132. {
  1133.     MLOG_MISC(m_pErrorMessages,
  1134.               "0x%08x::EndStream()n",
  1135.               this);
  1136.     // We're finished with the stream, but we may have
  1137.     // more rendering to do
  1138.     HX_RELEASE(m_pStream);
  1139.     return HXR_OK;
  1140. }
  1141. STDMETHODIMP CGIFRenderer::AttachSite(IHXSite *pSite)
  1142. {
  1143.     MLOG_MISC(m_pErrorMessages,
  1144.               "0x%08x::AttachSite(0x%08x)n",
  1145.               this, pSite);
  1146.     // Check for input error
  1147.     if (pSite == NULL)
  1148.     {
  1149.         return HXR_INVALID_PARAMETER;
  1150.     }
  1151.     // Check to see if we alredy have a site interface
  1152.     if (m_pMISUSSite)
  1153.     {
  1154.         return HXR_UNEXPECTED;
  1155.     }
  1156.     // Save a copy of the IHXSite interface
  1157.     m_pMISUSSite = pSite;
  1158.     m_pMISUSSite->AddRef();
  1159.     // Fill in the size
  1160.     m_cSize.cx = m_ulWidth;
  1161.     m_cSize.cy = m_ulHeight;
  1162.     // Tell the site of our size
  1163.     m_pMISUSSite->SetSize(m_cSize);
  1164.     // Lets see if we have a new site that supports sub rects.
  1165.     IHXSubRectSite* pSubRectSite = NULL;
  1166.     if(HXR_OK == m_pMISUSSite->QueryInterface(IID_IHXSubRectSite,
  1167.                                               (void**)&pSubRectSite))
  1168.     {
  1169.         //If so, since IHXSubRectSite inheirits from IHXSite, lets just
  1170.         //swap the pointers and sign up for the service.
  1171.         HX_RELEASE(m_pMISUSSite);
  1172.         m_pMISUSSite = pSubRectSite;
  1173.         pSubRectSite->SendSubRectMessages(TRUE);
  1174.         // Set the flag
  1175.         m_bCanBltSubRects = TRUE;
  1176.     }
  1177.     // Set the site attached flag
  1178.     m_bSiteAttached = TRUE;
  1179.     return HXR_OK;
  1180. }
  1181. STDMETHODIMP CGIFRenderer::DetachSite()
  1182. {
  1183.     MLOG_MISC(m_pErrorMessages,
  1184.               "0x%08x::DetachSite()n",
  1185.               this);
  1186.     if (m_pCallback)
  1187.     {
  1188.         if (m_pCallback->IsCallbackPending())
  1189.         {
  1190.             m_pCallback->RemovePendingCallback();
  1191.         }
  1192.     }
  1193.     if (m_pClientAdviseSink)
  1194.     {
  1195.         m_pClientAdviseSink->Close();
  1196.     }
  1197.     // Release the callback
  1198.     // XXXMEH - MUST DO THIS HERE or we'll have circular
  1199.     // dependency and leak CGIFRenderers
  1200.     HX_RELEASE(m_pCallback);
  1201.     // Release our site interface
  1202.     HX_RELEASE(m_pMISUSSite);
  1203.     // We're done with these...
  1204.     if (m_pMISUS)
  1205.     {
  1206.         m_pMISUS->ReleaseSingleSiteUser();
  1207.     }
  1208.     HX_RELEASE(m_pMISUS);
  1209.     // Clear the site attached flag
  1210.     m_bSiteAttached = FALSE;
  1211.     return HXR_OK;
  1212. }
  1213. STDMETHODIMP_(BOOL) CGIFRenderer::NeedsWindowedSites()
  1214. {
  1215.     return FALSE;
  1216. }
  1217. STDMETHODIMP CGIFRenderer::InitializeStatistics(UINT32 ulRegistryID)
  1218. {
  1219.     MLOG_MISC(m_pErrorMessages,
  1220.               "0x%08x::InitializeStatistics(%lu)n",
  1221.               this, ulRegistryID);
  1222.     // Add our renderer name to the HXRegistry
  1223.     IHXRegistry *pRegistry = NULL;
  1224.     HX_RESULT retVal = m_pContext->QueryInterface(IID_IHXRegistry, (void **) &pRegistry);
  1225.     if (retVal == HXR_OK)
  1226.     {
  1227.         // Get the current registry key name
  1228.         IHXBuffer *pszRegistryName = NULL;
  1229.         retVal                      = pRegistry->GetPropName(ulRegistryID, pszRegistryName);
  1230.         if (retVal == HXR_OK)
  1231.         {
  1232.             // Create an IHXBuffer to hold the name
  1233.         
  1234.             IHXBuffer* pValue = NULL;
  1235.             if (m_pCommonClassFactory)
  1236.             {
  1237.                 IUnknown* pUnknown = NULL;
  1238.                 m_pCommonClassFactory->CreateInstance(CLSID_IHXBuffer, (void**)&pUnknown);
  1239.                 if (pUnknown)
  1240.                 {
  1241.                     pUnknown->QueryInterface(IID_IHXBuffer, (void**)&pValue);
  1242.                     HX_RELEASE(pUnknown);
  1243.                 }
  1244.             }
  1245.             if (!pValue)
  1246.             {
  1247.                 HX_RELEASE(pszRegistryName);
  1248.                 HX_RELEASE(pRegistry);
  1249.                 return HXR_OUTOFMEMORY;
  1250.             }
  1251.             pValue->AddRef();
  1252.             // Create the key name
  1253.             char szRegistryEntry[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
  1254.             SafeSprintf(szRegistryEntry, MAX_DISPLAY_NAME, "%s.name", pszRegistryName->GetBuffer());
  1255.             // Set the key value
  1256.             retVal = pValue->Set((const BYTE*) m_pszName, strlen(m_pszName) + 1);
  1257.             if (retVal != HXR_OK)
  1258.             {
  1259.                 HX_RELEASE(pValue);
  1260.                 HX_RELEASE(pszRegistryName);
  1261.                 HX_RELEASE(pRegistry);
  1262.                 return retVal;
  1263.             }
  1264.             // Add the key/value pair to the registry
  1265.             pRegistry->AddStr(szRegistryEntry, pValue);
  1266.             HX_RELEASE(pValue);
  1267.             HX_RELEASE(pszRegistryName);
  1268.         }
  1269.         HX_RELEASE(pRegistry);
  1270.     }
  1271.     return retVal;
  1272. }
  1273. STDMETHODIMP CGIFRenderer::UpdateStatistics()
  1274. {
  1275.     MLOG_MISC(m_pErrorMessages,
  1276.               "0x%08x::UpdateStatistics()n",
  1277.               this);
  1278.     return HXR_OK;
  1279. }
  1280. STDMETHODIMP CGIFRenderer::SetPropertyULONG32(const char* pName, ULONG32 ulVal)
  1281. {
  1282.     HX_RESULT retVal = HXR_FAIL;
  1283.     if (m_pValues)
  1284.     {
  1285.         // Clear the update needed flag
  1286.         BOOL bUpdateNeeded = FALSE;
  1287.         if (!strcmp(pName, "backgroundOpacity"))
  1288.         {
  1289.             if (ulVal > 255) ulVal = 255;
  1290.             if (ulVal != m_ulBackgroundOpacity) bUpdateNeeded = TRUE;
  1291.             m_ulBackgroundOpacity = ulVal;
  1292.         }
  1293.         else if (!strcmp(pName, "mediaOpacity"))
  1294.         {
  1295.             if (ulVal > 255) ulVal = 255;
  1296.             if (ulVal != m_ulMediaOpacity) bUpdateNeeded = TRUE;
  1297.             m_ulMediaOpacity = ulVal;
  1298.         }
  1299.         else if (!strcmp(pName, "chromaKey"))
  1300.         {
  1301.             if (ulVal != m_ulMediaChromaKey) bUpdateNeeded = TRUE;
  1302.             m_ulMediaChromaKey         = ulVal;
  1303.             m_bMediaChromaKeySpecified = TRUE;
  1304.         }
  1305.         else if (!strcmp(pName, "chromaKeyTolerance"))
  1306.         {
  1307.             if (ulVal != m_ulMediaChromaKeyTolerance) bUpdateNeeded = TRUE;
  1308.             m_ulMediaChromaKeyTolerance = ulVal;
  1309.         }
  1310.         else if (!strcmp(pName, "chromaKeyOpacity"))
  1311.         {
  1312.             if (ulVal != m_ulMediaChromaKeyOpacity) bUpdateNeeded = TRUE;
  1313.             m_ulMediaChromaKeyOpacity = ulVal;
  1314.         }
  1315.         // Did any values change?
  1316.         if (bUpdateNeeded)
  1317.         {
  1318.             // If we have not seen our first time sync yet, then
  1319.             // there is no need to update the buffer, since the first
  1320.             // copy has not been done yet
  1321.             if (!m_bFirstTimeSync && m_pGIFCodec)
  1322.             {
  1323.                 // Compute the current frame we are on (note that
  1324.                 // m_ulCurImg contains the index of the NEXT frame
  1325.                 // that we are about to draw
  1326.                 UINT32 ulCurFrame = (m_ulCurImg > 0 ? m_ulCurImg - 1 : 0);
  1327.                 // Update the buffer
  1328.                 // XXXMEH - optimization for later. In some cases if we 
  1329.                 // just changed the media opacity, then it may not be necessary
  1330.                 // to start back at the beginning and rebuild the frame buffer
  1331.                 // from the first frame.
  1332.                 m_pGIFCodec->GetRGBImageEx(-1,
  1333.                                            ulCurFrame,
  1334.                                            m_pOutputBuffer->GetBuffer(),
  1335.                                            m_pGIFCodec->GetLogicalScreenWidth(),
  1336.                                            m_pGIFCodec->GetLogicalScreenHeight(),
  1337.                                            m_ulPadWidth,
  1338.                                            m_ulBytesPerPixel,
  1339.                                            m_bRowsInverted,
  1340.                                            m_bRGBOrdering,
  1341.                                            m_ulBackgroundColor,
  1342.                                            (m_ulMediaOpacity == 255 ? FALSE : TRUE),
  1343.                                            m_ulMediaOpacity,
  1344.                                            m_bMediaChromaKeySpecified,
  1345.                                            m_ulMediaChromaKey,
  1346.                                            m_ulMediaChromaKeyTolerance,
  1347.                                            m_ulMediaChromaKeyOpacity);
  1348.                 // XXXMEH - do dumb assignment for now. We should later check
  1349.                 // chroma key to find if any colors were actually encountered.
  1350.                 if (m_ulBackgroundOpacity < 255 ||
  1351.                     m_ulMediaOpacity < 255      ||
  1352.                     m_bMediaChromaKeySpecified)
  1353.                 {
  1354.                     m_bUsesAlphaChannel = TRUE;
  1355.                 }
  1356.             }
  1357.         }
  1358.         retVal = m_pValues->SetPropertyULONG32(pName, ulVal);
  1359.     }
  1360.     return retVal;
  1361. }
  1362. STDMETHODIMP CGIFRenderer::GetPropertyULONG32(const char* pName, REF(ULONG32) rulVal)
  1363. {
  1364.     HX_RESULT retVal = HXR_FAIL;
  1365.     if (m_pValues)
  1366.     {
  1367.         retVal = m_pValues->GetPropertyULONG32(pName, rulVal);
  1368.     }
  1369.     return retVal;
  1370. }
  1371. STDMETHODIMP CGIFRenderer::GetFirstPropertyULONG32(REF(const char*) rpName, REF(ULONG32) rulVal)
  1372. {
  1373.     HX_RESULT retVal = HXR_FAIL;
  1374.     if (m_pValues)
  1375.     {
  1376.         retVal = m_pValues->GetFirstPropertyULONG32(rpName, rulVal);
  1377.     }
  1378.     return retVal;
  1379. }
  1380. STDMETHODIMP CGIFRenderer::GetNextPropertyULONG32(REF(const char*) rpName, REF(ULONG32) rulVal)
  1381. {
  1382.     HX_RESULT retVal = HXR_FAIL;
  1383.     if (m_pValues)
  1384.     {
  1385.         retVal = m_pValues->GetNextPropertyULONG32(rpName, rulVal);
  1386.     }
  1387.     return retVal;
  1388. }
  1389. STDMETHODIMP CGIFRenderer::SetPropertyBuffer(const char* pName, IHXBuffer* pVal)
  1390. {
  1391.     HX_RESULT retVal = HXR_FAIL;
  1392.     if (m_pValues)
  1393.     {
  1394.         retVal = m_pValues->SetPropertyBuffer(pName, pVal);
  1395.     }
  1396.     return retVal;
  1397. }
  1398. STDMETHODIMP CGIFRenderer::GetPropertyBuffer(const char* pName, REF(IHXBuffer*) rpVal)
  1399. {
  1400.     HX_RESULT retVal = HXR_FAIL;
  1401.     if (m_pValues)
  1402.     {
  1403.         retVal = m_pValues->GetPropertyBuffer(pName, rpVal);
  1404.     }
  1405.     return retVal;
  1406. }
  1407. STDMETHODIMP CGIFRenderer::GetFirstPropertyBuffer(REF(const char*) rpName, REF(IHXBuffer*) rpVal)
  1408. {
  1409.     HX_RESULT retVal = HXR_FAIL;
  1410.     if (m_pValues)
  1411.     {
  1412.         retVal = m_pValues->GetFirstPropertyBuffer(rpName, rpVal);
  1413.     }
  1414.     return retVal;
  1415. }
  1416. STDMETHODIMP CGIFRenderer::GetNextPropertyBuffer(REF(const char*) rpName, REF(IHXBuffer*) rpVal)
  1417. {
  1418.     HX_RESULT retVal = HXR_FAIL;
  1419.     if (m_pValues)
  1420.     {
  1421.         retVal = m_pValues->GetNextPropertyBuffer(rpName, rpVal);
  1422.     }
  1423.     return retVal;
  1424. }
  1425. STDMETHODIMP CGIFRenderer::SetPropertyCString(const char* pName, IHXBuffer* pVal)
  1426. {
  1427.     HX_RESULT retVal = HXR_FAIL;
  1428.     if (m_pValues)
  1429.     {
  1430.         // Check for the default SMIL namespace
  1431.         BOOL bUpdateNeeded = FALSE;
  1432.         if (!strcmp(pName, "SMILDefaultNamespace"))
  1433.         {
  1434.             if (m_ulBackgroundOpacity != 0)
  1435.             {
  1436.                 bUpdateNeeded = TRUE;
  1437.             }
  1438.             m_ulBackgroundOpacity = 0;
  1439.             // Update the background color
  1440.             UINT32 ulBgAlpha    = 255 - m_ulBackgroundOpacity;
  1441.             m_ulBackgroundColor = (m_ulBackgroundColor & 0x00FFFFFF) |
  1442.                                   ((ulBgAlpha << 24)   & 0xFF000000);
  1443.         }
  1444.         // Do we need to update the display buffer
  1445.         if (bUpdateNeeded && !m_bImageBombed)
  1446.         {
  1447.             // If we haven't received our first time sync yet
  1448.             // (m_bFirstTimeSync == TRUE), then all we need to do
  1449.             // is redraw the transparent background color into the
  1450.             // the display buffer. If we have already received our
  1451.             // first time sync, then we need to redraw the entire buffer,
  1452.             // including redrawing the frames
  1453.             if (m_bFirstTimeSync)
  1454.             {
  1455.                 // We haven't draw any frames into our display buffer
  1456.                 // yet, so all we have to do is redraw a transparent
  1457.                 // background color into the buffer.
  1458.                 DrawBackgroundColor();
  1459.                 // We definitely will be using the alpha channel
  1460.                 m_bUsesAlphaChannel = TRUE;
  1461.             }
  1462.             else
  1463.             {
  1464.                 if (m_pGIFCodec && m_pOutputBuffer)
  1465.                 {
  1466.                     // Compute the current frame we are on (note that
  1467.                     // m_ulCurImg contains the index of the NEXT frame
  1468.                     // that we are about to draw
  1469.                     UINT32 ulCurFrame = (m_ulCurImg > 0 ? m_ulCurImg - 1 : 0);
  1470.                     // Update the buffer
  1471.                     // XXXMEH - optimization for later. In some cases if we 
  1472.                     // just changed the media opacity, then it may not be necessary
  1473.                     // to start back at the beginning and rebuild the frame buffer
  1474.                     // from the first frame.
  1475.                     m_pGIFCodec->GetRGBImageEx(-1,
  1476.                                                ulCurFrame,
  1477.                                                m_pOutputBuffer->GetBuffer(),
  1478.                                                m_pGIFCodec->GetLogicalScreenWidth(),
  1479.                                                m_pGIFCodec->GetLogicalScreenHeight(),
  1480.                                                m_ulPadWidth,
  1481.                                                m_ulBytesPerPixel,
  1482.                                                m_bRowsInverted,
  1483.                                                m_bRGBOrdering,
  1484.                                                m_ulBackgroundColor,
  1485.                                                (m_ulMediaOpacity == 255 ? FALSE : TRUE),
  1486.                                                m_ulMediaOpacity,
  1487.                                                m_bMediaChromaKeySpecified,
  1488.                                                m_ulMediaChromaKey,
  1489.                                                m_ulMediaChromaKeyTolerance,
  1490.                                                m_ulMediaChromaKeyOpacity);
  1491.                     // XXXMEH - do dumb assignment for now. We should later check
  1492.                     // chroma key to find if any colors were actually encountered.
  1493.                     if (m_ulBackgroundOpacity < 255 ||
  1494.                         m_ulMediaOpacity < 255      ||
  1495.                         m_bMediaChromaKeySpecified)
  1496.                     {
  1497.                         m_bUsesAlphaChannel = TRUE;
  1498.                     }
  1499.                 }
  1500.             }
  1501.         }
  1502.         retVal = m_pValues->SetPropertyCString(pName, pVal);
  1503.     }
  1504.     return retVal;
  1505. }
  1506. STDMETHODIMP CGIFRenderer::GetPropertyCString(const char* pName, REF(IHXBuffer*) rpVal)
  1507. {
  1508.     HX_RESULT retVal = HXR_FAIL;
  1509.     if (m_pValues)
  1510.     {
  1511.         retVal = m_pValues->GetPropertyCString(pName, rpVal);
  1512.     }
  1513.     return retVal;
  1514. }
  1515. STDMETHODIMP CGIFRenderer::GetFirstPropertyCString(REF(const char*) rpName, REF(IHXBuffer*) rpVal)
  1516. {
  1517.     HX_RESULT retVal = HXR_FAIL;
  1518.     if (m_pValues)
  1519.     {
  1520.         retVal = m_pValues->GetFirstPropertyCString(rpName, rpVal);
  1521.     }
  1522.     return retVal;
  1523. }
  1524. STDMETHODIMP CGIFRenderer::GetNextPropertyCString(REF(const char*) rpName, REF(IHXBuffer*) rpVal)
  1525. {
  1526.     HX_RESULT retVal = HXR_FAIL;
  1527.     if (m_pValues)
  1528.     {
  1529.         retVal = m_pValues->GetNextPropertyCString(rpName, rpVal);
  1530.     }
  1531.     return retVal;
  1532. }
  1533. STDMETHODIMP CGIFRenderer::UpdatePacketTimeOffset(INT32 lTimeOffset)
  1534. {
  1535.     HX_RESULT retVal = HXR_OK;
  1536.     // Save the time offset
  1537.     // XXXMEH - should this be negative
  1538.     m_lTimeOffset = -lTimeOffset;
  1539.     return retVal;
  1540. }
  1541. /************************************************************************
  1542.  * Method:
  1543.  *     IHXUpdateProperties::UpdatePlayTimes
  1544.  * Purpose:
  1545.  *     Call this method to update the playtime attributes
  1546.  */
  1547. STDMETHODIMP
  1548. CGIFRenderer::UpdatePlayTimes(IHXValues* pProps)
  1549. {
  1550.     return HXR_OK;
  1551. }
  1552. STDMETHODIMP CGIFRenderer::HandleCallback(UINT32 ulSchedulerTime, UINT32 ulInstance)
  1553. {
  1554.     HX_RESULT retVal = HXR_OK;
  1555.     
  1556.     if (!m_bPaused)
  1557.     {
  1558.         // Get the current scheduler time
  1559.         HXTimeval cTime = m_pScheduler->GetCurrentSchedulerTime();
  1560.         // Compute the difference in scheduler time
  1561.         UINT32 ulSchedDiff = GetTimevalDiff(m_tSchedulerTimeBase, cTime);
  1562.         // Compute the time in our timeline
  1563.         UINT32 ulTime = m_ulTimeAtSchedulerTimeBase + ulSchedDiff;
  1564.         // Update the display (if necessary)
  1565.         retVal = UpdateDisplay(ulTime);
  1566.     }
  1567.     return retVal;
  1568. }
  1569. STDMETHODIMP CGIFRenderer::CASOnPosLength(UINT32 ulPosition, UINT32 ulLength)
  1570. {
  1571.     HX_RESULT retVal = HXR_OK;
  1572.     // XXXMEH
  1573. //    char szDbgStr[128];
  1574. //    DEBUGPRINTF(szDbgStr, "CGIFRenderer::CASOnPosLength(%lu,%lu) tick=%lun",
  1575. //                ulPosition, ulLength, HX_GET_BETTERTICKCOUNT());
  1576.     if (m_bPaused)
  1577.     {
  1578.         // Clear the paused flag
  1579.         m_bPaused = FALSE;
  1580.         // Adjust the time according to the
  1581.         // offset passed in through OnPacket()
  1582.         INT32  lAdjustedTime  = ((INT32) ulPosition) + m_lTimeOffset;
  1583.         UINT32 ulAdjustedTime = (UINT32) (lAdjustedTime >= 0 ? lAdjustedTime : 0);
  1584.         // Set the current scheduler time base
  1585.         if (m_pScheduler)
  1586.         {
  1587.             // Compute time in milliseconds
  1588.             m_tSchedulerTimeBase = m_pScheduler->GetCurrentSchedulerTime();
  1589.             m_ulTimeAtSchedulerTimeBase = ulAdjustedTime;
  1590.         }
  1591.         // Update the display
  1592.         UpdateDisplay(ulAdjustedTime);
  1593.     }
  1594.     return retVal;
  1595. }
  1596. STDMETHODIMP CGIFRenderer::CASOnPresentationOpened()
  1597. {
  1598.     HX_RESULT retVal = HXR_OK;
  1599.     return retVal;
  1600. }
  1601. STDMETHODIMP CGIFRenderer::CASOnPresentationClosed()
  1602. {
  1603.     HX_RESULT retVal = HXR_OK;
  1604.     return retVal;
  1605. }
  1606. STDMETHODIMP CGIFRenderer::CASOnStatisticsChanged()
  1607. {
  1608.     HX_RESULT retVal = HXR_OK;
  1609.     return retVal;
  1610. }
  1611. STDMETHODIMP CGIFRenderer::CASOnPreSeek(ULONG32 ulOldTime, ULONG32 ulNewTime)
  1612. {
  1613.     HX_RESULT retVal = HXR_OK;
  1614.     return retVal;
  1615. }
  1616. STDMETHODIMP CGIFRenderer::CASOnPostSeek(ULONG32 ulOldTime, ULONG32 ulNewTime)
  1617. {
  1618.     HX_RESULT retVal = HXR_OK;
  1619.     return retVal;
  1620. }
  1621. STDMETHODIMP CGIFRenderer::CASOnStop()
  1622. {
  1623.     HX_RESULT retVal = HXR_OK;
  1624.     return retVal;
  1625. }
  1626. STDMETHODIMP CGIFRenderer::CASOnPause(ULONG32 ulTime)
  1627. {
  1628.     MLOG_MISC(m_pErrorMessages,
  1629.               "0x%08x::CASOnPause(%lu)n",
  1630.               this, ulTime);
  1631.     HX_RESULT retVal = HXR_OK;
  1632.     m_bPaused = TRUE;
  1633.     return retVal;
  1634. }
  1635. STDMETHODIMP CGIFRenderer::CASOnBegin(ULONG32 ulTime)
  1636. {
  1637.     MLOG_MISC(m_pErrorMessages,
  1638.               "0x%08x::CASOnBegin(%lu)n",
  1639.               this, ulTime);
  1640.     HX_RESULT retVal = HXR_OK;
  1641.     return retVal;
  1642. }
  1643. STDMETHODIMP CGIFRenderer::CASOnBuffering(ULONG32 ulFlags, UINT16 unPercentComplete)
  1644. {
  1645.     HX_RESULT retVal = HXR_OK;
  1646.     return retVal;
  1647. }
  1648. STDMETHODIMP CGIFRenderer::CASOnContacting(const char* pHostName)
  1649. {
  1650.     HX_RESULT retVal = HXR_OK;
  1651.     return retVal;
  1652. }
  1653. void CGIFRenderer::OnMouseMove(INT16 fwKeys, INT16 xPos, INT16 yPos)
  1654. {
  1655.     // Make sure we're up and running
  1656.     if (!m_pGIFCodec)
  1657.     {
  1658.         return;
  1659.     }
  1660.     // don't do anything if the x/y coordinates have changed from the
  1661.     // last call to OnMouseMove - this is needed because the call to
  1662.     // IHXStatusMessage::SetStatus() results in a WM_MOUSEMOVE event
  1663.     if(xPos == m_sOldMouseX && yPos == m_sOldMouseY)
  1664.     {
  1665.         return;
  1666.     }
  1667.     m_sOldMouseX = xPos;
  1668.     m_sOldMouseY = yPos;
  1669. #if defined(_WINDOWS)
  1670.     HCURSOR hCurrentCursor = GetCursor();
  1671. #endif
  1672.     if (xPos >= 0 && xPos < (INT16) m_pGIFCodec->GetLogicalScreenWidth()  &&
  1673.         yPos >= 0 && yPos < (INT16) m_pGIFCodec->GetLogicalScreenHeight() &&
  1674.         m_cURL.length() > 0) // we have a link
  1675.     {
  1676.         // We ARE over a hyperlink
  1677. #if defined(_WINDOWS)
  1678.         if(!m_hHyperlinkCursor)
  1679.         {
  1680.             m_hHyperlinkCursor = LoadCursor(g_hInstance, MAKEINTRESOURCE(HANDCURSOR));
  1681.             if(!m_hHyperlinkCursor)
  1682.             {
  1683.                 m_hHyperlinkCursor = LoadCursor(NULL, IDC_UPARROW);
  1684.             }
  1685.         }
  1686.         if(m_hHyperlinkCursor && hCurrentCursor != m_hHyperlinkCursor)
  1687.         {
  1688.             // We're over a link and the cursor is NOT already the hyperlink cursor,
  1689.             // so change it. This will happen when we get a WM_SETCURSOR event
  1690.             m_bSetHyperlinkCursor = TRUE;
  1691.         }
  1692. #elif defined(_MACINTOSH)
  1693.         if (m_hHyperlinkCursor)
  1694.         {
  1695.             ::SetCursor(*m_hHyperlinkCursor);
  1696.             m_eCurrentCursor = CURSOR_HYPERLINK;
  1697.         }
  1698. #elif defined(_UNIX) && defined(USE_XWINDOWS)
  1699.     if (m_hCurrentCursor == -1 && m_pDisplay && m_Window && m_hHyperlinkCursor != -1)
  1700.     {
  1701.         XDefineCursor(m_pDisplay, m_Window, m_hHyperlinkCursor);
  1702.         m_hCurrentCursor = m_hHyperlinkCursor;
  1703.     }
  1704. #endif
  1705.     if (m_pStatusMessage)
  1706.     {
  1707. m_bStatusMsgWillNeedErasing = TRUE;
  1708.         m_pStatusMessage->SetStatus(m_cURL.c_str());
  1709.     }
  1710.     }
  1711.     else
  1712.     {
  1713.         // We are NOT over a hyperlink
  1714. #if defined(_WINDOWS)
  1715.         if(hCurrentCursor == m_hHyperlinkCursor)
  1716.         {
  1717.             // We are not over a hyperlink and out cursor IS the hyperlink cursor,
  1718.             // so we need to change it back. This will happen when we get a WM_SETCURSOR event
  1719.             m_bSetHyperlinkCursor = FALSE;
  1720.         }
  1721. #elif defined(_MACINTOSH)
  1722.         if (m_eCurrentCursor == CURSOR_HYPERLINK)
  1723.         {
  1724.             ::InitCursor();
  1725.             m_eCurrentCursor = CURSOR_ARROW;
  1726.         }
  1727. #elif defined(_UNIX) && defined(USE_XWINDOWS)
  1728.     if (m_hCurrentCursor == m_hHyperlinkCursor)
  1729.     {
  1730.         if (m_pDisplay && m_Window)
  1731.         {
  1732.         XUndefineCursor(m_pDisplay, m_Window);
  1733.         m_hCurrentCursor = -1;
  1734.         }
  1735.     }
  1736. #endif
  1737. if (m_pStatusMessage  &&
  1738. // /Fixes PR 65008 (GIF version): only set this to NULL if we
  1739. // have recently set the status message, otherwise we may
  1740. // cause SMIL's setting of the status message to be
  1741. // overwritten with NULL, i.e., erased:
  1742. m_bStatusMsgWillNeedErasing)
  1743. {
  1744.     m_bStatusMsgWillNeedErasing = FALSE;
  1745.     m_pStatusMessage->SetStatus(NULL);
  1746. }
  1747.     }
  1748. }
  1749. STDMETHODIMP CGIFRenderer::HandleEvent(HXxEvent* pEvent)
  1750. {
  1751.     HX_RESULT retVal = HXR_OK;
  1752.     if (pEvent)
  1753.     {
  1754.         // Set defaults
  1755.         pEvent->handled = FALSE;
  1756.         pEvent->result  = 0;
  1757.         // Switch based on event type
  1758.         switch (pEvent->event)
  1759.         {
  1760.             case HX_SURFACE_UPDATE:
  1761.                 {
  1762.                     if (m_pOutputBuffer)
  1763.                     {
  1764.                         IHXVideoSurface *pSurface = (IHXVideoSurface *) (pEvent->param1);
  1765.                         HXxSize           size;
  1766.                         m_pMISUSSite->GetSize(size);
  1767.                         DrawToRMASurface(pSurface, 0, 0, size);
  1768.                     }
  1769. #if defined(_UNIX) && defined(USE_XWINDOWS)
  1770.                     {
  1771.                         HXxWindow *pWnd = (HXxWindow*)pEvent->param2;
  1772.                         if (pWnd) 
  1773.                         {
  1774.                             m_pDisplay = (Display*)pWnd->display;
  1775.                             m_Window = (Window)pWnd->window;
  1776.                             if (m_pDisplay && m_hHyperlinkCursor == -1)
  1777.                             m_hHyperlinkCursor = XCreateFontCursor(m_pDisplay, 
  1778.                                                    XC_hand2);
  1779.                         }
  1780.                     }
  1781. #endif
  1782.                     pEvent->handled = TRUE;
  1783.                 }
  1784.                 break;
  1785.             case HX_SURFACE_UPDATE2:
  1786.                 {
  1787.                    HXxExposeInfo* pExpose = (HXxExposeInfo*)pEvent->param2;
  1788.                    IHXSubRectVideoSurface* pSurface =
  1789.                        (IHXSubRectVideoSurface*) pEvent->param1;
  1790.                    if (pSurface)
  1791.                    {
  1792.                        pSurface->AddRef();
  1793.                        RMASurfaceUpdate2(pSurface,
  1794.                                          &pExpose->extents,
  1795.                                          pExpose->pRegion);
  1796.                        pSurface->Release();
  1797.                    }
  1798.                    pEvent->handled = TRUE;           
  1799.                 }
  1800.                 break;
  1801.             case HX_MOUSE_ENTER:
  1802.             case HX_MOUSE_LEAVE:
  1803.             case HX_MOUSE_MOVE:
  1804.                 {
  1805.                     HXxPoint* mousePt = (HXxPoint*) pEvent->param1;
  1806.                     OnMouseMove (0, (INT16)mousePt->x, (INT16)mousePt->y);
  1807.                     pEvent->handled = TRUE;
  1808.                 }
  1809.                 break;
  1810.             case HX_PRIMARY_BUTTON_UP:
  1811.                 {
  1812. #if defined(HELIX_FEATURE_HYPER_NAVIGATE)
  1813.                     HandleClick();
  1814. #endif // (HELIX_FEATURE_HYPER_NAVIGATE)
  1815.                     pEvent->handled = TRUE;
  1816.                 }
  1817.                 break;
  1818. #ifdef _WINDOWS
  1819.             case WM_SETCURSOR:
  1820.                 {
  1821.                     if(m_bSetHyperlinkCursor)
  1822.                     {
  1823.                         pEvent->handled       = TRUE;
  1824.                         m_hPreHyperlinkCursor = SetCursor(m_hHyperlinkCursor);
  1825.                     }
  1826.                     else
  1827.                     {
  1828.                         // pngui will handle the setting of the cursor (back to arrow cursor)
  1829.                         pEvent->handled       = FALSE;
  1830.                     }
  1831.                 }
  1832.                 break;
  1833. #endif
  1834.             default:
  1835.                 break;
  1836.         }
  1837.     }
  1838.     else
  1839.     {
  1840.         retVal = HXR_FAIL;
  1841.     }
  1842.     return retVal;
  1843. }
  1844. void CGIFRenderer::DrawToRMASurface(IHXVideoSurface *pVideoSurface, UINT32 ulX, UINT32 ulY, const HXxSize &size)
  1845. {
  1846. #if defined(HELIX_FEATURE_GIF_BROKENIMAGE)
  1847.     if (m_bImageBombed && m_bNoNativeSize &&
  1848.         (size.cx != (INT32) m_ulWidth ||
  1849.          size.cy != (INT32) m_ulHeight))
  1850.     {
  1851.         // Copy the bomb image
  1852.         PXMakeBombImage* pMakeBomb = new PXMakeBombImage();
  1853.         if (pMakeBomb)
  1854.         {
  1855.             PXImage*  pImage = NULL;
  1856.             HX_RESULT rv     = pMakeBomb->MakeBombImage(m_pContext,
  1857.                                                         (UINT32) size.cx,
  1858.                                                         (UINT32) size.cy,
  1859.                                                         m_ulBackgroundColor,
  1860.                                                         pImage);
  1861.             if (SUCCEEDED(rv))
  1862.             {
  1863.                 IHXBuffer* pImageStore = NULL;
  1864.                 rv = pImage->GetImageStore(&pImageStore);
  1865.                 if (SUCCEEDED(rv))
  1866.                 {
  1867.                     m_ulWidth  = (UINT32) size.cx;
  1868.                     m_ulHeight = (UINT32) size.cy;
  1869.                     HX_RELEASE(m_pOutputBuffer);
  1870.                     m_pOutputBuffer = pImageStore;
  1871.                     m_pOutputBuffer->AddRef();
  1872.                 }
  1873.                 HX_RELEASE(pImageStore);
  1874.             }
  1875.             HX_RELEASE(pImage);
  1876.         }
  1877.         HX_DELETE(pMakeBomb);
  1878.     }
  1879. #endif /* #if defined(HELIX_FEATURE_GIF_BROKENIMAGE) */
  1880.     if (m_pOutputBuffer)
  1881.     {
  1882.         pVideoSurface->AddRef();
  1883.         HXxRect rDestRect = { 0, 0, size.cx, size.cy};
  1884.         HXxRect rSrcRect  = { 0, 0, m_ulWidth,
  1885.                                     m_ulHeight };
  1886.         HXBitmapInfoHeader cHeader;
  1887.         cHeader.biSize          = 40;
  1888.         cHeader.biWidth         = (INT32) m_ulWidth;
  1889.         cHeader.biHeight        = (INT32) m_ulHeight;
  1890.         cHeader.biPlanes        = 1;
  1891.         cHeader.biBitCount      = 32;
  1892.         cHeader.biCompression   = (m_bUsesAlphaChannel ? ARGB_CID : HX_RGB);
  1893.         cHeader.biSizeImage     = 0;
  1894.         cHeader.biXPelsPerMeter = 0;
  1895.         cHeader.biYPelsPerMeter = 0;
  1896.         cHeader.biClrUsed       = 0;
  1897.         cHeader.biClrImportant  = 0;
  1898.         pVideoSurface->Blt(m_pOutputBuffer->GetBuffer(),
  1899.                            &cHeader,
  1900.                            rDestRect,
  1901.                            rSrcRect);
  1902.         HX_RELEASE(pVideoSurface);
  1903.     }
  1904. }
  1905. HX_RESULT CGIFRenderer::RMASurfaceUpdate2(IHXSubRectVideoSurface* pSurface,
  1906.                                           HXxRect*                 pExtents,
  1907.                                           HXxBoxRegion*              pDirtyRegion)
  1908. {
  1909.     MLOG_MISC(m_pErrorMessages,
  1910.               "%lu RMASurfaceUpdate2() this=0x%08xn",
  1911.               HX_GET_BETTERTICKCOUNT(), this);
  1912.     HX_RESULT retVal = HXR_OK;
  1913.     if (pSurface && m_pMISUSSite && m_pOutputBuffer)
  1914.     {
  1915.         // Get the size of the site
  1916.         HXxSize size;
  1917.         m_pMISUSSite->GetSize(size);
  1918.         // Scale dirty rects.
  1919.         float fx = (float) m_ulWidth  / (float) size.cx;
  1920.         float fy = (float) m_ulHeight / (float) size.cy;
  1921.         // Allocate space for the scaled subrects
  1922.         HXBOX* pSrcRects = new HXBOX[pDirtyRegion->numRects];
  1923.         if (pSrcRects)
  1924.         {
  1925.             // Go through each rect in the dirty region and scale it to 
  1926.             // generate the src rects.
  1927.             INT32 i = 0;
  1928.             for(i = 0; i < pDirtyRegion->numRects; i++)
  1929.             {
  1930.                 pSrcRects[i].x1 = (float) pDirtyRegion->rects[i].x1 * fx + 0.5;
  1931.                 pSrcRects[i].x2 = (float) pDirtyRegion->rects[i].x2 * fx + 0.5;
  1932.                 pSrcRects[i].y1 = (float) pDirtyRegion->rects[i].y1 * fy + 0.5;
  1933.                 pSrcRects[i].y2 = (float) pDirtyRegion->rects[i].y2 * fy + 0.5;
  1934.             }
  1935.             // Set up Src region.
  1936.             HXxBoxRegion srcRegion;
  1937.             srcRegion.numRects = pDirtyRegion->numRects;
  1938.             srcRegion.rects    = pSrcRects;
  1939.             // Set the values in the bitmap info header
  1940.             HXBitmapInfoHeader cHeader;
  1941.             cHeader.biSize          = 40;
  1942.             cHeader.biWidth         = m_ulWidth;
  1943.             cHeader.biHeight        = m_ulHeight;
  1944.             cHeader.biPlanes        = 1;
  1945.             cHeader.biBitCount      = 32;
  1946.             cHeader.biCompression   = (m_bUsesAlphaChannel ? ARGB_CID : HX_RGB);
  1947.             cHeader.biSizeImage     = 0;
  1948.             cHeader.biXPelsPerMeter = 0;
  1949.             cHeader.biYPelsPerMeter = 0;
  1950.             cHeader.biClrUsed       = 0;
  1951.             cHeader.biClrImportant  = 0;
  1952.             cHeader.rcolor          = 0;
  1953.             cHeader.gcolor          = 0;
  1954.             cHeader.bcolor          = 0;
  1955.             // Blit to the video surface
  1956.             MLOG_MISC(m_pErrorMessages,
  1957.                       "    numRects=%ldn",
  1958.                       srcRegion.numRects);
  1959.             for (i = 0; i < srcRegion.numRects; i++)
  1960.             {
  1961.                 MLOG_MISC(m_pErrorMessages,
  1962.                           "        rect[%ld] = (%d,%d,%d,%d)n",
  1963.                           i,
  1964.                           srcRegion.rects[i].x1,
  1965.                           srcRegion.rects[i].y1,
  1966.                           srcRegion.rects[i].x2,
  1967.                           srcRegion.rects[i].y2);
  1968.             }
  1969.             pSurface->BltSubRects(m_pOutputBuffer->GetBuffer(),
  1970.                                   &cHeader,
  1971.                                   pDirtyRegion,
  1972.                                   &srcRegion,
  1973.                                   1.0/fx, 1.0/fy);
  1974.         }
  1975.         HX_VECTOR_DELETE(pSrcRects);
  1976.     }
  1977.     else
  1978.     {
  1979.         retVal = HXR_FAIL;
  1980.     }
  1981.     return retVal;
  1982. }
  1983. void CGIFRenderer::HandleClick()
  1984. {
  1985. #if defined(HELIX_FEATURE_HYPER_NAVIGATE)
  1986.     if (m_pHyperNavigate && m_cURL.length() > 0)
  1987.     {
  1988.         m_pHyperNavigate->GoToURL(m_cURL.c_str(), (m_ucTarget == kTargetPlayer) ? "_player" : (const char*) NULL);
  1989.     }
  1990. #endif // (HELIX_FEATURE_HYPER_NAVIGATE)
  1991. }
  1992. HX_RESULT CGIFRenderer::CopyBombImage()
  1993. {
  1994.     HX_RESULT retVal = HXR_OK;
  1995. #if defined(HELIX_FEATURE_GIF_BROKENIMAGE)
  1996.     // Set the image bombed flag
  1997.     m_bImageBombed  = TRUE;
  1998.     // Copy the bomb image
  1999.     PXMakeBombImage* pMakeBomb = new PXMakeBombImage();
  2000.     if (pMakeBomb)
  2001.     {
  2002.         PXImage* pImage = NULL;
  2003.         retVal          = pMakeBomb->MakeBombImage(m_pContext,
  2004.                                                    m_ulWidth,
  2005.                                                    m_ulHeight,
  2006.                                                    m_ulBackgroundColor,
  2007.                                                    pImage);
  2008.         if (SUCCEEDED(retVal))
  2009.         {
  2010.             IHXBuffer* pImageStore = NULL;
  2011.             retVal = pImage->GetImageStore(&pImageStore);
  2012.             if (SUCCEEDED(retVal))
  2013.             {
  2014. UINT32 ulSafeSizeToCopy = pImageStore->GetSize();
  2015. UINT32 ulOutputBufSize = m_pOutputBuffer->GetSize();
  2016. if (ulSafeSizeToCopy > ulOutputBufSize)
  2017. {
  2018.     ulSafeSizeToCopy = ulOutputBufSize;
  2019. }
  2020.                 memcpy(m_pOutputBuffer->GetBuffer(), /* Flawfinder: ignore */
  2021.                        pImageStore->GetBuffer(),
  2022.                        ulSafeSizeToCopy);
  2023.             }
  2024.             HX_RELEASE(pImageStore);
  2025.         }
  2026.         HX_RELEASE(pImage);
  2027.     }
  2028.     else
  2029.     {
  2030.         retVal = HXR_OUTOFMEMORY;
  2031.     }
  2032.     HX_DELETE(pMakeBomb);
  2033. #endif /* #if defined(HELIX_FEATURE_GIF_BROKENIMAGE) */
  2034.     return retVal;
  2035. }
  2036. void CGIFRenderer::DrawBackgroundColor()
  2037. {
  2038.     if (m_pOutputBuffer)
  2039.     {
  2040.         // Combine background color and background opacity
  2041.         UINT32 ulBgAlpha    = 255 - m_ulBackgroundOpacity;
  2042.         m_ulBackgroundColor = (m_ulBackgroundColor & 0x00FFFFFF) |
  2043.                               ((ulBgAlpha << 24)   & 0xFF000000);
  2044.         // Fill the output buffer with the background color
  2045.         UINT32  ulNumPixels  = m_ulWidth * m_ulHeight;
  2046.         UINT32* pDst         = (UINT32*) m_pOutputBuffer->GetBuffer();
  2047.         while (ulNumPixels--)
  2048.         {
  2049.             *pDst++ = m_ulBackgroundColor;
  2050.         }
  2051.     }
  2052. }
  2053. UINT32 CGIFRenderer::GetCycleTime()
  2054. {
  2055.     UINT32 ulRet = 0;
  2056.     if (m_pGIFCodec)
  2057.     {
  2058.         UINT32 ulNumFrames = m_pGIFCodec->GetNumImages();
  2059.         for (UINT32 i = 0; i < ulNumFrames; i++)
  2060.         {
  2061.             CGIFImage* pFrame = m_pGIFCodec->GetImage(i);
  2062.             if (pFrame)
  2063.             {
  2064.                 // Get delay in ms
  2065.                 UINT32 ulFrameDelay = pFrame->GetDelayTime() * 10;
  2066.                 // Add this delay to the total
  2067.                 ulRet += ulFrameDelay;
  2068.             }
  2069.         }
  2070.     }
  2071.     return ulRet;
  2072. }
  2073. UINT32 CGIFRenderer::GetNextFrameTime(UINT32 ulTime)
  2074. {
  2075.     UINT32 ulRet = ulTime;
  2076.     if (m_pGIFCodec)
  2077.     {
  2078.         UINT32 ulCycleTime = GetCycleTime();
  2079.         if (ulCycleTime)
  2080.         {
  2081.             // Get the modulo time
  2082.             UINT32 ulIter      = ulTime / ulCycleTime;
  2083.             UINT32 ulIterStart = ulIter * ulCycleTime;
  2084.             UINT32 ulModTime   = ulTime - ulIterStart;
  2085.             // Now see which frame is next after this time
  2086.             UINT32 ulNumFrames     = m_pGIFCodec->GetNumImages();
  2087.             UINT32 ulCurFrameStart = 0;
  2088.             for (UINT32 i = 0; i < ulNumFrames; i++)
  2089.             {
  2090.                 CGIFImage* pFrame = m_pGIFCodec->GetImage(i);
  2091.                 if (pFrame)
  2092.                 {
  2093.                     // Get this frame's delay in ms
  2094.                     UINT32 ulFrameDelay = pFrame->GetDelayTime() * 10;
  2095.                     // Get the ending time of this frame
  2096.                     UINT32 ulCurFrameEnd = ulCurFrameStart + ulFrameDelay;
  2097.                     // Is this time in this frame's range?
  2098.                     if (ulModTime >= ulCurFrameStart &&
  2099.                         ulModTime <  ulCurFrameEnd)
  2100.                     {
  2101.                         // We found the right frame, so make 
  2102.                         // sure and add back in the time that this
  2103.                         // iteration started.
  2104.                         ulRet = ulIterStart + ulCurFrameEnd;
  2105.                         break;
  2106.                     }
  2107.                     // Add the delay of this frame to the running sum
  2108.                     ulCurFrameStart += ulFrameDelay;
  2109.                 }
  2110.             }
  2111.         }
  2112.     }
  2113.     return ulRet;
  2114. }
  2115. UINT32 CGIFRenderer::GetTimevalDiff(HXTimeval t1, HXTimeval t2)
  2116. {
  2117.     UINT32 ulRet = 0;
  2118.     // Compute the sec diff with 32-bit wrap
  2119.     HXTimeval cDiff = {0, 0};
  2120.     if (t2.tv_sec >= t1.tv_sec)
  2121.     {
  2122.         cDiff.tv_sec = t2.tv_sec - t1.tv_sec;
  2123.     }
  2124.     else
  2125.     {
  2126.         cDiff.tv_sec = 0xFFFFFFFF - t2.tv_sec + t1.tv_sec;
  2127.     }
  2128.     // Compute the usec diff
  2129.     if (t2.tv_usec >= t1.tv_usec)
  2130.     {
  2131.         cDiff.tv_usec = t2.tv_usec - t1.tv_usec;
  2132.     }
  2133.     else
  2134.     {
  2135.         // We have to borrow from the sec diff
  2136.         if (cDiff.tv_sec > 0)
  2137.         {
  2138.             cDiff.tv_usec = 1000000 + t2.tv_usec - t1.tv_usec;
  2139.             cDiff.tv_sec  -= 1;
  2140.         }
  2141.     }
  2142.     // Convert diff to milliseconds
  2143.     ulRet = (cDiff.tv_sec * 1000) + ((cDiff.tv_usec + 500) / 1000);
  2144.     return ulRet;
  2145. }
  2146. HX_RESULT STDAPICALLTYPE CGIFRenderer::HXCreateInstance(IUnknown** ppIUnknown)
  2147. {
  2148.     HX_RESULT retVal = HXR_OK;
  2149.     if (ppIUnknown)
  2150.     {
  2151.         // Set default
  2152.         *ppIUnknown = NULL;
  2153.         // Create the object
  2154.         CGIFRenderer *pObj = new CGIFRenderer();
  2155.         if (pObj)
  2156.         {
  2157.             // QI for IUnknown
  2158.             retVal = pObj->QueryInterface(IID_IUnknown, (void**) ppIUnknown);
  2159.         }
  2160.         else
  2161.         {
  2162.             retVal = HXR_OUTOFMEMORY;
  2163.         }
  2164.         if (FAILED(retVal))
  2165.         {
  2166.             HX_DELETE(pObj);
  2167.         }
  2168.     }
  2169.     else
  2170.     {
  2171.         retVal = HXR_FAIL;
  2172.     }
  2173.     return HXR_OK;
  2174. }
  2175. void CGIFRenderer::DamageFrameRect(UINT32 i)
  2176. {
  2177.     if (m_pGIFCodec &&
  2178.         m_pMISUSSite &&
  2179.         i < m_pGIFCodec->GetNumImages())
  2180.     {
  2181.         CGIFImage* pImg = m_pGIFCodec->GetImage(i);
  2182.         if (pImg)
  2183.         {
  2184.             // Get the rect for the frame
  2185.             HXxRect cRect;
  2186.             cRect.left   = (INT32) pImg->GetImageLeft();
  2187.             cRect.top    = (INT32) pImg->GetImageTop();
  2188.             cRect.right  = cRect.left + (INT32) pImg->GetImageWidth();
  2189.             cRect.bottom = cRect.top  + (INT32) pImg->GetImageHeight();
  2190.             // Get the size of the logical screen
  2191.             HXxSize cLSSize = {0, 0};
  2192.             cLSSize.cx = (INT32) m_pGIFCodec->GetLogicalScreenWidth();
  2193.             cLSSize.cy = (INT32) m_pGIFCodec->GetLogicalScreenHeight();
  2194.             // Get the current size of the site
  2195.             HXxSize cSiteSize = {0, 0};
  2196.             m_pMISUSSite->GetSize(cSiteSize);
  2197.             // If the current size of the site is not the
  2198.             // same as the logical screen, then we need to scale the
  2199.             // damage rect
  2200.             if (cSiteSize.cx != cLSSize.cx ||
  2201.                 cSiteSize.cy != cLSSize.cy)
  2202.             {
  2203.                 // Scale the damage rect
  2204.                 cRect.left   = cRect.left   * cSiteSize.cx / cLSSize.cx;
  2205.                 cRect.top    = cRect.top    * cSiteSize.cy / cLSSize.cy;
  2206.                 cRect.right  = cRect.right  * cSiteSize.cx / cLSSize.cx;
  2207.                 cRect.bottom = cRect.bottom * cSiteSize.cy / cLSSize.cy;
  2208.             }
  2209.             // Damage this rect
  2210.             MLOG_MISC(m_pErrorMessages,
  2211.                       "tDamaging Frame %lu: (%ld,%ld,%ld,%ld) (%ld x %ld)n",
  2212.                       i, cRect.left, cRect.top, cRect.right, cRect.bottom,
  2213.                       HXxRECT_WIDTH(cRect), HXxRECT_HEIGHT(cRect));
  2214.             m_pMISUSSite->DamageRect(cRect);
  2215.         }
  2216.     }
  2217. }