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

Symbian

开发平台:

Visual C++

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