Files
UnrealEngineUWP/Engine/Source/Developer/WebBrowser/Private/WebBrowserWindow.cpp
Matthew Griffin 98cbfe5555 Adding a loading spinner to SWebBrowser to be shown before page is first rendered.
Also ignore changes to viewport size that can't be seen, to avoid the whole page being rendered again when it becomes visible.

[CL 2351745 by Matthew Griffin in Main branch]
2014-11-06 15:23:27 -05:00

480 lines
12 KiB
C++

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#include "WebBrowserPrivatePCH.h"
#include "WebBrowserWindow.h"
#include "SlateCore.h"
#include "SlateBasics.h"
#if WITH_CEF3
FWebBrowserWindow::FWebBrowserWindow(FIntPoint InViewportSize)
: UpdatableTexture(nullptr)
, ViewportSize(InViewportSize)
, bIsClosing(false)
, bHasBeenPainted(false)
{
TextureData.Reserve(ViewportSize.X * ViewportSize.Y * 4);
TextureData.SetNumZeroed(ViewportSize.X * ViewportSize.Y * 4);
if (FSlateApplication::Get().GetRenderer().IsValid())
{
UpdatableTexture = FSlateApplication::Get().GetRenderer()->CreateUpdatableTexture(ViewportSize.X, ViewportSize.Y);
}
}
FWebBrowserWindow::~FWebBrowserWindow()
{
CloseBrowser();
if (FSlateApplication::Get().GetRenderer().IsValid() && UpdatableTexture != nullptr)
{
FSlateApplication::Get().GetRenderer()->ReleaseUpdatableTexture(UpdatableTexture);
}
UpdatableTexture = nullptr;
}
void FWebBrowserWindow::SetViewportSize(FVector2D WindowSize)
{
// Magic number for texture size, can't access GetMax2DTextureDimension easily
FIntPoint ClampedWindowSize = WindowSize.ClampAxes(1, 2048).IntPoint();
// Ignore sizes that can't be seen as it forces CEF to re-render whole image
if (WindowSize >= FVector2D::UnitVector && ViewportSize != ClampedWindowSize)
{
FIntPoint OldViewportSize = MoveTemp(ViewportSize);
TArray<uint8> OldTextureData = MoveTemp(TextureData);
ViewportSize = ClampedWindowSize;
TextureData.SetNumZeroed(ViewportSize.X * ViewportSize.Y * 4);
// copy row by row to avoid texture distortion
const int32 WriteWidth = FMath::Min(OldViewportSize.X, ViewportSize.X) * 4;
const int32 WriteHeight = FMath::Min(OldViewportSize.Y, ViewportSize.Y);
for (int32 RowIndex = 0; RowIndex < WriteHeight; ++RowIndex)
{
FMemory::Memcpy(TextureData.GetData() + ViewportSize.X * RowIndex * 4, OldTextureData.GetData() + OldViewportSize.X * RowIndex * 4, WriteWidth);
}
if (UpdatableTexture != nullptr)
{
UpdatableTexture->ResizeTexture(ViewportSize.X, ViewportSize.Y);
UpdatableTexture->UpdateTexture(TextureData);
}
if (IsValid())
{
InternalCefBrowser->GetHost()->WasResized();
}
}
}
FSlateShaderResource* FWebBrowserWindow::GetTexture()
{
if (UpdatableTexture != nullptr)
{
return UpdatableTexture->GetSlateResource();
}
return nullptr;
}
bool FWebBrowserWindow::IsValid() const
{
return InternalCefBrowser.get() != nullptr;
}
bool FWebBrowserWindow::HasBeenPainted() const
{
return bHasBeenPainted;
}
bool FWebBrowserWindow::IsClosing() const
{
return bIsClosing;
}
FString FWebBrowserWindow::GetTitle() const
{
return Title;
}
void FWebBrowserWindow::OnKeyDown(const FKeyEvent& InKeyEvent)
{
if (IsValid())
{
CefKeyEvent KeyEvent;
KeyEvent.windows_key_code = InKeyEvent.GetKeyCode();
// TODO: Figure out whether this is a system key if we come across problems
/*KeyEvent.is_system_key = message == WM_SYSCHAR ||
message == WM_SYSKEYDOWN ||
message == WM_SYSKEYUP;*/
KeyEvent.type = KEYEVENT_RAWKEYDOWN;
KeyEvent.modifiers = GetCefKeyboardModifiers(InKeyEvent);
InternalCefBrowser->GetHost()->SendKeyEvent(KeyEvent);
}
}
void FWebBrowserWindow::OnKeyUp(const FKeyEvent& InKeyEvent)
{
if (IsValid())
{
CefKeyEvent KeyEvent;
KeyEvent.windows_key_code = InKeyEvent.GetKeyCode();
// TODO: Figure out whether this is a system key if we come across problems
/*KeyEvent.is_system_key = message == WM_SYSCHAR ||
message == WM_SYSKEYDOWN ||
message == WM_SYSKEYUP;*/
KeyEvent.type = KEYEVENT_KEYUP;
KeyEvent.modifiers = GetCefKeyboardModifiers(InKeyEvent);
InternalCefBrowser->GetHost()->SendKeyEvent(KeyEvent);
}
}
void FWebBrowserWindow::OnKeyChar(const FCharacterEvent& InCharacterEvent)
{
if (IsValid())
{
CefKeyEvent KeyEvent;
KeyEvent.windows_key_code = InCharacterEvent.GetCharacter();
// TODO: Figure out whether this is a system key if we come across problems
/*KeyEvent.is_system_key = message == WM_SYSCHAR ||
message == WM_SYSKEYDOWN ||
message == WM_SYSKEYUP;*/
KeyEvent.type = KEYEVENT_CHAR;
KeyEvent.modifiers = GetCefInputModifiers(InCharacterEvent);
InternalCefBrowser->GetHost()->SendKeyEvent(KeyEvent);
}
}
void FWebBrowserWindow::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (IsValid())
{
FKey Button = MouseEvent.GetEffectingButton();
CefBrowserHost::MouseButtonType Type =
(Button == EKeys::LeftMouseButton ? MBT_LEFT : (
Button == EKeys::RightMouseButton ? MBT_RIGHT : MBT_MIDDLE));
CefMouseEvent Event;
FVector2D LocalPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
Event.x = LocalPos.X;
Event.y = LocalPos.Y;
Event.modifiers = GetCefMouseModifiers(MouseEvent);
InternalCefBrowser->GetHost()->SendMouseClickEvent(Event, Type, false,1);
}
}
void FWebBrowserWindow::OnMouseButtonUp(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (IsValid())
{
FKey Button = MouseEvent.GetEffectingButton();
CefBrowserHost::MouseButtonType Type =
(Button == EKeys::LeftMouseButton ? MBT_LEFT : (
Button == EKeys::RightMouseButton ? MBT_RIGHT : MBT_MIDDLE));
CefMouseEvent Event;
FVector2D LocalPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
Event.x = LocalPos.X;
Event.y = LocalPos.Y;
Event.modifiers = GetCefMouseModifiers(MouseEvent);
InternalCefBrowser->GetHost()->SendMouseClickEvent(Event, Type, true, 1);
}
}
void FWebBrowserWindow::OnMouseButtonDoubleClick(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (IsValid())
{
FKey Button = MouseEvent.GetEffectingButton();
CefBrowserHost::MouseButtonType Type =
(Button == EKeys::LeftMouseButton ? MBT_LEFT : (
Button == EKeys::RightMouseButton ? MBT_RIGHT : MBT_MIDDLE));
CefMouseEvent Event;
FVector2D LocalPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
Event.x = LocalPos.X;
Event.y = LocalPos.Y;
Event.modifiers = GetCefMouseModifiers(MouseEvent);
InternalCefBrowser->GetHost()->SendMouseClickEvent(Event, Type, false, 2);
}
}
void FWebBrowserWindow::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if (IsValid())
{
CefMouseEvent Event;
FVector2D LocalPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
Event.x = LocalPos.X;
Event.y = LocalPos.Y;
Event.modifiers = GetCefMouseModifiers(MouseEvent);
InternalCefBrowser->GetHost()->SendMouseMoveEvent(Event, false);
}
}
void FWebBrowserWindow::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
{
if(IsValid())
{
// The original delta is reduced so this should bring it back to what CEF expects
const float SpinFactor = 120.0f;
const float TrueDelta = MouseEvent.GetWheelDelta() * SpinFactor;
CefMouseEvent Event;
FVector2D LocalPos = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition());
Event.x = LocalPos.X;
Event.y = LocalPos.Y;
Event.modifiers = GetCefMouseModifiers(MouseEvent);
InternalCefBrowser->GetHost()->SendMouseWheelEvent(Event,
MouseEvent.IsShiftDown() ? TrueDelta : 0,
!MouseEvent.IsShiftDown() ? TrueDelta : 0);
}
}
void FWebBrowserWindow::OnFocus(bool SetFocus)
{
if (IsValid())
{
InternalCefBrowser->GetHost()->SendFocusEvent(SetFocus);
}
}
void FWebBrowserWindow::OnCaptureLost()
{
if (IsValid())
{
InternalCefBrowser->GetHost()->SendCaptureLostEvent();
}
}
bool FWebBrowserWindow::CanGoBack() const
{
if (IsValid())
{
return InternalCefBrowser->CanGoBack();
}
return false;
}
void FWebBrowserWindow::GoBack()
{
if (IsValid())
{
InternalCefBrowser->GoBack();
}
}
bool FWebBrowserWindow::CanGoForward() const
{
if (IsValid())
{
return InternalCefBrowser->CanGoForward();
}
return false;
}
void FWebBrowserWindow::GoForward()
{
if (IsValid())
{
InternalCefBrowser->GoForward();
}
}
bool FWebBrowserWindow::IsLoading() const
{
if (IsValid())
{
return InternalCefBrowser->IsLoading();
}
return false;
}
void FWebBrowserWindow::Reload()
{
if (IsValid())
{
InternalCefBrowser->Reload();
}
}
void FWebBrowserWindow::StopLoad()
{
if (IsValid())
{
InternalCefBrowser->StopLoad();
}
}
void FWebBrowserWindow::SetHandler(CefRefPtr<FWebBrowserHandler> InHandler)
{
if (InHandler.get())
{
Handler = InHandler;
Handler->SetBrowserWindow(SharedThis(this));
}
}
void FWebBrowserWindow::CloseBrowser()
{
bIsClosing = true;
if (IsValid())
{
InternalCefBrowser->GetHost()->CloseBrowser(false);
InternalCefBrowser = nullptr;
Handler = nullptr;
}
}
void FWebBrowserWindow::BindCefBrowser(CefRefPtr<CefBrowser> Browser)
{
InternalCefBrowser = Browser;
}
void FWebBrowserWindow::SetTitle(const CefString& InTitle)
{
Title = InTitle.c_str();
OnTitleChangedDelegate.Broadcast(Title);
}
bool FWebBrowserWindow::GetViewRect(CefRect& Rect)
{
Rect.x = 0;
Rect.y = 0;
Rect.width = ViewportSize.X;
Rect.height = ViewportSize.Y;
return true;
}
void FWebBrowserWindow::OnPaint(CefRenderHandler::PaintElementType Type, const CefRenderHandler::RectList& DirtyRects, const void* Buffer, int Width, int Height)
{
const int32 BufferSize = Width*Height*4;
if (BufferSize == TextureData.Num())
{
FMemory::Memcpy(TextureData.GetData(), Buffer, BufferSize);
}
else
{
// copy row by row to avoid texture distortion
const int32 WriteWidth = FMath::Min(Width, ViewportSize.X) * 4;
const int32 WriteHeight = FMath::Min(Height, ViewportSize.Y);
for (int32 RowIndex = 0; RowIndex < WriteHeight; ++RowIndex)
{
FMemory::Memcpy(TextureData.GetData() + ViewportSize.X * RowIndex * 4, static_cast<const uint8*>(Buffer) + Width * RowIndex * 4, WriteWidth);
}
}
if (UpdatableTexture != nullptr)
{
UpdatableTexture->UpdateTexture(TextureData);
}
bHasBeenPainted = true;
}
void FWebBrowserWindow::OnCursorChange(CefCursorHandle Cursor)
{
// TODO: Figure out Unreal cursor type from this,
// may need to reload unreal cursors to compare handles
//::SetCursor( Cursor );
}
int32 FWebBrowserWindow::GetCefKeyboardModifiers(const FKeyEvent& KeyEvent)
{
int32 Modifiers = GetCefInputModifiers(KeyEvent);
const FKey Key = KeyEvent.GetKey();
if (Key == EKeys::LeftAlt ||
Key == EKeys::LeftCommand ||
Key == EKeys::LeftControl ||
Key == EKeys::LeftShift)
{
Modifiers |= EVENTFLAG_IS_LEFT;
}
if (Key == EKeys::RightAlt ||
Key == EKeys::RightCommand ||
Key == EKeys::RightControl ||
Key == EKeys::RightShift)
{
Modifiers |= EVENTFLAG_IS_RIGHT;
}
if (Key == EKeys::NumPadZero ||
Key == EKeys::NumPadOne ||
Key == EKeys::NumPadTwo ||
Key == EKeys::NumPadThree ||
Key == EKeys::NumPadFour ||
Key == EKeys::NumPadFive ||
Key == EKeys::NumPadSix ||
Key == EKeys::NumPadSeven ||
Key == EKeys::NumPadEight ||
Key == EKeys::NumPadNine)
{
Modifiers |= EVENTFLAG_IS_KEY_PAD;
}
return Modifiers;
}
int32 FWebBrowserWindow::GetCefMouseModifiers(const FPointerEvent& InMouseEvent)
{
int32 Modifiers = GetCefInputModifiers(InMouseEvent);
if (InMouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton))
{
Modifiers |= EVENTFLAG_LEFT_MOUSE_BUTTON;
}
if (InMouseEvent.IsMouseButtonDown(EKeys::MiddleMouseButton))
{
Modifiers |= EVENTFLAG_MIDDLE_MOUSE_BUTTON;
}
if (InMouseEvent.IsMouseButtonDown(EKeys::RightMouseButton))
{
Modifiers |= EVENTFLAG_RIGHT_MOUSE_BUTTON;
}
return Modifiers;
}
int32 FWebBrowserWindow::GetCefInputModifiers(const FInputEvent& InputEvent)
{
int32 Modifiers = 0;
if (InputEvent.IsShiftDown())
{
Modifiers |= EVENTFLAG_SHIFT_DOWN;
}
if (InputEvent.IsControlDown())
{
Modifiers |= EVENTFLAG_CONTROL_DOWN;
}
if (InputEvent.IsAltDown())
{
Modifiers |= EVENTFLAG_ALT_DOWN;
}
if (InputEvent.IsCommandDown())
{
Modifiers |= EVENTFLAG_COMMAND_DOWN;
}
if (InputEvent.AreCapsLocked())
{
Modifiers |= EVENTFLAG_CAPS_LOCK_ON;
}
// TODO: Add function for this if necessary
/*if (InputEvent.AreNumsLocked())
{
Modifiers |= EVENTFLAG_NUM_LOCK_ON;
}*/
return Modifiers;
}
#endif