From 39ed87570bdb2f86969d4be821c94b722dc71179 Mon Sep 17 00:00:00 2001 From: Joe Ludwig Date: Wed, 26 Jun 2013 15:22:04 -0700 Subject: First version of the SOurce SDK 2013 --- mp/src/vgui2/chromehtml/chromewrapper.cpp | 441 ++++++++++++++++++++++++++++++ 1 file changed, 441 insertions(+) create mode 100644 mp/src/vgui2/chromehtml/chromewrapper.cpp (limited to 'mp/src/vgui2/chromehtml/chromewrapper.cpp') 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 + +//----------------------------------------------------------------------------- +// 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 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 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 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 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 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 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 + + + -- cgit v1.2.3