summaryrefslogtreecommitdiff
path: root/public/panorama/controls/html.h
blob: b1b9902d546a840c8c9b7be482bc30ddbbced3c5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
//=========== Copyright Valve Corporation, All rights reserved. ===============//
//
// Purpose: 
//=============================================================================//

#ifndef PANORAMA_HTML_H
#define PANORAMA_HTML_H

#ifdef _WIN32
#pragma once
#endif

#include "panel2d.h"
#include "tier1/utlmap.h"
#include "tier1/utlstring.h"
#include "../uievent.h"
#include "mathlib/beziercurve.h"
#include "../textinput/textinput.h"

#if !defined( SOURCE2_PANORAMA ) && !defined( PANORAMA_PUBLIC_STEAM_SDK )
#include "html/ihtmlchrome.h"
#include "tier1/shared_memory.h"
#endif

class CTexturePanel;
namespace panorama
{
class CTextTooltip;
class CHTML;
class CFileOpenDialog;

struct HtmlFormHasFocus_t
{
	HtmlFormHasFocus_t() :
		m_bInput( false ),
		m_bInputHasMultiplePeers( false ),
		m_bUserInputThisPage( false ),
		m_bFocusedElementChanged( true )
	{
	}
	void Reset()
	{
		m_bInput = false;
		m_bUserInputThisPage = false;
		m_bInputHasMultiplePeers = false;
		m_bFocusedElementChanged = true;
	}

	bool operator==(const HtmlFormHasFocus_t &rhs) const
	{
		return rhs.m_bInput == m_bInput && 
			rhs.m_sName == m_sName &&
			rhs.m_sSearchLabel == m_sSearchLabel &&
			rhs.m_sInputType == m_sInputType;
	}
	bool			m_bInput;
	CUtlString		m_sName;
	CUtlString		m_sSearchLabel;
	bool			m_bInputHasMultiplePeers;
	bool			m_bUserInputThisPage;
	CUtlString		m_sInputType;
	bool			m_bFocusedElementChanged;
};

DECLARE_PANEL_EVENT2( HTMLURLChanged, const char *, const char * )
DECLARE_PANEL_EVENT1( HTMLLoadPage, const char * )
DECLARE_PANEL_EVENT2( HTMLFinishRequest, const char *, const char * )
DECLARE_PANEL_EVENT1( HTMLTitle, const char * )
DECLARE_PANEL_EVENT1( HTMLStatusText, const char * )
DECLARE_PANEL_EVENT2( HTMLJSAlert, const char *, bool * )
DECLARE_PANEL_EVENT2( HTMLJSConfirm, const char *, bool * )
DECLARE_PANEL_EVENT2( HMTLLinkAtPosition, const char *, bool )
DECLARE_PANEL_EVENT4( HMTLThumbNailImage, int, CUtlBuffer *, uint32, uint32  )
DECLARE_PANEL_EVENT1( HTMLOpenLinkInNewTab, const char * )
DECLARE_PANEL_EVENT2( HTMLOpenPopupTab,  CHTML *, const char * )
DECLARE_PANEL_EVENT2( HTMLBackForwardState, bool, bool )
DECLARE_PANEL_EVENT2( HTMLUpdatePageSize, int, int )
DECLARE_PANEL_EVENT5( HTMLSecurityStatus, const char *, bool, bool, bool, const char * )
DECLARE_PANEL_EVENT1( HTMLFullScreen, bool )
DECLARE_PANEL_EVENT2( HTMLStartMousePanning, int, int )
DECLARE_PANEL_EVENT0( HTMLStopMousePanning )
DECLARE_PANEL_EVENT0( HTMLCloseWindow )
DECLARE_PANEL_EVENT2( HTMLFormHasFocus, HtmlFormHasFocus_t, const char * /* URL */ )
DECLARE_PANEL_EVENT2( HTMLScreenShotTaken, const char *, const char * )
DECLARE_PANEL_EVENT1( HTMLFocusedNodeValue, const char * )
DECLARE_PANEL_EVENT0( HTMLSteamRightPadMoving );
DECLARE_PANEL_EVENT2( HTMLStartRequest, const char *, bool * );

class CImagePanel;

enum CursorCode
{
	eCursorNone,
	eCursorArrow
};

class IUIDoubleBufferedTexture;
class CTransform3D;
extern const int k_nExtraScrollRoom; // max number of padding pixels to use if needed

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CHTML : public CPanel2D, public ITextInputControl
#if !defined( SOURCE2_PANORAMA ) && !defined( PANORAMA_PUBLIC_STEAM_SDK )
	, public IHTMLResponses
#endif
{
	DECLARE_PANEL2D( CHTML, CPanel2D );

public:
	CHTML( CPanel2D *parent, const char * pchPanelID,  bool bPopup = false );
	virtual ~CHTML();
	void Shutdown();

	// panel2d overrides
	virtual void Paint();
	virtual bool BSetProperty( CPanoramaSymbol symName, const char *pchValue ) OVERRIDE;
	virtual void OnLayoutTraverse( float flFinalWidth, float flFinalHeight );
	virtual void OnStylesChanged();
	virtual bool BRequiresContentClipLayer() OVERRIDE { return true; } // BUGBUG Alfred - fix ::Paint to scale u/v offsets rather than requiring a clipping

	// simple browser management
	void OpenURL(const char *);
	void PostURL( const char *pchURL, const char *pchPostData );
	void AddHeader( const char *pchHeader, const char *pchValue );
	void StopLoading();
	void Refresh();
	void GoBack();
	void GoForward();
	bool BCanGoBack();
	bool BCanGoForward();
	
	// kb/mouse management
	virtual bool OnKeyDown( const KeyData_t &code ) OVERRIDE;
	virtual bool OnKeyUp( const KeyData_t & code ) OVERRIDE;
	virtual bool OnKeyTyped( const KeyData_t &unichar ) OVERRIDE;
	virtual bool OnGamePadDown( const GamePadData_t &code ) OVERRIDE;
	virtual bool OnGamePadUp( const GamePadData_t &code ) OVERRIDE;
	virtual bool OnGamePadAnalog( const GamePadData_t &code ) OVERRIDE;
	virtual bool OnMouseButtonDown( const MouseData_t &code ) OVERRIDE;
	virtual bool OnMouseButtonUp( const MouseData_t &code ) OVERRIDE;
	virtual bool OnMouseButtonDoubleClick( const MouseData_t &code ) OVERRIDE;
	virtual bool OnMouseWheel( const MouseData_t &code ) OVERRIDE;
	virtual void OnMouseMove( float flMouseX, float flMouseY ) OVERRIDE;

	virtual void SetupJavascriptObjectTemplate() OVERRIDE;

	// run input event processing for something that may not be a real input event, so don't bubble to parents, etc.
	bool OnGamePadDownImpl( const GamePadData_t &code, bool *out_pbOptionalResult = nullptr );
	bool OnGamePadAnalogImpl( const GamePadData_t &code, bool *out_pbOptionalResult = nullptr );
	
	bool ProcessAnalogScroll( float fValueX, float fValueY, double fTimeDelta, float fDeadzoneValue );
	bool ProcessAnalogZoom( float fValueX, float fValueY, double fTimeDelta, float fDeadzoneValue );
	void ProcessRawScroll( bool bFingerDown );
	void ProcessRawZoom( float fValueRaw );

	// browser helpers
	void Copy();
	void Paste();
	void RequestLinkUnderGamepad() { RequestLinkAtPosition( GetActualLayoutWidth()/2 - GetHScrollOffset(), GetActualLayoutHeight()/2 - GetVScrollOffset() ); }
	void RequestLinkUnderMouse() { RequestLinkAtPosition( m_flCursorX - GetHScrollOffset(), m_flCursorY - GetVScrollOffset() ); }
	void ZoomToElementUnderPanelCenter();
	void ZoomToElementUnderMouse();
	const char *PchLastLinkAtPosition() { return m_LinkAtPos.m_sURL; }
	void RunJavascript( const char *pchScript );
	void ViewSource();
	void SetHorizontalScroll( int scroll );
	void SetVerticalScroll( int scroll );
	void OnHTMLCursorMove( float flMouseX, float flMouseY );

	// finding text on the page
	void Find( const char *pchSubStr );
	void StopFind();
	void FindNext();
	void FindPrevious();

	void SetFileDialogChoice( const char *pchFileName ); // callback if cef wanted us to pick a file

	bool BAcceptMouseInput(); // returns true if the control is listening to mouse input right now, false if gamepad input mode is on
	virtual bool BRequiresFocus() OVERRIDE { return true; }

	bool BIgnoreMouseBackForwardButtons() { return m_bIgnoreMouseBackForwardButtons; }
	void SetIgnoreMouseBackForwardButtons( bool bIgnore ) { m_bIgnoreMouseBackForwardButtons = bIgnore; }

	const char *PchCurrentURL() { return m_sCurrentURL; } // the current URL the browser has loaded
	const char *PchCurrentPageTitle() { return m_sHTMLTitle; } // the title of the currently loaded page

	void SaveCurrentPageToJPEG( const char *pchFileName, int nWide, int nTall ); // save this current page to a jpeg

	// results for JS alert popups
	void DismissJSDialog( bool bRetVal );

	static uint32 GetAndResetPaintCounter();

	void ReleaseTextureMemory( bool bSuppressTextureLoads = false );
	void RefreshTextureMemory();

	void CaptureThumbNailImage( CPanel2D *pEventTarget, int iUserData );
	void IncrementPageScale( float flScaleIncrement, bool bZoomFromOrigin = false );
	void ExitFullScreen();
	void ExecuteJavaScript( const char *pchScript );

	// SSL/security state for the loaded html page
	bool BIsSecure() const { return m_bIsSecure; }
	bool BIsCertError() const { return m_bIsCertError; }
	bool BIsEVCert() const { return m_bIsEVCert; }
	const char *PchCertName() const { return m_sCertName; }

	// if true don't allow the page to scroll beyond the page edges
	void SetDontAllowOverScroll( bool bState );
	void SetEmbeddedMode( bool bState );

	void ZoomPageToFocusedElement( int nLeftOffset, int nTopOffset );

	// ITextInputControl helpers
	virtual int32 GetCursorOffset() const { return 0; }
	virtual  uint GetCharCount() const { return 0; }

	virtual const char *PchGetText() const { return ""; }
	virtual const wchar_t *PwchGetText() const { return L""; }

	virtual void InsertCharacterAtCursor( const wchar_t &unichar );
	virtual void InsertCharactersAtCursor( const wchar_t *pwch, size_t cwch ) 
	{
		for ( uint i = 0; i < cwch; i++ )
			InsertCharacterAtCursor( pwch[i] ); 
	}
	bool BSupportsImmediateTextReturn() { return false; }
	void RequestControlString() { RequestFocusedNodeValue(); }

	virtual CPanel2D *GetAssociatedPanel() { return this; }

	void PauseFlashVideoIfVisible();

	void ResetScrollbarsAndClearOverflow();

	void SetPopupChild(CHTML *pChild) { m_pPopupChild = pChild; }

#ifdef DBGFLAG_VALIDATE
	virtual void ValidateClientPanel( CValidator &validator, const char *pchName ) OVERRIDE;
	static void ValidateStatics( CValidator &validator, const char *pchName );
#endif

	class CHTMLVerticalScrollBar : public CScrollBar
	{
		DECLARE_PANEL2D( CHTMLVerticalScrollBar, CScrollBar );

	public:
		CHTMLVerticalScrollBar( CPanel2D *parent, const char * pchPanelID ) : CScrollBar( parent, pchPanelID )
		{
			m_pScrollThumb->AddClass( "VerticalScrollThumb" );
		}

		void ScrollToMousePos()
		{
			float flHeight = GetActualLayoutHeight();
			if ( flHeight > 0.00001f )
			{
				if ( m_bMouseWentDownOnThumb )
				{
					float flPercentDiff = (m_flMouseY - m_flMouseStartY) / flHeight;
					float flPositionOffset = flPercentDiff * GetRangeSize();
					float flPosition = m_flScrollStartPosition + flPositionOffset;
					SetScrollWindowPosition( clamp( flPosition, 0.0f, GetRangeSize() - GetScrollWindowSize() ), true );
				}
				else
				{
					float flPercent = m_flMouseY / flHeight;
					float flPos = GetRangeSize() * flPercent;
					SetScrollWindowPosition( clamp( flPos, 0.0f, GetRangeSize() - GetScrollWindowSize() ), true );
				}
			}
		}


		virtual ~CHTMLVerticalScrollBar() {}

	protected:
		virtual void UpdateLayout( bool bImmediateMove )
		{
			CUILength zero;
			zero.SetLength( 0.0f );

			if ( GetRangeSize() < 0.001f )
				return;

			CUILength length;

			float flXPosPercent = (GetScrollWindowPosition() - GetRangeMin()) / GetRangeSize();
			length.SetPercent( flXPosPercent * 100.0f );
			if ( bImmediateMove )
				m_pScrollThumb->SetPositionWithoutTransition( zero, length, zero );
			else
				m_pScrollThumb->SetPosition( zero, length, zero );

			float flWidthPercent = GetScrollWindowSize() / GetRangeSize();

			length.SetPercent( flWidthPercent*100.0f );
			m_pScrollThumb->AccessStyleDirty()->SetHeight( length );
			length.SetPercent( 100.0f );
			m_pScrollThumb->AccessStyleDirty()->SetWidth( length );

			m_bLastMoveImmediate = bImmediateMove;
		}
	};

	class CHTMLHorizontalScrollBar : public CScrollBar
	{
		DECLARE_PANEL2D( CHTMLHorizontalScrollBar, CScrollBar );

	public:
		CHTMLHorizontalScrollBar( CPanel2D *parent, const char * pchPanelID ) : CScrollBar( parent, pchPanelID )
		{
			m_pScrollThumb->AddClass( "HorizontalScrollThumb" );
		}

		void ScrollToMousePos()
		{
			float flWidth = GetActualLayoutWidth();
			if ( flWidth > 0.00001f )
			{
				if ( m_bMouseWentDownOnThumb )
				{
					float flPercentDiff = (m_flMouseX - m_flMouseStartX) / flWidth;
					float flPositionOffset = flPercentDiff * GetRangeSize();
					float flPosition = m_flScrollStartPosition + flPositionOffset;
					SetScrollWindowPosition( clamp( flPosition, 0.0f, GetRangeSize() - GetScrollWindowSize() ), true );
				}
				else
				{
					float flPercent = m_flMouseX / flWidth;
					float flPos = GetRangeSize() * flPercent;
					SetScrollWindowPosition( clamp( flPos, 0.0f, GetRangeSize() - GetScrollWindowSize() ), true );
				}
			}
		}


		virtual ~CHTMLHorizontalScrollBar() {}

	protected:
		virtual void UpdateLayout( bool bImmediateMove )
		{
			CUILength zero;
			zero.SetLength( 0.0f );

			if ( GetRangeSize() < 0.001f )
				return;

			CUILength length;

			float flXPosPercent = (GetScrollWindowPosition() - GetRangeMin()) / GetRangeSize();
			length.SetPercent( flXPosPercent * 100.0f );
			if ( bImmediateMove )
				m_pScrollThumb->SetPositionWithoutTransition( length, zero, zero );
			else
				m_pScrollThumb->SetPosition( length, zero, zero );

			float flWidthPercent = GetScrollWindowSize() / GetRangeSize();

			length.SetPercent( flWidthPercent*100.0f );
			m_pScrollThumb->AccessStyleDirty()->SetWidth( length );
			length.SetPercent( 100.0f );
			m_pScrollThumb->AccessStyleDirty()->SetHeight( length );
			m_bLastMoveImmediate = bImmediateMove;
		}
	};

	enum EHTMLScrollDirection
	{
		kHTMLScrollDirection_Up,
		kHTMLScrollDirection_Down,
		kHTMLScrollDirection_Left,
		kHTMLScrollDirection_Right
	};

	bool BCanScrollInDirection( EHTMLScrollDirection eDirection ) const;

	static float GetScrollDeadzoneScale() { return s_fScrollDeadzoneScale; }

protected:
	// functions you can override to specialize html behavior
	virtual void OnURLChanged( const char *url, const char *pchPostData, bool bIsRedirect );
	virtual void OnFinishRequest(const char *url, const char *pageTitle);
	virtual void OnPageLoaded( const char *url, const char *pageTitle, const CUtlMap < CUtlString, CUtlString > &headers );
	virtual bool OnStartRequestInternal( const char *url, const char *target, const char *pchPostData, bool bIsRedirect );
	virtual void ShowPopup();
	virtual void HidePopup();
	virtual bool OnOpenNewTab( const char *pchURL, bool bForeground );
	virtual bool OnPopupHTMLWindow( const char *pchURL, int x, int y, int wide, int tall );
	virtual void SetHTMLTitle( const char *pchTitle );
	virtual void OnLoadingResource( const char *pchURL );
	virtual void OnSetStatusText(const char *text);
	virtual void OnSetCursor( CursorCode cursor );
	virtual void OnFileLoadDialog( const char *pchTitle, const char *pchInitialFile );
	virtual void OnShowToolTip( const char *pchText );
	virtual void OnUpdateToolTip( const char *pchText );
	virtual void OnHideToolTip();
	virtual void OnSearchResults( int iActiveMatch, int nResults );

	friend class ::CTexturePanel;
	IUIDoubleBufferedTexture *m_pDoubleBufferedTexture;
	IUIDoubleBufferedTexture *m_pDoubleBufferedTexturePending;
	IUIDoubleBufferedTexture *m_pDoubleBufferedTextureComboBox;
	int32 m_nTextureSerial; // serial number of the last texture we uploaded

	void RequestFocusedNodeValue();
	// if true then our html control overrides scrolling and scrollbars, if false we 
	// let the web control scroll itself
	void SetManualHTMLScroll( bool bControlScroll ) { m_bControlPageScrolling = bControlScroll;  }

private:
	typedef void (CHTML::* ScrollFunc_t)( float, bool );
	bool ProcessAnalogScrollAxis( float fValue, float fDeadzoneValue, double fTimeDelta, ScrollFunc_t ScrollFunc );

	// we used to create the virtual mouse in our constructor, but now we don't know enough information at
	// construction time to know whether we want one (ie., if we're wrapped by CHTMLSimpleNavigationWrapper
	// we disable touchpad navigation). Instead we just try to lazy-create one at first use.
	void LazyCreateVirtualMouseIfNecessary();

	// getters/setters for html cef object
	void SetHTMLFocus();
	void KillHTMLFocus();
	int HorizontalScroll();
	int VerticalScroll();
	bool IsHorizontalScrollBarVisible();
	bool IsVeritcalScrollBarVisible();
	void RequestLinkAtPosition( int x, int y );
	void GetCookiesForURL( const char *pchURL );
	void UpdatePanoramaScrollBars();
	bool BHandleKeyPressPageScroll() const;

#if defined( SOURCE2_PANORAMA ) || defined( PANORAMA_PUBLIC_STEAM_SDK )
	STEAM_CALLBACK( CHTML, OnLinkAtPositionResponse, HTML_LinkAtPosition_t, m_LinkAtPosRespose );

	STEAM_CALLBACK( CHTML, OnHTMLNeedsPaint, HTML_NeedsPaint_t, m_HTML_NeedsPaint );
	STEAM_CALLBACK( CHTML, OnHTMLStartRequest, HTML_StartRequest_t, m_HTML_StartRequest );
	STEAM_CALLBACK( CHTML, OnHTMLCloseBrowser, HTML_CloseBrowser_t, m_HTML_CloseBrowser );
	STEAM_CALLBACK( CHTML, OnHTMLURLChanged, HTML_URLChanged_t, m_HTML_URLChanged );
	STEAM_CALLBACK( CHTML, OnHTMLFinishedRequest, HTML_FinishedRequest_t, m_HTML_FinishedRequest );
	STEAM_CALLBACK( CHTML, OnHTMLOpenLinkInNewTab, HTML_OpenLinkInNewTab_t, m_HTML_OpenLinkInNewTab );
	STEAM_CALLBACK( CHTML, OnHTMLChangedTitle, HTML_ChangedTitle_t, m_HTML_ChangedTitle );
	STEAM_CALLBACK( CHTML, OnHTMLSearchResults, HTML_SearchResults_t, m_HTML_SearchResults );
	STEAM_CALLBACK( CHTML, OnHTMLCanGoBackAndForward, HTML_CanGoBackAndForward_t, m_HTML_CanGoBackAndForward );
	STEAM_CALLBACK( CHTML, OnHTMLHorizontalScroll, HTML_HorizontalScroll_t, m_HTML_HorizontalScroll );
	STEAM_CALLBACK( CHTML, OnHTMLVerticalScroll, HTML_VerticalScroll_t, m_HTML_VerticalScroll );
	STEAM_CALLBACK( CHTML, OnHTMLJSAlert, HTML_JSAlert_t, m_HTML_JSAlert );
	STEAM_CALLBACK( CHTML, OnHTMLJSConfirm, HTML_JSConfirm_t, m_HTML_JSConfirm );
	STEAM_CALLBACK( CHTML, OnHTMLFileOpenDialog, HTML_FileOpenDialog_t, m_HTML_FileOpenDialog );
	STEAM_CALLBACK( CHTML, OnHTMLNewWindow, HTML_NewWindow_t, m_HTML_NewWindow );
	STEAM_CALLBACK( CHTML, OnHTMLSetCursor, HTML_SetCursor_t, m_HTML_SetCursor );
	STEAM_CALLBACK( CHTML, OnHTMLStatusText, HTML_StatusText_t, m_HTML_StatusText );
	STEAM_CALLBACK( CHTML, OnHTMLShowToolTip, HTML_ShowToolTip_t, m_HTML_ShowToolTip );
	STEAM_CALLBACK( CHTML, OnHTMLUpdateToolTip, HTML_UpdateToolTip_t, m_HTML_UpdateToolTip );
	STEAM_CALLBACK( CHTML, OnHTMLHideToolTip, HTML_HideToolTip_t, m_HTML_HideToolTip );
#else
	// message handlers for ipc thread
	void BrowserSetIndex( int idx ) { m_iBrowser = idx; SendPendingHTMLMessages(); }
	int  BrowserGetIndex() { return m_iBrowser; }
	void BrowserReady( const CMsgBrowserReady *pCmd );
	void BrowserSetSharedPaintBuffers( const CMsgSetSharedPaintBuffers *pCmd );
	void BrowserNeedsPaint( const CMsgNeedsPaint *pCmd );
	void BrowserStartRequest( const CMsgStartRequest *pCmd );
	void BrowserURLChanged( const CMsgURLChanged *pCmd );
	void BrowserLoadedRequest( const CMsgLoadedRequest *pCmd );
	void BrowserFinishedRequest(const CMsgFinishedRequest *pCmd);
	void BrowserPageSecurity( const CMsgPageSecurity *pCmd );
	void BrowserShowPopup( const CMsgShowPopup *pCmd );
	void BrowserHidePopup( const CMsgHidePopup *pCmd );
	void BrowserOpenNewTab( const CMsgOpenNewTab *pCmd );
	IHTMLResponses *BrowserPopupHTMLWindow( const CMsgPopupHTMLWindow *pCmd );
	void BrowserSetHTMLTitle( const CMsgSetHTMLTitle *pCmd );
	void BrowserLoadingResource( const CMsgLoadingResource *pCmd );
	void BrowserStatusText( const CMsgStatusText *pCmd );
	void BrowserSetCursor( const CMsgSetCursor *pCmd );
	void BrowserFileLoadDialog( const CMsgFileLoadDialog *pCmd );
	void BrowserShowToolTip( const CMsgShowToolTip *pCmd );
	void BrowserUpdateToolTip( const CMsgUpdateToolTip *pCmd );
	void BrowserHideToolTip( const CMsgHideToolTip *pCmd );
	void BrowserSearchResults( const CMsgSearchResults *pCmd );
	void BrowserClose( const CMsgClose *pCmd );
	void BrowserHorizontalScrollBarSizeResponse( const CMsgHorizontalScrollBarSizeResponse *pCmd );
	void BrowserVerticalScrollBarSizeResponse( const CMsgVerticalScrollBarSizeResponse *pCmd );
	void BrowserGetZoomResponse( const CMsgGetZoomResponse *pCmd ) {}
	void BrowserLinkAtPositionResponse( const CMsgLinkAtPositionResponse *pCmd );
	void BrowserZoomToElementAtPositionResponse( const CMsgZoomToElementAtPositionResponse *pCmd );
	void BrowserJSAlert( const CMsgJSAlert *pCmd );
	void BrowserJSConfirm( const CMsgJSConfirm *pCmd );
	void BrowserCanGoBackandForward( const CMsgCanGoBackAndForward *pCmd );
	void BrowserOpenSteamURL( const CMsgOpenSteamURL *pCmd );
	void BrowserSizePopup( const CMsgSizePopup *pCmd );
	void BrowserScalePageToValueResponse( const CMsgScalePageToValueResponse *pCmd );
	void BrowserRequestFullScreen( const CMsgRequestFullScreen *pCmd );
	void BrowserExitFullScreen( const CMsgExitFullScreen *pCmd );
	void BrowserGetCookiesForURLResponse( const CMsgGetCookiesForURLResponse *pCmd );
	void BrowserNodeGotFocus( const CMsgNodeHasFocus *pCmd );
	void BrowserSavePageToJPEGResponse( const CMsgSavePageToJPEGResponse *pCmd );
	void BrowserFocusedNodeValueResponse( const CMsgFocusedNodeTextResponse *pCmd );
	void BrowserComboNeedsPaint(const CMsgComboNeedsPaint *pCmd);
	bool BSupportsOffMainThreadPaints();
	void ThreadNotifyPendingPaints();
#endif

	// helpers to control browser side, pos and textures
	void SetBrowserSize( int wide, int tall );
	void SendPendingHTMLMessages();

	// helpers to move the html page around inside the control
	void ScrollPageUp( float flScrollValue, bool bApplyBezier );
	void ScrollPageDown( float flScrollValue, bool bApplyBezier );
	void ScrollPageLeft( float flScrollValue, bool bApplyBezier );
	void ScrollPageRight( float flScrollValue, bool bApplyBezier );

	// Overrides for scroll bar to call back to us rather than normal panel2d call
	virtual void ScrollToXPercent( float flXPercent );
	virtual void ScrollToYPercent( float flXPercent );

	// event handlers
	bool OnGamepadInput();
	bool OnPropertyTransitionEnd( const CPanelPtr< IUIPanel > &pPanel, CStyleSymbol prop );
	bool OnSetBrowserSize( const CPanelPtr< IUIPanel > &pPanel, int nWide, int nTall );
	bool OnHTMLFormFocusPending( const CPanelPtr< IUIPanel > &pPanel );
	bool OnInputFocusSet( const panorama::CPanelPtr< panorama::IUIPanel > &ptrPanel );
	bool OnInputFocusLost( const panorama::CPanelPtr< panorama::IUIPanel > &ptrPanel );
	bool OnHTMLScreenShotCaptured( const panorama::CPanelPtr< panorama::IUIPanel > &ptrPanel, int nThumbNailWidth, int nThumbNailHeight  );
	bool OnHTMLCommitZoom( const panorama::CPanelPtr< panorama::IUIPanel > &ptrPanel, float flZoom );
	bool OnHTMLRequestRepaint( const panorama::CPanelPtr< panorama::IUIPanel > &ptrPanel );

#if defined( SOURCE2_PANORAMA ) || defined( PANORAMA_PUBLIC_STEAM_SDK )
	bool OnFileOpenDialogFilesSelected( const panorama::CPanelPtr< panorama::IUIPanel > &ptrPanel, const char *pszFiles );
#endif

	// moving the html texture around
	void ResizeBrowserTextureIfNeeded();
	int AdjustPageScrollForTextureOffset( int &nTargetValue, const int nCurScroll, const int nMaxScroll, float &flOffsetTextureScroll, const float flMaxTextureScroll );

	int GetHScrollOffset() 
	{ 
		return m_ScrollLeft.m_flOffsetTextureScroll;
	}

	int GetVScrollOffset() 
	{ 
		return m_ScrollUp.m_flOffsetTextureScroll;
	}

	void ClampTextureScroll( bool bAllowScrollBorder = true );

	bool m_bInitialized; // used to prevent double shutdown
	bool m_bReady; // When we are ready to load a url
	CTexturePanel *m_pTexurePanel;

	int m_nWindowWide, m_nWindowTall; // how big the html texture should be
	int m_nTextureWide, m_nTextureTall;

	// find in page state
	bool m_bInFind;
	CUtlString m_sLastSearchString;

	CUtlString m_sURLToLoad; // url to load once the browser is created
	CUtlString m_sURLPostData; // post data for url to load

	CUtlString m_sCurrentURL; // the current url we have loaded
	CUtlString m_sHTMLTitle; // the title of the page we are on

	int m_iBrowser; // our browser handle

	float m_flZoom; // what zoom level we are at
	bool m_bLastKeyFocus; // tracking for when key focus changes in style application

	struct ScrollControl_t
	{
		ScrollControl_t()
		{
			Reset();
		}

		void Reset()
		{
			m_flOffsetTextureScroll = 0.0f;
			m_bScrollingUp = false;
			m_flLastScrollTime = 0.0f;
		}

		float m_flOffsetTextureScroll; // amount the html texture is scrolled around the panel itself
		bool m_bScrollingUp; // we are scrolling up (or left) on the page last?
		double m_flLastScrollTime; // when did we scroll in this direction last, used for accel curve
	};

	ScrollControl_t m_ScrollUp;
	ScrollControl_t m_ScrollLeft;

	struct ScrollData_t
	{
		ScrollData_t() 
		{
			m_bVisible = false;
			m_nMaxScroll = m_nScroll = m_nPageSize = m_nWebScroll = 0;
		}

		bool operator==( const ScrollData_t &rhs ) const
		{
			return rhs.m_bVisible == m_bVisible &&
				rhs.m_nScroll == m_nScroll &&
				rhs.m_nPageSize == m_nPageSize &&
				rhs.m_nMaxScroll == m_nMaxScroll;
		}

		bool operator!=( const ScrollData_t &rhs ) const
		{
			return !operator==(rhs);
		}

		bool m_bVisible; // is the scroll bar visible
		int m_nMaxScroll; // most amount of pixels we can scroll
		int m_nPageSize; // the underlying size of the page itself in pixels
		int m_nScroll; // currently scrolled amount of pixels
		int m_nWebScroll; // last scrolled return value from cef, not updated locally
	};
	bool ScrollHelper( ScrollControl_t &scrollControl, float flScrollDelta, int iMaxScrollOffset, ScrollData_t &scrollBar, float &flScrollHTMLAmount, bool bApplyBezier ); // shared code when scrolling around the page
	bool SetupScrollBar( const ScrollData_t & scrollData, bool bHorizontal, float flContentSize, float flMaxSize );
	CScrollBar *MakeScrollBar( bool bHorizontal);

	ScrollData_t m_scrollHorizontal; // details of horizontal scroll bar
	ScrollData_t m_scrollVertical; // details of vertical scroll bar
	CCubicBezierCurve< Vector2D > m_ScrollBezier; // the curve to scale scroll accel by

	struct LinkAtPos_t
	{
		LinkAtPos_t() { m_bLiveLink = false; }
		CUtlString m_sURL;
		bool m_bLiveLink;
		bool m_bInput;
	};
	LinkAtPos_t m_LinkAtPos; // cache for link at pos requests, because the request is async

	// last position we saw the mouse at
	float m_flCursorX;
	float m_flCursorY;

	double m_flGamePadInputTime; // last time we saw input from the gamepad

	bool m_bPopupVisible; // true if a popup menu is visible on the client
	bool m_bCanGoBack;
	bool m_bCanGoForward;
	bool m_bIgnoreMouseBackForwardButtons;

	int m_nHTMLPageWide; // last size we told CEF the page should be 
	int m_nHTMLPageTall;

	CHTMLVerticalScrollBar *m_pVerticalScrollBar; // our own copy of the scroll bars that we control manually
	CHTMLHorizontalScrollBar *m_pHorizontalScrollBar;
	float m_flLastVeritcalScrollPos;
	float m_flLastHorizontalScrollPos;

	static uint32 sm_PaintCount;
	uint32 m_PageLoadCount; // the number of posturl calls we have made
#if !defined( SOURCE2_PANORAMA ) && !defined( PANORAMA_PUBLIC_STEAM_SDK )
	CUtlVector<HTMLCommandBuffer_t *> m_vecPendingMessages;
#endif
	bool m_bSuppressTextureLoads;

	bool m_bCaptureThumbNailThisFrame;
	CPanel2D *m_pCaptureEventTarget;
	int m_nCaptureUserData;

	bool m_bCommenceZoomOperationOnTextureUpload; // when the next texture upload is ready, should we apply scale/offset transforms we have saved above
	float m_flHorizScrollOffset; // the offset between page scroll and texture scroll we had at the start of a zoom
	float m_flVertScrollOffset; // the offset between page scroll and texture scroll we had at the start of a zoom
	bool m_bFullScreen; // are we in fullscreen right now?
	bool m_bConfigureYouTubeHTML5OptIn; // are we doing the forcefully opt into youtube html5 beta path
	bool m_bMousePanningActive; // true if the mouse is in panning mode
	Vector2D m_vecMousePanningPos; // the x,y pos of the mouse over the panel when middle panning started
	CImagePanel *m_pMousePanningImage; // the image to show when panning
	CCubicBezierCurve< Vector2D > m_MousePanBezier; // the curve to scale panning accel by
	bool m_bIsSecure; // is this page ssl secure?
	bool m_bIsCertError; // did we have a cert error when loading? 
	bool m_bIsEVCert; // is it an EV cert?
	CUtlString m_sCertName; // who was the cert issued to?
	bool m_bEmbedded; // if true we are embedded instance, just show html pages and simple scrolling, not complex interactions
	bool m_bAllowOverScroll; // if true allow scrolling the edge of the texture beyond the edge of the screen (i.e so you can hover the recticle at any point)
	bool m_bLastScrollbarSetupAllowedOverScroll;
	float m_flMouseLastX;
	float m_flMouseLastY;
	float m_flLastSteamPadScroll;
	uint32 m_unSteamPadScrollRepeats;

	panorama::HtmlFormHasFocus_t m_evtFocus;		// used for saving state of controls that have focus info dispatched

	bool m_bPendingInputZoom; // true if we are zooming into an input element
	bool m_bFocusEventSentForClick; // time we sent a focus event to the browser
	bool m_bDidMousePanWhileMouseDown; // did we do panning with the mouse held down
	bool m_bWaitingForZoomResponse;

	Vector2D m_LastSteamRightPad;

	panorama::CTextTooltip *m_pTooltip;
	bool m_bGotKeyDown;
#if defined( SOURCE2_PANORAMA ) || defined( PANORAMA_PUBLIC_STEAM_SDK )
	HHTMLBrowser m_HTMLBrowser;
	void OnBrowserReady( HTML_BrowserReady_t *pBrowserReady, bool bIOFailure );
	CCallResult< CHTML, HTML_BrowserReady_t > m_SteamCallResultBrowserReady;

	CPanelPtr< CFileOpenDialog > m_pFileOpenDialog;
	
	CUtlVector<HHTMLBrowser> m_vecDenyNewBrowserWindows;
#else
	CChromePaintBufferClient m_SharedPaintBuffer;
#endif

	int m_nPopupX;
	int m_nPopupY;
	int m_nPopupWide;
	int m_nPopupTall;
	int m_nTextureSerialCombo;
	CUtlBuffer m_ComboTexture;
	CHTML *m_pPopupChild;

	CThreadMutex m_mutexHTMLTexture;
	CThreadMutex m_mutexScreenShot;
	CUtlBuffer m_bufScreenshotTexture;
	float m_flScrollRemainder;
	int m_nTargetHorizontalScrollValue;
	int m_nTargetVerticalScrollValue;
	bool m_bControlPageScrolling;

	// virtual mouse used when steam controller is connected
	IVirtualMouse *m_pLeftMousePad;
	Vector2D m_vecVirtualScrollPrev;
	Vector2D m_vecVirtualScrollOrigin;
	bool m_bVerticalAxisSnap;
	bool m_bClickingLeftPad;
	bool m_bMarkZoomStart;
	float m_flInitialZoomLevel;
	float m_flZoomSwipeOriginPosition;

	static const float s_fScrollDeadzoneScale;
};

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CHTMLSimpleNavigationWrapper : public CPanel2D
{
	DECLARE_PANEL2D( CHTMLSimpleNavigationWrapper, CPanel2D );

public:
	CHTMLSimpleNavigationWrapper( CPanel2D *pParent, const char *pchPanelID );

	virtual bool BSetProperty( CPanoramaSymbol symName, const char *pchValue ) OVERRIDE;

	virtual bool OnGamePadDown( const GamePadData_t &code ) OVERRIDE;
	virtual bool OnGamePadAnalog( const GamePadData_t &code ) OVERRIDE;
	virtual bool OnMouseWheel( const MouseData_t &code ) OVERRIDE;

private:
	void EnsureHTMLPanelReference();

private:
	CHTML *m_pHTML;
	CPanoramaSymbol m_symWrappedHTMLID;
	bool m_bInEventProcessing;
};

} // namespace panorama

#endif // PANORAMA_HTML_H