Files
UnrealEngineUWP/Engine/Source/Runtime/WebBrowser/Private/SWebBrowserView.cpp
Peter Knepley fa984a1bcf Copying //UE4/UT-Staging to //UE4/Dev-Main
#lockdown Nick.Penwarden

==========================
MAJOR FEATURES + CHANGES
==========================

3306447 Joe.Wilcox
Fix typo introduced in SWebBrowser

3306444 Joe.Wilcox
Added a way for games to restrict the context menu on Chromium Embedded Framework
-in fullscreen the window switch would cause a minimize

3306305 Peter.Knepley
Give gamestate a notification when async loading has succeeded for a package

3306275 Peter.Knepley
Fix netspeed in local replay situations

3267864 Peter.Knepley
Fix crash in AGameModeBase::GenericPlayerInitialization (may already be fixed in main)

3258890 Matt.Oelfke
Discard all navigation updates caused by octree construction needed to be moved up

3245388 Steve.Polge
DeltaTime parameter for HandleSwimmingWallHit

3245385 Steve.Polge
Added HandleSwimmingWallHit() to CharacterMovementComponent

3245011 Peter.Knepley
Extra safety for GetMoviePlayer() and slate loading thread

3242810 Joe.Wilcox
Made SSlider::CommitValue virtual

3235608 Peter.Knepley
Fix crash in APlayerController::Reset (may already be in main)

3224903 Joe.Wilcox
SC_CLOSE should translate to WM_CLOSE to fix corner cases with mouse focus and ALT+F4

3223132 Peter.Knepley
GetOutdatedFiles needs to be exported for non-monolithic builds to be able to link to it

[CL 3368714 by Peter Knepley in Main branch]
2017-03-28 17:14:05 -04:00

587 lines
14 KiB
C++

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
#include "SWebBrowserView.h"
#include "Misc/CommandLine.h"
#include "Containers/Ticker.h"
#include "WebBrowserModule.h"
#include "Layout/WidgetPath.h"
#include "Framework/Application/MenuStack.h"
#include "Framework/Application/SlateApplication.h"
#include "IWebBrowserDialog.h"
#include "IWebBrowserWindow.h"
#include "WebBrowserViewport.h"
#include "IWebBrowserAdapter.h"
#if PLATFORM_ANDROID
# include "Android/AndroidWebBrowserWindow.h"
#elif PLATFORM_IOS
# include "IOS/IOSPlatformWebBrowser.h"
#elif PLATFORM_PS4
# include "PS4/PS4PlatformWebBrowser.h"
#elif WITH_CEF3
# include "CEF/CEFWebBrowserWindow.h"
#else
# define DUMMY_WEB_BROWSER 1
#endif
#define LOCTEXT_NAMESPACE "WebBrowser"
SWebBrowserView::SWebBrowserView()
{
}
SWebBrowserView::~SWebBrowserView()
{
if (BrowserWindow.IsValid())
{
BrowserWindow->OnDocumentStateChanged().RemoveAll(this);
BrowserWindow->OnNeedsRedraw().RemoveAll(this);
BrowserWindow->OnTitleChanged().RemoveAll(this);
BrowserWindow->OnUrlChanged().RemoveAll(this);
BrowserWindow->OnToolTip().RemoveAll(this);
BrowserWindow->OnShowPopup().RemoveAll(this);
BrowserWindow->OnDismissPopup().RemoveAll(this);
BrowserWindow->OnShowDialog().Unbind();
BrowserWindow->OnDismissAllDialogs().Unbind();
BrowserWindow->OnCreateWindow().Unbind();
BrowserWindow->OnCloseWindow().Unbind();
if (BrowserWindow->OnBeforeBrowse().IsBoundToObject(this))
{
BrowserWindow->OnBeforeBrowse().Unbind();
}
if (BrowserWindow->OnLoadUrl().IsBoundToObject(this))
{
BrowserWindow->OnLoadUrl().Unbind();
}
if (BrowserWindow->OnBeforePopup().IsBoundToObject(this))
{
BrowserWindow->OnBeforePopup().Unbind();
}
}
if (SlateParentWindowSetupTickHandle.IsValid())
{
FTicker::GetCoreTicker().RemoveTicker(SlateParentWindowSetupTickHandle);
SlateParentWindowSetupTickHandle.Reset();
}
if (SlateParentWindowPtr.IsValid())
{
SlateParentWindowPtr.Pin()->GetOnWindowDeactivatedEvent().RemoveAll(this);
}
}
void SWebBrowserView::Construct(const FArguments& InArgs, const TSharedPtr<IWebBrowserWindow>& InWebBrowserWindow)
{
OnLoadCompleted = InArgs._OnLoadCompleted;
OnLoadError = InArgs._OnLoadError;
OnLoadStarted = InArgs._OnLoadStarted;
OnTitleChanged = InArgs._OnTitleChanged;
OnUrlChanged = InArgs._OnUrlChanged;
OnBeforeNavigation = InArgs._OnBeforeNavigation;
OnLoadUrl = InArgs._OnLoadUrl;
OnShowDialog = InArgs._OnShowDialog;
OnDismissAllDialogs = InArgs._OnDismissAllDialogs;
OnBeforePopup = InArgs._OnBeforePopup;
OnCreateWindow = InArgs._OnCreateWindow;
OnCloseWindow = InArgs._OnCloseWindow;
AddressBarUrl = FText::FromString(InArgs._InitialURL);
PopupMenuMethod = InArgs._PopupMenuMethod;
BrowserWindow = InWebBrowserWindow;
if(!BrowserWindow.IsValid())
{
static bool AllowCEF = !FParse::Param(FCommandLine::Get(), TEXT("nocef"));
if (AllowCEF)
{
FCreateBrowserWindowSettings Settings;
Settings.InitialURL = InArgs._InitialURL;
Settings.bUseTransparency = InArgs._SupportsTransparency;
Settings.bThumbMouseButtonNavigation = InArgs._SupportsThumbMouseButtonNavigation;
Settings.ContentsToLoad = InArgs._ContentsToLoad;
Settings.bShowErrorMessage = InArgs._ShowErrorMessage;
Settings.BackgroundColor = InArgs._BackgroundColor;
Settings.Context = InArgs._ContextSettings;
BrowserWindow = IWebBrowserModule::Get().GetSingleton()->CreateBrowserWindow(Settings);
}
}
SlateParentWindowPtr = InArgs._ParentWindow;
if (BrowserWindow.IsValid())
{
#ifndef DUMMY_WEB_BROWSER
// The inner widget creation is handled by the WebBrowserWindow implementation.
const auto& BrowserWidgetRef = static_cast<FWebBrowserWindow*>(BrowserWindow.Get())->CreateWidget();
ChildSlot
[
BrowserWidgetRef
];
BrowserWidget = BrowserWidgetRef;
#endif
if(OnCreateWindow.IsBound())
{
BrowserWindow->OnCreateWindow().BindSP(this, &SWebBrowserView::HandleCreateWindow);
}
if(OnCloseWindow.IsBound())
{
BrowserWindow->OnCloseWindow().BindSP(this, &SWebBrowserView::HandleCloseWindow);
}
BrowserWindow->OnDocumentStateChanged().AddSP(this, &SWebBrowserView::HandleBrowserWindowDocumentStateChanged);
BrowserWindow->OnNeedsRedraw().AddSP(this, &SWebBrowserView::HandleBrowserWindowNeedsRedraw);
BrowserWindow->OnTitleChanged().AddSP(this, &SWebBrowserView::HandleTitleChanged);
BrowserWindow->OnUrlChanged().AddSP(this, &SWebBrowserView::HandleUrlChanged);
BrowserWindow->OnToolTip().AddSP(this, &SWebBrowserView::HandleToolTip);
if (!BrowserWindow->OnBeforeBrowse().IsBound())
{
BrowserWindow->OnBeforeBrowse().BindSP(this, &SWebBrowserView::HandleBeforeNavigation);
}
else
{
check(!OnBeforeNavigation.IsBound());
}
if (!BrowserWindow->OnLoadUrl().IsBound())
{
BrowserWindow->OnLoadUrl().BindSP(this, &SWebBrowserView::HandleLoadUrl);
}
else
{
check(!OnLoadUrl.IsBound());
}
if (!BrowserWindow->OnBeforePopup().IsBound())
{
BrowserWindow->OnBeforePopup().BindSP(this, &SWebBrowserView::HandleBeforePopup);
}
else
{
check(!OnBeforePopup.IsBound());
}
BrowserWindow->OnShowDialog().BindSP(this, &SWebBrowserView::HandleShowDialog);
BrowserWindow->OnDismissAllDialogs().BindSP(this, &SWebBrowserView::HandleDismissAllDialogs);
BrowserWindow->OnShowPopup().AddSP(this, &SWebBrowserView::HandleShowPopup);
BrowserWindow->OnDismissPopup().AddSP(this, &SWebBrowserView::HandleDismissPopup);
BrowserWindow->OnSuppressContextMenu().BindSP(this, &SWebBrowserView::HandleSuppressContextMenu);
OnSuppressContextMenu = InArgs._OnSuppressContextMenu;
BrowserViewport = MakeShareable(new FWebBrowserViewport(BrowserWindow));
#if WITH_CEF3
BrowserWidget->SetViewportInterface(BrowserViewport.ToSharedRef());
#endif
SetupParentWindowHandlers();
// If we could not obtain the parent window during widget construction, we'll defer and keep trying.
if (!SlateParentWindowPtr.IsValid())
{
SlateParentWindowSetupTickHandle = FTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateLambda([this](float) -> bool
{
this->SetupParentWindowHandlers();
bool ContinueTick = !SlateParentWindowPtr.IsValid();
return ContinueTick;
}));
}
BrowserWindow->SetParentWindow(InArgs._ParentWindow);
}
else
{
OnLoadError.ExecuteIfBound();
}
}
void SWebBrowserView::HandleWindowDeactivated()
{
if (BrowserViewport.IsValid())
{
BrowserViewport->OnFocusLost(FFocusEvent());
}
}
void SWebBrowserView::HandleWindowActivated()
{
if (BrowserViewport.IsValid())
{
if (HasAnyUserFocusOrFocusedDescendants())
{
BrowserViewport->OnFocusReceived(FFocusEvent());
}
}
}
void SWebBrowserView::LoadURL(FString NewURL)
{
AddressBarUrl = FText::FromString(NewURL);
if (BrowserWindow.IsValid())
{
BrowserWindow->LoadURL(NewURL);
}
}
void SWebBrowserView::LoadString(FString Contents, FString DummyURL)
{
if (BrowserWindow.IsValid())
{
BrowserWindow->LoadString(Contents, DummyURL);
}
}
void SWebBrowserView::Reload()
{
if (BrowserWindow.IsValid())
{
BrowserWindow->Reload();
}
}
void SWebBrowserView::StopLoad()
{
if (BrowserWindow.IsValid())
{
BrowserWindow->StopLoad();
}
}
FText SWebBrowserView::GetTitleText() const
{
if (BrowserWindow.IsValid())
{
return FText::FromString(BrowserWindow->GetTitle());
}
return LOCTEXT("InvalidWindow", "Browser Window is not valid/supported");
}
FString SWebBrowserView::GetUrl() const
{
if (BrowserWindow.IsValid())
{
return BrowserWindow->GetUrl();
}
return FString();
}
FText SWebBrowserView::GetAddressBarUrlText() const
{
if(BrowserWindow.IsValid())
{
return AddressBarUrl;
}
return FText::GetEmpty();
}
bool SWebBrowserView::IsLoaded() const
{
if (BrowserWindow.IsValid())
{
return (BrowserWindow->GetDocumentLoadingState() == EWebBrowserDocumentState::Completed);
}
return false;
}
bool SWebBrowserView::IsLoading() const
{
if (BrowserWindow.IsValid())
{
return (BrowserWindow->GetDocumentLoadingState() == EWebBrowserDocumentState::Loading);
}
return false;
}
bool SWebBrowserView::CanGoBack() const
{
if (BrowserWindow.IsValid())
{
return BrowserWindow->CanGoBack();
}
return false;
}
void SWebBrowserView::GoBack()
{
if (BrowserWindow.IsValid())
{
BrowserWindow->GoBack();
}
}
bool SWebBrowserView::CanGoForward() const
{
if (BrowserWindow.IsValid())
{
return BrowserWindow->CanGoForward();
}
return false;
}
void SWebBrowserView::GoForward()
{
if (BrowserWindow.IsValid())
{
BrowserWindow->GoForward();
}
}
bool SWebBrowserView::IsInitialized() const
{
return BrowserWindow.IsValid() && BrowserWindow->IsInitialized();
}
void SWebBrowserView::SetupParentWindowHandlers()
{
if (!SlateParentWindowPtr.IsValid())
{
SlateParentWindowPtr = FSlateApplication::Get().FindWidgetWindow(SharedThis(this));
}
if (SlateParentWindowPtr.IsValid() && BrowserWindow.IsValid())
{
SlateParentWindowPtr.Pin()->GetOnWindowDeactivatedEvent().AddSP(this, &SWebBrowserView::HandleWindowDeactivated);
SlateParentWindowPtr.Pin()->GetOnWindowActivatedEvent().AddSP(this, &SWebBrowserView::HandleWindowActivated);
}
}
void SWebBrowserView::HandleBrowserWindowDocumentStateChanged(EWebBrowserDocumentState NewState)
{
switch (NewState)
{
case EWebBrowserDocumentState::Completed:
{
if (BrowserWindow.IsValid())
{
for (auto Adapter : Adapters)
{
Adapter->ConnectTo(BrowserWindow.ToSharedRef());
}
}
OnLoadCompleted.ExecuteIfBound();
}
break;
case EWebBrowserDocumentState::Error:
OnLoadError.ExecuteIfBound();
break;
case EWebBrowserDocumentState::Loading:
OnLoadStarted.ExecuteIfBound();
break;
}
}
void SWebBrowserView::HandleBrowserWindowNeedsRedraw()
{
if (FSlateApplication::Get().IsSlateAsleep())
{
// Tell slate that the widget needs to wake up for one frame to get redrawn
RegisterActiveTimer(0.f, FWidgetActiveTimerDelegate::CreateLambda([this](double InCurrentTime, float InDeltaTime) { return EActiveTimerReturnType::Stop; }));
}
}
void SWebBrowserView::HandleTitleChanged( FString NewTitle )
{
const FText NewTitleText = FText::FromString(NewTitle);
OnTitleChanged.ExecuteIfBound(NewTitleText);
}
void SWebBrowserView::HandleUrlChanged( FString NewUrl )
{
AddressBarUrl = FText::FromString(NewUrl);
OnUrlChanged.ExecuteIfBound(AddressBarUrl);
}
void SWebBrowserView::HandleToolTip(FString ToolTipText)
{
if(ToolTipText.IsEmpty())
{
FSlateApplication::Get().CloseToolTip();
SetToolTip(nullptr);
}
else
{
SetToolTipText(FText::FromString(ToolTipText));
FSlateApplication::Get().UpdateToolTip(true);
}
}
bool SWebBrowserView::HandleBeforeNavigation(const FString& Url, const FWebNavigationRequest& Request)
{
if(OnBeforeNavigation.IsBound())
{
return OnBeforeNavigation.Execute(Url, Request);
}
return false;
}
bool SWebBrowserView::HandleLoadUrl(const FString& Method, const FString& Url, FString& OutResponse)
{
if(OnLoadUrl.IsBound())
{
return OnLoadUrl.Execute(Method, Url, OutResponse);
}
return false;
}
EWebBrowserDialogEventResponse SWebBrowserView::HandleShowDialog(const TWeakPtr<IWebBrowserDialog>& DialogParams)
{
if(OnShowDialog.IsBound())
{
return OnShowDialog.Execute(DialogParams);
}
return EWebBrowserDialogEventResponse::Unhandled;
}
void SWebBrowserView::HandleDismissAllDialogs()
{
OnDismissAllDialogs.ExecuteIfBound();
}
bool SWebBrowserView::HandleBeforePopup(FString URL, FString Target)
{
if (OnBeforePopup.IsBound())
{
return OnBeforePopup.Execute(URL, Target);
}
return false;
}
void SWebBrowserView::ExecuteJavascript(const FString& ScriptText)
{
if (BrowserWindow.IsValid())
{
BrowserWindow->ExecuteJavascript(ScriptText);
}
}
void SWebBrowserView::GetSource(TFunction<void (const FString&)> Callback) const
{
if (BrowserWindow.IsValid())
{
BrowserWindow->GetSource(Callback);
}
}
bool SWebBrowserView::HandleCreateWindow(const TWeakPtr<IWebBrowserWindow>& NewBrowserWindow, const TWeakPtr<IWebBrowserPopupFeatures>& PopupFeatures)
{
if(OnCreateWindow.IsBound())
{
return OnCreateWindow.Execute(NewBrowserWindow, PopupFeatures);
}
return false;
}
bool SWebBrowserView::HandleCloseWindow(const TWeakPtr<IWebBrowserWindow>& NewBrowserWindow)
{
if(OnCloseWindow.IsBound())
{
return OnCloseWindow.Execute(NewBrowserWindow);
}
return false;
}
void SWebBrowserView::BindUObject(const FString& Name, UObject* Object, bool bIsPermanent)
{
if (BrowserWindow.IsValid())
{
BrowserWindow->BindUObject(Name, Object, bIsPermanent);
}
}
void SWebBrowserView::UnbindUObject(const FString& Name, UObject* Object, bool bIsPermanent)
{
if (BrowserWindow.IsValid())
{
BrowserWindow->UnbindUObject(Name, Object, bIsPermanent);
}
}
void SWebBrowserView::BindAdapter(const TSharedRef<IWebBrowserAdapter>& Adapter)
{
Adapters.Add(Adapter);
if (BrowserWindow.IsValid())
{
Adapter->ConnectTo(BrowserWindow.ToSharedRef());
}
}
void SWebBrowserView::UnbindAdapter(const TSharedRef<IWebBrowserAdapter>& Adapter)
{
Adapters.Remove(Adapter);
if (BrowserWindow.IsValid())
{
Adapter->DisconnectFrom(BrowserWindow.ToSharedRef());
}
}
void SWebBrowserView::HandleShowPopup(const FIntRect& PopupSize)
{
check(!PopupMenuPtr.IsValid())
TSharedPtr<SViewport> MenuContent;
SAssignNew(MenuContent, SViewport)
.ViewportSize(PopupSize.Size())
.EnableGammaCorrection(false)
.EnableBlending(false)
.IgnoreTextureAlpha(true)
.Visibility(EVisibility::Visible);
MenuViewport = MakeShareable(new FWebBrowserViewport(BrowserWindow, true));
MenuContent->SetViewportInterface(MenuViewport.ToSharedRef());
FWidgetPath WidgetPath;
FSlateApplication::Get().GeneratePathToWidgetUnchecked(SharedThis(this), WidgetPath);
if (WidgetPath.IsValid())
{
TSharedRef< SWidget > MenuContentRef = MenuContent.ToSharedRef();
const FGeometry& BrowserGeometry = WidgetPath.Widgets.Last().Geometry;
const FVector2D NewPosition = BrowserGeometry.LocalToAbsolute(PopupSize.Min);
// Open the pop-up. The popup method will be queried from the widget path passed in.
TSharedPtr<IMenu> NewMenu = FSlateApplication::Get().PushMenu(SharedThis(this), WidgetPath, MenuContentRef, NewPosition, FPopupTransitionEffect( FPopupTransitionEffect::ComboButton ), false);
NewMenu->GetOnMenuDismissed().AddSP(this, &SWebBrowserView::HandleMenuDismissed);
PopupMenuPtr = NewMenu;
}
}
void SWebBrowserView::HandleMenuDismissed(TSharedRef<IMenu>)
{
PopupMenuPtr.Reset();
}
void SWebBrowserView::HandleDismissPopup()
{
if (PopupMenuPtr.IsValid())
{
PopupMenuPtr.Pin()->Dismiss();
FSlateApplication::Get().SetKeyboardFocus(SharedThis(this), EFocusCause::SetDirectly);
}
}
bool SWebBrowserView::HandleSuppressContextMenu()
{
if (OnSuppressContextMenu.IsBound())
{
return OnSuppressContextMenu.Execute();
}
return false;
}
#undef LOCTEXT_NAMESPACE