diff options
| author | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
|---|---|---|
| committer | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
| commit | 39ed87570bdb2f86969d4be821c94b722dc71179 (patch) | |
| tree | abc53757f75f40c80278e87650ea92808274aa59 /mp/src/vgui2/chromehtml | |
| download | source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip | |
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/vgui2/chromehtml')
| -rw-r--r-- | mp/src/vgui2/chromehtml/chromewrapper.cpp | 441 | ||||
| -rw-r--r-- | mp/src/vgui2/chromehtml/html_chrome.cpp | 3508 | ||||
| -rw-r--r-- | mp/src/vgui2/chromehtml/html_chrome.h | 637 | ||||
| -rw-r--r-- | mp/src/vgui2/chromehtml/html_mac.mm | 16 | ||||
| -rw-r--r-- | mp/src/vgui2/chromehtml/htmlmanager.h | 30 | ||||
| -rw-r--r-- | mp/src/vgui2/chromehtml/htmlmessages.proto | 1025 | ||||
| -rw-r--r-- | mp/src/vgui2/chromehtml/stdafx.h | 19 |
7 files changed, 5676 insertions, 0 deletions
diff --git a/mp/src/vgui2/chromehtml/chromewrapper.cpp b/mp/src/vgui2/chromehtml/chromewrapper.cpp new file mode 100644 index 00000000..179974f0 --- /dev/null +++ b/mp/src/vgui2/chromehtml/chromewrapper.cpp @@ -0,0 +1,441 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Creates a HTML control
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "winlite.h"
+#include "html_chrome.h"
+#include "tier1/interface.h"
+#include "reliabletimer.h"
+#include "htmlmanager.h"
+
+#include "html/htmlprotobuf.h"
+#include <html/ichromehtmlwrapper.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: owner object that gets responses from the CEF thread and dispatches them
+//-----------------------------------------------------------------------------
+class CHTMLController : public IHTMLChromeController
+{
+public:
+ CHTMLController() { m_BrowserSerial = 0; m_nCefTargetFrameRate = 0; SetDefLessFunc( m_mapBrowserRequests ); SetDefLessFunc( m_mapBrowsers ); }
+ ~CHTMLController() {}
+
+ bool Init( const char *pchHTMLCacheDir, const char *pchCookiePath );
+ void Shutdown();
+
+ void SetWebCookie( const char *pchHostname, const char *pchKey, const char *pchValue, const char *pchPath, RTime32 nExpires );
+ void GetWebCookiesForURL( CUtlString *pstrValue, const char *pchURL, const char *pchName );
+ void SetClientBuildID( uint64 ulBuildID );
+
+ bool BHasPendingMessages();
+
+ void CreateBrowser( IHTMLResponses *pBrowser, bool bPopupWindow, const char *pchUserAgentIdentifier );
+ void RemoveBrowser( IHTMLResponses *pBrowser );
+ bool RunFrame();
+
+ void WakeThread() { AccessHTMLWrapper().WakeThread(); }
+ HTMLCommandBuffer_t *GetFreeCommandBuffer( EHTMLCommands eCmd, int iBrowser ) { return AccessHTMLWrapper().GetFreeCommandBuffer( eCmd, iBrowser ); }
+ void PushCommand( HTMLCommandBuffer_t *pCmd ) { AccessHTMLWrapper().PushCommand( pCmd ); }
+
+
+ bool GetMainThreadCommand( HTMLCommandBuffer_t **pCmd ) { return AccessHTMLWrapper().GetMainThreadCommand( pCmd ); }
+ void ReleaseCommandBuffer( HTMLCommandBuffer_t *pCmd ) { AccessHTMLWrapper().ReleaseCommandBuffer( pCmd ); }
+
+#ifdef DBGFLAG_VALIDATE
+ void Validate( CValidator &validator, const char *pchName );
+ bool ChromePrepareForValidate();
+ bool ChromeResumeFromValidate();
+#endif
+
+ void SetCefThreadTargetFrameRate( uint32 nFPS );
+
+private:
+ // keeps track of outstanding browser create requests
+ CUtlMap< uint32, IHTMLResponses *, int > m_mapBrowserRequests;
+ // the next unique identifier to use when doing a browser create
+ uint32 m_BrowserSerial;
+ // the map of browser handles to our html panel objects, used for cef thread command dispatching
+ CUtlMap< uint32, IHTMLResponses *, int > m_mapBrowsers;
+
+ int m_nCefTargetFrameRate;
+};
+
+
+static CHTMLController s_HTMLController;
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CHTMLController, IHTMLChromeController, CHROMEHTML_CONTROLLER_INTERFACE_VERSION, s_HTMLController );
+
+
+//-----------------------------------------------------------------------------
+// Purpose: request the cef thread to make a new browser
+//-----------------------------------------------------------------------------
+void CHTMLController::CreateBrowser( IHTMLResponses *pBrowser, bool bPopupWindow, const char *pchUserAgentIdentifier )
+{
+ m_BrowserSerial++;
+ m_mapBrowserRequests.Insert( m_BrowserSerial, pBrowser );
+
+ CHTMLProtoBufMsg<CMsgBrowserCreate> cmd( eHTMLCommands_BrowserCreate );
+ cmd.Body().set_request_id( m_BrowserSerial );
+ cmd.Body().set_popup( bPopupWindow );
+ cmd.Body().set_useragent( pchUserAgentIdentifier );
+ HTMLCommandBuffer_t *pBuf = AccessHTMLWrapper().GetFreeCommandBuffer( eHTMLCommands_BrowserCreate, -1 );
+ cmd.SerializeCrossProc( &pBuf->m_Buffer );
+ AccessHTMLWrapper().PushCommand( pBuf );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: delete a browser we have
+//-----------------------------------------------------------------------------
+void CHTMLController::RemoveBrowser( IHTMLResponses *pBrowser )
+{
+
+ // pull ourselves from the browser handle list as we are doing away
+ FOR_EACH_MAP_FAST( m_mapBrowsers, i)
+ {
+ if ( m_mapBrowsers[i] == pBrowser )
+ {
+ // tell the cef thread this browser is going away
+ CHTMLProtoBufMsg<CMsgBrowserRemove> cmd( eHTMLCommands_BrowserRemove );
+ cmd.Body().set_browser_handle( pBrowser->BrowserGetIndex() );
+ HTMLCommandBuffer_t *pBuf = AccessHTMLWrapper().GetFreeCommandBuffer( eHTMLCommands_BrowserRemove, pBrowser->BrowserGetIndex() );
+ cmd.SerializeCrossProc( &pBuf->m_Buffer );
+ AccessHTMLWrapper().PushCommand( pBuf );
+
+ // now kill it
+ m_mapBrowsers.RemoveAt( i );
+ }
+ }
+
+ // also remove us from pending list if in it
+ FOR_EACH_MAP_FAST( m_mapBrowserRequests, i)
+ {
+ if ( m_mapBrowserRequests[i] == pBrowser )
+ m_mapBrowserRequests.RemoveAt( i );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: turn on the cef engine
+//-----------------------------------------------------------------------------
+bool CHTMLController::Init( const char *pchHTMLCacheDir, const char *pchCookiePath )
+{
+#if !defined(WIN64) && !defined(STATIC_TIER0)
+ ChromeInit( pchHTMLCacheDir, pchCookiePath );
+#endif
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: shutdown chrome
+//-----------------------------------------------------------------------------
+void CHTMLController::Shutdown()
+{
+#if !defined(WIN64) && !defined(STATIC_TIER0)
+ ChromeShutdown();
+#endif
+}
+
+
+
+// helper macro to dispatch messages from the cef thread
+#define HTML_MSG_FUNC( eHTMLCommand, bodyType, commandFunc ) \
+ case eHTMLCommand: \
+{ \
+ CHTMLProtoBufMsg< bodyType > cmd( pCmd->m_eCmd ); \
+ if ( !cmd.BDeserializeCrossProc( &pCmd->m_Buffer ) ) \
+{ \
+ bError = true; \
+} \
+ else \
+{ \
+ int idx = m_mapBrowsers.Find( cmd.BodyConst().browser_handle() ); \
+ if ( idx != m_mapBrowsers.InvalidIndex() ) \
+{ \
+ if ( m_mapBrowsers[idx] ) \
+ m_mapBrowsers[idx]->commandFunc( &cmd.BodyConst() ); \
+} \
+} \
+} \
+ break; \
+
+
+//-----------------------------------------------------------------------------
+// Purpose: process any ipc responses we have pending
+//-----------------------------------------------------------------------------
+bool CHTMLController::RunFrame()
+{
+ VPROF_BUDGET( "CHTMLController::RunFrame", VPROF_BUDGETGROUP_TENFOOT );
+ HTMLCommandBuffer_t *pCmd;
+ bool bError = false;
+ bool bDidwork = false;
+
+ // Paint messages are dispatched last to avoid doing excessive work on
+ // the main thread when two paint messages have stacked up in the queue.
+ // This could be greatly optimized by doing atomic buffer swaps instead
+ // of pushing the paint updates through a queue, but this helps for now.
+ // -henryg
+ CUtlVector< HTMLCommandBuffer_t * > vecDeferredPaint;
+
+ while( GetMainThreadCommand( &pCmd ) )
+ {
+ bool bRelease = true;
+ bDidwork = true;
+ //Msg( "Got response %d\n", pCmd->m_eCmd );
+ switch( pCmd->m_eCmd )
+ {
+ default:
+ break;
+ case eHTMLCommands_BrowserCreateResponse:
+ {
+ CHTMLProtoBufMsg< CMsgBrowserCreateResponse > cmd( pCmd->m_eCmd );
+ if ( !cmd.BDeserializeCrossProc( &pCmd->m_Buffer ) )
+ {
+ bError = true;
+ }
+ else
+ {
+ int idx = m_mapBrowserRequests.Find( cmd.BodyConst().request_id() );
+ if ( idx != m_mapBrowserRequests.InvalidIndex() )
+ {
+ m_mapBrowsers.Insert( cmd.BodyConst().browser_handle(), m_mapBrowserRequests[idx] );
+ m_mapBrowserRequests[idx]->BrowserSetIndex( cmd.BodyConst().browser_handle() );
+ m_mapBrowserRequests.RemoveAt( idx );
+ }
+ }
+ }
+ break;
+ case eHTMLCommands_NeedsPaint:
+ {
+ bRelease = false;
+ vecDeferredPaint.AddToTail( pCmd );
+ }
+ break;
+
+ HTML_MSG_FUNC( eHTMLCommands_BrowserReady, CMsgBrowserReady, BrowserReady );
+ HTML_MSG_FUNC( eHTMLCommands_StartRequest, CMsgStartRequest, BrowserStartRequest );
+ HTML_MSG_FUNC( eHTMLCommands_URLChanged, CMsgURLChanged, BrowserURLChanged );
+ HTML_MSG_FUNC( eHTMLCommands_FinishedRequest, CMsgFinishedRequest, BrowserFinishedRequest );
+ HTML_MSG_FUNC( eHTMLCommands_ShowPopup, CMsgShowPopup, BrowserShowPopup );
+ HTML_MSG_FUNC( eHTMLCommands_HidePopup, CMsgHidePopup, BrowserHidePopup );
+ HTML_MSG_FUNC( eHTMLCommands_OpenNewTab, CMsgOpenNewTab, BrowserOpenNewTab );
+ HTML_MSG_FUNC( eHTMLCommands_PopupHTMLWindow, CMsgPopupHTMLWindow, BrowserPopupHTMLWindow );
+ HTML_MSG_FUNC( eHTMLCommands_SetHTMLTitle, CMsgSetHTMLTitle, BrowserSetHTMLTitle );
+ HTML_MSG_FUNC( eHTMLCommands_LoadingResource, CMsgLoadingResource, BrowserLoadingResource );
+ HTML_MSG_FUNC( eHTMLCommands_StatusText, CMsgStatusText, BrowserStatusText );
+ HTML_MSG_FUNC( eHTMLCommands_SetCursor, CMsgSetCursor, BrowserSetCursor );
+ HTML_MSG_FUNC( eHTMLCommands_FileLoadDialog, CMsgFileLoadDialog, BrowserFileLoadDialog );
+ HTML_MSG_FUNC( eHTMLCommands_ShowToolTip, CMsgShowToolTip, BrowserShowToolTip );
+ HTML_MSG_FUNC( eHTMLCommands_UpdateToolTip, CMsgUpdateToolTip, BrowserUpdateToolTip );
+ HTML_MSG_FUNC( eHTMLCommands_HideToolTip, CMsgHideToolTip, BrowserHideToolTip );
+ HTML_MSG_FUNC( eHTMLCommands_SearchResults, CMsgSearchResults, BrowserSearchResults );
+ HTML_MSG_FUNC( eHTMLCommands_Close, CMsgClose, BrowserClose );
+ HTML_MSG_FUNC( eHTMLCommands_GetZoomResponse, CMsgGetZoomResponse, BrowserGetZoomResponse );
+ HTML_MSG_FUNC( eHTMLCommands_HorizontalScrollBarSizeResponse, CMsgHorizontalScrollBarSizeResponse, BrowserHorizontalScrollBarSizeResponse );
+ HTML_MSG_FUNC( eHTMLCommands_VerticalScrollBarSizeResponse, CMsgVerticalScrollBarSizeResponse, BrowserVerticalScrollBarSizeResponse );
+ HTML_MSG_FUNC( eHTMLCommands_LinkAtPositionResponse, CMsgLinkAtPositionResponse, BrowserLinkAtPositionResponse );
+ HTML_MSG_FUNC( eHTMLCommands_ZoomToElementAtPositionResponse, CMsgZoomToElementAtPositionResponse, BrowserZoomToElementAtPositionResponse );
+ HTML_MSG_FUNC( eHTMLCommands_JSAlert, CMsgJSAlert, BrowserJSAlert );
+ HTML_MSG_FUNC( eHTMLCommands_JSConfirm, CMsgJSConfirm, BrowserJSConfirm );
+ HTML_MSG_FUNC( eHTMLCommands_OpenSteamURL, CMsgOpenSteamURL, BrowserOpenSteamURL );
+ HTML_MSG_FUNC( eHTMLCommands_CanGoBackandForward, CMsgCanGoBackAndForward, BrowserCanGoBackandForward );
+ HTML_MSG_FUNC( eHTMLCommands_SizePopup, CMsgSizePopup, BrowserSizePopup );
+ HTML_MSG_FUNC( eHTMLCommands_ScaleToValueResponse, CMsgScalePageToValueResponse, BrowserScalePageToValueResponse );
+ HTML_MSG_FUNC( eHTMLCommands_RequestFullScreen, CMsgRequestFullScreen, BrowserRequestFullScreen );
+ HTML_MSG_FUNC( eHTMLCommands_ExitFullScreen, CMsgExitFullScreen, BrowserExitFullScreen );
+ HTML_MSG_FUNC( eHTMLCommands_GetCookiesForURLResponse, CMsgGetCookiesForURLResponse, BrowserGetCookiesForURLResponse );
+ HTML_MSG_FUNC( eHTMLCommands_NodeGotFocus, CMsgNodeHasFocus, BrowserNodeGotFocus );
+ HTML_MSG_FUNC( eHTMLCommands_SavePageToJPEGResponse, CMsgSavePageToJPEGResponse, BrowserSavePageToJPEGResponse );
+ HTML_MSG_FUNC( eHTMLCommands_GetFocusedNodeValueResponse, CMsgFocusedNodeTextResponse, BrowserFocusedNodeValueResponse );
+ }
+ if ( bError )
+ {
+ Warning( "Failed to parse command %d", pCmd->m_eCmd );
+ Assert( !"Bad Command" );
+ }
+ if ( bRelease )
+ {
+ ReleaseCommandBuffer( pCmd );
+ }
+ }
+
+ // Collapse deferred paints by browser ID and process them; the latest texture always
+ // has fully updated bits, we simply union its dirty rect with the skipped updates.
+ // Note: browser resizes always include a full dirty rect, we don't have to check here.
+ while ( vecDeferredPaint.Count() )
+ {
+ // Pull the last paint off the queue
+ pCmd = vecDeferredPaint[ vecDeferredPaint.Count() - 1 ];
+ int iBrowser = pCmd->m_iBrowser;
+ CHTMLProtoBufMsg<CMsgNeedsPaint> cmd( eHTMLCommands_NeedsPaint );
+ DbgVerify( cmd.BDeserializeCrossProc( &pCmd->m_Buffer ) );
+ ReleaseCommandBuffer( pCmd );
+ vecDeferredPaint.Remove( vecDeferredPaint.Count() - 1 );
+
+
+ CMsgNeedsPaint &body = cmd.Body();
+ CChromeUpdateRegion region;
+ if ( body.updatewide() && body.updatetall() )
+ {
+ region.MarkDirtyRect( body.updatex(), body.updatey(), body.updatex() + body.updatewide(), body.updatey() + body.updatetall() );
+ }
+ else
+ {
+ region.MarkAllDirty();
+ }
+
+ // Remove earlier paints for the same browser from the queue
+ for ( int i = vecDeferredPaint.Count() - 1; i >= 0; --i )
+ {
+ if ( vecDeferredPaint[i]->m_iBrowser == iBrowser )
+ {
+ // Decode
+ CHTMLProtoBufMsg<CMsgNeedsPaint> cmdMerge( eHTMLCommands_NeedsPaint );
+ DbgVerify( cmdMerge.BDeserializeCrossProc( &vecDeferredPaint[i]->m_Buffer ) );
+ CMsgNeedsPaint &bodyMerge = cmdMerge.Body();
+
+ if ( body.browser_handle() == bodyMerge.browser_handle() )
+ {
+ ReleaseCommandBuffer( vecDeferredPaint[i] );
+ vecDeferredPaint.Remove( i );
+
+ // Merge update region
+ if ( bodyMerge.updatewide() && bodyMerge.updatetall() )
+ {
+ region.MarkDirtyRect( bodyMerge.updatex(), bodyMerge.updatey(), bodyMerge.updatex() + bodyMerge.updatewide(), bodyMerge.updatey() + bodyMerge.updatetall() );
+ }
+ else
+ {
+ region.MarkAllDirty();
+ }
+
+ // Send response to the skipped paint update to free up the texture slot
+ pCmd = GetFreeCommandBuffer( eHTMLCommands_NeedsPaintResponse, bodyMerge.browser_handle() );
+ CHTMLProtoBufMsg<CMsgNeedsPaintResponse> cmdResponse( eHTMLCommands_NeedsPaintResponse );
+ cmdResponse.Body().set_browser_handle( bodyMerge.browser_handle() );
+ cmdResponse.Body().set_textureid( bodyMerge.textureid() );
+ cmdResponse.SerializeCrossProc( &pCmd->m_Buffer );
+ PushCommand( pCmd );
+ }
+ }
+ }
+
+ // Dispatch the merged update
+ int idxBrowser = m_mapBrowsers.Find( body.browser_handle() );
+ if ( idxBrowser != m_mapBrowsers.InvalidIndex() )
+ {
+ if ( m_mapBrowsers[idxBrowser] )
+ {
+ int updateWide = region.GetUpdateWide( body.wide() );
+ int updateTall = region.GetUpdateTall( body.tall() );
+ if ( updateWide != body.wide() || updateTall != body.tall() )
+ {
+ body.set_updatex( region.GetUpdateX( body.wide() ) );
+ body.set_updatey( region.GetUpdateY( body.tall() ) );
+ body.set_updatewide( updateWide );
+ body.set_updatetall( updateTall );
+ }
+ else
+ {
+ body.clear_updatex();
+ body.clear_updatey();
+ body.clear_updatewide();
+ body.clear_updatetall();
+ }
+ m_mapBrowsers[idxBrowser]->BrowserNeedsPaint( &body );
+ }
+ }
+ }
+
+ return bDidwork;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: set a cef cookie
+//-----------------------------------------------------------------------------
+void CHTMLController::SetWebCookie( const char *pchHostname, const char *pchKey, const char *pchValue, const char *pchPath, RTime32 nExpires )
+{
+#if !defined(WIN64) && !defined(STATIC_TIER0)
+ ChromeSetWebCookie( pchHostname, pchKey, pchValue, pchPath, nExpires );
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: set the buildid to report
+//-----------------------------------------------------------------------------
+void CHTMLController::SetClientBuildID( uint64 ulBuildID )
+{
+#if !defined(WIN64) && !defined(STATIC_TIER0)
+ ChromeSetClientBuildID( ulBuildID );
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: get the cef cookies for a url
+//-----------------------------------------------------------------------------
+void CHTMLController::GetWebCookiesForURL( CUtlString *pstrValue, const char *pchURL, const char *pchName )
+{
+#if !defined(WIN64) && !defined(STATIC_TIER0)
+ ChromeGetWebCookiesForURL( pstrValue, pchURL, pchName );
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: true if any pending html message in the queue
+//-----------------------------------------------------------------------------
+bool CHTMLController::BHasPendingMessages()
+{
+ return AccessHTMLWrapper().BHasPendingMessages();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: tell the cef thread the frame rate to use if it changes
+//-----------------------------------------------------------------------------
+void CHTMLController::SetCefThreadTargetFrameRate( uint32 nFPS )
+{
+ if ( nFPS != m_nCefTargetFrameRate )
+ {
+ m_nCefTargetFrameRate = nFPS;
+ CHTMLProtoBufMsg<CMsgSetTargetFrameRate> cmd( eHTMLCommands_SetTargetFrameRate );
+ cmd.Body().set_ntargetframerate( nFPS );
+ HTMLCommandBuffer_t *pBuf = AccessHTMLWrapper().GetFreeCommandBuffer( eHTMLCommands_SetTargetFrameRate, -1 );
+ cmd.SerializeCrossProc( &pBuf->m_Buffer );
+ AccessHTMLWrapper().PushCommand( pBuf );
+ }
+}
+
+#ifdef DBGFLAG_VALIDATE
+//-----------------------------------------------------------------------------
+// Purpose: validate mem
+//-----------------------------------------------------------------------------
+void CHTMLController::Validate( CValidator &validator, const char *pchName )
+{
+ ChromeValidate( validator, "ChromeValidate" );
+
+ validator.Push( "CHTMLController::ValidateStatics", NULL, pchName );
+ ValidateObj( m_mapBrowserRequests );
+ ValidateObj( m_mapBrowsers );
+ validator.Pop();
+}
+
+bool CHTMLController::ChromeResumeFromValidate()
+{
+ return ::ChromeResumeFromValidate();
+}
+
+bool CHTMLController::ChromePrepareForValidate()
+{
+ return ::ChromePrepareForValidate();
+}
+#endif // DBGFLAG_VALIDATE
+
+
+
diff --git a/mp/src/vgui2/chromehtml/html_chrome.cpp b/mp/src/vgui2/chromehtml/html_chrome.cpp new file mode 100644 index 00000000..0af67f82 --- /dev/null +++ b/mp/src/vgui2/chromehtml/html_chrome.cpp @@ -0,0 +1,3508 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//=============================================================================//
+
+#include "winlite.h"
+#include "html_chrome.h"
+#include "cef/include/cef_cookie.h"
+#include "imageloadwrapper.h"
+#include "html/ichromehtmlwrapper.h"
+#include "input/mousecursors.h"
+//#include "rtime.h"
+#ifdef OSX
+extern "C" void *CreateAutoReleasePool();
+extern "C" void ReleaseAutoReleasePool( void *pool );
+#endif
+#ifdef WIN32
+#include <TlHelp32.h>
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+static uint64 sm_ulBuildID = 0; // will be appended to the user agent
+static CCEFThread g_CEFThread; // main thread for CEF to do its thinking
+
+// access for main thread to get to the html object
+CCEFThread &AccessHTMLWrapper()
+{
+ return g_CEFThread;
+}
+
+// helper macro to send a command to the CEF thread
+#define DISPATCH_MESSAGE( eCmd ) \
+ cmd.Body().set_browser_handle( m_iBrowser ); \
+ HTMLCommandBuffer_t *pBuf = g_CEFThread.GetFreeCommandBuffer( eCmd, m_iBrowser ); \
+ cmd.SerializeCrossProc( &pBuf->m_Buffer ); \
+ g_CEFThread.PushResponse( pBuf ); \
+
+// wrappers for our handle to list index/serial, lower 16 bits are list index, top 16 bits are the serial number
+#define BROWSER_HANDLE_FROM_INDEX_SERIAL( iList, nSerial ) iList + ((int)nSerial<<16)
+#define BROWSER_SERIAL_FROM_HANDLE( nHandle ) (uint32)nHandle>>16
+
+const int k_ScreenshotQuality = 95; // quality value used when making a jpeg image of a web page
+const float k_flMaxScreenshotWaitTime = 5.0; // wait up to 5 sec before taking a screenshot
+
+//-----------------------------------------------------------------------------
+// Purpose: thread to manage pumping the CEF message loop
+//-----------------------------------------------------------------------------
+CCEFThread::CCEFThread()
+{
+ m_bExit = false;
+ m_nTargetFrameRate = 60; // 60 Hz by default
+ m_nBrowserSerial = 0;
+ m_bFullScreenFlashVisible = false;
+ m_bSawUserInputThisFrame = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: destructor
+//-----------------------------------------------------------------------------
+CCEFThread::~CCEFThread()
+{
+ // This can get called by the main thread before the actual thread exits,
+ // if there is a forced process exit due to some error. In this case,
+ // force the thread to exit before destroying the member variables it
+ // is depending on.
+ if ( !m_bExit )
+ {
+ TriggerShutdown();
+ Join( 20 * k_nThousand );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: tell cef where to place its state dirs
+//-----------------------------------------------------------------------------
+void CCEFThread::SetCEFPaths( const char *pchHTMLCacheDir, const char *pchCookiePath )
+{
+ Assert( !IsAlive() );
+ m_sHTMLCacheDir = pchHTMLCacheDir;
+ m_sCookiePath = pchCookiePath;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: set the exit event on the cef thread
+//-----------------------------------------------------------------------------
+void CCEFThread::TriggerShutdown()
+{
+ m_bExit = true;
+ m_WakeEvent.Set();
+ m_evWaitingForCommand.Set();
+ m_eventDidExit.Wait( k_nThousand ); // wait 1 second at most for it to go away
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: tickle the run loop of the thread to run more commands
+//-----------------------------------------------------------------------------
+void CCEFThread::WakeThread()
+{
+ m_WakeEvent.Set();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: helper macro for message dispatch
+//-----------------------------------------------------------------------------
+#define HTML_MSG_FUNC( eHTMLCommand, bodyType, commandFunc ) \
+ case eHTMLCommand: \
+ { \
+ CHTMLProtoBufMsg< bodyType > cmd( pCmd->m_eCmd ); \
+ if ( !cmd.BDeserializeCrossProc( &pCmd->m_Buffer ) ) \
+ { \
+ bError = true; \
+ } \
+ else \
+ { \
+ cmd.Body().set_browser_handle( pCmd->m_iBrowser ); \
+ g_CEFThread.commandFunc( cmd ); \
+ } \
+ } \
+ break;
+
+
+#define HTML_MSG_FUNC_NOHANDLE( eHTMLCommand, bodyType, commandFunc ) \
+ case eHTMLCommand: \
+ { \
+ CHTMLProtoBufMsg< bodyType > cmd( pCmd->m_eCmd ); \
+ if ( !cmd.BDeserializeCrossProc( &pCmd->m_Buffer ) ) \
+ { \
+ bError = true; \
+ } \
+ else \
+ { \
+ g_CEFThread.commandFunc( cmd ); \
+ } \
+ } \
+ break;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: clear any pending commands from the main thread
+//-----------------------------------------------------------------------------
+void CCEFThread::RunCurrentCommands()
+{
+ bool bError = false;
+ HTMLCommandBuffer_t *pCmd =NULL;
+
+ while( GetCEFThreadCommand( &pCmd ) )
+ {
+ //Msg( "Got command %d\n", pCmd->m_eCmd );
+ switch( pCmd->m_eCmd )
+ {
+ HTML_MSG_FUNC_NOHANDLE( eHTMLCommands_BrowserCreate, CMsgBrowserCreate, ThreadCreateBrowser );
+ HTML_MSG_FUNC( eHTMLCommands_BrowserRemove, CMsgBrowserRemove, ThreadRemoveBrowser );
+ HTML_MSG_FUNC( eHTMLCommands_BrowserSize, CMsgBrowserSize, ThreadBrowserSize );
+ HTML_MSG_FUNC( eHTMLCommands_BrowserPosition, CMsgBrowserPosition, ThreadBrowserPosition );
+ HTML_MSG_FUNC( eHTMLCommands_PostURL, CMsgPostURL, ThreadBrowserPostURL );
+ HTML_MSG_FUNC( eHTMLCommands_StopLoad, CMsgStopLoad, ThreadBrowserStopLoad );
+ HTML_MSG_FUNC( eHTMLCommands_Reload, CMsgReload, ThreadBrowserReload );
+ HTML_MSG_FUNC( eHTMLCommands_GoForward, CMsgGoForward, ThreadBrowserGoForward );
+ HTML_MSG_FUNC( eHTMLCommands_GoBack, CMsgGoBack, ThreadBrowserGoBack );
+ HTML_MSG_FUNC( eHTMLCommands_Copy, CMsgCopy, ThreadBrowserCopy );
+ HTML_MSG_FUNC( eHTMLCommands_Paste, CMsgPaste, ThreadBrowserPaste );
+ HTML_MSG_FUNC( eHTMLCommands_ExecuteJavaScript, CMsgExecuteJavaScript, ThreadBrowserExecuteJavascript );
+ HTML_MSG_FUNC( eHTMLCommands_SetFocus, CMsgSetFocus, ThreadBrowserSetFocus );
+ HTML_MSG_FUNC( eHTMLCommands_HorizontalScrollBarSize, CMsgHorizontalScrollBarSize, ThreadBrowserHorizontalScrollBarSize );
+ HTML_MSG_FUNC( eHTMLCommands_VerticalScrollBarSize, CMsgVerticalScrollBarSize, ThreadBrowserVerticalScrollBarSize );
+ HTML_MSG_FUNC( eHTMLCommands_Find, CMsgFind, ThreadBrowserFind );
+ HTML_MSG_FUNC( eHTMLCommands_StopFind, CMsgStopFind, ThreadBrowserStopFind );
+ HTML_MSG_FUNC( eHTMLCommands_SetHorizontalScroll, CMsgSetHorizontalScroll, ThreadBrowserSetHorizontalScroll );
+ HTML_MSG_FUNC( eHTMLCommands_SetVerticalScroll, CMsgSetVerticalScroll, ThreadBrowserSetVerticalScroll );
+ HTML_MSG_FUNC( eHTMLCommands_SetZoomLevel, CMsgSetZoomLevel, ThreadBrowserSetZoomLevel );
+ HTML_MSG_FUNC( eHTMLCommands_ViewSource, CMsgViewSource, ThreadBrowserViewSource );
+ HTML_MSG_FUNC( eHTMLCommands_NeedsPaintResponse, CMsgNeedsPaintResponse, ThreadNeedsPaintResponse );
+ HTML_MSG_FUNC( eHTMLCommands_BrowserErrorStrings, CMsgBrowserErrorStrings, ThreadBrowserErrorStrings );
+ HTML_MSG_FUNC( eHTMLCommands_AddHeader, CMsgAddHeader, ThreadAddHeader );
+ HTML_MSG_FUNC( eHTMLCommands_GetZoom, CMsgGetZoom, ThreadGetZoom );
+ HTML_MSG_FUNC_NOHANDLE( eHTMLCommands_SetCookie, CMsgSetCookie, ThreadSetCookie );
+ HTML_MSG_FUNC_NOHANDLE( eHTMLCommands_SetTargetFrameRate, CMsgSetTargetFrameRate, ThreadSetTargetFrameRate );
+ HTML_MSG_FUNC( eHTMLCommands_HidePopup, CMsgHidePopup, ThreadHidePopup );
+ HTML_MSG_FUNC( eHTMLCommands_FullRepaint, CMsgFullRepaint, ThreadFullRepaint );
+ HTML_MSG_FUNC( eHTMLCommands_GetCookiesForURL, CMsgGetCookiesForURL, ThreadGetCookiesForURL );
+ HTML_MSG_FUNC( eHTMLCommands_ZoomToCurrentlyFocusedNode, CMsgZoomToFocusedElement, ThreadZoomToFocusedElement );
+ HTML_MSG_FUNC( eHTMLCommands_GetFocusedNodeValue, CMsgFocusedNodeText, ThreadGetFocusedNodeText );
+
+ HTML_MSG_FUNC( eHTMLCommands_MouseDown, CMsgMouseDown, ThreadMouseButtonDown );
+ HTML_MSG_FUNC( eHTMLCommands_MouseUp, CMsgMouseUp, ThreadMouseButtonUp );
+ HTML_MSG_FUNC( eHTMLCommands_MouseDblClick, CMsgMouseDblClick, ThreadMouseButtonDlbClick );
+ HTML_MSG_FUNC( eHTMLCommands_MouseWheel, CMsgMouseWheel, ThreadMouseWheel );
+ HTML_MSG_FUNC( eHTMLCommands_KeyDown, CMsgKeyDown, ThreadKeyDown );
+ HTML_MSG_FUNC( eHTMLCommands_KeyUp, CMsgKeyUp, ThreadKeyUp );
+ HTML_MSG_FUNC( eHTMLCommands_KeyChar, CMsgKeyChar, ThreadKeyTyped );
+ HTML_MSG_FUNC( eHTMLCommands_MouseMove, CMsgMouseMove, ThreadMouseMove );
+ HTML_MSG_FUNC( eHTMLCommands_MouseLeave, CMsgMouseLeave, ThreadMouseLeave );
+ HTML_MSG_FUNC( eHTMLCommands_LinkAtPosition, CMsgLinkAtPosition, ThreadLinkAtPosition );
+ HTML_MSG_FUNC( eHTMLCommands_ZoomToElementAtPosition, CMsgZoomToElementAtPosition, ThreadZoomToElementAtPosition );
+ HTML_MSG_FUNC( eHTMLCommands_SavePageToJPEG, CMsgSavePageToJPEG, ThreadSavePageToJPEG );
+ HTML_MSG_FUNC( eHTMLCommands_SetPageScale, CMsgScalePageToValue, ThreadSetPageScale );
+ HTML_MSG_FUNC( eHTMLCommands_ExitFullScreen, CMsgExitFullScreen, ThreadExitFullScreen );
+ HTML_MSG_FUNC( eHTMLCommands_CloseFullScreenFlashIfOpen, CMsgCloseFullScreenFlashIfOpen, ThreadCloseFullScreenFlashIfOpen );
+ HTML_MSG_FUNC( eHTMLCommands_PauseFullScreenFlashMovieIfOpen, CMsgPauseFullScreenFlashMovieIfOpen, ThreadPauseFullScreenFlashMovieIfOpen );
+
+ default:
+ bError = true;
+ AssertMsg1( false, "Invalid message in browser stream (%d)", pCmd->m_eCmd );
+ break;
+ }
+
+ if ( pCmd->m_eCmd == eHTMLCommands_MouseDown || pCmd->m_eCmd == eHTMLCommands_MouseDblClick || pCmd->m_eCmd == eHTMLCommands_KeyDown )
+ m_bSawUserInputThisFrame = true;
+
+ ReleaseCommandBuffer( pCmd );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: done with this buffer, put it in the free queue
+//-----------------------------------------------------------------------------
+void CCEFThread::ReleaseCommandBuffer( HTMLCommandBuffer_t *pBuf )
+{
+ pBuf->m_eCmd = eHTMLCommands_None;
+ pBuf->m_iBrowser = -1;
+ pBuf->m_Buffer.Clear();
+ m_tslUnsedBuffers.PushItem( pBuf );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: get the next free cef thread command buffer to write into
+//-----------------------------------------------------------------------------
+HTMLCommandBuffer_t *CCEFThread::GetFreeCommandBuffer( EHTMLCommands eCmd, int iBrowser )
+{
+ HTMLCommandBuffer_t *pBuf;
+ if ( !m_tslUnsedBuffers.PopItem( &pBuf ) ) // if nothing in the free queue just make a new one
+ pBuf = new HTMLCommandBuffer_t;
+
+ pBuf->m_eCmd = eCmd;
+ pBuf->m_iBrowser = iBrowser;
+ return pBuf;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: wait for a command of this type on the cef thread
+//-----------------------------------------------------------------------------
+HTMLCommandBuffer_t *CCEFThread::BWaitForCommand( EHTMLCommands eCmd, int iBrowser )
+{
+ while ( !m_bExit )
+ {
+ if ( m_bSleepForValidate )
+ {
+ m_bSleepingForValidate = true;
+ ThreadSleep( 100 );
+ continue;
+ }
+ m_bSleepingForValidate = false;
+
+ HTMLCommandBuffer_t *pBuf = NULL;
+ while ( m_tslCommandBuffers.PopItem( &pBuf ) && pBuf )
+ {
+ if ( pBuf->m_iBrowser == iBrowser )
+ {
+ if ( pBuf->m_eCmd == eCmd ) // it is what we have been waiting for
+ return pBuf;
+ if ( pBuf->m_eCmd == eHTMLCommands_BrowserRemove ) // check to see if this is being deleted while its launching
+ return NULL;
+ }
+
+ m_vecQueueCommands.AddToTail( pBuf );
+ pBuf = NULL;
+ }
+ Assert( pBuf == NULL );
+ m_evWaitingForCommand.Wait();
+ }
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: wait for a command of this type on the cef thread
+//-----------------------------------------------------------------------------
+HTMLCommandBuffer_t *CCEFThread::BWaitForResponse( EHTMLCommands eCmd, int iBrowser )
+{
+ while ( !m_bExit )
+ {
+ if ( m_bSleepForValidate )
+ {
+ m_bSleepingForValidate = true;
+ ThreadSleep( 100 );
+ continue;
+ }
+ m_bSleepingForValidate = false;
+
+ HTMLCommandBuffer_t *pBuf = NULL;
+ while ( m_tslResponseBuffers.PopItem( &pBuf ) && pBuf )
+ {
+ if ( pBuf->m_iBrowser == iBrowser )
+ {
+ if ( pBuf->m_eCmd == eCmd ) // it is what we have been waiting for
+ return pBuf;
+ if ( pBuf->m_eCmd == eHTMLCommands_BrowserRemove ) // check to see if this is being deleted while its launching
+ return NULL;
+ }
+
+ m_vecQueueResponses.AddToTail( pBuf );
+ pBuf = NULL;
+ }
+ Assert( pBuf == NULL );
+ m_evWaitingForResponse.Wait();
+ }
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: add a command for the cef thread
+//-----------------------------------------------------------------------------
+void CCEFThread::PushCommand( HTMLCommandBuffer_t *pBuf )
+{
+ m_tslCommandBuffers.PushItem( pBuf );
+ m_evWaitingForCommand.Set();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: add a command for the main thread
+//-----------------------------------------------------------------------------
+void CCEFThread::PushResponse( HTMLCommandBuffer_t *pBuf )
+{
+ m_tslResponseBuffers.PushItem( pBuf );
+ m_evWaitingForResponse.Set();
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: get any cef responses on the main thread, returns false if there are none
+//-----------------------------------------------------------------------------
+bool CCEFThread::GetMainThreadCommand( HTMLCommandBuffer_t **pBuf )
+{
+ if ( m_vecQueueResponses.Count() )
+ {
+ *pBuf = m_vecQueueResponses[0];
+ m_vecQueueResponses.Remove(0);
+ return true;
+ }
+ else
+ return m_tslResponseBuffers.PopItem( pBuf );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: get the next cef thread protobuf command to run, return false if there are none
+//-----------------------------------------------------------------------------
+bool CCEFThread::GetCEFThreadCommand( HTMLCommandBuffer_t **pBuf )
+{
+ if ( m_vecQueueCommands.Count() )
+ {
+ *pBuf = m_vecQueueCommands[0];
+ m_vecQueueCommands.Remove(0);
+ return true;
+ }
+ else
+ return m_tslCommandBuffers.PopItem( pBuf );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: the user agent to report when using this browser control
+//-----------------------------------------------------------------------------
+const char *CCEFThread::PchWebkitUserAgent()
+{
+ return "Mozilla/5.0 (%s; U; %s; en-US; %s/%llu; %s) AppleWebKit/535.15 (KHTML, like Gecko) Chrome/18.0.989.0 Safari/535.11";
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: make a new browser object
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadCreateBrowser( const CHTMLProtoBufMsg<CMsgBrowserCreate> &htmlCommand )
+{
+ int idx = m_listClientHandlers.AddToTail();
+ ++m_nBrowserSerial;
+ CClientHandler *pBrowser = new CClientHandler( BROWSER_HANDLE_FROM_INDEX_SERIAL( idx, m_nBrowserSerial ), PchWebkitUserAgent(), m_nBrowserSerial );
+ pBrowser->SetUserAgentIdentifier( htmlCommand.BodyConst().useragent().c_str() );
+
+ // send the handle info back to the main thread, needs to be before the CreateBrowser below
+ // to stop a race condition of the browser being ready before the main thread knows its handle
+ CHTMLProtoBufMsg<CMsgBrowserCreateResponse> cmd( eHTMLCommands_BrowserCreateResponse );
+ cmd.Body().set_browser_handle( BROWSER_HANDLE_FROM_INDEX_SERIAL( idx, m_nBrowserSerial ) );
+ cmd.Body().set_request_id( htmlCommand.BodyConst().request_id() );
+ HTMLCommandBuffer_t *pBuf = GetFreeCommandBuffer( eHTMLCommands_BrowserCreateResponse, idx );
+ cmd.SerializeCrossProc( &pBuf->m_Buffer );
+ PushResponse( pBuf );
+
+ m_listClientHandlers[idx] = pBrowser;
+ pBrowser->AddRef();
+
+ CefWindowInfo info;
+ info.SetAsOffScreen( NULL );
+ info.m_bPopupWindow = htmlCommand.BodyConst().popup();
+
+ CefBrowserSettings settings;
+ settings.fullscreen_enabled = true;
+ settings.threaded_compositing_enabled = true;
+ settings.java_disabled = true;
+ //settings.accelerated_compositing_enabled = true; // not supported when going into fullscreen mode
+
+ // Drag and drop is supposed to be disabled automatically for offscreen views, but
+ // ports for Mac and Linux have bugs where it is not really disabled, causing havoc
+ settings.drag_drop_disabled = true;
+
+#ifdef LINUX
+ // Turn off web features here that don't work on Linux
+ settings.webgl_disabled = true;
+#endif
+
+ CefBrowser::CreateBrowserSync( info, pBrowser, "", settings );
+ CefDoMessageLoopWork();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: return true if this browser handle resolves into a currently valid browser handler object
+//-----------------------------------------------------------------------------
+bool CCEFThread::BIsValidBrowserHandle( uint32 nHandle, int &iClient )
+{
+ iClient = nHandle & 0xffff;
+ if ( m_listClientHandlers.IsValidIndex( nHandle & 0xffff ) )
+ {
+ if ( m_listClientHandlers[ iClient ]->NSerial() == BROWSER_SERIAL_FROM_HANDLE( nHandle ) )
+ return true;
+ }
+ iClient = -1;
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: delete this browser object, we are done with it
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadRemoveBrowser( const CHTMLProtoBufMsg<CMsgBrowserRemove> &htmlCommand )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ m_listClientHandlers[iClient]->CloseBrowser();
+ m_listClientHandlers[iClient]->Release();
+ m_listClientHandlers[iClient] = NULL;
+ m_listClientHandlers.Remove( iClient );
+ }
+}
+
+
+// helper macro to call browser functions if you have a valid handle
+#define GET_BROSWER_FUNC( msg, cmd ) \
+ int iClient; \
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) ) \
+ { \
+ if ( m_listClientHandlers[iClient]->GetBrowser() ) \
+ m_listClientHandlers[iClient]->GetBrowser()->cmd; \
+ } \
+
+ //else \
+ // Assert( false );
+
+
+//-----------------------------------------------------------------------------
+// Purpose: make the web page this many pixels wide&tall
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserSize( const CHTMLProtoBufMsg<CMsgBrowserSize> &htmlCommand )
+{
+ GET_BROSWER_FUNC( htmlCommand, SetSize( PET_VIEW, htmlCommand.BodyConst().width(), htmlCommand.BodyConst().height() ) );
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ m_listClientHandlers[iClient]->SetSize( htmlCommand.BodyConst().width(), htmlCommand.BodyConst().height() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: set the global position of the browser to these co-ords, used by some activeX controls
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserPosition( const CHTMLProtoBufMsg<CMsgBrowserPosition> &htmlCommand )
+{
+ // no longer used - BUGBUG remove me
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: load this url in the browser with optional post data
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserPostURL( const CHTMLProtoBufMsg<CMsgPostURL> &htmlCommand )
+{
+ if ( htmlCommand.BodyConst().url().empty() )
+ return; // they asked us to load nothing, ignore them
+
+ const char *pchPostData = htmlCommand.BodyConst().post().c_str();
+ if ( !pchPostData || !pchPostData[0] )
+ {
+ GET_BROSWER_FUNC( htmlCommand, GetMainFrame()->LoadURL( std::wstring( CStrAutoEncode( htmlCommand.BodyConst().url().c_str() ).ToWString() ) ) );
+ }
+ else
+ {
+ // Create a new request
+ CefRefPtr<CefRequest> request(CefRequest::CreateRequest());
+
+ // Set the request URL
+ request->SetURL( CStrAutoEncode( htmlCommand.BodyConst().url().c_str() ).ToWString() );
+
+ // Add post data to the request. The correct method and content-
+ // type headers will be set by CEF.
+ CefRefPtr<CefPostDataElement> postDataElement( CefPostDataElement::CreatePostDataElement() );
+
+ std::string data = pchPostData;
+
+ postDataElement->SetToBytes(data.length(), data.c_str());
+
+ CefRefPtr<CefPostData> postData(CefPostData::CreatePostData());
+
+ postData->AddElement(postDataElement);
+ request->SetPostData(postData);
+
+ GET_BROSWER_FUNC( htmlCommand, GetMainFrame()->LoadRequest( request ) );
+ }
+
+ int iClient;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ m_listClientHandlers[iClient]->SetPendingPageSerial( htmlCommand.BodyConst().pageserial() );
+
+ CefDoMessageLoopWork(); // make sure CEF processes this load before we do anything else (like delete the browser control)
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: stop loading the page we are on
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserStopLoad( const CHTMLProtoBufMsg<CMsgStopLoad> &htmlCommand )
+{
+ GET_BROSWER_FUNC( htmlCommand, StopLoad() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: reload the current page
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserReload( const CHTMLProtoBufMsg<CMsgReload> &htmlCommand )
+{
+ GET_BROSWER_FUNC( htmlCommand, Reload() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: go forward one page in its history
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserGoForward( const CHTMLProtoBufMsg<CMsgGoForward> &htmlCommand )
+{
+ GET_BROSWER_FUNC( htmlCommand, GoForward() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: go back one page in its history
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserGoBack( const CHTMLProtoBufMsg<CMsgGoBack> &htmlCommand )
+{
+ GET_BROSWER_FUNC( htmlCommand, GoBack() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: copy selected text to the clipboard
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserCopy( const CHTMLProtoBufMsg<CMsgCopy> &htmlCommand )
+{
+ GET_BROSWER_FUNC( htmlCommand, GetMainFrame()->Copy() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: paste from the clipboard into the web page
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserPaste( const CHTMLProtoBufMsg<CMsgPaste> &htmlCommand )
+{
+ GET_BROSWER_FUNC( htmlCommand, GetMainFrame()->Paste() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: run this javascript on the current page
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserExecuteJavascript( const CHTMLProtoBufMsg<CMsgExecuteJavaScript> &htmlCommand )
+{
+ GET_BROSWER_FUNC( htmlCommand, GetMainFrame()->ExecuteJavaScript(
+ CStrAutoEncode( htmlCommand.BodyConst().script().c_str() ).ToWString(), L"", 0 ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: tell the browser it has key focus
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserSetFocus( const CHTMLProtoBufMsg<CMsgSetFocus> &htmlCommand )
+{
+ GET_BROSWER_FUNC( htmlCommand, SetFocus( htmlCommand.BodyConst().focus() ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: get the size of the horizontal scroll bar
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserHorizontalScrollBarSize( const CHTMLProtoBufMsg<CMsgHorizontalScrollBarSize> &htmlCommand )
+{
+ ThreadBrowserHorizontalScrollBarSizeHelper( htmlCommand.BodyConst().browser_handle(), true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: tell the main thread details of the horiztonal scrollbar
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserHorizontalScrollBarSizeHelper( int iBrowser, bool bForceSendUpdate )
+{
+ CClientHandler::CachedScrollBarState_t scroll = { };
+ float flZoom = 0.0f;
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( iBrowser, iClient ) )
+ {
+ CClientHandler *pHandler = m_listClientHandlers[iClient];
+
+ if ( pHandler->GetBrowser() )
+ {
+ scroll.m_nMax = pHandler->GetBrowser()->HorizontalScrollMax();
+ scroll.m_nScroll = pHandler->GetBrowser()->HorizontalScroll();
+ scroll.m_bVisible = pHandler->GetBrowser()->IsHorizontalScrollBarVisible();
+ pHandler->GetBrowser()->HorizontalScrollBarSize( scroll.m_nX, scroll.m_nY, scroll.m_nWide, scroll.m_nTall );
+ flZoom = pHandler->GetBrowser()->GetZoomLevel();
+ if ( scroll.m_nMax < 0 )
+ scroll.m_nMax = 0;
+ if ( flZoom == 0.0f )
+ flZoom = 1.0f;
+ }
+
+ if ( bForceSendUpdate || 0 != memcmp( &pHandler->m_CachedHScroll, &scroll, sizeof( scroll ) ) )
+ {
+ pHandler->m_CachedHScroll = scroll;
+
+ CHTMLProtoBufMsg<CMsgHorizontalScrollBarSizeResponse> cmd( eHTMLCommands_HorizontalScrollBarSizeResponse );
+ cmd.Body().set_x( scroll.m_nX );
+ cmd.Body().set_y( scroll.m_nY );
+ cmd.Body().set_wide( scroll.m_nWide );
+ cmd.Body().set_tall( scroll.m_nTall );
+ cmd.Body().set_scroll_max( scroll.m_nMax );
+ cmd.Body().set_scroll( scroll.m_nScroll );
+ cmd.Body().set_visible( scroll.m_bVisible != 0 );
+ cmd.Body().set_zoom( flZoom );
+ int m_iBrowser = iBrowser;
+ DISPATCH_MESSAGE( eHTMLCommands_HorizontalScrollBarSizeResponse );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: get the size of the verical scrollbar
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserVerticalScrollBarSize( const CHTMLProtoBufMsg<CMsgVerticalScrollBarSize> &htmlCommand )
+{
+ ThreadBrowserVerticalScrollBarSizeHelper( htmlCommand.BodyConst().browser_handle(), true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: tell the main thread details of the vertical scrollbar
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserVerticalScrollBarSizeHelper( int iBrowser, bool bForceSendUpdate )
+{
+ CClientHandler::CachedScrollBarState_t scroll = { };
+ float flZoom = 0.0f;
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( iBrowser, iClient ) )
+ {
+ CClientHandler *pHandler = m_listClientHandlers[iClient];
+
+ if ( pHandler->GetBrowser() )
+ {
+ scroll.m_nMax = pHandler->GetBrowser()->VerticalScrollMax();
+ scroll.m_nScroll = pHandler->GetBrowser()->VerticalScroll();
+ scroll.m_bVisible = pHandler->GetBrowser()->IsVeritcalScrollBarVisible();
+ pHandler->GetBrowser()->VerticalScrollBarSize( scroll.m_nX, scroll.m_nY, scroll.m_nWide, scroll.m_nTall );
+ flZoom = pHandler->GetBrowser()->GetZoomLevel();
+ if ( scroll.m_nMax < 0 )
+ scroll.m_nMax = 0;
+ if ( flZoom == 0.0f )
+ flZoom = 1.0f;
+ }
+
+ if ( bForceSendUpdate || 0 != memcmp( &pHandler->m_CachedVScroll, &scroll, sizeof( scroll ) ) )
+ {
+ pHandler->m_CachedVScroll = scroll;
+
+ CHTMLProtoBufMsg<CMsgVerticalScrollBarSizeResponse> cmd( eHTMLCommands_VerticalScrollBarSizeResponse );
+ cmd.Body().set_x( scroll.m_nX );
+ cmd.Body().set_y( scroll.m_nY );
+ cmd.Body().set_wide( scroll.m_nWide );
+ cmd.Body().set_tall( scroll.m_nTall );
+ cmd.Body().set_scroll_max( scroll.m_nMax );
+ cmd.Body().set_scroll( scroll.m_nScroll );
+ cmd.Body().set_visible( scroll.m_bVisible != 0 );
+ cmd.Body().set_zoom( flZoom );
+ int m_iBrowser = iBrowser;
+ DISPATCH_MESSAGE( eHTMLCommands_VerticalScrollBarSizeResponse );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: start a find in a web page
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserFind( const CHTMLProtoBufMsg<CMsgFind> &htmlCommand )
+{
+ GET_BROSWER_FUNC( htmlCommand, Find( 1, htmlCommand.BodyConst().find().c_str(), !htmlCommand.BodyConst().reverse(), false, htmlCommand.BodyConst().infind() ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: dismiss a current find
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserStopFind( const CHTMLProtoBufMsg<CMsgStopFind> &htmlCommand )
+{
+ GET_BROSWER_FUNC( htmlCommand, StopFinding( 1 ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: scroll the page horizontally to this pos
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserSetHorizontalScroll( const CHTMLProtoBufMsg<CMsgSetHorizontalScroll> &htmlCommand )
+{
+ GET_BROSWER_FUNC( htmlCommand, SetHorizontalScroll( htmlCommand.BodyConst().scroll() ) );
+
+ ThreadBrowserHorizontalScrollBarSizeHelper( htmlCommand.BodyConst().browser_handle(), true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: scroll the page vertically to this pos
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserSetVerticalScroll( const CHTMLProtoBufMsg<CMsgSetVerticalScroll> &htmlCommand )
+{
+ GET_BROSWER_FUNC( htmlCommand, SetVerticalScroll( htmlCommand.BodyConst().scroll() ) );
+
+ ThreadBrowserVerticalScrollBarSizeHelper( htmlCommand.BodyConst().browser_handle(), true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: set the zoom to this level, 100% means normal size, 200% double size
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserSetZoomLevel( const CHTMLProtoBufMsg<CMsgSetZoomLevel> &htmlCommand )
+{
+ GET_BROSWER_FUNC( htmlCommand, SetZoomLevel( htmlCommand.BodyConst().zoom() ) );
+
+ CefDoMessageLoopWork(); // tell cef to think one frame, Zoom is in a work queue and we want it to apply right away so think now
+
+ // now tell if about the scrollbars we now have
+ ThreadBrowserHorizontalScrollBarSizeHelper( htmlCommand.BodyConst().browser_handle(), true );
+ ThreadBrowserVerticalScrollBarSizeHelper( htmlCommand.BodyConst().browser_handle(), true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: show the page source in notepad
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserViewSource( const CHTMLProtoBufMsg<CMsgViewSource> &htmlCommand )
+{
+ GET_BROSWER_FUNC( htmlCommand, GetMainFrame()->ViewSource() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: add a header to any requests we make
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadAddHeader( const CHTMLProtoBufMsg<CMsgAddHeader> &htmlCommand )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ m_listClientHandlers[iClient]->AddHeader( htmlCommand.BodyConst().key().c_str(), htmlCommand.BodyConst().value().c_str() );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: main thread is done with a paint buffer, tell our handler
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadNeedsPaintResponse( const CHTMLProtoBufMsg<CMsgNeedsPaintResponse> &htmlCommand )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ m_listClientHandlers[iClient]->SetTextureUploaded( htmlCommand.BodyConst().textureid() );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: set the error strings to display on page load
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadBrowserErrorStrings( const CHTMLProtoBufMsg<CMsgBrowserErrorStrings> &cmd )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( cmd.BodyConst().browser_handle(), iClient ) )
+ {
+ m_listClientHandlers[iClient]->SetErrorStrings( cmd.BodyConst().title().c_str(), cmd.BodyConst().header().c_str(),
+ cmd.BodyConst().cache_miss().c_str(), cmd.BodyConst().bad_url().c_str(),
+ cmd.BodyConst().connection_problem().c_str(),
+ cmd.BodyConst().proxy_problem().c_str(), cmd.BodyConst().unknown().c_str() );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: return the zoom level for the current page, 100% means actual size, 200% double size
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadGetZoom( const CHTMLProtoBufMsg<CMsgGetZoom> &htmlCmd )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCmd.BodyConst().browser_handle(), iClient ) )
+ {
+ float flZoom = 0.0f;
+ if ( m_listClientHandlers[iClient]->GetBrowser() )
+ flZoom = m_listClientHandlers[iClient]->GetBrowser()->GetZoomLevel();
+ if ( flZoom == 0.0f )
+ flZoom = 1.0f;
+ if ( flZoom > 100.0f )
+ flZoom /= 100.0f;
+ CHTMLProtoBufMsg<CMsgGetZoomResponse> cmd( eHTMLCommands_GetZoomResponse );
+ cmd.Body().set_zoom( flZoom );
+ int m_iBrowser = htmlCmd.BodyConst().browser_handle();
+ DISPATCH_MESSAGE( eHTMLCommands_GetZoomResponse );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handler func to throw the cookie call to the cef IO thread
+//-----------------------------------------------------------------------------
+void IOT_SetCookie(const CefString& url, CefCookie* cookie, CThreadEvent *pEvent )
+{
+ CefSetCookie(url, *cookie);
+ pEvent->Set();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: set this cookie into the cef instance
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadSetCookie( const CHTMLProtoBufMsg<CMsgSetCookie> &htmlCommand )
+{
+ CefCookie cookie;
+ cef_string_utf8_copy( htmlCommand.BodyConst().key().c_str(), htmlCommand.BodyConst().key().size(), &cookie.name );
+ cef_string_utf8_copy( htmlCommand.BodyConst().value().c_str(), htmlCommand.BodyConst().value().size(), &cookie.value );
+ cef_string_utf8_copy( htmlCommand.BodyConst().path().c_str(), htmlCommand.BodyConst().path().size(), &cookie.path );
+ if ( htmlCommand.BodyConst().has_expires() )
+ {
+ AssertMsg( false, "Cookie expiration not implemented -- rtime.cpp needs to be ported." );
+ /*
+ cookie.has_expires = true;
+ CRTime rtExpire( (RTime32)htmlCommand.BodyConst().expires() );
+ cookie.expires.year = rtExpire.GetLocalYear();
+ cookie.expires.month = rtExpire.GetLocalMonth();
+#if !defined(OS_MACOSX)
+ cookie.expires.day_of_week = rtExpire.GetLocalDayOfWeek();
+#endif
+ cookie.expires.day_of_month = rtExpire.GetLocalMonth();
+ cookie.expires.hour = rtExpire.GetLocalHour();
+ cookie.expires.minute = rtExpire.GetLocalMinute();
+ cookie.expires.second = rtExpire.GetLocalSecond();
+ */
+ }
+
+ CThreadEvent event;
+ CefPostTask(TID_IO, NewCefRunnableFunction( IOT_SetCookie, htmlCommand.BodyConst().host().c_str(), &cookie, &event));
+ event.Wait();
+}
+
+
+struct CCefCookie
+{
+ CUtlString sValue;
+ CUtlString sName;
+ CUtlString sDomain;
+ CUtlString sPath;
+};
+//-----------------------------------------------------------------------------
+// Purpose: helper class to iterator cookies
+//-----------------------------------------------------------------------------
+class CookieVisitor : public CefCookieVisitor {
+public:
+ CookieVisitor( CUtlVector<CCefCookie> *pVec, CThreadEvent *pEvent )
+ {
+ m_pVecCookies = pVec;
+ m_pEvent = pEvent;
+ }
+ ~CookieVisitor()
+ {
+ m_pEvent->Set();
+ }
+
+ virtual bool Visit(const CefCookie& cookie, int count, int total,
+ bool& deleteCookie) {
+
+ CCefCookie cookieCopy;
+ cookieCopy.sValue = cookie.value.str;
+ cookieCopy.sName = cookie.name.str;
+ cookieCopy.sDomain = cookie.domain.str;
+ cookieCopy.sPath = cookie.path.str;
+ m_pVecCookies->AddToTail( cookieCopy );
+ return true;
+ }
+
+private:
+ CUtlVector<CCefCookie> *m_pVecCookies;
+ CThreadEvent *m_pEvent;
+
+ IMPLEMENT_REFCOUNTING(CookieVisitor);
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handler func to throw the cookie call to the cef IO thread
+//-----------------------------------------------------------------------------
+void IOT_CookiesForURL(const CefString& url, CThreadEvent *pEvent, CUtlVector<CCefCookie> *pVecCookies )
+{
+ CefVisitUrlCookies( url, false, new CookieVisitor( pVecCookies, pEvent ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: get all the cookies for this URL
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadGetCookiesForURL( const CHTMLProtoBufMsg<CMsgGetCookiesForURL> &htmlCommand )
+{
+ CUtlVector<CCefCookie> vecCookies;
+ CThreadEvent event;
+ CefPostTask(TID_IO, NewCefRunnableFunction( IOT_CookiesForURL, htmlCommand.BodyConst().url().c_str(), &event, &vecCookies ));
+ event.Wait();
+
+ CHTMLProtoBufMsg<CMsgGetCookiesForURLResponse> cmd( eHTMLCommands_GetCookiesForURLResponse );
+ int m_iBrowser = htmlCommand.BodyConst().browser_handle();
+ cmd.Body().set_url( htmlCommand.BodyConst().url() );
+
+ FOR_EACH_VEC( vecCookies, i )
+ {
+ CCookie *pCookie = cmd.Body().add_cookies();
+ pCookie->set_name( vecCookies[i].sName );
+ pCookie->set_value( vecCookies[i].sValue );
+ pCookie->set_domain( vecCookies[i].sDomain );
+ pCookie->set_path( vecCookies[i].sPath );
+ }
+
+ DISPATCH_MESSAGE( eHTMLCommands_GetCookiesForURLResponse );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: set the framerate to run CEF at
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadSetTargetFrameRate( const CHTMLProtoBufMsg<CMsgSetTargetFrameRate> &htmlCommand )
+{
+ m_nTargetFrameRate = htmlCommand.BodyConst().ntargetframerate();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: hide any showing popup for this browser
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadHidePopup( const CHTMLProtoBufMsg<CMsgHidePopup> &htmlCommand )
+{
+ GET_BROSWER_FUNC( htmlCommand, HidePopup() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: request a full redraw of the client
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadFullRepaint( const CHTMLProtoBufMsg<CMsgFullRepaint> &htmlCommand )
+{
+ int iClient;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ if ( m_listClientHandlers[iClient]->GetBrowser()->IsVisuallyNonEmpty() )
+ {
+ int wide, tall;
+ m_listClientHandlers[iClient]->GetExpectedSize( wide, tall);
+ CefRect rect;
+ rect.x = rect.y = 0;
+ rect.width = wide;
+ rect.height = tall;
+ m_listClientHandlers[iClient]->GetBrowser()->Invalidate( rect );
+ }
+ else
+ m_listClientHandlers[iClient]->GetBrowser()->Reload();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: configure the options we want for cef
+//-----------------------------------------------------------------------------
+void CCEFThread::AppGetSettings(CefSettings& settings, CefRefPtr<CefApp>& app)
+{
+ settings.multi_threaded_message_loop = false;
+#if defined(OS_WIN)
+ settings.auto_detect_proxy_settings_enabled = true;
+#endif
+
+ CefString(&settings.cache_path) = m_sHTMLCacheDir;
+ CefString(&settings.product_version) = "Steam";
+// CefString(&settings.log_file) =
+/*#ifdef WIN32
+ settings.graphics_implementation = ANGLE_IN_PROCESS_COMMAND_BUFFER;
+#else*/
+ settings.graphics_implementation = DESKTOP_IN_PROCESS_COMMAND_BUFFER;
+//#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: clean up the temp folders cef can leave around on crash
+//-----------------------------------------------------------------------------
+void CCEFThread::CleanupTempFolders()
+{
+ /*
+ // Temporarily commented out to avoid bringing in additional code.
+#if defined( WIN32 )
+ char rgchPath[MAX_PATH];
+ if ( GetTempPathA( Q_ARRAYSIZE( rgchPath ), rgchPath ) == 0 )
+ return;
+
+ CUtlString strPath = rgchPath;
+#elif defined( LINUX ) || defined( OSX )
+ // TMPDIR first, T_tmpdir next, /tmp last.
+ char *pszDir = getenv( "TMPDIR" );
+ if ( pszDir == NULL )
+ {
+ pszDir = P_tmpdir;
+ if ( pszDir == NULL )
+ pszDir = "/tmp";
+ }
+ if ( pszDir == NULL )
+ return;
+
+ CUtlString strPath = pszDir;
+#endif
+
+ if ( strPath[strPath.Length()-1] != CORRECT_PATH_SEPARATOR )
+ strPath += CORRECT_PATH_SEPARATOR_S;
+
+ CUtlString strSearch = strPath;
+ strSearch += "scoped_dir*";
+ CDirIterator tempDirIterator( strSearch.String() );
+
+ while ( tempDirIterator.BNextFile() )
+ {
+ if ( tempDirIterator.BCurrentIsDir() )
+ {
+ CUtlString sStrDir = strPath;
+ sStrDir += tempDirIterator.CurrentFileName();
+ BRemoveDirectoryRecursive( sStrDir );
+ }
+ }
+ */
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: main thread for pumping CEF, get commands from the main thread and dispatches responses to it
+//-----------------------------------------------------------------------------
+int CCEFThread::Run()
+{
+ { // scope to trigger destructors before setting the we have exited event
+ CefSettings settings;
+ CefRefPtr<CefApp> app;
+
+ // blow away any temp folders CEF left lying around if we crashed last
+ CleanupTempFolders();
+
+ // Populate the settings based on command line arguments.
+ AppGetSettings(settings, app);
+
+ // Initialize CEF.
+ CefInitialize(settings, app, "");
+
+ #if defined( VPROF_ENABLED )
+ //CVProfile *pProfile = GetVProfProfileForCurrentThread();
+ #endif
+
+ CLimitTimer timer;
+ CLimitTimer timerLastCefThink; // track when we think cef so we can do it at a minimum of 10hz
+ timerLastCefThink.SetLimit( k_nMillion ); // 1Hz min think time
+#ifdef WIN32
+ CLimitTimer timerLastFlashFullscreenThink; // track when we think cef so we can do it at a minimum of 10hz
+ timerLastFlashFullscreenThink.SetLimit( k_nMillion * k_nMillion ); // think again in the distance future
+ bool bInitialThinkAfterInput = false;
+#endif
+ while( !m_bExit )
+ {
+ #ifdef OSX
+ void *pool = CreateAutoReleasePool();
+ #endif
+
+ if ( m_bSleepForValidate )
+ {
+ m_bSleepingForValidate = true;
+ ThreadSleep( 100 );
+ continue;
+ }
+ m_bSleepingForValidate = false;
+
+ m_bSawUserInputThisFrame = false;
+
+ #if defined( VPROF_ENABLED )
+ //if ( pProfile )
+ // pProfile->MarkFrame( "UI CEF HTML Thread" );
+ #endif
+ // Limit animation frame rate
+ timer.SetLimit( k_nMillion/m_nTargetFrameRate );
+
+ // run any pending commands, get ack'd paint buffers
+ {
+ VPROF_BUDGET( "CCEFThread - RunCurrentCommands()", VPROF_BUDGETGROUP_VGUI );
+ RunCurrentCommands();
+ }
+
+ // now let cef think
+ if ( m_listClientHandlers.Count() || timerLastCefThink.BLimitReached() )
+ {
+ VPROF_BUDGET( "CCEFThread - CefDoMessageLoopWork()", VPROF_BUDGETGROUP_TENFOOT );
+ CefDoMessageLoopWork();
+ timerLastCefThink.SetLimit( k_nMillion ); // 1Hz min think time
+ }
+ #ifdef OSX
+ ReleaseAutoReleasePool( pool );
+ #endif
+
+ // push any changes to scrollbar data and refresh HTML element hover states
+ {
+ VPROF_BUDGET( "CCEFThread - Scroll", VPROF_BUDGETGROUP_VGUI );
+ FOR_EACH_LL( m_listClientHandlers, i )
+ {
+ int nBrowser = BROWSER_HANDLE_FROM_INDEX_SERIAL( i, m_listClientHandlers[i]->NSerial() );
+ ThreadBrowserHorizontalScrollBarSizeHelper( nBrowser, false );
+ ThreadBrowserVerticalScrollBarSizeHelper( nBrowser, false );
+
+ // workaround a CEF issue where mouse hover states don't update after scrolling
+ m_listClientHandlers[i]->RefreshCEFHoverStatesAfterScroll();
+ }
+ }
+
+ {
+ VPROF_BUDGET( "CCEFThread - SendSizeChangeEvents", VPROF_BUDGETGROUP_VGUI );
+ SendSizeChangeEvents();
+ }
+
+ //see if we need a paint
+ {
+ VPROF_BUDGET( "CCEFThread - Paint", VPROF_BUDGETGROUP_VGUI );
+ FOR_EACH_LL( m_listClientHandlers, i )
+ {
+ if ( !m_listClientHandlers[i]->GetBrowser() )
+ continue;
+
+ m_listClientHandlers[i]->Paint();
+ if ( m_listClientHandlers[i]->BPaintBufferReady() && m_listClientHandlers[i]->BNeedsPaint() )
+ {
+ uint32 textureID = m_listClientHandlers[i]->FlipTexture();
+ const byte *pRGBA = m_listClientHandlers[i]->PComposedTextureData( textureID );
+ if ( pRGBA )
+ {
+ CClientHandler *pHandler = m_listClientHandlers[i];
+ pHandler->Lock();
+ if ( pHandler->BPendingScreenShot() )
+ {
+ pHandler->SavePageToJPEGIfNeeded( pHandler->GetBrowser(), pRGBA, pHandler->GetTextureWide(), pHandler->GetTextureTall() );
+ }
+ CHTMLProtoBufMsg<CMsgNeedsPaint> cmd( eHTMLCommands_NeedsPaint );
+ cmd.Body().set_browser_handle( BROWSER_HANDLE_FROM_INDEX_SERIAL( i, pHandler->NSerial() ) );
+ cmd.Body().set_wide( pHandler->GetTextureWide() );
+ cmd.Body().set_tall( pHandler->GetTextureTall() );
+ cmd.Body().set_rgba( (uint64)pRGBA );
+ cmd.Body().set_pageserial( pHandler->GetPageSerial() );
+ cmd.Body().set_textureid( textureID );
+ cmd.Body().set_updatex( pHandler->GetUpdateX() );
+ cmd.Body().set_updatey( pHandler->GetUpdateY() );
+ cmd.Body().set_updatewide( pHandler->GetUpdateWide() );
+ cmd.Body().set_updatetall( pHandler->GetUpdateTall() );
+ cmd.Body().set_scrollx( pHandler->GetBrowser()->HorizontalScroll() );
+ cmd.Body().set_scrolly( pHandler->GetBrowser()->VerticalScroll() );
+
+ if ( pHandler->BPopupVisibleAndPainted() ) // add in the combo box's texture data if visible
+ {
+ int x,y,wide,tall; // popup sizes
+ pHandler->PopupRect( x, y, wide, tall );
+ cmd.Body().set_combobox_rgba( (uint64)pHandler->PPopupTextureDataCached() );
+ cmd.Body().set_combobox_wide( wide );
+ cmd.Body().set_combobox_tall( tall );
+ }
+
+ // Texture update rect has now been pushed to main thread
+ pHandler->ClearUpdateRect();
+
+ HTMLCommandBuffer_t *pBuf = g_CEFThread.GetFreeCommandBuffer( eHTMLCommands_NeedsPaint, i );
+ cmd.SerializeCrossProc( &pBuf->m_Buffer );
+ pHandler->Unlock();
+
+ g_CEFThread.PushResponse( pBuf );
+ }
+ else
+ {
+ m_listClientHandlers[i]->SetTextureUploaded( textureID );
+ }
+ }
+ }
+ }
+
+#ifdef WIN32
+ if ( m_bSawUserInputThisFrame )
+ {
+ if ( timerLastFlashFullscreenThink.CMicroSecLeft() > k_nMillion/10 || timerLastFlashFullscreenThink.BLimitReached() )
+ {
+ timerLastFlashFullscreenThink.SetLimit( k_nMillion/10 ); // check in 100msec
+ }
+ bInitialThinkAfterInput = true;
+ }
+
+ if ( m_listClientHandlers.Count() && timerLastFlashFullscreenThink.BLimitReached() )
+ {
+ CheckForFullScreenFlashControl();
+ if ( ( !m_bFullScreenFlashVisible && bInitialThinkAfterInput ) || m_bFullScreenFlashVisible )
+ {
+ timerLastFlashFullscreenThink.SetLimit( k_nMillion ); // could be a slow machine, check again in 1 sec
+ }
+ else
+ {
+ timerLastFlashFullscreenThink.SetLimit( k_nMillion * k_nMillion ); // think again in the distance future
+ }
+
+ bInitialThinkAfterInput= false;
+ }
+#endif
+
+ {
+ VPROF_BUDGET( "Sleep - FPS Limiting", VPROF_BUDGETGROUP_TENFOOT );
+ if ( timer.BLimitReached() )
+ ThreadSleep( 1 );
+ else
+ m_WakeEvent.Wait( timer.CMicroSecLeft() / 1000 );
+ }
+ }
+
+ FOR_EACH_LL( m_listClientHandlers, i )
+ {
+ if ( m_listClientHandlers[i] )
+ m_listClientHandlers[i]->CloseBrowser();
+ m_listClientHandlers[i] = NULL;;
+ }
+ m_listClientHandlers.RemoveAll();
+
+ CefDoMessageLoopWork(); // pump the message loop to clear the close browser calls from above
+
+ CefShutdown();
+ }
+ m_eventDidExit.Set();
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: special code to sniff for flash doing its usual naughty things
+//-----------------------------------------------------------------------------
+void CCEFThread::CheckForFullScreenFlashControl()
+{
+#ifdef WIN32
+ VPROF_BUDGET( "Searching for Flash fullscreen - FindWindowEx", VPROF_BUDGETGROUP_TENFOOT );
+
+ // see if we need to drag the flash fullscreen window to front
+ HWND flashfullscreenHWND = ::FindWindowEx( NULL, NULL, "ShockwaveFlashFullScreen", NULL );
+ if ( flashfullscreenHWND )
+ {
+ DWORD proccess_id;
+ GetWindowThreadProcessId( flashfullscreenHWND, &proccess_id);
+ TCHAR exe_path[MAX_PATH];
+ GetModuleFileName( GetModuleHandle(NULL), exe_path, MAX_PATH);
+ HANDLE hmodule = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, proccess_id);
+ MODULEENTRY32 mod = { sizeof(MODULEENTRY32) };
+ if ( Module32First( hmodule, &mod) )
+ {
+ if ( Q_stricmp(mod.szExePath, exe_path) == 0 )
+ {
+ if ( !m_bFullScreenFlashVisible )
+ {
+ m_bFullScreenFlashVisible = true;
+ m_flashfullscreenHWND = flashfullscreenHWND;
+
+ FOR_EACH_LL( m_listClientHandlers, i )
+ {
+ if ( m_listClientHandlers[i] )
+ m_listClientHandlers[i]->GetRenderHandler()->OnEnterFullScreen( m_listClientHandlers[i]->GetBrowser() );
+ }
+
+ SetForegroundWindow( m_flashfullscreenHWND );
+ }
+ }
+ else
+ {
+ if ( m_bFullScreenFlashVisible )
+ {
+ m_bFullScreenFlashVisible = false;
+ m_flashfullscreenHWND = NULL;
+ FOR_EACH_LL( m_listClientHandlers, i )
+ {
+ if ( m_listClientHandlers[i] )
+ m_listClientHandlers[i]->GetRenderHandler()->OnExitFullScreen( m_listClientHandlers[i]->GetBrowser() );
+ }
+ }
+ }
+ }
+ CloseHandle( hmodule );
+ }
+ else
+ {
+ if ( m_bFullScreenFlashVisible )
+ {
+ m_bFullScreenFlashVisible = false;
+ m_flashfullscreenHWND = NULL;
+ FOR_EACH_LL( m_listClientHandlers, i )
+ {
+ if ( m_listClientHandlers[i] )
+ m_listClientHandlers[i]->GetRenderHandler()->OnExitFullScreen( m_listClientHandlers[i]->GetBrowser() );
+ }
+ }
+ }
+#else
+#warning "Do we need to sniff for fullscreen flash and it breaking us?"
+#endif
+}
+
+
+#ifdef DBGFLAG_VALIDATE
+//-----------------------------------------------------------------------------
+// Purpose: validate mem
+//-----------------------------------------------------------------------------
+void CCEFThread::Validate( CValidator &validator, const tchar *pchName )
+{
+ // hacky but reliable way to avoid both vgui and panorama validating all this stuff twice
+ if ( !validator.IsClaimed( m_sHTMLCacheDir.Access() ) )
+ {
+ VALIDATE_SCOPE();
+ ValidateObj( m_sHTMLCacheDir );
+ ValidateObj( m_sCookiePath );
+ ValidateObj( m_listClientHandlers );
+ FOR_EACH_LL( m_listClientHandlers, i )
+ {
+ ValidatePtr( m_listClientHandlers[i] );
+ }
+ ValidateObj( m_vecQueueCommands );
+ FOR_EACH_VEC( m_vecQueueCommands, i )
+ {
+ ValidatePtr( m_vecQueueCommands[i] );
+ }
+ ValidateObj( m_vecQueueResponses );
+ FOR_EACH_VEC( m_vecQueueResponses, i )
+ {
+ ValidatePtr( m_vecQueueResponses[i] );
+ }
+
+ ValidateObj( m_tslUnsedBuffers );
+ {
+ CTSList<HTMLCommandBuffer_t*>::Node_t *pNode = m_tslUnsedBuffers.Detach();
+ while ( pNode )
+ {
+ CTSList<HTMLCommandBuffer_t*>::Node_t *pNext = (CTSList<HTMLCommandBuffer_t*>::Node_t *)pNode->Next;
+ ValidatePtr( pNode->elem );
+ m_tslUnsedBuffers.Push( pNode );
+ pNode = pNext;
+ }
+ }
+
+ ValidateObj( m_tslCommandBuffers );
+ ValidateObj( m_tslResponseBuffers );
+ }
+}
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Purpose: turn on CEF and its supporting thread
+//-----------------------------------------------------------------------------
+void ChromeInit( const char *pchHTMLCacheDir, const char *pchCookiePath )
+{
+ Assert( !g_CEFThread.IsAlive() );
+ g_CEFThread.SetCEFPaths( pchHTMLCacheDir, pchCookiePath );
+ g_CEFThread.SetName( "UICEFThread" );
+ g_CEFThread.Start();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: turn off CEF
+//-----------------------------------------------------------------------------
+void ChromeShutdown()
+{
+ g_CEFThread.TriggerShutdown();
+ g_CEFThread.Join( 20 *k_nThousand );
+}
+
+
+#ifdef DBGFLAG_VALIDATE
+//-----------------------------------------------------------------------------
+// Purpose: suspend the cef thread so we can validate mem
+//-----------------------------------------------------------------------------
+bool ChromePrepareForValidate()
+{
+ g_CEFThread.SleepForValidate();
+ while ( !g_CEFThread.BSleepingForValidate() )
+ ThreadSleep( 100 );
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: wake the cef thread back up
+//-----------------------------------------------------------------------------
+bool ChromeResumeFromValidate()
+{
+ g_CEFThread.WakeFromValidate();
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void ChromeValidate( CValidator &validator, const char *pchName )
+{
+ g_CEFThread.Validate( validator, "g_CEFThread" );
+}
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Purpose: set this cookie to be used by cef
+//-----------------------------------------------------------------------------
+bool ChromeSetWebCookie( const char *pchHostname, const char *pchName, const char *pchValue, const char *pchPath, RTime32 nExpires )
+{
+ CHTMLProtoBufMsg< CMsgSetCookie > cmd( eHTMLCommands_SetCookie );
+ cmd.Body().set_value( pchValue );
+ cmd.Body().set_key( pchName );
+ cmd.Body().set_path( pchPath );
+ cmd.Body().set_host( pchHostname );
+ if ( nExpires )
+ cmd.Body().set_expires( nExpires );
+
+ HTMLCommandBuffer_t *pBuf = g_CEFThread.GetFreeCommandBuffer( eHTMLCommands_SetCookie, -1 );
+ cmd.SerializeCrossProc( &pBuf->m_Buffer );
+ g_CEFThread.PushCommand( pBuf );
+ g_CEFThread.WakeThread();
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: set this cookie to be used by cef
+//-----------------------------------------------------------------------------
+bool ChromeGetWebCookiesForURL( CUtlString *pstrValue, const char *pchURL, const char *pchName )
+{
+ pstrValue->Clear();
+
+ {
+ CHTMLProtoBufMsg<CMsgGetCookiesForURL> cmd( eHTMLCommands_GetCookiesForURL );
+ cmd.Body().set_url( pchURL );
+
+ HTMLCommandBuffer_t *pCmd = g_CEFThread.GetFreeCommandBuffer( eHTMLCommands_GetCookiesForURL, -1 );
+ cmd.SerializeCrossProc( &pCmd->m_Buffer );
+ g_CEFThread.PushCommand( pCmd );
+ }
+
+ HTMLCommandBuffer_t *pBuf = g_CEFThread.BWaitForResponse( eHTMLCommands_GetCookiesForURLResponse, -1 );
+ if ( pBuf )
+ {
+ CHTMLProtoBufMsg< CMsgGetCookiesForURLResponse > cmdResponse( eHTMLCommands_GetCookiesForURLResponse );
+ if ( cmdResponse.BDeserializeCrossProc( &pBuf->m_Buffer ) )
+ {
+ for ( int i = 0; i < cmdResponse.BodyConst().cookies_size(); i++ )
+ {
+ const CCookie &cookie = cmdResponse.BodyConst().cookies(i);
+ if ( cookie.name() == pchName )
+ pstrValue->Set( cookie.value().c_str() );
+ }
+ }
+ g_CEFThread.ReleaseCommandBuffer( pBuf );
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: set the build number to report in our user agent
+//-----------------------------------------------------------------------------
+void ChromeSetClientBuildID( uint64 ulBuildID )
+{
+ sm_ulBuildID = ulBuildID;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: constructor
+//-----------------------------------------------------------------------------
+CChromePainter::CChromePainter( CClientHandler *pParent )
+{
+ m_iNextTexture = 0;
+ m_iTexturesInFlightBits = 0;
+ m_pParent = pParent;
+ m_bUpdated = false;
+ m_bPopupVisible = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: destructor
+//-----------------------------------------------------------------------------
+CChromePainter::~CChromePainter()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: cef is calling us back and saying it updated the html texture
+//-----------------------------------------------------------------------------
+void CChromePainter::OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type, const RectList& dirtyRects, const void* buffer)
+{
+ VPROF_BUDGET( "CChromePainter::DrawSubTextureRGBA", VPROF_BUDGETGROUP_VGUI );
+
+ int wide, tall;
+ browser->GetSize( type, wide, tall );
+
+ if ( wide <= 0 || tall <= 0 )
+ return;
+
+ if ( type == PET_POPUP )
+ {
+ m_nPopupWide = wide;
+ m_nPopupTall = tall;
+
+ m_PopupTexture.EnsureCount( tall*wide*4 );
+ Q_memcpy( m_PopupTexture.Base(), buffer, tall*wide*4 );
+
+ // force a recomposition + display whenever painting a popup
+ m_bUpdated = true;
+ }
+ else
+ {
+ // main browser painting
+
+ if ( !m_pParent->IsVisuallyNonEmpty() )
+ {
+ return;
+ }
+
+ // If there were no dirty regions (unlikely), perhaps due to a bug, be conservative and paint all
+ if ( dirtyRects.empty() )
+ {
+ m_MainTexture.MarkAllDirty();
+ }
+ else
+ {
+ for ( RectList::const_iterator iter = dirtyRects.begin(); iter != dirtyRects.end(); ++iter )
+ {
+ m_MainTexture.MarkDirtyRect( iter->x, iter->y, iter->x + iter->width, iter->y + iter->height );
+ }
+ }
+
+ // Refresh all dirty main texture pixels from the chromium rendering buffer
+ if ( m_MainTexture.BUpdatePixels( (byte*)buffer, wide, tall ) )
+ {
+ // at least one pixel in the main texture has changed
+ m_bUpdated = true;
+
+ // Notify the main thread that this newly painted region is dirty
+ m_UpdateRect.MarkDirtyRect( m_MainTexture );
+
+ // Merge update region into all buffer textures so that at composition time,
+ // they know to copy the union of all updates since the last composition
+ for ( size_t i = 0; i < Q_ARRAYSIZE(m_Texture); ++i )
+ {
+ m_Texture[i].MarkDirtyRect( m_MainTexture );
+ }
+ }
+
+ // The main texture is now a clean copy of chromium's canvas backing
+ m_MainTexture.MarkAllClean();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: true if we have had a paint call from cef
+//-----------------------------------------------------------------------------
+bool CChromePainter::BUpdated()
+{
+ return m_bUpdated;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: force the updated state
+//-----------------------------------------------------------------------------
+void CChromePainter::SetUpdated( bool state )
+{
+ m_bUpdated = state;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: move to the next html texture to render into
+//-----------------------------------------------------------------------------
+uint32 CChromePainter::FlipTexture()
+{
+ int iTex = m_iNextTexture;
+ m_iTexturesInFlightBits |= ( 1<<iTex );
+ m_iNextTexture = (m_iNextTexture+1)%Q_ARRAYSIZE(m_Texture);
+ return iTex;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: we are done with this texture on the main (and render) threads
+//-----------------------------------------------------------------------------
+void CChromePainter::SetTextureUploaded( uint32 id )
+{
+ // Don't need to check for id < 0 because it is unsigned.
+ Assert( id < Q_ARRAYSIZE(m_Texture) );
+ if ( id < Q_ARRAYSIZE(m_Texture) )
+ {
+ m_iTexturesInFlightBits &= ~(1<<id);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: get the texure data for this textureid
+//-----------------------------------------------------------------------------
+byte *CChromePainter::PComposedTextureData( uint32 iTexture )
+{
+ Assert( iTexture < Q_ARRAYSIZE(m_Texture) );
+ // Update pixels and then clean the dirty list
+ m_Texture[ iTexture ].BUpdatePixels( m_MainTexture.GetPixels(), m_MainTexture.GetWide(), m_MainTexture.GetTall() );
+ m_Texture[ iTexture ].MarkAllClean();
+ byte *pTexture = m_Texture[ iTexture ].GetPixels();
+
+ // overlay a popup if we have one
+ if ( BPopupVisibleAndPainted() )
+ {
+ // composite in the popup texture, clipped to the browser width/height, and mark those pixels dirty
+
+ int nCopyWide = MIN( GetPopupWide(), m_Texture[ iTexture ].GetWide() - GetPopupX() );
+ int nCopyTall = MIN( GetPopupTall(), m_Texture[ iTexture ].GetTall() - GetPopupY() );
+
+ // Notify the main thread that the composited popup region is dirty
+ m_UpdateRect.MarkDirtyRect( GetPopupX(), GetPopupY(), GetPopupX() + nCopyWide, GetPopupY() + nCopyTall );
+
+ byte *pCurTextureByte = pTexture;
+ pCurTextureByte += ( GetPopupY() * m_Texture[ iTexture ].GetWide() * 4 ); // move ahead to the right row
+ pCurTextureByte += ( GetPopupX() * 4 ); // now offset into the edge as needed
+
+ const byte *pPopupTexture = PPopupTextureData();
+ for ( int iRow = 0; iRow < nCopyTall; iRow++ )
+ {
+ Q_memcpy( pCurTextureByte, pPopupTexture, nCopyWide*4 );
+ pCurTextureByte += ( m_Texture[ iTexture ].GetWide() * 4 ); // move ahead one row in both images
+ pPopupTexture += ( GetPopupWide() * 4 );
+ }
+ }
+
+ return pTexture;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: true if we have a free slot in our paint buffers
+//-----------------------------------------------------------------------------
+bool CChromePainter::BPaintBufferAvailable()
+{
+ return (m_MainTexture.GetWide() > 0 && m_MainTexture.GetTall() > 0) && !( m_iTexturesInFlightBits & (1<<m_iNextTexture) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: copy off the current popup texture so we can hand it off to the main thread
+//-----------------------------------------------------------------------------
+const byte *CChromePainter::PPopupTextureDataCached()
+{
+ m_PopupTextureCache.EnsureCount( m_PopupTexture.Count() );
+ Q_memcpy( m_PopupTextureCache.Base(), m_PopupTexture.Base(), m_PopupTexture.Count() );
+ return m_PopupTextureCache.Base();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Client implementation of the browser handler class
+//-----------------------------------------------------------------------------
+#pragma warning( push )
+#pragma warning( disable : 4355 ) // 'this' : used in base member initializer list
+CClientHandler::CClientHandler( int iBrowser, const char *pchUserAgent, uint16 nSerial ) : m_Painter( this )
+{
+ m_nSerial = nSerial;
+ m_iBrowser = iBrowser;
+ m_nExpectedWide = m_nExpectedTall = 0;
+ m_szUserAgentExtras[0] = 0;
+ m_Browser = NULL;
+ m_bShowingToolTip = false;
+ m_strUserAgent = pchUserAgent;
+ m_bPendingPaint = false;
+ m_nMouseX = 0;
+ m_nMouseY = 0;
+ m_nMouseScrolledX = 0;
+ m_nMouseScrolledY = 0;
+ m_bMouseFocus = false;
+ m_bBrowserClosing = false;
+ m_nPageSerial = 0;
+ m_nPendingPageSerial = 0;
+ m_Painter.AddRef();
+ memset( &m_CachedHScroll, 0, sizeof( m_CachedHScroll ) );
+ memset( &m_CachedVScroll, 0, sizeof( m_CachedVScroll ) );
+}
+#pragma warning( pop )
+
+
+//-----------------------------------------------------------------------------
+// Purpose: destructor
+//-----------------------------------------------------------------------------
+CClientHandler::~CClientHandler()
+{
+ Assert( m_Browser == NULL );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Event called to request a new tab is created. The |parentBrowser| parameter
+// will point to the parent browser window, if any. The |foreground| parameter
+// will be true if the new tab should take the foreground. If you create the window
+// yourself you should populate the window handle member of |createInfo| and
+// return RV_HANDLED. Otherwise, return RV_CONTINUE and the framework may
+// create a tab. By default, a newly created tab will receive the
+// same handler as the parent window. To change the handler for the new
+// window modify the object that |handler| points to.
+//-----------------------------------------------------------------------------
+bool CClientHandler::OnNewTab(CefRefPtr<CefBrowser> parentBrowser,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ const CefString& url,
+ bool bForeground,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings )
+{
+ CHTMLProtoBufMsg<CMsgOpenNewTab> cmd( eHTMLCommands_OpenNewTab );
+ cmd.Body().set_url( url.c_str() );
+ cmd.Body().set_bforeground( bForeground );
+
+ DISPATCH_MESSAGE( eHTMLCommands_OpenNewTab );
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Called before a new popup window is created. The |parentBrowser| parameter
+// will point to the parent browser window. The |popupFeatures| parameter will
+// contain information about the style of popup window requested. Return false
+// to have the framework create the new popup window based on the parameters
+// in |windowInfo|. Return true to cancel creation of the popup window. By
+// default, a newly created popup window will have the same client and
+// settings as the parent window. To change the client for the new window
+// modify the object that |client| points to. To change the settings for the
+// new window modify the |settings| structure.
+//-----------------------------------------------------------------------------
+bool CClientHandler::OnBeforePopup(CefRefPtr<CefBrowser> parentBrowser,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ const CefString& url,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings)
+{
+ // If it's a steam:// url we already have a scheme handler installed, however that's too late to block the frame navigating
+ // and we'll end up loading a blank new window. So preempt that happening here and handle early returning that we've handled so
+ // chromium won't actually change URLs or navigate at all.
+ if ( url.size() > 0 && ( Q_stristr( url.c_str(), "steam://" ) || Q_stristr( url.c_str(), "steambeta://" ) ) && Q_stristr( url.c_str(), "/close" ) == NULL )
+ {
+ CStrAutoEncode urlString( url.c_str() );
+ CHTMLProtoBufMsg<CMsgOpenSteamURL> cmd( eHTMLCommands_OpenSteamURL );
+ cmd.Body().set_url( urlString.ToString() );
+ DISPATCH_MESSAGE( eHTMLCommands_OpenSteamURL );
+
+ return true;
+ }
+
+ CStrAutoEncode urlString( url.c_str() );
+ static bool bInPopup = false;
+ // if we get an empty url string when loading a new popup page just don't load it, we don't support the make a
+ // new popup and .write() into the buffer to make the contents because we want to make a whole new VGUI HTML object
+ // that contains the webkit widget for that popup, not allow this inline one
+ if ( urlString.ToString() && Q_strlen( urlString.ToString() ) > 0 )
+ {
+ if ( !bInPopup )
+ {
+ bInPopup = true;
+ CHTMLProtoBufMsg<CMsgPopupHTMLWindow> cmd( eHTMLCommands_PopupHTMLWindow );
+ cmd.Body().set_url( urlString.ToString() );
+ if ( popupFeatures.xSet )
+ cmd.Body().set_x( popupFeatures.x );
+ if ( popupFeatures.ySet )
+ cmd.Body().set_y( popupFeatures.y );
+ if ( popupFeatures.widthSet )
+ cmd.Body().set_wide( popupFeatures.width );
+ if ( popupFeatures.heightSet )
+ cmd.Body().set_tall( popupFeatures.height );
+
+ DISPATCH_MESSAGE( eHTMLCommands_PopupHTMLWindow );
+ bInPopup = false;
+ return true;
+ }
+ }
+ if ( !bInPopup )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Event called after a new window is created. The return value is currently
+// ignored.
+//-----------------------------------------------------------------------------
+void CClientHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser)
+{
+ Lock();
+ if ( !m_Browser )
+ {
+ // We need to keep the main child window, but not popup windows
+ m_Browser = browser;
+ browser->SetShowScrollBars( false );
+ SetBrowserAgent( browser );
+ if ( m_nExpectedWide > 0 && m_nExpectedTall > 0 )
+ browser->SetSize( PET_VIEW, m_nExpectedWide, m_nExpectedTall );
+
+ CHTMLProtoBufMsg<CMsgBrowserReady> cmd( eHTMLCommands_BrowserReady );
+ DISPATCH_MESSAGE( eHTMLCommands_BrowserReady );
+ }
+ Unlock();
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Event called when the page title changes. The return value is currently
+// ignored.
+//-----------------------------------------------------------------------------
+void CClientHandler::OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title)
+{
+ if ( !title.empty() )
+ {
+ CHTMLProtoBufMsg<CMsgSetHTMLTitle> cmd( eHTMLCommands_SetHTMLTitle );
+ cmd.Body().set_title( title );
+
+ DISPATCH_MESSAGE( eHTMLCommands_SetHTMLTitle );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Event called before browser navigation. The client has an opportunity to
+// modify the |request| object if desired. Return RV_HANDLED to cancel
+// navigation.
+//-----------------------------------------------------------------------------
+bool CClientHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ NavType navType,
+ bool isRedirect,
+ bool isNewTabRequest
+ )
+{
+ std::string sURL = request->GetURL();
+
+ // If it's a steam:// url we already have a scheme handler installed, however that's too late to block the frame navigating
+ // and we'll end up loading a blank page. So preempt that happening here and handle early returning that we've handled so
+ // chromium won't actually change URLs or navigate at all.
+ if ( sURL.size() > 0 && (sURL.find( "steam://" ) == 0 || sURL.find( "steambeta://" ) == 0) && sURL.find( "/close" ) == std::wstring::npos )
+ {
+ CHTMLProtoBufMsg<CMsgOpenSteamURL> cmd( eHTMLCommands_OpenSteamURL );
+ cmd.Body().set_url( CStrAutoEncode( request->GetURL().c_str() ).ToString() );
+ DISPATCH_MESSAGE( eHTMLCommands_OpenSteamURL );
+
+ return true ;
+ }
+
+ if ( isNewTabRequest )
+ return false;
+
+ // We only care about these on the main frame
+ if( !frame.get() || !frame->IsMain() )
+ return false;
+
+ if ( request->GetPostData() )
+ {
+ CefPostData::ElementVector elements;
+ request->GetPostData()->GetElements( elements );
+ CefPostData::ElementVector::const_iterator it = elements.begin();
+ m_strPostData = "";
+ CUtlVector<char> vecPostBytes;
+ while ( it != elements.end() )
+ {
+ if ( it->get()->GetType() == PDE_TYPE_BYTES )
+ {
+ size_t nBytes = it->get()->GetBytesCount();
+ int curInsertPos = vecPostBytes.Count();
+ vecPostBytes.EnsureCount( curInsertPos + nBytes + 1 );
+ it->get()->GetBytes( nBytes, vecPostBytes.Base() + curInsertPos );
+ vecPostBytes[ curInsertPos + nBytes ] = 0;
+ }
+ it++;
+ }
+
+ m_strPostData = vecPostBytes.Base();
+ }
+ else
+ m_strPostData = "";
+
+ CStrAutoEncode strURL( sURL.c_str() );
+
+ if ( isRedirect )
+ m_strLastRedirectURL = strURL.ToString();
+
+ bool rv = false;
+
+ {
+ // scope this so the wait below doesn't keep this allocation on the stack
+ CHTMLProtoBufMsg<CMsgStartRequest> cmd( eHTMLCommands_StartRequest );
+ cmd.Body().set_url( strURL.ToString() );
+ CefString frameName = frame->GetName();
+ if ( !frameName.empty() )
+ cmd.Body().set_target( frameName.c_str() );
+ cmd.Body().set_postdata( m_strPostData );
+ cmd.Body().set_bisredirect( isRedirect );
+
+ DISPATCH_MESSAGE( eHTMLCommands_StartRequest );
+ }
+
+ HTMLCommandBuffer_t *pBuf = g_CEFThread.BWaitForCommand( eHTMLCommands_StartRequestResponse, m_iBrowser );
+ if ( pBuf )
+ {
+ CHTMLProtoBufMsg< CMsgStartRequestResponse > cmd( eHTMLCommands_StartRequestResponse );
+ if ( cmd.BDeserializeCrossProc( &pBuf->m_Buffer ) )
+ {
+ if ( !cmd.BodyConst().ballow() )
+ rv = true ;
+ }
+ g_CEFThread.ReleaseCommandBuffer( pBuf );
+ }
+
+ if ( m_Snapshot.m_sURLSnapshot.IsValid() )
+ m_Snapshot.m_flRequestTimeout = Plat_FloatTime(); // before we change URL lets queue up a snapshot for the next paint
+
+ return rv;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Event called when the browser begins loading a page. The |frame| pointer
+// will be empty if the event represents the overall load status and not the
+// load status for a particular frame. The return value is currently ignored.
+//-----------------------------------------------------------------------------
+void CClientHandler::OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame, bool bIsNewNavigation )
+{
+ if ( !frame.get() )
+ return;
+
+ {
+ if ( !frame->IsMain() )
+ return;
+
+ std::wstring sURL = frame->GetURL();
+ if ( sURL.empty() )
+ return;
+
+ CStrAutoEncode url( sURL.c_str() );
+ m_strCurrentUrl = url.ToString();
+
+ if ( m_strCurrentUrl.IsEmpty() )
+ return;
+
+ bool bIsRedirect = false;
+ if ( m_strCurrentUrl == m_strLastRedirectURL )
+ bIsRedirect = true;
+
+ CHTMLProtoBufMsg<CMsgURLChanged> cmd( eHTMLCommands_URLChanged );
+ cmd.Body().set_url( url.ToString() );
+ cmd.Body().set_bnewnavigation( bIsNewNavigation );
+
+ if ( !m_strPostData.IsEmpty() )
+ cmd.Body().set_postdata( m_strPostData.String() );
+
+ cmd.Body().set_bisredirect( bIsRedirect );
+ CefString frameName = frame->GetName();
+ if ( !frameName.empty() )
+ cmd.Body().set_pagetitle( frameName.c_str() );
+
+ DISPATCH_MESSAGE( eHTMLCommands_URLChanged );
+ }
+
+ {
+ CHTMLProtoBufMsg<CMsgCanGoBackAndForward> cmd( eHTMLCommands_CanGoBackandForward );
+ cmd.Body().set_bgoback( browser->CanGoBack() );
+ cmd.Body().set_bgoforward( browser->CanGoForward() );
+ DISPATCH_MESSAGE( eHTMLCommands_CanGoBackandForward );
+ }
+
+ m_nPageSerial = m_nPendingPageSerial;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Event called when the browser is done loading a page. The |frame| pointer
+// will be empty if the event represents the overall load status and not the
+// load status for a particular frame. This event will be generated
+// irrespective of whether the request completes successfully. The return
+// value is currently ignored.
+//-----------------------------------------------------------------------------
+void CClientHandler::OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode, CefRefPtr<CefRequest> request )
+{
+ // We only care about these on the main frame
+ if( !frame.get() || !frame->IsMain() )
+ return;
+
+ {
+ CHTMLProtoBufMsg<CMsgFinishedRequest> cmd( eHTMLCommands_FinishedRequest );
+ cmd.Body().set_url( CStrAutoEncode( browser->GetMainFrame()->GetURL().c_str() ).ToString() );
+ CefString frameName = browser->GetMainFrame()->GetName();
+ if ( !frameName.empty() )
+ cmd.Body().set_pagetitle( frameName.c_str() );
+
+ if ( request.get() )
+ {
+ CefRequest::HeaderMap headerMap;
+ request->GetHeaderMap( headerMap );
+
+ CefRequest::HeaderMap::const_iterator it;
+ for(it = headerMap.begin(); it != headerMap.end(); ++it)
+ {
+ CHTMLHeader *pHeader = cmd.Body().add_headers();
+ if ( !it->first.empty() )
+ pHeader->set_key( it->first.c_str() );
+ if ( !it->second.empty() )
+ pHeader->set_value( it->second.c_str() );
+ }
+
+ CefRefPtr<CefSecurityDetails> pRefSecurityDetails = request->SecurityDetails();
+ CHTMLPageSecurityInfo *pSecurityInfo = cmd.Body().mutable_security_info();
+ if ( pRefSecurityDetails.get() )
+ {
+ pSecurityInfo->set_bissecure( pRefSecurityDetails->BIsSecure() );
+ pSecurityInfo->set_bhascerterror( pRefSecurityDetails->BHasCertError() );
+ pSecurityInfo->set_issuername( pRefSecurityDetails->PchCertIssuer() );
+ pSecurityInfo->set_certname( pRefSecurityDetails->PchCertCommonName() );
+ pSecurityInfo->set_certexpiry( pRefSecurityDetails->TCertExpiry() );
+ pSecurityInfo->set_bisevcert( pRefSecurityDetails->BIsEVCert() );
+ pSecurityInfo->set_ncertbits( pRefSecurityDetails->NCertBits() );
+ }
+ else
+ {
+ pSecurityInfo->set_bissecure( false );
+ }
+ }
+
+ DISPATCH_MESSAGE( eHTMLCommands_FinishedRequest );
+ }
+
+ {
+ CHTMLProtoBufMsg<CMsgCanGoBackAndForward> cmd( eHTMLCommands_CanGoBackandForward );
+ cmd.Body().set_bgoback( browser->CanGoBack() );
+ cmd.Body().set_bgoforward( browser->CanGoForward() );
+ DISPATCH_MESSAGE( eHTMLCommands_CanGoBackandForward );
+ }
+
+ if ( m_Snapshot.m_sURLSnapshot.IsValid() )
+ m_Snapshot.m_flRequestTimeout = Plat_FloatTime(); // finished page load, lets queue up a snapshot for the next paint
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Called when the browser fails to load a resource. |errorCode| is the
+// error code number and |failedUrl| is the URL that failed to load. To
+// provide custom error text assign the text to |errorText| and return
+// RV_HANDLED. Otherwise, return RV_CONTINUE for the default error text.
+//-----------------------------------------------------------------------------
+bool CClientHandler::OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& failedUrl,
+ CefString& errorText)
+{
+ // If it's a steam:// url we always get an error, but we handle it ok internally already, just ignore
+ if ( failedUrl.size() > 0 && ( Q_stristr( failedUrl.c_str(), "steam://" ) || Q_stristr( failedUrl.c_str(), "steambeta://" ) ) )
+ return false;
+
+ const char *pchDetail = NULL;
+ switch ( errorCode )
+ {
+ case ERR_ABORTED:
+ // We'll get this in cases where we just start another URL before finishing a previous and such, don't show it.
+ return false;
+ break;
+ case ERR_CACHE_MISS:
+ pchDetail = m_sErrorCacheMiss;
+ break;
+ case ERR_UNKNOWN_URL_SCHEME:
+ case ERR_INVALID_URL:
+ pchDetail = m_sErrorBadURL;
+ break;
+ case ERR_CONNECTION_CLOSED:
+ case ERR_CONNECTION_RESET:
+ case ERR_CONNECTION_REFUSED:
+ case ERR_CONNECTION_ABORTED:
+ case ERR_CONNECTION_FAILED:
+ case ERR_NAME_NOT_RESOLVED:
+ case ERR_INTERNET_DISCONNECTED:
+ case ERR_CONNECTION_TIMED_OUT:
+ pchDetail = m_sErrorConnectionProblem;
+ break;
+ case ERR_UNEXPECTED_PROXY_AUTH:
+ case ERR_EMPTY_PROXY_LIST:
+ pchDetail = m_sErrorProxyProblem;
+ break;
+ default:
+ pchDetail = m_sErrorUnknown;
+ break;
+ }
+
+ char rgchError[4096];
+ Q_snprintf( rgchError, Q_ARRAYSIZE( rgchError ),
+ "<html>"
+ "<head>"
+ "<title>%s</title>"
+ "</head>"
+ "<body style=\"background-color:#2D2D2B; color=#939393; font-family: Arial,Helvetica; margin:20px;\">"
+ "<h1 style=\"color: #E1E1E1; font-size: 26px; font-weight: normal\">%s%d</h1>"
+ "<p style=\"line-height: 17px; margin-top:10px; color: #939393;\">"
+ "%s"
+ "</p>"
+ "</body>"
+ "</html>",
+ m_sErrorTitle.String(),
+ m_sErrorHeader.String(),
+ errorCode,
+ pchDetail );
+
+ errorText = rgchError;
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Event called before a resource is loaded. To allow the resource to load
+// normally return RV_CONTINUE. To redirect the resource to a new url
+// populate the |redirectUrl| value and return RV_CONTINUE. To specify
+// data for the resource return a CefStream object in |resourceStream|, set
+// 'mimeType| to the resource stream's mime type, and return RV_CONTINUE.
+// To cancel loading of the resource return RV_HANDLED.
+//-----------------------------------------------------------------------------
+bool CClientHandler::OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefRequest> request,
+ CefString& redirectUrl,
+ CefRefPtr<CefStreamReader>& resourceStream,
+ CefRefPtr<CefResponse> response,
+ int loadFlags)
+{
+ CHTMLProtoBufMsg<CMsgLoadingResource> cmd( eHTMLCommands_LoadingResource );
+ cmd.Body().set_url( CStrAutoEncode( request->GetURL().c_str() ).ToString() );
+ DISPATCH_MESSAGE( eHTMLCommands_LoadingResource );
+
+ // insert custom headers
+ CefRequest::HeaderMap headerMap;
+ request->GetHeaderMap( headerMap );
+ FOR_EACH_VEC( m_vecHeaders, i )
+ {
+ headerMap.insert( m_vecHeaders[i] );
+ }
+
+ request->SetHeaderMap( headerMap );
+
+ return false;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Run a JS alert message. Return RV_CONTINUE to display the default alert
+// or RV_HANDLED if you displayed a custom alert.
+//-----------------------------------------------------------------------------
+bool CClientHandler::OnJSAlert(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& message)
+{
+ {
+ // scope this so the wait below doesn't keep this allocation on the stack
+ CHTMLProtoBufMsg<CMsgJSAlert> cmd( eHTMLCommands_JSAlert );
+ cmd.Body().set_message( message.c_str() );
+ DISPATCH_MESSAGE( eHTMLCommands_JSAlert );
+ }
+
+ HTMLCommandBuffer_t *pBuf = g_CEFThread.BWaitForCommand( eHTMLCommands_JSDialogResponse, m_iBrowser );
+ if ( pBuf )
+ {
+ CHTMLProtoBufMsg< CMsgJSDialogResponse > cmd( eHTMLCommands_JSDialogResponse );
+ g_CEFThread.ReleaseCommandBuffer( pBuf );
+ }
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Run a JS confirm request. Return RV_CONTINUE to display the default alert
+// or RV_HANDLED if you displayed a custom alert. If you handled the alert
+// set |CefHandler::RetVal| to true if the user accepted the confirmation.
+//-----------------------------------------------------------------------------
+bool CClientHandler::OnJSConfirm(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& message,
+ bool& retval)
+{
+ {
+ // scope this so the wait below doesn't keep this allocation on the stack
+ CHTMLProtoBufMsg<CMsgJSConfirm> cmd( eHTMLCommands_JSConfirm );
+ cmd.Body().set_message( message.c_str() );
+ DISPATCH_MESSAGE( eHTMLCommands_JSConfirm );
+ }
+
+ retval = false;
+
+ HTMLCommandBuffer_t *pBuf = g_CEFThread.BWaitForCommand( eHTMLCommands_JSDialogResponse, m_iBrowser );
+ if ( pBuf )
+ {
+ CHTMLProtoBufMsg< CMsgJSDialogResponse > cmd( eHTMLCommands_JSDialogResponse );
+ if ( cmd.BDeserializeCrossProc( &pBuf->m_Buffer ) )
+ {
+ if ( cmd.BodyConst().result() )
+ retval = true ;
+ }
+
+ g_CEFThread.ReleaseCommandBuffer( pBuf );
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Run a JS prompt request. Return RV_CONTINUE to display the default prompt
+// or RV_HANDLED if you displayed a custom prompt. If you handled the prompt
+// set |CefHandler::RetVal| to true if the user accepted the prompt and request and
+// |result| to the resulting value.
+//-----------------------------------------------------------------------------
+bool CClientHandler::OnJSPrompt(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& message,
+ const CefString& defaultValue,
+ bool& retval,
+ CefString& result)
+{
+ retval = false; // just don't pop JS prompts for now
+ result = defaultValue;
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Called just before a window is closed.
+//-----------------------------------------------------------------------------
+void CClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser)
+{
+ Lock();
+ if ( m_Browser )
+ {
+ // Free the browser pointer so that the browser can be destroyed
+ m_Browser = NULL;
+
+ if ( !m_bBrowserClosing )
+ {
+ CHTMLProtoBufMsg<CMsgClose> cmd( eHTMLCommands_Close );
+ DISPATCH_MESSAGE( eHTMLCommands_Close );
+ }
+ }
+ Unlock();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: show a html popup, a pulldown menu or the like
+//-----------------------------------------------------------------------------
+void CChromePainter::OnPopupShow(CefRefPtr<CefBrowser> browser, bool show)
+{
+ m_bPopupVisible = show;
+ int m_iBrowser = m_pParent->m_iBrowser;
+ if ( show )
+ {
+ CHTMLProtoBufMsg<CMsgShowPopup> cmd( eHTMLCommands_ShowPopup );
+ DISPATCH_MESSAGE( eHTMLCommands_ShowPopup );
+ }
+ else
+ {
+ CHTMLProtoBufMsg<CMsgHidePopup> cmd( eHTMLCommands_HidePopup );
+ DISPATCH_MESSAGE( eHTMLCommands_HidePopup );
+
+ // redraw the buffered texture behind the rectangle that was previously composited
+ for ( size_t i = 0; i < Q_ARRAYSIZE( m_Texture ); ++i )
+ {
+ m_Texture[i].MarkDirtyRect( m_nPopupX, m_nPopupY, m_nPopupX + m_nPopupWide, m_nPopupY + m_nPopupTall );
+ }
+
+ // and notify the main thread to redraw the previously composited area as well
+ m_UpdateRect.MarkDirtyRect( m_nPopupX, m_nPopupY, m_nPopupX + m_nPopupWide, m_nPopupY + m_nPopupTall );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: make the popup this big
+//-----------------------------------------------------------------------------
+void CChromePainter::OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect )
+{
+ if ( m_bPopupVisible )
+ {
+ // redraw the buffered texture behind the rectangle that was previously composited
+ for ( size_t i = 0; i < Q_ARRAYSIZE( m_Texture ); ++i )
+ {
+ m_Texture[i].MarkDirtyRect( m_nPopupX, m_nPopupY, m_nPopupX + m_nPopupWide, m_nPopupY + m_nPopupTall );
+ }
+
+ // and notify the main thread to redraw the previously composited area as well
+ m_UpdateRect.MarkDirtyRect( m_nPopupX, m_nPopupY, m_nPopupX + m_nPopupWide, m_nPopupY + m_nPopupTall );
+ }
+
+ m_bPopupVisible = true;
+ m_nPopupX = rect.x;
+ m_nPopupWide = rect.width;
+ m_nPopupY = rect.y;
+ m_nPopupTall = rect.height;
+
+ int m_iBrowser = m_pParent->m_iBrowser;
+ CHTMLProtoBufMsg<CMsgSizePopup> cmd( eHTMLCommands_SizePopup );
+ cmd.Body().set_x( m_nPopupX );
+ cmd.Body().set_y( m_nPopupY );
+ cmd.Body().set_wide( m_nPopupWide );
+ cmd.Body().set_tall( m_nPopupTall );
+ DISPATCH_MESSAGE( eHTMLCommands_SizePopup );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: cef has status text for us
+//-----------------------------------------------------------------------------
+void CClientHandler::OnStatusMessage(CefRefPtr<CefBrowser> browser, const CefString& value, StatusType type)
+{
+ if ( !value.empty() )
+ {
+ CHTMLProtoBufMsg<CMsgStatusText> cmd( eHTMLCommands_StatusText );
+ cmd.Body().set_text( value.c_str() );
+ DISPATCH_MESSAGE( eHTMLCommands_StatusText );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: show tooltip please
+//-----------------------------------------------------------------------------
+bool CClientHandler::OnTooltip(CefRefPtr<CefBrowser> browser, CefString& text)
+{
+ if ( !m_bShowingToolTip && !text.empty() )
+ {
+ m_bShowingToolTip = true;
+ m_strToolTip = text.c_str();
+
+ CHTMLProtoBufMsg<CMsgShowToolTip> cmd( eHTMLCommands_ShowToolTip );
+ cmd.Body().set_text( m_strToolTip );
+ DISPATCH_MESSAGE( eHTMLCommands_ShowToolTip );
+ }
+ else if ( m_bShowingToolTip && !text.empty() )
+ {
+ if ( m_strToolTip != text.c_str() )
+ {
+ m_strToolTip = text.c_str();
+
+ CHTMLProtoBufMsg<CMsgUpdateToolTip> cmd( eHTMLCommands_UpdateToolTip );
+ cmd.Body().set_text( m_strToolTip );
+ DISPATCH_MESSAGE( eHTMLCommands_UpdateToolTip );
+ }
+ }
+ else if ( m_bShowingToolTip )
+ {
+ CHTMLProtoBufMsg<CMsgHideToolTip> cmd( eHTMLCommands_HideToolTip );
+ DISPATCH_MESSAGE( eHTMLCommands_HideToolTip );
+
+ m_bShowingToolTip = false;
+ m_strToolTip.Clear();
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: set the mouse cursor to this image
+//-----------------------------------------------------------------------------
+bool CChromePainter::OnSetCursor( CefRefPtr<CefBrowser> browser, const CursorType type, const void *pchIconData, int iWide, int iTall, int xHotSpot, int yHotSpot )
+{
+ int m_iBrowser = m_pParent->m_iBrowser;
+ CHTMLProtoBufMsg<CMsgSetCursor> cmd( eHTMLCommands_SetCursor );
+
+ EMouseCursor cursor;
+ switch( type )
+ {
+ case TypeCustom:
+ cursor = dc_last;
+ break;
+ case TypeCross:
+ cursor = dc_crosshair;
+ break;
+ case TypeHand:
+ cursor = dc_hand;
+ break;
+ case TypeIBeam:
+ cursor = dc_ibeam;
+ break;
+ case TypeWait:
+ cursor = dc_hourglass;
+ break;
+ case TypeHelp:
+ cursor = dc_help;
+ break;
+ case TypeEastResize:
+ cursor = dc_sizee;
+ break;
+ case TypeNorthResize:
+ cursor = dc_sizen;
+ break;
+ case TypeNorthEastResize:
+ cursor = dc_sizene;
+ break;
+ case TypeNorthWestResize:
+ cursor = dc_sizenw;
+ break;
+ case TypeSouthResize:
+ cursor = dc_sizes;
+ break;
+ case TypeSouthEastResize:
+ cursor = dc_sizese;
+ break;
+ case TypeSouthWestResize:
+ cursor = dc_sizesw;
+ break;
+ case TypeNorthSouthResize:
+ cursor = dc_sizes;
+ break;
+ case TypeEastWestResize:
+ cursor = dc_sizew;
+ break;
+ case TypeNorthEastSouthWestResize:
+ cursor = dc_sizeall;
+ break;
+ case TypeColumnResize:
+ cursor = dc_colresize;
+ break;
+ case TypeRowResize:
+ cursor = dc_rowresize;
+ break;
+ case TypeMiddlePanning:
+ cursor = dc_middle_pan;
+ break;
+ case TypeEastPanning:
+ cursor = dc_east_pan;
+ break;
+ case TypeNorthPanning:
+ cursor = dc_north_pan;
+ break;
+ case TypeNorthEastPanning:
+ cursor = dc_north_east_pan;
+ break;
+ case TypeNorthWestPanning:
+ cursor = dc_north_west_pan;
+ break;
+ case TypeSouthPanning:
+ cursor = dc_south_pan;
+ break;
+ case TypeSouthEastPanning:
+ cursor = dc_south_east_pan;
+ break;
+ case TypeSouthWestPanning:
+ cursor = dc_south_west_pan;
+ break;
+ case TypeWestPanning:
+ cursor = dc_west_pan;
+ break;
+ case TypeMove:
+ cursor = dc_sizeall;
+ break;
+ case TypeVerticalText:
+ cursor = dc_verticaltext;
+ break;
+ case TypeCell:
+ cursor = dc_cell;
+ break;
+ case TypeContextMenu:
+ cursor = dc_none;
+ break;
+ case TypeAlias:
+ cursor = dc_alias;
+ break;
+ case TypeProgress:
+ cursor = dc_waitarrow;
+ break;
+ case TypeNoDrop:
+ cursor = dc_no;
+ break;
+ case TypeCopy:
+ cursor = dc_copycur;
+ break;
+ case TypeNone:
+ cursor = dc_none;
+ break;
+ case TypeNotAllowed:
+ cursor = dc_no;
+ break;
+ case TypeZoomIn:
+ cursor = dc_zoomin;
+ break;
+ case TypeZoomOut:
+ cursor = dc_zoomout;
+ break;
+ case TypePointer:
+ default:
+ cursor = dc_arrow;
+ }
+ cmd.Body().set_cursor( cursor );
+ cmd.Body().set_data( (uint32)pchIconData ); // we are relying on chrome keeping around the cursor data after this call completes, it does right now.
+ cmd.Body().set_wide( iWide );
+ cmd.Body().set_tall( iTall );
+ cmd.Body().set_xhotspot( xHotSpot );
+ cmd.Body().set_yhotspot( yHotSpot );
+ DISPATCH_MESSAGE( eHTMLCommands_SetCursor );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: file open dialog to be shown
+//-----------------------------------------------------------------------------
+bool CChromePainter::OnFileOpenDialog( CefRefPtr<CefBrowser> browser, bool bMultiSelect, const CefString &default_title, const CefString &default_file, CefWebFileChooserCallback *pCallback )
+{
+ if ( !pCallback )
+ return true;
+
+ int m_iBrowser = m_pParent->m_iBrowser;
+ {
+ // scope this so this allocation doesn't stay on the stack during validate
+ CHTMLProtoBufMsg<CMsgFileLoadDialog> cmd( eHTMLCommands_FileLoadDialog );
+ if ( !default_title.empty() )
+ cmd.Body().set_title( default_title );
+ if ( !default_file.empty() )
+ cmd.Body().set_initialfile( default_file );
+ DISPATCH_MESSAGE( eHTMLCommands_FileLoadDialog );
+ }
+
+ HTMLCommandBuffer_t *pBuf = g_CEFThread.BWaitForCommand( eHTMLCommands_FileLoadDialogResponse, m_iBrowser );
+ if ( pBuf )
+ {
+ CHTMLProtoBufMsg< CMsgFileLoadDialogResponse > cmd( eHTMLCommands_FileLoadDialogResponse );
+ if ( cmd.BDeserializeCrossProc( &pBuf->m_Buffer ) )
+ {
+ std::vector<std::wstring> files;
+ for ( int i = 0; i < cmd.BodyConst().files_size(); i++ )
+ {
+ if ( !cmd.BodyConst().files(i).empty() )
+ {
+ CPathString path( cmd.BodyConst().files(i).c_str() );
+ files.push_back( path.GetWCharPathPrePended() );
+ }
+ }
+
+ // if you have a DEBUG build and are crashing here it is because
+ // Chrome is a release library and the std::vector iterator isn't crossing
+ // the interface happyily. Build release and you will run fine.
+#if defined(DEBUG) && defined(WIN32)
+ Assert( !"File select dialog not available in debug due to STL debug/release issues\n" );
+#else
+ pCallback->OnFileChoose( files );
+#endif
+ }
+ g_CEFThread.ReleaseCommandBuffer( pBuf );
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: CEF is asking if it can show itself fullscreen
+//-----------------------------------------------------------------------------
+bool CChromePainter::OnEnterFullScreen( CefRefPtr<CefBrowser> browser )
+{
+ int m_iBrowser = m_pParent->m_iBrowser;
+ {
+ // scope this so this allocation doesn't stay on the stack during validate
+ CHTMLProtoBufMsg<CMsgRequestFullScreen> cmd( eHTMLCommands_RequestFullScreen );
+ DISPATCH_MESSAGE( eHTMLCommands_RequestFullScreen );
+ }
+
+ HTMLCommandBuffer_t *pBuf = g_CEFThread.BWaitForCommand( eHTMLCommands_RequestFullScreenResponse, m_iBrowser );
+ if ( pBuf )
+ {
+ CHTMLProtoBufMsg< CMsgRequestFullScreenResponse > cmd( eHTMLCommands_RequestFullScreenResponse );
+ if ( cmd.BDeserializeCrossProc( &pBuf->m_Buffer ) )
+ {
+ return cmd.BodyConst().ballow();
+ }
+ g_CEFThread.ReleaseCommandBuffer( pBuf );
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: cef is spewing to its console, print it
+//-----------------------------------------------------------------------------
+bool CChromePainter::OnExitFullScreen( CefRefPtr<CefBrowser> browser )
+{
+ int m_iBrowser = m_pParent->m_iBrowser;
+ {
+ // scope this so this allocation doesn't stay on the stack during validate
+ // tell the main thread we are exiting fullscreen
+ CHTMLProtoBufMsg<CMsgExitFullScreen> cmd( eHTMLCommands_ExitFullScreen );
+ DISPATCH_MESSAGE( eHTMLCommands_ExitFullScreen );
+ }
+
+ // BUGUBG - add a request/response here so you can disallow leaving fullscreen??
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: cef is spewing to its console, print it
+//-----------------------------------------------------------------------------
+bool CClientHandler::OnConsoleMessage(CefRefPtr<CefBrowser> browser,
+ const CefString& message,
+ const CefString& source,
+ int line)
+{
+ // the console is very chatty and doesn't provide useful information for us app developers, just for html/css editors, so lets ignore this for now
+ //Msg( "Browser Message: %s - %s:%d\n", message.c_str(), source.c_str(), line );
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: helper function to recurvisely search down the DOM for any input nodes and an input button name
+//-----------------------------------------------------------------------------
+void SearchForInputButtonAndOtherInputs_R( CefRefPtr<CefDOMNode> root, CefRefPtr<CefDOMNode> focusNode, bool &bHasMultipleTextInputNodes, CUtlString &sSearchButtonName, int nMaxRecurse )
+{
+ CefRefPtr<CefDOMNode> nodeChildren = root->GetFirstChild();
+ while ( nodeChildren.get() )
+ {
+ if ( !nodeChildren->IsSame( focusNode ) && nodeChildren->IsElement() )
+ {
+ CUtlString sElementType = nodeChildren->GetElementTagName().c_str();
+ if ( !Q_stricmp( "input", sElementType ) )
+ {
+ CUtlString sChildControlType = nodeChildren->GetFormControlElementType().c_str();
+ if ( sSearchButtonName.IsEmpty() && !Q_stricmp( sChildControlType, "submit" ) )
+ {
+ if ( nodeChildren->HasElementAttribute( "value" ) )
+ sSearchButtonName = nodeChildren->GetElementAttribute( "value" ).c_str();
+ }
+ else if ( !Q_stricmp( "text", sChildControlType ) || !Q_stricmp( "password", sChildControlType ) || !Q_stricmp( "email", sChildControlType ) )
+ {
+ //CefDOMNode::AttributeMap attrMap;
+ //nodeChildren->GetElementAttributes( attrMap );
+ if ( !nodeChildren->HasElementAttribute( "disabled" ) )
+ bHasMultipleTextInputNodes = true;
+ }
+ }
+ else if ( !Q_stricmp( "textarea", sElementType ) )
+ {
+ if ( !nodeChildren->HasElementAttribute( "disabled" ) )
+ bHasMultipleTextInputNodes = true;
+ }
+ else if ( nMaxRecurse > 0 /*&& !Q_stricmp( "div", sElementType ) || !Q_stricmp( "tr", sElementType ) || !Q_stricmp( "td", sElementType ) || !Q_stricmp( "table", sElementType ) || !Q_stricmp( "tbody", sElementType )*/ )
+ {
+ SearchForInputButtonAndOtherInputs_R( nodeChildren, focusNode, bHasMultipleTextInputNodes, sSearchButtonName, nMaxRecurse - 1 );
+ }
+ }
+ nodeChildren = nodeChildren->GetNextSibling();
+
+ if ( bHasMultipleTextInputNodes && sSearchButtonName.IsValid() )
+ break; // if we found both multiple nodes and a search button name we can bail early
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: a new node in the DOM has focus now
+//-----------------------------------------------------------------------------
+void CClientHandler::OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefDOMNode> node)
+{
+ VPROF_BUDGET( "CCEFThread - CClientHandler::OnFocusedNodeChanged()", VPROF_BUDGETGROUP_VGUI );
+
+ bool bIsInputNode = false;
+ CUtlString sElementType;
+ if ( node.get() )
+ sElementType = node->GetElementTagName().c_str();
+
+ CUtlString sName;
+ if ( node.get() )
+ sName = node->GetName().c_str();
+
+ CUtlString sSearchButtonName;
+ CUtlString sControlType;
+ bool bInputNode = !Q_stricmp( "input", sElementType );
+ bool bHasMultipleInputNodes = false;
+ if ( sElementType.IsValid() && ( bInputNode || !Q_stricmp( "textarea", sElementType ) ) )
+ {
+ sControlType = node->GetFormControlElementType().c_str();
+
+ // lets go searching for the submit button and grab the text it shows
+ bIsInputNode = true;
+ CefRefPtr<CefDOMNode> nodeParent = node->GetParent();
+ while( nodeParent.get() )
+ {
+ CUtlString sParentElementType = nodeParent->GetElementTagName().c_str();
+ if ( !Q_stricmp( "form", sParentElementType ) )
+ break;
+ nodeParent = nodeParent->GetParent();
+ }
+
+ if ( nodeParent.get() )
+ SearchForInputButtonAndOtherInputs_R( nodeParent, node, bHasMultipleInputNodes, sSearchButtonName, 32 );
+ }
+
+ if ( sElementType.IsValid() && !Q_stricmp( "div", sElementType ) )
+ {
+ if ( node->HasElementAttribute( "contenteditable" ) )
+ bIsInputNode = true;
+ }
+
+ if ( sSearchButtonName.IsEmpty() )
+ sSearchButtonName = "#Web_FormSubmit";
+
+ CHTMLProtoBufMsg<CMsgNodeHasFocus> cmd( eHTMLCommands_NodeGotFocus );
+ cmd.Body().set_binput( bIsInputNode );
+ if ( sName.IsValid() )
+ cmd.Body().set_name( sName );
+ if ( sElementType.IsValid() )
+ cmd.Body().set_elementtagname( sElementType );
+ if ( sSearchButtonName.IsValid() )
+ cmd.Body().set_searchbuttontext( sSearchButtonName );
+ cmd.Body().set_bhasmultipleinputs( bHasMultipleInputNodes );
+ if ( sControlType.IsValid() )
+ cmd.Body().set_input_type( sControlType );
+
+ DISPATCH_MESSAGE( eHTMLCommands_NodeGotFocus );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: a find has found matches on the page, feed back that info
+//-----------------------------------------------------------------------------
+void CClientHandler::OnFindResult(CefRefPtr<CefBrowser> browser,
+ int identifier,
+ int count,
+ const CefRect& selectionRect,
+ int activeMatchOrdinal,
+ bool finalUpdate)
+{
+ CHTMLProtoBufMsg<CMsgSearchResults> cmd( eHTMLCommands_SearchResults );
+ cmd.Body().set_activematch( activeMatchOrdinal );
+ cmd.Body().set_results( count );
+ DISPATCH_MESSAGE( eHTMLCommands_SearchResults );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: return a pointer to the CEF browser object
+//-----------------------------------------------------------------------------
+CefRefPtr<CefBrowser> CClientHandler::GetBrowser()
+{
+ return m_Browser;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CClientHandler::CloseBrowser()
+{
+ if ( m_Browser )
+ {
+ m_bBrowserClosing = true;
+ m_Browser->CloseBrowser();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CClientHandler::SetMouseLocation( int nMouseX, int nMouseY )
+{
+ m_nMouseX = nMouseX;
+ m_nMouseY = nMouseY;
+ if ( m_Browser.get() )
+ {
+ m_nMouseScrolledX = nMouseX + m_Browser->VerticalScroll();
+ m_nMouseScrolledY = nMouseY + m_Browser->HorizontalScroll();
+ m_bMouseFocus = true;
+ m_Browser->SendMouseMoveEvent( m_nMouseX, m_nMouseY, false );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: check if window has scrolled and generate a fake mouse move event
+// to force CEF to check for hover state changes (seems like a CEF bug...)
+//-----------------------------------------------------------------------------
+void CClientHandler::RefreshCEFHoverStatesAfterScroll()
+{
+ if ( m_Browser.get() && m_bMouseFocus )
+ {
+ int nScrolledX = m_nMouseX + m_Browser->VerticalScroll();
+ int nScrolledY = m_nMouseY + m_Browser->HorizontalScroll();
+ if ( nScrolledX != m_nMouseScrolledX || nScrolledY != m_nMouseScrolledY )
+ {
+ m_nMouseScrolledX = nScrolledX;
+ m_nMouseScrolledY = nScrolledY;
+ m_Browser->SendMouseMoveEvent( m_nMouseX, m_nMouseY, false );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: make the user agent for this browser
+//-----------------------------------------------------------------------------
+void CClientHandler::SetBrowserAgent( CefRefPtr<CefBrowser> browser )
+{
+ static bool bGotIEVersion = false;
+ static char rgchWindowsVersion[64] = "Windows NT 5.1"; // XP SP1
+ static char *rgchOS = "";
+
+ if ( !bGotIEVersion )
+ {
+#ifdef WIN32
+ rgchOS = "Windows";
+ // First get windows version
+ OSVERSIONINFO verInfo;
+ memset( &verInfo, 0, sizeof(OSVERSIONINFO) );
+ verInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+
+ if ( ::GetVersionEx( &verInfo ) )
+ {
+ // We only run on "Windows NT" os's, so we just need to append the major/minor version dynamically
+ Q_snprintf( rgchWindowsVersion, sizeof(rgchWindowsVersion), "Windows NT %u.%u", verInfo.dwMajorVersion, verInfo.dwMinorVersion );
+ //Log( "Windows Version is: %u.%u\n", verInfo.dwMajorVersion, verInfo.dwMinorVersion );
+ }
+
+#elif defined(OSX)
+ Q_snprintf( rgchWindowsVersion, sizeof(rgchWindowsVersion), "Macintosh" );
+ rgchOS = "Macintosh";
+#elif defined(LINUX)
+ Q_snprintf( rgchWindowsVersion, sizeof(rgchWindowsVersion), "X11" );// strange, but that's what Firefox uses
+ rgchOS = "Linux";
+#endif
+ }
+
+ // user agent is process wide for Chrome so you can only set it once and it appplies to everything you open
+ {
+ char szAgent[ 2048 ];
+ Q_snprintf( szAgent, sizeof(szAgent), m_strUserAgent.String(), rgchOS, rgchWindowsVersion, m_strUserAgentIdentifier.String(), sm_ulBuildID, m_szUserAgentExtras );
+ browser->SetUserAgent( szAgent );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: paint the cef control
+//-----------------------------------------------------------------------------
+void CClientHandler::Paint()
+{
+ Lock();
+ if ( m_Browser )
+ {
+ m_bPendingPaint |= m_Painter.BUpdated();
+ m_Painter.SetUpdated( false );
+ }
+ Unlock();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: did we have a paint that updated the texture buffer?
+//-----------------------------------------------------------------------------
+bool CClientHandler::BNeedsPaint()
+{
+ bool bVal = m_bPendingPaint;
+ m_bPendingPaint = false;
+ return bVal;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: get the texture data for the control
+//-----------------------------------------------------------------------------
+const byte *CClientHandler::PComposedTextureData( uint32 iTexture )
+{
+ VPROF_BUDGET( "CClientHandler::PTextureData", VPROF_BUDGETGROUP_VGUI );
+
+ return m_Painter.PComposedTextureData( iTexture );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: true if something valid has rendered (i.e not the blank page)
+//-----------------------------------------------------------------------------
+bool CClientHandler::IsVisuallyNonEmpty()
+{
+ if ( m_Browser )
+ return m_Browser->IsVisuallyNonEmpty();
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: set the loc strings to display on error
+//-----------------------------------------------------------------------------
+void CClientHandler::SetErrorStrings( const char *pchTitle, const char *pchHeader, const char *pchCacheMiss, const char *pchBadURL, const char *pchConnectionProblem,
+ const char *pchProxyProblem, const char *pchUnknown )
+{
+ m_sErrorTitle = pchTitle;
+ m_sErrorHeader = pchHeader;
+ m_sErrorCacheMiss = pchCacheMiss;
+ m_sErrorBadURL = pchBadURL;
+ m_sErrorConnectionProblem = pchConnectionProblem;
+ m_sErrorProxyProblem = pchProxyProblem;
+ m_sErrorUnknown = pchUnknown;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: the user wants us to take a screenshot of a page
+//-----------------------------------------------------------------------------
+void CClientHandler::RequestScreenShot( const CHTMLProtoBufMsg<CMsgSavePageToJPEG> &cmd )
+{
+ m_Snapshot.m_sURLSnapshot = cmd.BodyConst().url().c_str();
+ m_Snapshot.m_sFileNameSnapshot = cmd.BodyConst().filename().c_str();
+ m_Snapshot.m_nWide = cmd.BodyConst().width();
+ m_Snapshot.m_nTall = cmd.BodyConst().height();
+ m_Snapshot.m_flRequestTimeout = Plat_FloatTime() + k_flMaxScreenshotWaitTime;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: save a screenshot of the current html page to this file with this size
+//-----------------------------------------------------------------------------
+void CClientHandler::SavePageToJPEGIfNeeded( CefRefPtr<CefBrowser> browser, const byte *pRGBA, int wide, int tall )
+{
+ if ( m_Snapshot.m_sURLSnapshot.IsValid() && wide && tall
+ && m_Snapshot.m_sURLSnapshot == CStrAutoEncode( browser->GetMainFrame()->GetURL().c_str() ).ToString() )
+ {
+ VPROF_BUDGET( "CClientHandler::SavePageToJPEGIfNeeded", VPROF_BUDGETGROUP_TENFOOT );
+
+ CUtlBuffer bufRGB;
+
+ bufRGB.Put( pRGBA, wide * tall *4 );
+ if ( !BConvertRGBAToRGB( bufRGB, wide, tall ) )
+ return;
+
+ BResizeImageRGB( bufRGB, wide, tall, m_Snapshot.m_nWide, m_Snapshot.m_nTall );
+ // input format is actually BGRA so now swizzle to rgb
+ byte *pBGR = (byte *)bufRGB.Base();
+ for ( int i = 0; i < m_Snapshot.m_nTall; i++ )
+ {
+ for ( int j = 0; j < m_Snapshot.m_nWide; j++ )
+ {
+ char cR = pBGR[0];
+ pBGR[0] = pBGR[2];
+ pBGR[2] = cR;
+ pBGR += 3;
+ }
+ }
+
+ if ( !ConvertRGBToJpeg( m_Snapshot.m_sFileNameSnapshot, k_ScreenshotQuality, m_Snapshot.m_nWide, m_Snapshot.m_nTall, bufRGB ) )
+ return;
+
+ CHTMLProtoBufMsg<CMsgSavePageToJPEGResponse> cmd( eHTMLCommands_SavePageToJPEGResponse );
+ cmd.Body().set_url( m_Snapshot.m_sURLSnapshot );
+ cmd.Body().set_filename( m_Snapshot.m_sFileNameSnapshot );
+ DISPATCH_MESSAGE( eHTMLCommands_SavePageToJPEGResponse );
+
+ m_Snapshot.m_sURLSnapshot.Clear();
+ m_Snapshot.m_flRequestTimeout = 0.0f;
+
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: return the url located at this position if there is one
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadLinkAtPosition( const CHTMLProtoBufMsg<CMsgLinkAtPosition> &htmlCommand )
+{
+ CefString pchURL;
+ int iClient = 0;
+ int bLiveLink = false;
+ int bInput = false;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ if ( m_listClientHandlers[iClient]->GetBrowser() )
+ pchURL = m_listClientHandlers[iClient]->GetBrowser()->GetLinkAtPosition( htmlCommand.BodyConst().x(), htmlCommand.BodyConst().y(), bLiveLink, bInput );
+ }
+
+ CHTMLProtoBufMsg<CMsgLinkAtPositionResponse> cmd( eHTMLCommands_LinkAtPositionResponse );
+ cmd.Body().set_x( htmlCommand.BodyConst().x() );
+ cmd.Body().set_y( htmlCommand.BodyConst().y() );
+ cmd.Body().set_blivelink( bLiveLink>0 ? true: false );
+ cmd.Body().set_binput( bInput>0 ? true: false );
+ if ( !pchURL.empty() )
+ cmd.Body().set_url( pchURL );
+ int m_iBrowser = htmlCommand.BodyConst().browser_handle();
+ DISPATCH_MESSAGE( eHTMLCommands_LinkAtPositionResponse );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: zoom the screen to the element at this position
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadZoomToElementAtPosition( const CHTMLProtoBufMsg<CMsgZoomToElementAtPosition> &htmlCommand )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ if ( m_listClientHandlers[iClient]->GetBrowser() )
+ {
+ CefRect initialRect, finalRect;
+ float zoomLevel = m_listClientHandlers[iClient]->GetBrowser()->scalePageToFitElementAt(
+ htmlCommand.BodyConst().x(), htmlCommand.BodyConst().y(),
+ initialRect, finalRect );
+ int m_iBrowser = htmlCommand.BodyConst().browser_handle();
+ ThreadBrowserVerticalScrollBarSizeHelper( m_iBrowser, true );
+ ThreadBrowserHorizontalScrollBarSizeHelper( m_iBrowser, true );
+ {
+ CHTMLProtoBufMsg<CMsgZoomToElementAtPositionResponse> cmd( eHTMLCommands_ZoomToElementAtPositionResponse );
+ cmd.Body().set_zoom( zoomLevel );
+ cmd.Body().set_initial_x( initialRect.x );
+ cmd.Body().set_initial_y( initialRect.y );
+ cmd.Body().set_initial_width( initialRect.width );
+ cmd.Body().set_initial_height( initialRect.height );
+ cmd.Body().set_final_x( finalRect.x );
+ cmd.Body().set_final_y( finalRect.y );
+ cmd.Body().set_final_width( finalRect.width );
+ cmd.Body().set_final_height( finalRect.height );
+ DISPATCH_MESSAGE( eHTMLCommands_ZoomToElementAtPositionResponse );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: zoom the screen to the element at this position
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadZoomToFocusedElement( const CHTMLProtoBufMsg<CMsgZoomToFocusedElement> &htmlCommand )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ if ( m_listClientHandlers[iClient]->GetBrowser() )
+ {
+ CefRect initialRect, finalRect;
+ float zoomLevel = m_listClientHandlers[iClient]->GetBrowser()->scalePageToFocusedElement( htmlCommand.BodyConst().leftoffset(), htmlCommand.BodyConst().topoffset(), initialRect, finalRect );
+ int m_iBrowser = htmlCommand.BodyConst().browser_handle();
+ ThreadBrowserVerticalScrollBarSizeHelper( m_iBrowser, true );
+ ThreadBrowserHorizontalScrollBarSizeHelper( m_iBrowser, true );
+ {
+ CHTMLProtoBufMsg<CMsgZoomToElementAtPositionResponse> cmd( eHTMLCommands_ZoomToElementAtPositionResponse );
+ cmd.Body().set_zoom( zoomLevel );
+ cmd.Body().set_initial_x( initialRect.x );
+ cmd.Body().set_initial_y( initialRect.y );
+ cmd.Body().set_initial_width( initialRect.width );
+ cmd.Body().set_initial_height( initialRect.height );
+ cmd.Body().set_final_x( finalRect.x );
+ cmd.Body().set_final_y( finalRect.y );
+ cmd.Body().set_final_width( finalRect.width );
+ cmd.Body().set_final_height( finalRect.height );
+ DISPATCH_MESSAGE( eHTMLCommands_ZoomToElementAtPositionResponse );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: increment the scale factor on the page by an increment
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadSetPageScale( const CHTMLProtoBufMsg<CMsgScalePageToValue> &htmlCommand )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ CClientHandler *pHandler = m_listClientHandlers[iClient];
+ if ( pHandler->GetBrowser() )
+ {
+ int nPageHeightBefore = pHandler->GetBrowser()->VerticalScrollMax();
+ int nPageWidthBefore = pHandler->GetBrowser()->HorizontalScrollMax();
+
+ float zoomLevel = pHandler->GetBrowser()->setPageScaleFactor( htmlCommand.BodyConst().scale(), htmlCommand.BodyConst().x(), htmlCommand.BodyConst().y() );
+
+ int idx = m_mapSizeChangesPending.Find( htmlCommand.BodyConst().browser_handle() );
+ if ( idx == m_mapSizeChangesPending.InvalidIndex() )
+ {
+ SizeChange_t &sizeChange = m_mapSizeChangesPending [ m_mapSizeChangesPending.Insert( htmlCommand.BodyConst().browser_handle() ) ];
+ sizeChange.iBrowser = htmlCommand.BodyConst().browser_handle();
+ sizeChange.nBeforeHeight = nPageHeightBefore;
+ sizeChange.nBeforeWidth = nPageWidthBefore;
+ sizeChange.flNewZoom = zoomLevel;
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: fire off the details of any page scale changes we had pending from last frame
+//-----------------------------------------------------------------------------
+void CCEFThread::SendSizeChangeEvents()
+{
+ FOR_EACH_MAP_FAST( m_mapSizeChangesPending, i )
+ {
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( m_mapSizeChangesPending[i].iBrowser, iClient ) )
+ {
+ CClientHandler *pHandler = m_listClientHandlers[iClient];
+ if ( pHandler->GetBrowser() )
+ {
+ int nPageHeightAfter = pHandler->GetBrowser()->VerticalScrollMax();
+ int nPageWidthAfter = pHandler->GetBrowser()->HorizontalScrollMax();
+
+ int m_iBrowser = m_mapSizeChangesPending[i].iBrowser;
+
+ ThreadBrowserVerticalScrollBarSizeHelper( m_iBrowser, true );
+ ThreadBrowserHorizontalScrollBarSizeHelper( m_iBrowser, true );
+ {
+ CHTMLProtoBufMsg<CMsgScalePageToValueResponse> cmd( eHTMLCommands_ScaleToValueResponse );
+ cmd.Body().set_zoom( m_mapSizeChangesPending[i].flNewZoom );
+ cmd.Body().set_width_delta( nPageWidthAfter - m_mapSizeChangesPending[i].nBeforeWidth );
+ cmd.Body().set_height_delta( nPageHeightAfter - m_mapSizeChangesPending[i].nBeforeHeight );
+ DISPATCH_MESSAGE( eHTMLCommands_ScaleToValueResponse );
+ }
+ }
+ }
+ }
+ m_mapSizeChangesPending.RemoveAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: exit from fullscreen if in it
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadExitFullScreen( const CHTMLProtoBufMsg<CMsgExitFullScreen> &htmlCommand )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ m_listClientHandlers[ iClient ]->GetBrowser()->ExitFullScreen();
+ }
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: the user has requested we save this url to a file on local disk
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadSavePageToJPEG( const CHTMLProtoBufMsg<CMsgSavePageToJPEG> &htmlCommand )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ m_listClientHandlers[ iClient ]->RequestScreenShot( htmlCommand );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: mouse moved to this x,y on the page
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadMouseMove( const CHTMLProtoBufMsg<CMsgMouseMove> &htmlCommand )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ m_listClientHandlers[ iClient ]->SetMouseLocation( htmlCommand.BodyConst().x(), htmlCommand.BodyConst().y() );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: mouse left the control, tell cef
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadMouseLeave( const CHTMLProtoBufMsg<CMsgMouseLeave> &htmlCommand )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ CefRefPtr<CefBrowser> browser = m_listClientHandlers[ iClient ]->GetBrowser();
+ if ( !browser.get() )
+ return;
+
+ m_listClientHandlers[ iClient ]->SetMouseFocus( false );
+
+ int mx, my;
+ m_listClientHandlers[ iClient ]->GetMouseLocation( mx, my );
+ browser->SendMouseMoveEvent( mx, my, true );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: helper to convert UI mouse codes to CEF ones
+//-----------------------------------------------------------------------------
+CefBrowser::MouseButtonType ConvertMouseCodeToCEFCode( int code )
+{
+ // BUGBUG
+ switch( code )
+ {
+ case 0:
+ return MBT_LEFT;
+ break;
+ case 1:
+ return MBT_RIGHT;
+ break;
+ case 2:
+ return MBT_MIDDLE;
+ break;
+ default:
+ return MBT_LEFT;
+ break;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: mouse button pressed
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadMouseButtonDown( const CHTMLProtoBufMsg<CMsgMouseDown> &htmlCommand )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+
+ CefRefPtr<CefBrowser> browser = m_listClientHandlers[ iClient ]->GetBrowser();
+ if ( !browser.get() )
+ return;
+ int nMouseX, nMouseY;
+ m_listClientHandlers[ iClient ]->GetMouseLocation( nMouseX, nMouseY );
+
+ browser->SendMouseClickEvent( nMouseX, nMouseY, ConvertMouseCodeToCEFCode( htmlCommand.BodyConst().mouse_button() ), false, 1 );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: mouse button released
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadMouseButtonUp( const CHTMLProtoBufMsg<CMsgMouseUp> &htmlCommand )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ CefRefPtr<CefBrowser> browser = m_listClientHandlers[ iClient ]->GetBrowser();
+ if ( !browser.get() )
+ return;
+ int nMouseX, nMouseY;
+ m_listClientHandlers[ iClient ]->GetMouseLocation( nMouseX, nMouseY );
+
+ browser->SendMouseClickEvent( nMouseX, nMouseY, ConvertMouseCodeToCEFCode( htmlCommand.BodyConst().mouse_button() ), true, 1 );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: mouse button double pressed
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadMouseButtonDlbClick( const CHTMLProtoBufMsg<CMsgMouseDblClick> &htmlCommand )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ CefRefPtr<CefBrowser> browser = m_listClientHandlers[ iClient ]->GetBrowser();
+ if ( !browser.get() )
+ return;
+ int nMouseX, nMouseY;
+ m_listClientHandlers[ iClient ]->GetMouseLocation( nMouseX, nMouseY );
+
+ browser->SendMouseClickEvent( nMouseX, nMouseY, ConvertMouseCodeToCEFCode( htmlCommand.BodyConst().mouse_button() ), false, 2 );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: mouse was wheeled
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadMouseWheel( const CHTMLProtoBufMsg<CMsgMouseWheel> &htmlCommand )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ CefRefPtr<CefBrowser> browser = m_listClientHandlers[ iClient ]->GetBrowser();
+ if ( !browser.get() )
+ return;
+ int nMouseX, nMouseY;
+ m_listClientHandlers[ iClient ]->GetMouseLocation( nMouseX, nMouseY );
+
+ browser->SendMouseWheelEvent( nMouseX, nMouseY, htmlCommand.BodyConst().delta() );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: unicode character was typed
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadKeyTyped( const CHTMLProtoBufMsg<CMsgKeyChar> &htmlCommand )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ CefRefPtr<CefBrowser> browser = m_listClientHandlers[ iClient ]->GetBrowser();
+ if ( !browser.get() )
+ return;
+
+ browser->SendKeyEvent( KT_CHAR, htmlCommand.BodyConst().unichar(), 0, false, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: raw key was pressed
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadKeyDown( const CHTMLProtoBufMsg<CMsgKeyDown> &htmlCommand )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ CefRefPtr<CefBrowser> browser = m_listClientHandlers[ iClient ]->GetBrowser();
+ if ( !browser.get() )
+ return;
+
+ browser->SendKeyEvent( KT_KEYDOWN, htmlCommand.BodyConst().keycode(), htmlCommand.BodyConst().modifiers(), false, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: raw key was released
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadKeyUp( const CHTMLProtoBufMsg<CMsgKeyUp> &htmlCommand )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ CefRefPtr<CefBrowser> browser = m_listClientHandlers[ iClient ]->GetBrowser();
+ if ( !browser.get() )
+ return;
+
+ browser->SendKeyEvent( KT_KEYUP, htmlCommand.BodyConst().keycode(), htmlCommand.BodyConst().modifiers(), false, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: please close any fullscreen flash controls you see
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadCloseFullScreenFlashIfOpen( const CHTMLProtoBufMsg<CMsgCloseFullScreenFlashIfOpen> &htmlCommand )
+{
+ CheckForFullScreenFlashControl();
+ if ( m_bFullScreenFlashVisible )
+ {
+#ifdef WIN32
+ ::PostMessageA( m_flashfullscreenHWND, WM_KEYDOWN, VK_ESCAPE, 0 );
+ ::PostMessageA( m_flashfullscreenHWND, WM_KEYUP, VK_ESCAPE, 0 );
+#endif
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: please close any fullscreen flash controls you see
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadPauseFullScreenFlashMovieIfOpen( const CHTMLProtoBufMsg<CMsgPauseFullScreenFlashMovieIfOpen> &htmlCommand )
+{
+ CheckForFullScreenFlashControl();
+ if ( m_bFullScreenFlashVisible )
+ {
+#ifdef WIN32
+ ::PostMessageA( m_flashfullscreenHWND, WM_KEYDOWN, VK_SPACE, 0 );
+ ::PostMessageA( m_flashfullscreenHWND, WM_KEYUP, VK_SPACE, 0 );
+#endif
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: helper class to get the focused node in the dom
+//-----------------------------------------------------------------------------
+class CVisitor : public CefDOMVisitor
+{
+public:
+ CVisitor( CThreadEvent *pEvent, CUtlString *psValue )
+ {
+ m_pEvent = pEvent;
+ m_psValue = psValue;
+ }
+
+ ~CVisitor()
+ {
+ m_pEvent->Set();
+ }
+
+ virtual void Visit(CefRefPtr<CefDOMDocument> document) {
+ CefRefPtr<CefDOMNode> focusedNode = document->GetFocusedNode();
+ *m_psValue = focusedNode->GetValue().c_str();
+ }
+
+
+private:
+ CThreadEvent *m_pEvent;
+ CUtlString *m_psValue;
+
+ IMPLEMENT_REFCOUNTING(CVisitor);
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: get the text out of the current dom field that has focus
+//-----------------------------------------------------------------------------
+void CCEFThread::ThreadGetFocusedNodeText( const CHTMLProtoBufMsg<CMsgFocusedNodeText> &htmlCommand )
+{
+ int iClient = 0;
+ if ( BIsValidBrowserHandle( htmlCommand.BodyConst().browser_handle(), iClient ) )
+ {
+ CefRefPtr<CefBrowser> browser = m_listClientHandlers[ iClient ]->GetBrowser();
+ if ( !browser.get() )
+ return;
+
+ CThreadEvent event;
+ CUtlString sValue;
+ browser->GetFocusedFrame()->VisitDOM( new CVisitor( &event, &sValue ) );
+ do
+ {
+ CefDoMessageLoopWork();
+ }
+ while ( !event.Wait( 100 ) ); // keep pumping CEF until it has done our walk
+
+ {
+ int m_iBrowser = htmlCommand.BodyConst().browser_handle();
+ CHTMLProtoBufMsg<CMsgFocusedNodeTextResponse> cmd( eHTMLCommands_GetFocusedNodeValueResponse );
+ cmd.Body().set_value( sValue );
+ DISPATCH_MESSAGE( eHTMLCommands_GetFocusedNodeValueResponse );
+ }
+ }
+}
diff --git a/mp/src/vgui2/chromehtml/html_chrome.h b/mp/src/vgui2/chromehtml/html_chrome.h new file mode 100644 index 00000000..5611180d --- /dev/null +++ b/mp/src/vgui2/chromehtml/html_chrome.h @@ -0,0 +1,637 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//=============================================================================//
+
+#ifndef HTML_CHROME_H
+#define HTML_CHROME_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "cef/include/cef_render_handler.h"
+#include "cef/include/cef_client.h"
+#include "cef/include/cef_app.h"
+#include "cef/include/cef_browser.h"
+#include "cef/include/cef_command_line.h"
+#include "cef/include/cef_frame.h"
+#include "cef/include/cef_runnable.h"
+#include "cef/include/cef_web_urlrequest.h"
+#include "cef/include/cef_request_handler.h"
+#include "cef/include/cef_load_handler.h"
+#include "cef/include/cef_display_handler.h"
+#include "cef/include/cef_life_span_handler.h"
+#include "cef/include/cef_render_handler.h"
+
+#include "tier0/platform.h"
+#include "tier0/vprof.h"
+#include "tier1/utlarray.h"
+#include "tier1/utlbuffer.h"
+#include "fileio.h"
+//#include "constants.h"
+#include "tier0/validator.h"
+#include "tier1/utlmap.h"
+#include "tier1/utlstring.h"
+#include "tier0/tslist.h"
+#include "html/ihtmlchrome.h"
+#include "html/htmlprotobuf.h"
+// These must be undefed so that the MacOS build will work -- their STL
+// fails if min and max are defined. I'm undefing them in all builds to
+// avoid having a Windows dependency on min/max creep in.
+#undef min
+#undef max
+#include "htmlmessages.pb.h"
+
+class CClientHandler;
+class CChromePainter;
+class ICookieCallback;
+
+bool ChromeSetWebCookie( const char *pchHostname, const char *pchName, const char *pchValue, const char *pchPath, RTime32 nExpires );
+bool ChromeGetWebCookiesForURL( CUtlString *pstrValue, const char *pchURL, const char *pchName );
+
+//-----------------------------------------------------------------------------
+// Purpose: track dirty rects, shuttle bits between renderer and main thread
+//-----------------------------------------------------------------------------
+class CChromeUpdateRegion
+{
+public:
+ CChromeUpdateRegion() { MarkAllClean(); }
+ int GetUpdateX( int clampWide ) const { return clamp( m_nUpdateX0, 0, clampWide ); }
+ int GetUpdateY( int clampTall ) const { return clamp( m_nUpdateY0, 0, clampTall ); }
+ int GetUpdateWide( int clampWide ) const { return clamp( m_nUpdateX1, 0, clampWide ) - GetUpdateX( clampWide ); }
+ int GetUpdateTall( int clampTall ) const { return clamp( m_nUpdateY1, 0, clampTall ) - GetUpdateY( clampTall ); }
+
+ void MarkAllClean() { m_nUpdateX0 = m_nUpdateY0 = INT_MAX; m_nUpdateX1 = m_nUpdateY1 = 0; }
+ void MarkAllDirty() { m_nUpdateX0 = m_nUpdateY0 = 0; m_nUpdateX1 = m_nUpdateY1 = INT_MAX; }
+ void MarkDirtyRect( int x0, int y0, int x1, int y1 )
+ {
+ if ( x0 >= x1 || y0 >= y1 ) return;
+ if ( m_nUpdateX0 > x0 ) m_nUpdateX0 = x0;
+ if ( m_nUpdateY0 > y0 ) m_nUpdateY0 = y0;
+ if ( m_nUpdateX1 < x1 ) m_nUpdateX1 = x1;
+ if ( m_nUpdateY1 < y1 ) m_nUpdateY1 = y1;
+ }
+ void MarkDirtyRect( const CChromeUpdateRegion& other )
+ {
+ MarkDirtyRect( other.m_nUpdateX0, other.m_nUpdateY0, other.m_nUpdateX1, other.m_nUpdateY1 );
+ }
+
+protected:
+ int m_nUpdateX0;
+ int m_nUpdateY0;
+ int m_nUpdateX1;
+ int m_nUpdateY1;
+};
+
+class CChromeRenderBuffer : public CChromeUpdateRegion
+{
+public:
+ CChromeRenderBuffer() { m_nWide = m_nTall = 0; }
+ void SetSize( int wide, int tall )
+ {
+ if ( wide != m_nWide || tall != m_nTall )
+ {
+ m_nWide = wide;
+ m_nTall = tall;
+ MarkAllDirty();
+ m_Texture.EnsureCapacity( wide * tall * 4 );
+ }
+ }
+ int GetWide() const { return m_nWide; }
+ int GetTall() const { return m_nTall; }
+ byte *GetPixels() { return m_Texture.Base(); }
+
+ bool BUpdatePixels( byte *pOther, int wide, int tall )
+ {
+ SetSize( wide, tall );
+ int x0 = clamp( m_nUpdateX0, 0, wide );
+ int y0 = clamp( m_nUpdateY0, 0, tall );
+ int x1 = clamp( m_nUpdateX1, 0, wide );
+ int y1 = clamp( m_nUpdateY1, 0, tall );
+ if ( x0 >= x1 || y0 >= y1 )
+ return false;
+
+ if ( x0 == 0 && x1 == wide )
+ {
+ byte *pDst = GetPixels() + y0*wide*4;
+ byte *pSrc = pOther + y0*wide*4;
+ Q_memcpy( pDst, pSrc, wide * ( y1 - y0 ) * 4 );
+ }
+ else
+ {
+ byte *pDst = GetPixels() + y0*wide*4 + x0*4;
+ byte *pSrc = pOther + y0*wide*4 + x0*4;
+ int nCopyBytesPerRow = (x1 - x0)*4;
+ for ( int rows = y1 - y0; rows > 0; --rows )
+ {
+ Q_memcpy( pDst, pSrc, nCopyBytesPerRow );
+ pSrc += wide * 4;
+ pDst += wide * 4;
+ }
+ }
+ return true;
+ }
+
+#ifdef DBGFLAG_VALIDATE
+ virtual void Validate( CValidator &validator, const char *pchName )
+ {
+ VALIDATE_SCOPE();
+ ValidateObj( m_Texture );
+ }
+#endif
+
+protected:
+ int m_nWide; // dimensions of the buffer
+ int m_nTall;
+ CUtlVector<byte> m_Texture; // rgba data
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: interface Chrome uses to send up paint messages
+//-----------------------------------------------------------------------------
+class CChromePainter : public CefRenderHandler
+{
+public:
+ CChromePainter( CClientHandler *pParent );
+ ~CChromePainter();
+
+ virtual bool GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) OVERRIDE { return false; }
+ virtual bool GetScreenRect(CefRefPtr<CefBrowser> browser, CefRect& rect) OVERRIDE { return false; }
+ virtual bool GetScreenPoint(CefRefPtr<CefBrowser> browser, int viewX, int viewY, int& screenX, int& screenY) OVERRIDE { return false; }
+
+ virtual void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) OVERRIDE;
+ virtual void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect) OVERRIDE;
+
+ virtual void OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type, const RectList& dirtyRects, const void* buffer) OVERRIDE;
+ virtual void OnCursorChange(CefRefPtr<CefBrowser> browser, CefCursorHandle cursor) OVERRIDE {}
+ virtual bool OnSetCursor( CefRefPtr<CefBrowser> browser, const CursorType type, const void *pchIconData, int iWide, int iTall, int xHotSpot, int yHotSpot ) OVERRIDE;
+ virtual bool OnFileOpenDialog( CefRefPtr<CefBrowser> browser, bool bMultiSelect, const CefString &default_title, const CefString &default_file, CefWebFileChooserCallback *pCallback ) OVERRIDE;
+ virtual bool OnEnterFullScreen( CefRefPtr<CefBrowser> browser ) OVERRIDE;
+ virtual bool OnExitFullScreen( CefRefPtr<CefBrowser> browser ) OVERRIDE;
+
+ bool BUpdated();
+ void SetUpdated( bool state );
+
+ int GetPopupTall() const { return m_nPopupTall; }
+ int GetPopupWide() const { return m_nPopupWide; }
+ int GetPopupX() const { return m_nPopupX; }
+ int GetPopupY() const { return m_nPopupY; }
+ const byte *PPopupTextureData()
+ {
+ return m_PopupTexture.Base();
+ }
+
+ uint32 FlipTexture();
+ void SetTextureUploaded( uint32 id );
+ bool BPaintBufferAvailable();
+
+ byte *PComposedTextureData( uint32 iTexture );
+ int GetTall() const { return m_MainTexture.GetTall(); }
+ int GetWide() const { return m_MainTexture.GetWide(); }
+ int GetUpdateX() const { return m_UpdateRect.GetUpdateX( GetWide() ); }
+ int GetUpdateY() const { return m_UpdateRect.GetUpdateY( GetTall() ); }
+ int GetUpdateWide() const { return m_UpdateRect.GetUpdateWide( GetWide() ); }
+ int GetUpdateTall() const { return m_UpdateRect.GetUpdateTall( GetTall() ); }
+ void ClearUpdateRect() { m_UpdateRect.MarkAllClean(); }
+
+ // XXX not shuttled safely between threads, should use real buffering
+ const byte *PPopupTextureDataCached();
+
+ bool BPopupVisible() const { return m_bPopupVisible; }
+ // WebKit will show popups before they have been given a size and painted and we may do
+ // a drawing pass during that time, so we want to make sure to only do something
+ // with the popup when it has an actual size and content.
+ bool BPopupVisibleAndPainted() const
+ {
+ return m_bPopupVisible &&
+ m_nPopupWide != 0 &&
+ m_nPopupTall != 0 &&
+ m_PopupTexture.Count() >= m_nPopupWide * m_nPopupTall * 4;
+ }
+ void PopupRect( int &x, int &y, int &wide, int &tall ) const { x = m_nPopupX; y = m_nPopupY; wide = m_nPopupWide; tall = m_nPopupTall; }
+
+#ifdef DBGFLAG_VALIDATE
+ virtual void Validate( CValidator &validator, const char *pchName )
+ {
+ VALIDATE_SCOPE();
+ for ( int i = 0; i < Q_ARRAYSIZE(m_Texture); i++ )
+ ValidateObj( m_Texture[i] );
+
+ ValidateObj( m_PopupTextureCache );
+ ValidateObj( m_PopupTexture );
+ ValidateObj( m_MainTexture );
+ }
+#endif
+ IMPLEMENT_REFCOUNTING(CChromePainter);
+
+private:
+ uint32 m_iNextTexture;
+ uint32 m_iTexturesInFlightBits;
+ int m_nPopupWide;
+ int m_nPopupTall;
+ CChromeRenderBuffer m_MainTexture;
+ CChromeRenderBuffer m_Texture[2]; // buffering -- XXX should use atomic swap, not push multiple buffers to command buffer
+ CChromeUpdateRegion m_UpdateRect;
+ CUtlVector<byte> m_PopupTextureCache;
+ CUtlVector<byte> m_PopupTexture;
+ bool m_bUpdated;
+ CClientHandler *m_pParent;
+ bool m_bPopupVisible;
+ int m_nPopupX, m_nPopupY;
+};
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: CEF callback object
+//-----------------------------------------------------------------------------
+class CClientHandler : public CefClient,
+ public CefLifeSpanHandler,
+ public CefLoadHandler,
+ public CefRequestHandler,
+ public CefDisplayHandler,
+
+ public CefJSDialogHandler,
+ public CefFindHandler,
+ public CefMenuHandler,
+ public CefFocusHandler,
+ public CefPermissionHandler
+{
+public:
+ CClientHandler( int iBrowser, const char *pchUserAgent, uint16 nSerial );
+ ~CClientHandler();
+
+ // CefClient methods
+ virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE {
+ return this;
+ }
+ virtual CefRefPtr<CefLoadHandler> GetLoadHandler() OVERRIDE {
+ return this;
+ }
+ virtual CefRefPtr<CefRequestHandler> GetRequestHandler() OVERRIDE {
+ return this;
+ }
+ virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE {
+ return this;
+ }
+ virtual CefRefPtr<CefRenderHandler> GetRenderHandler() OVERRIDE {
+ return &m_Painter;
+ }
+
+ virtual CefRefPtr<CefFocusHandler> GetFocusHandler() OVERRIDE {
+ return this;
+ }
+
+ virtual CefRefPtr<CefMenuHandler> GetMenuHandler() OVERRIDE {
+ return this;
+ }
+ virtual CefRefPtr<CefPermissionHandler> GetPermissionHandler() OVERRIDE {
+ return this;
+ }
+
+ virtual CefRefPtr<CefFindHandler> GetFindHandler() OVERRIDE {
+ return this;
+ }
+ virtual CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() OVERRIDE {
+ return this;
+ }
+
+
+ // CefLifeSpanHandler methods
+
+ virtual bool OnBeforePopup(CefRefPtr<CefBrowser> parentBrowser, const CefPopupFeatures& popupFeatures, CefWindowInfo& windowInfo, const CefString& url, CefRefPtr<CefClient>& client, CefBrowserSettings& settings) OVERRIDE;
+ virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
+ virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
+ virtual bool DoClose(CefRefPtr<CefBrowser> browser) { return false; }
+ virtual bool OnNewTab(CefRefPtr<CefBrowser> parentBrowser, const CefPopupFeatures& popupFeatures, CefWindowInfo& windowInfo, const CefString& url, bool bForeground, CefRefPtr<CefClient>& client, CefBrowserSettings& settings );
+
+ // CefLoadHandler methods
+ virtual void OnLoadStart(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, bool bIsNewNavigation ) OVERRIDE;
+
+ virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int httpStatusCode, CefRefPtr<CefRequest> request ) OVERRIDE;
+ virtual bool OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, ErrorCode errorCode, const CefString& failedUrl, CefString& errorText);
+
+ // CefRequestHandler methods
+ virtual bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, NavType navType, bool isRedirect, bool isNewTabRequest );
+ virtual bool OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser, CefRefPtr<CefRequest> request, CefString& redirectUrl, CefRefPtr<CefStreamReader>& resourceStream, CefRefPtr<CefResponse> response, int loadFlags);
+
+ // CefDisplayHandler methods
+ virtual void OnNavStateChange(CefRefPtr<CefBrowser> browser, bool canGoBack, bool canGoForward) OVERRIDE {}
+ virtual void OnAddressChange(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& url) OVERRIDE { }
+ virtual void OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title) OVERRIDE;
+
+ virtual bool OnTooltip(CefRefPtr<CefBrowser> browser, CefString& text);
+ virtual void OnStatusMessage(CefRefPtr<CefBrowser> browser, const CefString& value, StatusType type);
+ virtual bool OnConsoleMessage(CefRefPtr<CefBrowser> browser, const CefString& message, const CefString& source, int line);
+
+ virtual void OnTakeFocus(CefRefPtr<CefBrowser> browser, bool next) {}
+ virtual bool OnSetFocus(CefRefPtr<CefBrowser> browser, FocusSource source) { return true; }
+ virtual void OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefDOMNode> node);
+
+ virtual bool OnBeforeMenu(CefRefPtr<CefBrowser> browser, const CefMenuInfo& menuInfo) { return true; }
+ virtual void GetMenuLabel(CefRefPtr<CefBrowser> browser, MenuId menuId, CefString& label) {}
+ virtual bool OnMenuAction(CefRefPtr<CefBrowser> browser, MenuId menuId) { return true; }
+ virtual bool OnBeforeScriptExtensionLoad(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& extensionName) { return false; }
+
+ virtual void OnFindResult(CefRefPtr<CefBrowser> browser, int identifier, int count, const CefRect& selectionRect, int activeMatchOrdinal, bool finalUpdate);
+ virtual bool OnJSAlert(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& message);
+ virtual bool OnJSConfirm(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& message, bool& retval);
+ virtual bool OnJSPrompt(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& message, const CefString& defaultValue, bool& retval, CefString& result);
+
+ void FileOpenDialogResult( const char *pchFileName );
+
+
+ // paint helpers
+ void Paint();
+ bool BNeedsPaint();
+
+ int GetTextureTall() const { return m_Painter.GetTall(); }
+ int GetTextureWide() const { return m_Painter.GetWide(); }
+ int GetUpdateX() const { return m_Painter.GetUpdateX(); }
+ int GetUpdateY() const { return m_Painter.GetUpdateY(); }
+ int GetUpdateWide() const { return m_Painter.GetUpdateWide(); }
+ int GetUpdateTall() const { return m_Painter.GetUpdateTall(); }
+
+ const byte *PPopupTextureDataCached() { return m_Painter.PPopupTextureDataCached(); }
+ bool BPopupVisible() const { return m_Painter.BPopupVisible(); }
+ bool BPopupVisibleAndPainted() const { return m_Painter.BPopupVisibleAndPainted(); }
+ void PopupRect( int &x, int &y, int &wide, int &tall ) const { m_Painter.PopupRect( x, y, wide, tall ); }
+
+ const byte *PComposedTextureData( uint32 iTexture );
+ uint32 FlipTexture() { return m_Painter.FlipTexture(); }
+ void SetTextureUploaded( uint32 iTexture ) { m_Painter.SetTextureUploaded( iTexture ); }
+ void ClearUpdateRect() { m_Painter.ClearUpdateRect(); }
+ bool BPaintBufferReady() { return m_Painter.BPaintBufferAvailable(); }
+
+ // Helpers
+ CefRefPtr<CefBrowser> GetBrowser();
+ void CloseBrowser();
+ uint32 GetPageSerial() { return m_nPageSerial; }
+ void SetPendingPageSerial( uint32 nPageSerial )
+ {
+ m_nPendingPageSerial = nPageSerial;
+ }
+
+
+ void SetUserAgent( const char *pchAgent ) { Q_strncpy( m_szUserAgentExtras, pchAgent, sizeof(m_szUserAgentExtras) ); }
+ const char *PchCurrentURL() { return m_strCurrentUrl.String(); }
+ bool IsVisuallyNonEmpty();
+ void SetErrorStrings( const char *pchTitle, const char *pchHeader, const char *pchCacheMiss, const char *pchBadURL, const char *pchConnectionProblem,
+ const char *pchProxyProblem, const char *pchUnknown );
+ void SetMouseLocation( int x, int y );
+ void GetMouseLocation( int &x, int &y ) { x = m_nMouseX; y = m_nMouseY; }
+ void SetMouseFocus( bool bFocus ) { m_bMouseFocus = bFocus; }
+ void SetSize( int wide, int tall ) { m_nExpectedWide = wide; m_nExpectedTall = tall; }
+ void GetExpectedSize( int &wide, int &tall ) { wide = m_nExpectedWide; tall =m_nExpectedTall; }
+
+ //-----------------------------------------------------------------------------
+ // Purpose: Adds a custom header to all requests
+ //-----------------------------------------------------------------------------
+ void AddHeader( const char *pchHeader, const char *pchValue )
+ {
+ m_vecHeaders.AddToTail( std::make_pair( CStrAutoEncode( pchHeader ).ToWString(), CStrAutoEncode( pchValue ).ToWString() ) );
+ }
+
+ void RequestScreenShot( const CHTMLProtoBufMsg<CMsgSavePageToJPEG> &cmd );
+ void SavePageToJPEGIfNeeded( CefRefPtr<CefBrowser> browser, const byte *pRGBA, int wide, int tall );
+ bool BPendingScreenShot()
+ {
+ return m_Snapshot.m_flRequestTimeout > 0.0f && m_Snapshot.m_sURLSnapshot.IsValid() && m_Snapshot.m_flRequestTimeout < Plat_FloatTime();
+ }
+
+ void SetUserAgentIdentifier( const char *pchIdent )
+ {
+ m_strUserAgentIdentifier = pchIdent;
+ }
+
+ uint16 NSerial() { return m_nSerial; }
+
+ void RefreshCEFHoverStatesAfterScroll();
+
+#ifdef DBGFLAG_VALIDATE
+ virtual void Validate( CValidator &validator, const char *pchName )
+ {
+ VALIDATE_SCOPE();
+ ValidateObj( m_strCurrentUrl );
+ ValidateObj( m_strPostData );
+ ValidateObj( m_strLastRedirectURL );
+ ValidateObj( m_vecHeaders );
+ ValidateObj( m_strUserAgent );
+ ValidateObj( m_Painter );
+ ValidateObj( m_sErrorTitle );
+ ValidateObj( m_sErrorHeader );
+ ValidateObj( m_sErrorCacheMiss );
+ ValidateObj( m_sErrorBadURL );
+ ValidateObj( m_sErrorConnectionProblem );
+ ValidateObj( m_sErrorProxyProblem );
+ ValidateObj( m_sErrorUnknown );
+ ValidateObj( m_strUserAgentIdentifier );
+ // ValidateObj( m_vecHCursor );
+ }
+#endif
+
+ IMPLEMENT_REFCOUNTING(CClientHandler);
+ IMPLEMENT_LOCKING(CClientHandler);
+private:
+ friend class CChromePainter;
+ friend class CCEFThread;
+
+ void SetBrowserAgent( CefRefPtr<CefBrowser> browser );
+
+ // The child browser window
+ CefRefPtr<CefBrowser> m_Browser;
+
+ CefRenderHandler::CefWebFileChooserCallback *m_pOpenFileCallback;
+
+ uint16 m_nSerial;
+ char m_szUserAgentExtras[ 256 ];
+ CUtlString m_strCurrentUrl;
+ CUtlString m_strPostData;
+ CUtlString m_strLastRedirectURL;
+ CUtlString m_strUserAgent;
+ CUtlString m_strUserAgentIdentifier;
+ CUtlString m_strToolTip;
+ bool m_bShowingToolTip;
+ bool m_bPendingPaint;
+ bool m_bBrowserClosing;
+ bool m_bMouseFocus;
+ CChromePainter m_Painter;
+ CUtlVector< std::pair< std::wstring, std::wstring > > m_vecHeaders;
+ int m_iBrowser;
+ int m_nExpectedWide;
+ int m_nExpectedTall;
+ uint32 m_nPageSerial;
+ uint32 m_nPendingPageSerial;
+
+ CUtlString m_sErrorTitle;
+ CUtlString m_sErrorHeader;
+ CUtlString m_sErrorCacheMiss;
+ CUtlString m_sErrorBadURL;
+ CUtlString m_sErrorConnectionProblem;
+ CUtlString m_sErrorProxyProblem;
+ CUtlString m_sErrorUnknown;
+ int m_nMouseX;
+ int m_nMouseY;
+ int m_nMouseScrolledX;
+ int m_nMouseScrolledY;
+
+ struct SnapshotData_t
+ {
+ CUtlString m_sURLSnapshot;
+ CUtlString m_sFileNameSnapshot;
+ int m_nWide, m_nTall;
+ float m_flRequestTimeout;
+ };
+
+ SnapshotData_t m_Snapshot;
+
+ // Scroll bar state is cached and compared to CEF's current values every frame;
+ // any changes are passed on to the client handler as serialized update messages.
+ struct CachedScrollBarState_t
+ {
+ int m_nX;
+ int m_nY;
+ int m_nWide;
+ int m_nTall;
+ int m_nMax;
+ int m_nScroll;
+ int m_bVisible; // using 'int' to avoid padding bytes so memcmp can be used
+ };
+ CachedScrollBarState_t m_CachedVScroll;
+ CachedScrollBarState_t m_CachedHScroll;
+};
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: CEF thinking thread
+//-----------------------------------------------------------------------------
+class CCEFThread : public CValidatableThread
+{
+public:
+ CCEFThread();
+ ~CCEFThread();
+ void SetCEFPaths( const char *pchHTMLCacheDir, const char *pchCookiePath );
+ void TriggerShutdown();
+ void WakeThread();
+ virtual int Run();
+
+ bool BHasPendingMessages() { return m_tslResponseBuffers.Count() > 0; }
+
+ HTMLCommandBuffer_t *GetFreeCommandBuffer( EHTMLCommands eCmd, int iBrowser );
+ void ReleaseCommandBuffer( HTMLCommandBuffer_t *pBuf );
+ void PushCommand( HTMLCommandBuffer_t * );
+ void PushResponse( HTMLCommandBuffer_t * );
+ bool GetMainThreadCommand( HTMLCommandBuffer_t ** );
+ HTMLCommandBuffer_t *BWaitForCommand( EHTMLCommands eCmd, int iBrowser );
+ HTMLCommandBuffer_t *BWaitForResponse( EHTMLCommands eCmd, int iBrowser );
+ bool GetCEFThreadCommand( HTMLCommandBuffer_t **pBuf );
+
+#ifdef DBGFLAG_VALIDATE
+ virtual void SleepForValidate() { CValidatableThread::SleepForValidate(); m_evWaitingForCommand.Set(); WakeThread(); }
+ virtual void Validate( CValidator &validator, const tchar *pchName );
+#endif
+
+
+private:
+ void RunCurrentCommands();
+ const char *PchWebkitUserAgent();
+ void AppGetSettings(CefSettings& settings, CefRefPtr<CefApp>& app);
+ void CleanupTempFolders();
+
+ void ThreadCreateBrowser( const CHTMLProtoBufMsg<CMsgBrowserCreate> &htmlCommand );
+ void ThreadRemoveBrowser( const CHTMLProtoBufMsg<CMsgBrowserRemove> &htmlCommand );
+ void ThreadBrowserSize( const CHTMLProtoBufMsg<CMsgBrowserSize> &htmlCommand );
+ void ThreadBrowserPosition( const CHTMLProtoBufMsg<CMsgBrowserPosition> &htmlCommand );
+ void ThreadBrowserPostURL( const CHTMLProtoBufMsg<CMsgPostURL> &htmlCommand );
+ void ThreadBrowserStopLoad( const CHTMLProtoBufMsg<CMsgStopLoad> &htmlCommand );
+ void ThreadBrowserReload( const CHTMLProtoBufMsg<CMsgReload> &htmlCommand );
+ void ThreadBrowserGoForward( const CHTMLProtoBufMsg<CMsgGoForward> &htmlCommand );
+ void ThreadBrowserGoBack( const CHTMLProtoBufMsg<CMsgGoBack> &htmlCommand );
+ void ThreadBrowserCopy( const CHTMLProtoBufMsg<CMsgCopy> &htmlCommand );
+ void ThreadBrowserPaste( const CHTMLProtoBufMsg<CMsgPaste> &htmlCommand );
+ void ThreadBrowserExecuteJavascript( const CHTMLProtoBufMsg<CMsgExecuteJavaScript> &htmlCommand );
+ void ThreadBrowserSetFocus( const CHTMLProtoBufMsg<CMsgSetFocus> &htmlCommand );
+ void ThreadBrowserHorizontalScrollBarSize( const CHTMLProtoBufMsg<CMsgHorizontalScrollBarSize> &htmlCommand );
+ void ThreadBrowserVerticalScrollBarSize( const CHTMLProtoBufMsg<CMsgVerticalScrollBarSize> &htmlCommand );
+ void ThreadBrowserFind( const CHTMLProtoBufMsg<CMsgFind> &htmlCommand );
+ void ThreadBrowserStopFind( const CHTMLProtoBufMsg<CMsgStopFind> &htmlCommand );
+ void ThreadBrowserSetHorizontalScroll( const CHTMLProtoBufMsg<CMsgSetHorizontalScroll> &htmlCommand );
+ void ThreadBrowserSetVerticalScroll( const CHTMLProtoBufMsg<CMsgSetVerticalScroll> &htmlCommand );
+ void ThreadBrowserSetZoomLevel( const CHTMLProtoBufMsg<CMsgSetZoomLevel> &htmlCommand );
+ void ThreadBrowserViewSource( const CHTMLProtoBufMsg<CMsgViewSource> &htmlCommand );
+ void ThreadNeedsPaintResponse( const CHTMLProtoBufMsg<CMsgNeedsPaintResponse> &htmlCommand );
+ void ThreadBrowserErrorStrings( const CHTMLProtoBufMsg<CMsgBrowserErrorStrings> &htmlCommand );
+ void ThreadAddHeader( const CHTMLProtoBufMsg<CMsgAddHeader> &htmlCommand );
+ void ThreadGetZoom( const CHTMLProtoBufMsg<CMsgGetZoom> &htmlCommand );
+ void ThreadHidePopup( const CHTMLProtoBufMsg<CMsgHidePopup> &htmlCommand );
+ void ThreadGetCookiesForURL( const CHTMLProtoBufMsg<CMsgGetCookiesForURL> &htmlCommand );
+
+ void ThreadKeyDown( const CHTMLProtoBufMsg<CMsgKeyDown> &htmlCommand );
+ void ThreadKeyUp( const CHTMLProtoBufMsg<CMsgKeyUp> &htmlCommand );
+ void ThreadKeyTyped( const CHTMLProtoBufMsg<CMsgKeyChar> &htmlCommand );
+ void ThreadMouseButtonDown( const CHTMLProtoBufMsg<CMsgMouseDown> &htmlCommand );
+ void ThreadMouseButtonUp( const CHTMLProtoBufMsg<CMsgMouseUp> &htmlCommand );
+ void ThreadMouseButtonDlbClick( const CHTMLProtoBufMsg<CMsgMouseDblClick> &htmlCommand );
+ void ThreadMouseWheel( const CHTMLProtoBufMsg<CMsgMouseWheel> &htmlCommand );
+ void ThreadMouseMove( const CHTMLProtoBufMsg<CMsgMouseMove> &htmlCommand );
+ void ThreadMouseLeave( const CHTMLProtoBufMsg<CMsgMouseLeave> &htmlCommand );
+ void ThreadLinkAtPosition( const CHTMLProtoBufMsg<CMsgLinkAtPosition> &htmlCommand );
+ void ThreadZoomToElementAtPosition( const CHTMLProtoBufMsg<CMsgZoomToElementAtPosition> &htmlCommand );
+ void ThreadZoomToFocusedElement( const CHTMLProtoBufMsg<CMsgZoomToFocusedElement> &htmlCommand );
+ void ThreadSavePageToJPEG( const CHTMLProtoBufMsg<CMsgSavePageToJPEG> &htmlCommand );
+ void ThreadSetCookie( const CHTMLProtoBufMsg<CMsgSetCookie> &htmlCommand );
+ void ThreadSetTargetFrameRate( const CHTMLProtoBufMsg<CMsgSetTargetFrameRate> &htmlCommand );
+ void ThreadFullRepaint( const CHTMLProtoBufMsg<CMsgFullRepaint> &htmlCommand );
+ void ThreadSetPageScale( const CHTMLProtoBufMsg<CMsgScalePageToValue> &htmlCommand );
+ void ThreadExitFullScreen( const CHTMLProtoBufMsg<CMsgExitFullScreen> &htmlCommand );
+ void ThreadCloseFullScreenFlashIfOpen( const CHTMLProtoBufMsg<CMsgCloseFullScreenFlashIfOpen> &htmlCommand );
+ void ThreadPauseFullScreenFlashMovieIfOpen( const CHTMLProtoBufMsg<CMsgPauseFullScreenFlashMovieIfOpen> &htmlCommand );
+ void ThreadGetFocusedNodeText( const CHTMLProtoBufMsg<CMsgFocusedNodeText> &htmlCommand );
+
+ void ThreadBrowserVerticalScrollBarSizeHelper( int iBrowser, bool bForceSendUpdate );
+ void ThreadBrowserHorizontalScrollBarSizeHelper( int iBrowser, bool bForceSendUpdate );
+
+ bool BIsValidBrowserHandle( uint32 nHandle, int &iClient );
+ void SendSizeChangeEvents();
+ void CheckForFullScreenFlashControl();
+
+ CThreadEvent m_WakeEvent;
+ CUtlString m_sHTMLCacheDir;
+ CUtlString m_sCookiePath;
+ bool m_bExit;
+ CThreadEvent m_eventDidExit;
+
+ CUtlLinkedList<CClientHandler *> m_listClientHandlers;
+
+ CTSQueue<HTMLCommandBuffer_t*> m_tslCommandBuffers;
+ CUtlVector<HTMLCommandBuffer_t*> m_vecQueueCommands;
+ CTSQueue<HTMLCommandBuffer_t*> m_tslResponseBuffers;
+ CUtlVector<HTMLCommandBuffer_t*> m_vecQueueResponses;
+
+ CTSList<HTMLCommandBuffer_t*> m_tslUnsedBuffers;
+
+ CThreadEvent m_evWaitingForCommand;
+ CThreadEvent m_evWaitingForResponse;
+ int m_nTargetFrameRate;
+ uint16 m_nBrowserSerial;
+ bool m_bFullScreenFlashVisible;
+#ifdef WIN32
+ HWND m_flashfullscreenHWND;
+#endif
+ bool m_bSawUserInputThisFrame;
+
+ struct SizeChange_t
+ {
+ int iBrowser;
+ int nBeforeWidth;
+ int nBeforeHeight;
+ float flNewZoom;
+ };
+ CUtlMap< int, SizeChange_t, int > m_mapSizeChangesPending;
+};
+
+CCEFThread &AccessHTMLWrapper();
+
+#endif // HTML_CHROME_H
diff --git a/mp/src/vgui2/chromehtml/html_mac.mm b/mp/src/vgui2/chromehtml/html_mac.mm new file mode 100644 index 00000000..f85f091a --- /dev/null +++ b/mp/src/vgui2/chromehtml/html_mac.mm @@ -0,0 +1,16 @@ +//=========== Copyright Valve Corporation, All rights reserved. ===============//
+//
+// Purpose:
+//=============================================================================//
+
+#include <Cocoa/Cocoa.h>
+
+extern "C" void *CreateAutoReleasePool()
+{
+ return [[NSAutoreleasePool alloc] init];
+}
+
+extern "C" void ReleaseAutoReleasePool( void *pool )
+{
+ [pool release];
+}
\ No newline at end of file diff --git a/mp/src/vgui2/chromehtml/htmlmanager.h b/mp/src/vgui2/chromehtml/htmlmanager.h new file mode 100644 index 00000000..02b3728f --- /dev/null +++ b/mp/src/vgui2/chromehtml/htmlmanager.h @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//=============================================================================//
+
+#ifndef HTMLMANAGER_H
+#define HTMLMANAGER_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: helper funcs to pump chrome
+//-----------------------------------------------------------------------------
+void ChromeInit( const char *pchHTMLCacheDir, const char *pchCookiePath );
+void ChromeShutdown();
+
+#ifdef DBGFLAG_VALIDATE
+void ChromeValidate( CValidator &validator, const char *pchName );
+bool ChromeResumeFromValidate();
+bool ChromePrepareForValidate();
+#endif
+
+bool ChromeSetWebCookie( const char *pchHostname, const char *pchName, const char *pchValue, const char *pchPath );
+void ChromeSetClientBuildID( uint64 ulBuildID );
+
+enum EMouseState { UP,DOWN,MOVE,DBLCLICK };
+
+#endif // HTMLMANAGER_H
diff --git a/mp/src/vgui2/chromehtml/htmlmessages.proto b/mp/src/vgui2/chromehtml/htmlmessages.proto new file mode 100644 index 00000000..355f0942 --- /dev/null +++ b/mp/src/vgui2/chromehtml/htmlmessages.proto @@ -0,0 +1,1025 @@ +//====== Copyright 1996-2010, Valve Corporation, All rights reserved. =======
+//
+// Purpose: The file defines our Google Protocol Buffers which are used in IPC
+// and inter-thread communcations in the tenfoot UI rendering system.
+//
+//=============================================================================
+
+// We care more about speed than code size
+option optimize_for = SPEED;
+
+// We don't use the service generation functionality
+option cc_generic_services = false;
+
+//
+// STYLE NOTES:
+//
+// Use CamelCase CMsgMyMessageName style names for messages.
+//
+// Use lowercase _ delimited names like my_steam_id for field names, this is non-standard for Steam,
+// but plays nice with the Google formatted code generation.
+//
+// Try not to use required fields ever. Only do so if you are really really sure you'll never want them removed.
+// Optional should be preffered as it will make versioning easier and cleaner in the future if someone refactors
+// your message and wants to remove or rename fields. This is especially important for messages sent from the server
+// to clients. We may be able to safely remove a field if it's optional even if an old client expects it, but if it
+// was required we can't remove it. Using required doesn't really offer any advantages at all as you'll just end up
+// with an empty message with all default values if you receive a message missing a required field, so there is no
+// real advantage to using it ever.
+//
+// Use fixed64 for JobId_t, GID_t, or SteamID or GameID. This is appropriate for any field that is normally
+// going to be larger than 2^56. Otherwise use int64 for 64 bit values that are frequently smaller
+// than 2^56 as it will safe space on the wire in those cases.
+//
+// Similar to fixed64, use fixed32 for RTime32 or other 32 bit values that are frequently larger than
+// 2^28. It will safe space in those cases, otherwise use int32 which will safe space for smaller values.
+// An exception to this rule for RTime32 is if the value will frequently be zero rather than set to an actual
+// time.
+//
+// Use uint32 with [default = 2] for EResult values in messages. The default is important since the normal int/uint
+// default of 0 is not a valid EResult value. 2 is k_EResultFail.
+//
+// See: http://code.google.com/apis/protocolbuffers/docs/proto.html for a complete language guide.
+//
+
+
+//
+// key up - eHTMLCommands_KeyUp
+//
+message CMsgKeyUp
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 keyCode = 2;
+ optional uint32 modifiers = 3;
+}
+
+
+//
+// key down - eHTMLCommands_KeyDown
+//
+message CMsgKeyDown
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 keyCode = 2;
+ optional uint32 modifiers = 3;
+}
+
+
+//
+// key unichar - eHTMLCommands_KeyChar
+//
+message CMsgKeyChar
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 unichar = 2;
+}
+
+
+//
+// mouse down - eHTMLCommands_MouseDown
+//
+message CMsgMouseDown
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 mouse_button = 2;
+}
+
+
+//
+// mouse up - eHTMLCommands_MouseUp
+//
+message CMsgMouseUp
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 mouse_button = 2;
+}
+
+
+//
+// mouse dbl click - eHTMLCommands_MouseDblClick
+//
+message CMsgMouseDblClick
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 mouse_button = 2;
+}
+
+
+//
+// mouse wheel - eHTMLCommands_MouseWheel
+//
+message CMsgMouseWheel
+{
+ optional uint32 browser_handle = 1;
+ optional int32 delta = 2;
+}
+
+
+//
+// mouse move - eHTMLCommands_MouseMove
+//
+message CMsgMouseMove
+{
+ optional uint32 browser_handle = 1;
+ optional int32 x = 2;
+ optional int32 y = 3;
+}
+
+
+//
+// mouse leave - eHTMLCommands_MouseLeave
+//
+message CMsgMouseLeave
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// make a cef control - eHTMLCommands_BrowserCreate
+//
+message CMsgBrowserCreate
+{
+ optional uint32 request_id = 1;
+ optional bool popup = 2 [default = false];
+ optional string useragent = 3;
+}
+
+
+//
+// ack to the main thread a control was made - eHTMLCommands_BrowserCreateResponse
+//
+message CMsgBrowserCreateResponse
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 request_id = 2;
+}
+
+
+//
+// delete a browser - eHTMLCommands_BrowserRemove
+//
+message CMsgBrowserRemove
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// send loc strings over to use for error page - eHTMLCommands_BrowserErrorStrings
+//
+message CMsgBrowserErrorStrings
+{
+ optional uint32 browser_handle = 1;
+ optional string title = 2;
+ optional string header = 3;
+ optional string cache_miss = 4;
+ optional string bad_url = 5;
+ optional string connection_problem = 6;
+ optional string proxy_problem = 7;
+ optional string unknown = 8;
+}
+
+
+//
+// Set a browser to this size - eHTMLCommands_BrowserSize
+//
+message CMsgBrowserSize
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 width = 2;
+ optional uint32 height = 3;
+}
+
+
+//
+// Set position in the window - eHTMLCommands_BrowserPosition
+//
+message CMsgBrowserPosition
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 x = 2;
+ optional uint32 y = 3;
+}
+
+
+//
+// load this url - eHTMLCommands_PostURL
+//
+message CMsgPostURL
+{
+ optional uint32 browser_handle = 1;
+ optional string url = 2;
+ optional string post = 3;
+ optional uint32 pageserial = 4;
+}
+
+
+//
+// have cef send this html header for all page loads -eHTMLCommands_AddHeader
+//
+message CMsgAddHeader
+{
+ optional uint32 browser_handle = 1;
+ optional string key = 2;
+ optional string value = 3;
+}
+
+
+//
+// stop loading a page - eHTMLCommands_StopLoad
+//
+message CMsgStopLoad
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// reload a page - eHTMLCommands_Reload
+//
+message CMsgReload
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// next page - eHTMLCommands_GoForward
+//
+message CMsgGoForward
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// back a page in the stack - eHTMLCommands_GoBack
+//
+message CMsgGoBack
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// copy the currently selected text - eHTMLCommands_Copy
+//
+message CMsgCopy
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// paste text here from the clipboard - eHTMLCommands_Paste
+//
+message CMsgPaste
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// run this javascript on the current page - eHTMLCommands_ExecuteJavaScript
+//
+message CMsgExecuteJavaScript
+{
+ optional uint32 browser_handle = 1;
+ optional string script = 2;
+}
+
+
+//
+// tell it that it has key focus - eHTMLCommands_SetFocus
+//
+message CMsgSetFocus
+{
+ optional uint32 browser_handle = 1;
+ optional bool focus = 2;
+}
+
+
+//
+// how big is the scroll bar plz - eHTMLCommands_HorizontalScrollBarSize
+//
+message CMsgHorizontalScrollBarSize
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// its this big! - eHTMLCommands_HorizontalScrollBarSizeResponse
+//
+message CMsgHorizontalScrollBarSizeResponse
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 x = 2;
+ optional uint32 y = 3;
+ optional uint32 wide = 4;
+ optional uint32 tall = 5;
+ optional uint32 scroll_max = 6;
+ optional uint32 scroll = 7;
+ optional float zoom = 8;
+ optional bool visible = 9;
+}
+
+
+//
+// eHTMLCommands_VerticalScrollBarSize
+//
+message CMsgVerticalScrollBarSize
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// eHTMLCommands_VerticalScrollBarSizeResponse
+//
+message CMsgVerticalScrollBarSizeResponse
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 x = 2;
+ optional uint32 y = 3;
+ optional uint32 wide = 4;
+ optional uint32 tall = 5;
+ optional uint32 scroll_max = 6;
+ optional uint32 scroll = 7;
+ optional float zoom = 8;
+ optional bool visible = 9;
+}
+
+
+//
+// find this string in the page - eHTMLCommands_Find
+//
+message CMsgFind
+{
+ optional uint32 browser_handle = 1;
+ optional string find = 2;
+ optional bool infind = 3;
+ optional bool reverse = 4 [ default = false ];
+}
+
+//
+// done finding - eHTMLCommands_StopFind
+//
+message CMsgStopFind
+{
+ optional uint32 browser_handle = 1;
+}
+
+//
+// scroll here - eHTMLCommands_SetHorizontalScroll
+//
+message CMsgSetHorizontalScroll
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 scroll = 2;
+}
+
+
+//
+// scroll here - eHTMLCommands_SetHorizontalScroll
+//
+message CMsgSetVerticalScroll
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 scroll = 2;
+}
+
+
+//
+// zoom the page this much, 0 to 100 - eHTMLCommands_SetZoomLevel
+//
+message CMsgSetZoomLevel
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 zoom = 2;
+}
+
+
+//
+// look at the page source in notepad - eHTMLCommands_ViewSource
+//
+message CMsgViewSource
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// browser is setup and ready to load pages after a create - eHTMLCommands_BrowserReady
+//
+message CMsgBrowserReady
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// new url loaded - eHTMLCommands_URLChanged
+//
+message CMsgURLChanged
+{
+ optional uint32 browser_handle = 1;
+ optional string url = 2;
+ optional string postData = 3;
+ optional bool bIsRedirect = 4;
+ optional string pagetitle = 5;
+ optional bool bNewNavigation = 6;
+}
+
+
+message CHTMLHeader
+{
+ optional string key = 1;
+ optional string value = 2;
+}
+
+message CHTMLPageSecurityInfo
+{
+ optional bool bIsSecure = 1 [default = false];
+ optional bool bHasCertError = 2 [default = false];
+ optional string issuerName = 3 [default = ""];
+ optional string certName = 4 [default = "" ];
+ optional int32 certExpiry = 5 [default = 0];
+ optional int32 nCertBits = 6 [default = 0];
+ optional bool bIsEVCert = 7 [default = false];
+
+}
+
+//
+// finished loading a page - eHTMLCommands_FinishedRequest
+//
+message CMsgFinishedRequest
+{
+ optional uint32 browser_handle = 1;
+ optional string url = 2;
+ optional string pageTitle = 3;
+ optional CHTMLPageSecurityInfo security_info = 4;
+ repeated CHTMLHeader headers = 5;
+}
+
+
+//
+// starting a page load - eHTMLCommands_StartRequest
+//
+message CMsgStartRequest
+{
+ optional uint32 browser_handle = 1;
+ optional string url = 2;
+ optional string target = 3;
+ optional string postData = 4;
+ optional bool bIsRedirect = 5;
+}
+
+
+//
+// do we want to allow this load - eHTMLCommands_StartRequestResponse
+//
+message CMsgStartRequestResponse
+{
+ optional uint32 browser_handle = 1;
+ optional bool bAllow = 2;
+}
+
+
+//
+// a html popup is showing - eHTMLCommands_ShowPopup
+//
+message CMsgShowPopup
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// done with the popup - eHTMLCommands_HidePopup
+//
+message CMsgHidePopup
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// a html popup is changing size - eHTMLCommands_SizePopup
+//
+message CMsgSizePopup
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 x = 2;
+ optional uint32 y = 3;
+ optional uint32 wide = 4;
+ optional uint32 tall = 5;
+}
+
+
+//
+// new tab plz - eHTMLCommands_OpenNewTab
+//
+message CMsgOpenNewTab
+{
+ optional uint32 browser_handle = 1;
+ optional string url = 2;
+ optional bool bForeground = 3;
+}
+
+
+//
+// do we allow the tab - eHTMLCommands_OpenNewTabResponse
+//
+message CMsgOpenNewTabResponse
+{
+ optional uint32 browser_handle = 1;
+ optional bool bAllow = 2;
+}
+
+
+//
+// popup a new page here please - eHTMLCommands_PopupHTMLWindow
+//
+message CMsgPopupHTMLWindow
+{
+ optional uint32 browser_handle = 1;
+ optional string url = 2;
+ optional uint32 x = 3;
+ optional uint32 y = 4;
+ optional uint32 wide = 5;
+ optional uint32 tall = 6;
+}
+
+
+//
+// do we allow the popup - eHTMLCommands_PopupHTMLWindowResponse
+//
+message CMsgPopupHTMLWindowResponse
+{
+ optional uint32 browser_handle = 1;
+ optional bool bAllow = 2;
+}
+
+
+//
+// title for the page - eHTMLCommands_SetHTMLTitle
+//
+message CMsgSetHTMLTitle
+{
+ optional uint32 browser_handle = 1;
+ optional string title = 2;
+}
+
+//
+// loading a url on a page - eHTMLCommands_LoadingResource
+//
+message CMsgLoadingResource
+{
+ optional uint32 browser_handle = 1;
+ optional string url = 2;
+}
+
+//
+// status to display - eHTMLCommands_StatusText
+//
+message CMsgStatusText
+{
+ optional uint32 browser_handle = 1;
+ optional string text = 2;
+}
+
+//
+// mouse cursor to this - eHTMLCommands_SetCursor
+//
+message CMsgSetCursor
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 cursor = 2;
+ optional uint32 data = 3;
+ optional uint32 wide = 4;
+ optional uint32 tall = 5;
+ optional uint32 xhotspot = 6;
+ optional uint32 yhotspot = 7;
+}
+
+//
+// let the user pick a file - eHTMLCommands_FileLoadDialog
+//
+message CMsgFileLoadDialog
+{
+ optional uint32 browser_handle = 1;
+ optional string title = 2;
+ optional string initialFile = 3;
+}
+
+//
+// the user picked this - eHTMLCommands_FileLoadDialogResponse
+//
+message CMsgFileLoadDialogResponse
+{
+ optional uint32 browser_handle = 1;
+ repeated string files = 2;
+}
+
+
+//
+// show a tooltip - eHTMLCommands_ShowToolTip
+//
+message CMsgShowToolTip
+{
+ optional uint32 browser_handle = 1;
+ optional string text = 2;
+}
+
+
+//
+// update tooltip - eHTMLCommands_UpdateToolTip
+//
+message CMsgUpdateToolTip
+{
+ optional uint32 browser_handle = 1;
+ optional string text = 2;
+}
+
+
+//
+// done with tooltip - eHTMLCommands_HideToolTip
+//
+message CMsgHideToolTip
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// got search answers - eHTMLCommands_SearchResults
+//
+message CMsgSearchResults
+{
+ optional uint32 browser_handle = 1;
+ optional int32 activeMatch = 2;
+ optional int32 results = 3;
+}
+
+
+//
+// close this window plz - eHTMLCommands_Close
+//
+message CMsgClose
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// need image for the page - eHTMLCommands_NeedsPaint
+//
+message CMsgNeedsPaint
+{
+ optional uint32 browser_handle = 1;
+ optional uint64 rgba = 2;
+ optional uint32 wide = 3;
+ optional uint32 tall = 4;
+ optional uint32 textureid = 5;
+ optional uint32 updatex = 6;
+ optional uint32 updatey = 7;
+ optional uint32 updatewide = 8;
+ optional uint32 updatetall = 9;
+ optional uint32 scrollx = 10;
+ optional uint32 scrolly = 11;
+
+ optional uint64 combobox_rgba = 12 [default = 0];
+ optional uint32 combobox_wide = 13 [default = 0];
+ optional uint32 combobox_tall = 14 [default = 0];
+
+ optional uint32 pageserial = 15;
+}
+
+
+//
+// all done with the paint pointer - eHTMLCommands_NeedsPaintResponse
+//
+message CMsgNeedsPaintResponse
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 textureid = 2;
+}
+
+//
+// what zoom lvl we at? - eHTMLCommands_GetZoom
+//
+message CMsgGetZoom
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// this zoom level! - eHTMLCommands_GetZoomResponse
+//
+message CMsgGetZoomResponse
+{
+ optional uint32 browser_handle = 1;
+ optional float zoom = 2;
+}
+
+
+//
+// get the link at this x,y - eHTMLCommands_LinkAtPosition
+//
+message CMsgLinkAtPosition
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 x = 2;
+ optional uint32 y = 3;
+}
+
+
+//
+// link at this pos - eHTMLCommands_LinkAtPosition
+//
+message CMsgLinkAtPositionResponse
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 x = 2;
+ optional uint32 y = 3;
+ optional string url = 4;
+ optional bool blivelink = 5;
+ optional bool binput = 6;
+}
+
+
+//
+// scale the page to the element at this position on the page, for at least this size
+//
+message CMsgZoomToElementAtPosition
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 x = 2;
+ optional uint32 y = 3;
+}
+
+//
+// response from the zoom, what rect did we pick and what zoom factor
+//
+message CMsgZoomToElementAtPositionResponse
+{
+ optional uint32 browser_handle = 1;
+ optional sint32 initial_x = 2;
+ optional sint32 initial_y = 3;
+ optional uint32 initial_width = 4;
+ optional uint32 initial_height = 5;
+ optional sint32 final_x = 6;
+ optional sint32 final_y = 7;
+ optional uint32 final_width = 8;
+ optional uint32 final_height = 9;
+ optional float zoom = 10;
+}
+
+
+//
+// increase (or decrease if negative) the page scale factor used on this page
+//
+message CMsgScalePageToValue
+{
+ optional uint32 browser_handle = 1;
+ optional float scale = 2;
+ optional float x = 3;
+ optional float y = 4;
+}
+
+
+//
+// increase (or decrease if negative) the page scale factor used on this page
+//
+message CMsgScalePageToValueResponse
+{
+ optional uint32 browser_handle = 1;
+ optional float zoom = 2;
+ optional int32 width_delta = 3;
+ optional int32 height_delta = 4;
+}
+
+//
+// request a screenshot get written for this loaded url
+//
+message CMsgSavePageToJPEG
+{
+ optional uint32 browser_handle = 1;
+ optional string url = 2;
+ optional string filename = 3;
+ optional uint32 width = 4;
+ optional uint32 height = 5;
+}
+
+
+//
+// screenshot taken, tell the main thread we did it
+//
+message CMsgSavePageToJPEGResponse
+{
+ optional uint32 browser_handle = 1;
+ optional string url = 2;
+ optional string filename = 3;
+}
+
+
+//
+// web control wants to pop an alert dialog
+//
+message CMsgJSAlert
+{
+ optional uint32 browser_handle = 1;
+ optional string message = 2;
+}
+
+//
+// web control wants to pop an confirmation dialog
+//
+message CMsgJSConfirm
+{
+ optional uint32 browser_handle = 1;
+ optional string message = 2;
+}
+
+
+//
+// done showing the confirmation
+//
+message CMsgJSDialogResponse
+{
+ optional uint32 browser_handle = 1;
+ optional bool result = 2;
+}
+
+//
+// web control telling us the forward and back state
+//
+message CMsgCanGoBackAndForward
+{
+ optional uint32 browser_handle = 1;
+ optional bool bgoback = 2;
+ optional bool bgoforward = 3;
+}
+
+//
+// web control telling us to open a steam dialog
+//
+message CMsgOpenSteamURL
+{
+ optional uint32 browser_handle = 1;
+ optional string url = 2;
+}
+
+
+//
+// set a cookie for the cef instance
+//
+message CMsgSetCookie
+{
+ optional string key = 1;
+ optional string value = 2;
+ optional string path = 3;
+ optional string host = 4;
+ optional uint32 expires = 5;
+}
+
+
+//
+// tell cef that html isn't active so run slow
+//
+message CMsgSetTargetFrameRate
+{
+ optional uint32 nTargetFrameRate = 1; // FPS to run the CEF think loop at
+}
+
+
+//
+// request a full repaint of the control
+//
+message CMsgFullRepaint
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// CEF wants to go fullscreen please
+//
+message CMsgRequestFullScreen
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// do we allow fullscreen
+//
+message CMsgRequestFullScreenResponse
+{
+ optional uint32 browser_handle = 1;
+ optional bool ballow = 2;
+}
+
+
+//
+// exit fullscreen if we are in it
+//
+message CMsgExitFullScreen
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// request all the cookies for this url
+//
+message CMsgGetCookiesForURL
+{
+ optional uint32 browser_handle = 1;
+ optional string url = 2;
+}
+
+
+message CCookie
+{
+ optional string name = 1;
+ optional string value = 2;
+ optional string domain = 3;
+ optional string path = 4;
+}
+
+
+//
+// return all the cookies for this url
+//
+message CMsgGetCookiesForURLResponse
+{
+ optional uint32 browser_handle = 1;
+ optional string url = 2;
+ repeated CCookie cookies = 3;
+}
+
+
+//
+// sent when a html node gets key focus
+//
+message CMsgNodeHasFocus
+{
+ optional uint32 browser_handle = 1;
+ optional bool bInput = 2;
+ optional string name = 3;
+ optional string elementtagname = 4;
+ optional string searchbuttontext = 5;
+ optional bool bHasMultipleInputs = 6;
+ optional string input_type = 7; // type of input, if node is input; otherwise unset
+}
+
+
+//
+// zoom the html control to the node with input focus
+//
+message CMsgZoomToFocusedElement
+{
+ optional uint32 browser_handle = 1;
+ optional uint32 leftoffset = 2 [default = 0];
+ optional uint32 topoffset = 3 [default = 0];
+}
+
+
+//
+// ask a fullscreen flash control to close if open
+//
+message CMsgCloseFullScreenFlashIfOpen
+{
+ optional uint32 browser_handle = 1;
+}
+
+//
+// ask a fullscreen flash control to pause itself if open
+//
+message CMsgPauseFullScreenFlashMovieIfOpen
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// get the string currently contained in the focused node
+//
+message CMsgFocusedNodeText
+{
+ optional uint32 browser_handle = 1;
+}
+
+
+//
+// what text is in the focused node
+//
+message CMsgFocusedNodeTextResponse
+{
+ optional uint32 browser_handle = 1;
+ optional string value = 2;
+}
diff --git a/mp/src/vgui2/chromehtml/stdafx.h b/mp/src/vgui2/chromehtml/stdafx.h new file mode 100644 index 00000000..9746e141 --- /dev/null +++ b/mp/src/vgui2/chromehtml/stdafx.h @@ -0,0 +1,19 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+#ifndef STDAFX_H
+#define STDAFX_H
+
+#include "tier0/platform.h"
+#include "tier0/vprof.h"
+#include "tier1/utlarray.h"
+#include "tier1/utlbuffer.h"
+#include "fileio.h"
+//#include "constants.h"
+#include "steam/steamtypes.h"
+#include "tier0/validator.h"
+#include "tier1/utlmap.h"
+#include "tier1/utlstring.h"
+#include "tier0/tslist.h"
+#include "html/ihtmlchrome.h"
+#include "html/htmlprotobuf.h"
+
+#endif
|