From 34101fe2a12e8f70c7bafe52e4124fadb333ac6e Mon Sep 17 00:00:00 2001 From: getnamo Date: Sun, 24 Jan 2016 12:39:47 +0000 Subject: [PATCH] NexusVR updates -RenderHandler replaced by BrowserHandler. Adds support for CefDownloadHandler callbacks, considering this as a catch-all cef callback forwarder. -Added DownloadFile( url ) to BluEye -Added Zoom functionality for BluEye -Added Multicast delegates for download progress updates -CEF bind updated to 2556 for fullscreen API support, but current build will work with older build. --- .gitignore | 8 -- BLUI.uplugin | 7 +- Source/Blu/Private/BluEye.cpp | 93 ++++++++++--- Source/Blu/Private/BluPrivatePCH.h | 2 +- .../{RenderHandler.cpp => BrowserHandler.cpp} | 53 +++++++- Source/Blu/Public/BluEye.h | 42 +++++- Source/Blu/Public/BrowserHandler.h | 126 ++++++++++++++++++ Source/Blu/Public/RenderHandler.h | 69 ---------- 8 files changed, 299 insertions(+), 101 deletions(-) delete mode 100644 .gitignore rename Source/Blu/Private/{RenderHandler.cpp => BrowserHandler.cpp} (57%) create mode 100644 Source/Blu/Public/BrowserHandler.h delete mode 100644 Source/Blu/Public/RenderHandler.h diff --git a/.gitignore b/.gitignore deleted file mode 100644 index eccf617..0000000 --- a/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -Binaries/* -ThirdParty/cef/Linux/* -ThirdParty/cef/Mac/* -ThirdParty/cef/Win/* -*.dll -*.lib -Intermediate/* -ThirdParty/cef/LICENSE.txt diff --git a/BLUI.uplugin b/BLUI.uplugin index 0687c78..4d4bdb3 100644 --- a/BLUI.uplugin +++ b/BLUI.uplugin @@ -3,8 +3,8 @@ "FriendlyName": "BLUI", "Version": 3, - "VersionName": "3.1", - "EngineVersion": 1579795, + "VersionName": "3.1.1", + "EngineVersion": "4.9+", "Description": "Chrome powered HTML UI and HUD for Unreal Engine 4", "Category": "UI", "CreatedBy": "Aaron M. Shea", @@ -25,5 +25,6 @@ "LoadingPhase": "PreDefault", "BlacklistPlatforms": [ "HTML5", "Android", "iOS" ] } - ] + ], + "CanContainContent" : true } diff --git a/Source/Blu/Private/BluEye.cpp b/Source/Blu/Private/BluEye.cpp index c1007d4..b692189 100644 --- a/Source/Blu/Private/BluEye.cpp +++ b/Source/Blu/Private/BluEye.cpp @@ -3,6 +3,7 @@ UBluEye::UBluEye(const class FObjectInitializer& PCIP) : Super(PCIP) { + Texture = nullptr; Width = 800; Height = 600; @@ -11,17 +12,18 @@ UBluEye::UBluEye(const class FObjectInitializer& PCIP) } -void UBluEye::init(UObject* WorldContextObject) +void UBluEye::init() { - /** - * We don't want this running in editor unless it's PIE - * If we don't check this, CEF will spawn infinit processes with widget components - **/ - const UWorld* world = GEngine->GetWorldFromContextObject(WorldContextObject); + /** + * We don't want this running in editor unless it's PIE + * If we don't check this, CEF will spawn infinit processes with widget components + **/ + Texture = nullptr; + if (GEngine) { - if (!world->IsGameWorld() && !world->IsPlayInEditor()) + if (GEngine->IsEditor() && !GWorld->IsPlayInEditor()) { UE_LOG(LogBlu, Log, TEXT("Notice: not playing - Component Will Not Initialize")); return; @@ -38,7 +40,7 @@ void UBluEye::init(UObject* WorldContextObject) info.SetAsWindowless(0, bIsTransparent); renderer = new RenderHandler(Width, Height, this); - g_handler = new BrowserClient(renderer); + g_handler = new BrowserClient(renderer, this); browser = CefBrowserHost::CreateBrowserSync(info, g_handler.get(), "about:blank", browserSettings, NULL); // Setup JS event emitter @@ -60,6 +62,8 @@ void UBluEye::ResetTexture() // Here we init the texture to its initial state DestroyTexture(); + Texture = nullptr; + // init the new Texture2D Texture = UTexture2D::CreateTransient(Width, Height, PF_B8G8R8A8); Texture->AddToRoot(); @@ -97,7 +101,8 @@ void UBluEye::TextureUpdate(const void *buffer, FUpdateTextureRegion2D *updateRe return; } - if (Texture && Texture->Resource) + //todo: remove debug address hack + if (Texture && (int64)Texture != 0xdddddddddddddddd && Texture->IsValidLowLevel() && Texture->Resource) { if (buffer == nullptr) @@ -198,11 +203,38 @@ void UBluEye::LoadURL(const FString& newURL) } -bool UBluEye::IsBrowserLoading() +FString UBluEye::GetCurrentURL() { + return FString(browser->GetMainFrame()->GetURL().c_str()); +} - return browser->IsLoading(); +void UBluEye::SetZoom(const float scale /*= 1*/) +{ + browser->GetHost()->SetZoomLevel(scale); +} + +float UBluEye::GetZoom() +{ + return browser->GetHost()->GetZoomLevel(); +} + +void UBluEye::Test() +{ + /*CefRefPtr visitor; + browser->GetHost->GetNavigationEntries(visitor, false);*/ + + //for (auto in visitor) +} + +void UBluEye::DownloadFile(const FString& fileUrl) +{ + browser->GetHost()->StartDownload(*fileUrl); + //Todo: ensure downloading works in some way, shape or form? +} +bool UBluEye::IsBrowserLoading() +{ + return browser->IsLoading(); } void UBluEye::ReloadBrowser(bool IgnoreCache) @@ -239,8 +271,6 @@ void UBluEye::NavForward() UTexture2D* UBluEye::ResizeBrowser(const int32 NewWidth, const int32 NewHeight) { - // Do we even have a texture to try and resize? - verifyf(Texture, TEXT("Can't resize when there isn't a texture. Did you forget to call init?")); // Disable the web view while we resize bEnabled = false; @@ -253,8 +283,9 @@ UTexture2D* UBluEye::ResizeBrowser(const int32 NewWidth, const int32 NewHeight) renderer->Width = NewWidth; renderer->Height = NewHeight; - // We need to reset the texture - ResetTexture(); + Texture = UTexture2D::CreateTransient(Width, Height, PF_B8G8R8A8); + Texture->AddToRoot(); + Texture->UpdateResource(); // Let the browser's host know we resized it browser->GetHost()->WasResized(); @@ -268,6 +299,32 @@ UTexture2D* UBluEye::ResizeBrowser(const int32 NewWidth, const int32 NewHeight) } +UTexture2D* UBluEye::CropWindow(const int32 Y, const int32 X, const int32 NewWidth, const int32 NewHeight) +{ + // Disable the web view while we resize + bEnabled = false; + + + // Set our new Width and Height + Width = NewWidth; + Height = NewHeight; + + // Update our render handler + renderer->Width = NewWidth; + renderer->Height = NewHeight; + + Texture = UTexture2D::CreateTransient(Width, Height, PF_B8G8R8A8); + Texture->AddToRoot(); + Texture->UpdateResource(); + + // Now we can keep going + bEnabled = true; + + UE_LOG(LogBlu, Log, TEXT("BluEye was cropped!")) + + return Texture; +} + void UBluEye::TriggerMouseMove(const FVector2D& pos, const float scale) { @@ -459,7 +516,11 @@ void UBluEye::processKeyMods(FInputEvent InKey) UTexture2D* UBluEye::GetTexture() const { - verifyf(Texture, TEXT("There is no texture to return! Did you forget to call init?")); + if (!Texture) + { + return UTexture2D::CreateTransient(Width, Height); + } + return Texture; } diff --git a/Source/Blu/Private/BluPrivatePCH.h b/Source/Blu/Private/BluPrivatePCH.h index e0d387c..4bff62f 100644 --- a/Source/Blu/Private/BluPrivatePCH.h +++ b/Source/Blu/Private/BluPrivatePCH.h @@ -18,6 +18,6 @@ DECLARE_LOG_CATEGORY_EXTERN(LogBlu, Log, All); // Blu Classes #include "BluManager.h" #include "BluEye.h" -#include "RenderHandler.h" +#include "BrowserHandler.h" #include "BluJsonObj.h" #include "BluBlueprintFunctionLibrary.h" \ No newline at end of file diff --git a/Source/Blu/Private/RenderHandler.cpp b/Source/Blu/Private/BrowserHandler.cpp similarity index 57% rename from Source/Blu/Private/RenderHandler.cpp rename to Source/Blu/Private/BrowserHandler.cpp index 6b3f44e..ffbf7b7 100644 --- a/Source/Blu/Private/RenderHandler.cpp +++ b/Source/Blu/Private/BrowserHandler.cpp @@ -61,7 +61,58 @@ bool BrowserClient::OnProcessMessageReceived(CefRefPtr browser, CefP } + +//The path slashes have to be reversed to work with CEF +FString ReversePathSlashes(FString forwardPath) +{ + return forwardPath.Replace(TEXT("/"), TEXT("\\")); +} +FString UtilityBLUIDownloadsFolder() +{ + return ReversePathSlashes(FPaths::ConvertRelativePathToFull(FPaths::GameDir() + "Plugins/BLUI/Downloads/")); +} + + void BrowserClient::SetEventEmitter(FScriptEvent* emitter) { this->event_emitter = emitter; -} \ No newline at end of file +} + +void BrowserClient::OnBeforeDownload( + CefRefPtr browser, + CefRefPtr download_item, + const CefString & suggested_name, + CefRefPtr callback) +{ + UNREFERENCED_PARAMETER(browser); + UNREFERENCED_PARAMETER(download_item); + + //We use this concatenation method to mix c_str with regular FString and then convert the result back to c_str + FString downloadPath = UtilityBLUIDownloadsFolder() + FString(suggested_name.c_str()); + + callback->Continue(*downloadPath, false); //don't show the download dialog, just go for it + + UE_LOG(LogClass, Log, TEXT("Downloading file for path %s"), *downloadPath); +} + +void BrowserClient::OnDownloadUpdated( + CefRefPtr browser, + CefRefPtr download_item, + CefRefPtr callback) +{ + int percentage = download_item->GetPercentComplete(); + FString url = FString(download_item->GetFullPath().c_str()); + + UE_LOG(LogClass, Log, TEXT("Download %s Updated: %d"), *url , percentage); + + blu->DownloadUpdated.Broadcast(url, percentage); + + if (percentage == 100 && download_item->IsComplete()) { + UE_LOG(LogClass, Log, TEXT("Download %s Complete"), *url); + blu->DownloadComplete.Broadcast(url); + } + + //Example download cancel/pause etc, we just have to hijack this + //callback->Cancel(); +} + diff --git a/Source/Blu/Public/BluEye.h b/Source/Blu/Public/BluEye.h index 1e00f72..670804a 100644 --- a/Source/Blu/Public/BluEye.h +++ b/Source/Blu/Public/BluEye.h @@ -46,21 +46,31 @@ enum EBluSpecialKeys scrolllockkey = 145 UMETA(DisplayName = "Scroll Lock") }; +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDownloadCompleteSignature, FString, url); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FDownloadUpdatedSignature, FString, url, float, percentage); +//DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDownloadComplete); UCLASS(ClassGroup = Blu, Blueprintable) class BLU_API UBluEye : public UObject { - GENERATED_BODY() UBluEye(const class FObjectInitializer& PCIP); public: + + //Event delegates + UPROPERTY(BlueprintAssignable, Category = "Blu Browser Events") + FDownloadCompleteSignature DownloadComplete; + + UPROPERTY(BlueprintAssignable, Category = "Blu Browser Events") + FDownloadUpdatedSignature DownloadUpdated; + //GENERATED_UCLASS_BODY() /** Initialize function, should be called after properties are set */ - UFUNCTION(BlueprintCallable, Category = "Blu", meta = (WorldContext = "WorldContextObject")) - void init(UObject* WorldContextObject); + UFUNCTION(BlueprintCallable, Category = "Blu") + void init(); /** The default URL this UI component will load */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Blu") @@ -120,6 +130,26 @@ class BLU_API UBluEye : public UObject UFUNCTION(BlueprintCallable, Category = "Blu") void LoadURL(const FString& newURL); + /** Get the currently loaded URL */ + UFUNCTION(BlueprintPure, Category = "Blu") + FString GetCurrentURL(); + + /** Trigger Zoom */ + UFUNCTION(BlueprintCallable, Category = "Blu") + void SetZoom(const float scale = 1); + + /** Get our zoom level */ + UFUNCTION(BlueprintPure, Category = "Blu") + float GetZoom(); + + //Not ready yet + //UFUNCTION(BlueprintCallable, Category = "Blu Test") + void Test(); + + /** Download a file */ + UFUNCTION(BlueprintCallable, Category = "Blu") + void DownloadFile(const FString& fileUrl); + /** Trigger a LEFT click in the browser via a Vector2D */ UFUNCTION(BlueprintCallable, Category = "Blu") void TriggerLeftClick(const FVector2D& pos, const float scale = 1); @@ -221,6 +251,10 @@ class BLU_API UBluEye : public UObject UFUNCTION(BlueprintCallable, Category = "Blu") UTexture2D* ResizeBrowser(const int32 NewWidth, const int32 NewHeight); + //This cropping function doesn't work atm + //UFUNCTION(BlueprintCallable, Category = "Blu") + UTexture2D* CropWindow(const int32 Y, const int32 X, const int32 NewWidth, const int32 NewHeight); + CefRefPtr browser; void TextureUpdate(const void* buffer, FUpdateTextureRegion2D * updateRegions, uint32 regionCount); @@ -244,7 +278,9 @@ class BLU_API UBluEye : public UObject void processKeyMods(FInputEvent InKey); // Store UI state in this UTexture2D + UPROPERTY() UTexture2D* Texture; + UMaterialInstanceDynamic* MaterialInstance; CefMouseEvent mouse_event; diff --git a/Source/Blu/Public/BrowserHandler.h b/Source/Blu/Public/BrowserHandler.h new file mode 100644 index 0000000..d9fb74c --- /dev/null +++ b/Source/Blu/Public/BrowserHandler.h @@ -0,0 +1,126 @@ +#pragma once + +#if PLATFORM_WINDOWS +#include "AllowWindowsPlatformTypes.h" +#endif +#include "include/cef_client.h" +#include "include/cef_app.h" +#if PLATFORM_WINDOWS +#include "HideWindowsPlatformTypes.h" +#endif + +#include "../Public/BluEye.h" + + +class RenderHandler : public CefRenderHandler +{ + private: + UBluEye* parentUI; + + public: + + int32 Width; + int32 Height; + + // CefRenderHandler interface + bool GetViewRect(CefRefPtr browser, CefRect &rect) override; + + void OnPaint(CefRefPtr browser, PaintElementType type, const RectList &dirtyRects, const void *buffer, int width, int height) override; + + RenderHandler(int32 width, int32 height, UBluEye* ui); + + // CefBase interface + // NOTE: Must be at bottom + public: + IMPLEMENT_REFCOUNTING(RenderHandler) +}; + +// for manual render handler +class BrowserClient : public CefClient, CefDownloadHandler, CefLifeSpanHandler, CefDisplayHandler +{ + + private: + FScriptEvent* event_emitter; + UBluEye* blu; + + public: + BrowserClient(RenderHandler* renderHandler, UBluEye* bluEye) : m_renderHandler(renderHandler) + { + blu = bluEye; + }; + + virtual CefRefPtr GetRenderHandler() + { + return m_renderHandler; + }; + + CefRefPtr m_renderHandler; + + virtual CefRefPtr GetRenderHandlerCustom() + { + return m_renderHandler; + }; + + virtual CefRefPtr GetDownloadHandler() override { + return this; + } + + virtual CefRefPtr GetLifeSpanHandler() override { + return this; + } + + virtual CefRefPtr GetDisplayHandler() override { + return this; + } + + virtual bool OnProcessMessageReceived(CefRefPtr browser, CefProcessId source_process, CefRefPtr message) override; + void SetEventEmitter(FScriptEvent* emitter); + + //CefDownloadHandler + virtual void OnBeforeDownload( + CefRefPtr browser, + CefRefPtr download_item, + const CefString& suggested_name, + CefRefPtr callback) override; + + virtual void OnDownloadUpdated( + CefRefPtr browser, + CefRefPtr download_item, + CefRefPtr callback) override; + + //CefLifeSpanHandler + virtual bool OnBeforePopup(CefRefPtr browser, + CefRefPtr frame, + const CefString& target_url, + const CefString& target_frame_name, + WindowOpenDisposition target_disposition, + bool user_gesture, + const CefPopupFeatures& popupFeatures, + CefWindowInfo& windowInfo, + CefRefPtr& client, + CefBrowserSettings& settings, + bool* no_javascript_access) override + { + return false; + } + virtual void OnAfterCreated(CefRefPtr browser) override { + // Browser window created successfully... + } + virtual bool DoClose(CefRefPtr browser) override { + // Allow or block browser window close... + return true; + } + virtual void OnBeforeClose(CefRefPtr browser) override { + // Browser window is closed, perform cleanup... + } + + //Fullscreen handling - doesn't work on this patch + /*virtual void OnFullscreenModeChange(CefRefPtr browser, bool fullscreen) override{ + return; + }*/ + + + // NOTE: Must be at bottom + public: + IMPLEMENT_REFCOUNTING(BrowserClient) +}; \ No newline at end of file diff --git a/Source/Blu/Public/RenderHandler.h b/Source/Blu/Public/RenderHandler.h deleted file mode 100644 index 2dba6fe..0000000 --- a/Source/Blu/Public/RenderHandler.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#if PLATFORM_WINDOWS -#include "AllowWindowsPlatformTypes.h" -#endif -#include "include/cef_client.h" -#include "include/cef_app.h" -#if PLATFORM_WINDOWS -#include "HideWindowsPlatformTypes.h" -#endif - -#include "../Public/BluEye.h" - - -class RenderHandler : public CefRenderHandler -{ - private: - UBluEye* parentUI; - - public: - - int32 Width; - int32 Height; - - // CefRenderHandler interface - bool GetViewRect(CefRefPtr browser, CefRect &rect) override; - - void OnPaint(CefRefPtr browser, PaintElementType type, const RectList &dirtyRects, const void *buffer, int width, int height) override; - - RenderHandler(int32 width, int32 height, UBluEye* ui); - - // CefBase interface - // NOTE: Must be at bottom - public: - IMPLEMENT_REFCOUNTING(RenderHandler) -}; - -// for manual render handler -class BrowserClient : public CefClient -{ - - private: - FScriptEvent* event_emitter; - - public: - BrowserClient(RenderHandler* renderHandler) : m_renderHandler(renderHandler) - { - - }; - - virtual CefRefPtr GetRenderHandler() - { - return m_renderHandler; - }; - - CefRefPtr m_renderHandler; - - virtual CefRefPtr GetRenderHandlerCustom() - { - return m_renderHandler; - }; - - virtual bool OnProcessMessageReceived(CefRefPtr browser, CefProcessId source_process, CefRefPtr message) override; - void SetEventEmitter(FScriptEvent* emitter); - - // NOTE: Must be at bottom - public: - IMPLEMENT_REFCOUNTING(BrowserClient) -}; \ No newline at end of file