From 0dcf65ce4f6b89510338bb5be5b58d8ea6e566fd Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Wed, 24 Apr 2019 10:53:46 +0200 Subject: [PATCH] Feature/cef speedup (#806) * Improve cmake errors * Calling doMessageLoopWork more often to increase gui performance * Introduce frequent callbacks * Restructure browser update callbacks * Cleanup cef speedup * Add flag to toggle updating browser between renderable calls * CEF should not be used in single process mode * Update CEF version * Postbuild step for finding framework from web helper * Load libcef dynamically to fix issue with CEF update * Only include dynamic library loader on mac * Improve keyboard mapping support on MacOS * Add arrow keys * Rename manifest * Fix bug with missing blinking cursor in text fields * Bump minimum cmake version * CEF fixes: Runtime and correct helper path * Be true to actual sandbox compatibility specified by CEF * Cleanup --- CMakeLists.txt | 18 ++- apps/OpenSpace/CMakeLists.txt | 1 + apps/Wormhole/CMakeLists.txt | 1 + data/assets/util/webgui.asset | 4 +- include/openspace/engine/globalscallbacks.h | 12 ++ modules/cefwebgui/cefwebguimodule.cpp | 16 +- modules/cefwebgui/cefwebguimodule.h | 2 + modules/cefwebgui/include.cmake | 14 +- modules/fieldlines/include.cmake | 4 +- modules/fieldlinessequence/include.cmake | 2 +- modules/gaia/include.cmake | 4 +- modules/galaxy/include.cmake | 4 +- modules/globebrowsing/include.cmake | 5 +- modules/imgui/imguimodule.cpp | 4 + modules/iswa/include.cmake | 6 +- modules/kameleon/include.cmake | 2 +- modules/kameleonvolume/include.cmake | 4 +- modules/multiresvolume/include.cmake | 2 +- .../server/src/topics/setpropertytopic.cpp | 2 +- modules/spacecraftinstruments/include.cmake | 4 +- modules/spout/include.cmake | 8 +- modules/touch/src/touchinteraction.cpp | 9 +- modules/touch/touchmodule.cpp | 8 +- modules/toyvolume/include.cmake | 4 +- modules/volume/include.cmake | 3 +- modules/webbrowser/CMakeLists.txt | 22 ++- .../cmake/patch/cmake/cef_variables.cmake | 144 ++++++++++++------ .../webbrowser/cmake/webbrowser_helpers.cmake | 5 +- modules/webbrowser/include.cmake | 7 +- modules/webbrowser/include/browserinstance.h | 4 +- modules/webbrowser/include/cefhost.h | 1 + modules/webbrowser/include/eventhandler.h | 2 +- modules/webbrowser/include/webrenderhandler.h | 2 +- modules/webbrowser/mac/Info.plist | 7 + modules/webbrowser/mac/helper-Info.plist | 7 + ...manifest => openspace Helper.exe.manifest} | 0 modules/webbrowser/src/browserinstance.cpp | 18 ++- modules/webbrowser/src/cefhost.cpp | 24 ++- modules/webbrowser/src/eventhandler.cpp | 80 ++++++++-- modules/webbrowser/src/processhelpermac.cpp | 24 +++ modules/webbrowser/src/webrenderhandler.cpp | 3 +- modules/webbrowser/webbrowsermodule.cpp | 116 ++++++++++++-- modules/webbrowser/webbrowsermodule.h | 16 +- modules/webgui/include.cmake | 4 +- openspace.cfg | 3 +- src/engine/globalscallbacks.cpp | 6 + src/scene/scene.cpp | 5 +- 47 files changed, 498 insertions(+), 145 deletions(-) rename modules/webbrowser/{openspace_web_helper.exe.manifest => openspace Helper.exe.manifest} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b0b2f1362..11caad3a22 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # ########################################################################################## -cmake_minimum_required(VERSION 3.8 FATAL_ERROR) +cmake_minimum_required(VERSION 3.10 FATAL_ERROR) project(OpenSpace) @@ -46,12 +46,26 @@ include(${GHOUL_BASE_DIR}/support/cmake/message_macros.cmake) include(${GHOUL_BASE_DIR}/support/cmake/include_gtest.cmake) begin_header("Configuring OpenSpace project") +message(STATUS "CMake version: ${CMAKE_VERSION}") + +# Bail out if the user tries to generate a 32 bit project. +if (NOT ${CMAKE_SIZEOF_VOID_P} EQUAL 8) + message(FATAL_ERROR "OpenSpace can only be generated for 64 bit architectures.") +endif() ########################################################################################## # Cleanup project # ########################################################################################## set(OPENSPACE_APPS_DIR "${OPENSPACE_BASE_DIR}/apps") set(OPENSPACE_EXT_DIR "${OPENSPACE_BASE_DIR}/ext") + +if (NOT EXISTS ${OPENSPACE_EXT_DIR}/ghoul/CMakeLists.txt) + message(FATAL_ERROR "Git submodules are missing. Please run \n" + "git submodule update --init --recursive \n" + "to download the missing dependencies." + ) +endif() + set_property(GLOBAL PROPERTY USE_FOLDERS On) set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER CMake) @@ -225,6 +239,8 @@ if (OPENSPACE_MODULE_WEBBROWSER AND CEF_ROOT) # wanted by CEF set(CMAKE_BUILD_TYPE Debug CACHE INTERNAL "CMAKE_BUILD_TYPE") + set(PROJECT_ARCH "x86_64") + if (WIN32) set(RESOURCE_FILE ${OPENSPACE_APPS_DIR}/OpenSpace/openspace.rc) endif () diff --git a/apps/OpenSpace/CMakeLists.txt b/apps/OpenSpace/CMakeLists.txt index 67b2975c50..fa95613d56 100644 --- a/apps/OpenSpace/CMakeLists.txt +++ b/apps/OpenSpace/CMakeLists.txt @@ -153,6 +153,7 @@ end_header("Dependency: SGCT") if (OPENSPACE_MODULE_WEBBROWSER AND CEF_ROOT) # wanted by CEF set(CMAKE_BUILD_TYPE Debug CACHE INTERNAL "CMAKE_BUILD_TYPE") + set(PROJECT_ARCH "x86_64") if (WIN32) set(RESOURCE_FILE ${OPENSPACE_APPS_DIR}/OpenSpace/openspace.rc) diff --git a/apps/Wormhole/CMakeLists.txt b/apps/Wormhole/CMakeLists.txt index 0a919ab4f6..a740f9e340 100644 --- a/apps/Wormhole/CMakeLists.txt +++ b/apps/Wormhole/CMakeLists.txt @@ -46,6 +46,7 @@ target_link_libraries(Wormhole openspace-core) if (OPENSPACE_MODULE_WEBBROWSER AND CEF_ROOT) # wanted by CEF set(CMAKE_BUILD_TYPE Debug CACHE INTERNAL "CMAKE_BUILD_TYPE") + set(PROJECT_ARCH "x86_64") if (WIN32) set(RESOURCE_FILE ${OPENSPACE_APPS_DIR}/OpenSpace/openspace.rc) diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index 28fda00c90..d038e140bd 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -1,8 +1,8 @@ local guiCustomization = asset.require('customization/gui') -- Select which commit hashes to use for the frontend and backend -local frontendHash = "32c481c9337a62745669de66d909cf15bd2bae7a" -local backendHash = "6e773425b3e90ba93f0090e44427e474fe5c633f" +local frontendHash = "6a34f2b0c6cfde64b890f12aa5bfaa42ac61a40f" +local backendHash = "408142f26d3fa3d041399fcf58645874589d5b64" local dataProvider = "data.openspaceproject.com/files/webgui" diff --git a/include/openspace/engine/globalscallbacks.h b/include/openspace/engine/globalscallbacks.h index 99ed78b1d4..856cc79f4f 100644 --- a/include/openspace/engine/globalscallbacks.h +++ b/include/openspace/engine/globalscallbacks.h @@ -77,6 +77,18 @@ static std::vector>& mousePosition = static std::vector>& mouseScrollWheel = detail::gMouseScrollWheel(); + +/** + * If the framerate becomes slow, Chromium Embedded Framework (used in Web Browser Module) + * needs to perform its message loop work more frequently than once per frame. If this + * method is not called frequently enough, the GUI will become much less responsive. + * A future more long-term may decouple the browser's message work loop from the main + * render loop altogehter using a separate thread. + * Currently, this method is called from within the RenderEngine, + * between calls to individual renderables. + */ +extern void (*webBrowserPerformanceHotfix)(); + } // namespace callback } // namespace openspace::global diff --git a/modules/cefwebgui/cefwebguimodule.cpp b/modules/cefwebgui/cefwebguimodule.cpp index af79c0f9f2..e783eab1f4 100644 --- a/modules/cefwebgui/cefwebguimodule.cpp +++ b/modules/cefwebgui/cefwebguimodule.cpp @@ -46,6 +46,12 @@ namespace { "This setting determines whether the browser should be enabled or not." }; + constexpr openspace::properties::Property::PropertyInfo ReloadInfo = { + "Reload", + "Reload", + "Trigger this property to reload the browser." + }; + constexpr openspace::properties::Property::PropertyInfo VisibleInfo = { "Visible", "Is Visible", @@ -72,10 +78,12 @@ CefWebGuiModule::CefWebGuiModule() , _enabled(EnabledInfo, true) , _visible(VisibleInfo, true) , _url(GuiUrlInfo, "") - , _guiScale(GuiScaleInfo, 1.0, 0.1, 3.0) + , _reload(ReloadInfo) + , _guiScale(GuiScaleInfo, 1.f, 0.1f, 3.f) { addProperty(_enabled); addProperty(_visible); + addProperty(_reload); addProperty(_url); addProperty(_guiScale); } @@ -135,6 +143,12 @@ void CefWebGuiModule::internalInitialize(const ghoul::Dictionary& configuration) } }); + _reload.onChange([this]() { + if (_instance) { + _instance->reloadBrowser(); + } + }); + _guiScale.onChange([this]() { if (_instance) { _instance->setZoom(_guiScale); diff --git a/modules/cefwebgui/cefwebguimodule.h b/modules/cefwebgui/cefwebguimodule.h index 6296ebd314..81bf8231f4 100644 --- a/modules/cefwebgui/cefwebguimodule.h +++ b/modules/cefwebgui/cefwebguimodule.h @@ -29,6 +29,7 @@ #include #include +#include #include namespace openspace { @@ -48,6 +49,7 @@ private: properties::BoolProperty _enabled; properties::BoolProperty _visible; + properties::TriggerProperty _reload; properties::StringProperty _url; properties::FloatProperty _guiScale; std::unique_ptr _instance; diff --git a/modules/cefwebgui/include.cmake b/modules/cefwebgui/include.cmake index 0c49dbf058..188c9c1068 100644 --- a/modules/cefwebgui/include.cmake +++ b/modules/cefwebgui/include.cmake @@ -1,6 +1,12 @@ -set(DEFAULT_MODULE OFF) +if (APPLE OR WIN32) + set(DEFAULT_MODULE ON) +else () + # CefWebGui is not available on Linux + set(DEFAULT_MODULE OFF) +endif () + set(OPENSPACE_DEPENDENCIES - webbrowser - webgui - server + webbrowser + webgui + server ) diff --git a/modules/fieldlines/include.cmake b/modules/fieldlines/include.cmake index 1172d03089..947e563af0 100644 --- a/modules/fieldlines/include.cmake +++ b/modules/fieldlines/include.cmake @@ -1,4 +1,4 @@ set (OPENSPACE_DEPENDENCIES - kameleon - space + kameleon + space ) \ No newline at end of file diff --git a/modules/fieldlinessequence/include.cmake b/modules/fieldlinessequence/include.cmake index 67a0fe8d77..a746e4569e 100644 --- a/modules/fieldlinessequence/include.cmake +++ b/modules/fieldlinessequence/include.cmake @@ -1,3 +1,3 @@ set (OPENSPACE_DEPENDENCIES - space + space ) diff --git a/modules/gaia/include.cmake b/modules/gaia/include.cmake index 75b787f114..98bffaa6bf 100644 --- a/modules/gaia/include.cmake +++ b/modules/gaia/include.cmake @@ -1,6 +1,6 @@ set(DEFAULT_MODULE ON) set(OPENSPACE_DEPENDENCIES - fitsfilereader - globebrowsing + fitsfilereader + globebrowsing ) diff --git a/modules/galaxy/include.cmake b/modules/galaxy/include.cmake index b72153a3c4..8216f1c090 100644 --- a/modules/galaxy/include.cmake +++ b/modules/galaxy/include.cmake @@ -1,4 +1,4 @@ set (OPENSPACE_DEPENDENCIES - volume - space + volume + space ) \ No newline at end of file diff --git a/modules/globebrowsing/include.cmake b/modules/globebrowsing/include.cmake index 00b41af142..7f45a2d151 100644 --- a/modules/globebrowsing/include.cmake +++ b/modules/globebrowsing/include.cmake @@ -1,5 +1,6 @@ set (DEFAULT_MODULE ON) + set (OPENSPACE_DEPENDENCIES - debugging - space + debugging + space ) \ No newline at end of file diff --git a/modules/imgui/imguimodule.cpp b/modules/imgui/imguimodule.cpp index 7fbfb57113..a8ee5aacff 100644 --- a/modules/imgui/imguimodule.cpp +++ b/modules/imgui/imguimodule.cpp @@ -154,6 +154,10 @@ ImGUIModule::ImGUIModule() : OpenSpaceModule(Name) { const glm::ivec2 windowSize = delegate.currentWindowSize(); const glm::ivec2 resolution = delegate.currentWindowResolution(); + if (windowSize.x <= 0 || windowSize.y <= 0) { + return; + } + glm::vec2 mousePosition = delegate.mousePosition(); uint32_t mouseButtons = delegate.mouseButtons(2); diff --git a/modules/iswa/include.cmake b/modules/iswa/include.cmake index 8492fd468d..9c6bb4a938 100644 --- a/modules/iswa/include.cmake +++ b/modules/iswa/include.cmake @@ -1,5 +1,5 @@ set (OPENSPACE_DEPENDENCIES - base - kameleon - space + base + kameleon + space ) \ No newline at end of file diff --git a/modules/kameleon/include.cmake b/modules/kameleon/include.cmake index 1231f1db18..63c20b8181 100644 --- a/modules/kameleon/include.cmake +++ b/modules/kameleon/include.cmake @@ -1,3 +1,3 @@ set (OPENSPACE_DEPENDENCIES - space + space ) \ No newline at end of file diff --git a/modules/kameleonvolume/include.cmake b/modules/kameleonvolume/include.cmake index ba7e22287c..f8f58137dd 100644 --- a/modules/kameleonvolume/include.cmake +++ b/modules/kameleonvolume/include.cmake @@ -1,4 +1,4 @@ set (OPENSPACE_DEPENDENCIES - kameleon - volume + kameleon + volume ) \ No newline at end of file diff --git a/modules/multiresvolume/include.cmake b/modules/multiresvolume/include.cmake index 1231f1db18..63c20b8181 100644 --- a/modules/multiresvolume/include.cmake +++ b/modules/multiresvolume/include.cmake @@ -1,3 +1,3 @@ set (OPENSPACE_DEPENDENCIES - space + space ) \ No newline at end of file diff --git a/modules/server/src/topics/setpropertytopic.cpp b/modules/server/src/topics/setpropertytopic.cpp index b2aac239e8..584f8c2fe8 100644 --- a/modules/server/src/topics/setpropertytopic.cpp +++ b/modules/server/src/topics/setpropertytopic.cpp @@ -77,7 +77,7 @@ namespace { literal += "}"; return literal; }{ - return "null"; + return "nil"; } } } // namespace diff --git a/modules/spacecraftinstruments/include.cmake b/modules/spacecraftinstruments/include.cmake index 3c69ad5f63..659b975323 100644 --- a/modules/spacecraftinstruments/include.cmake +++ b/modules/spacecraftinstruments/include.cmake @@ -1,5 +1,5 @@ set(DEFAULT_MODULE ON) set (OPENSPACE_DEPENDENCIES - space -) \ No newline at end of file + space +) diff --git a/modules/spout/include.cmake b/modules/spout/include.cmake index 50632ddb05..2a359fe308 100644 --- a/modules/spout/include.cmake +++ b/modules/spout/include.cmake @@ -1,12 +1,12 @@ set (OPENSPACE_DEPENDENCIES - base + base ) if (WIN32) - set(DEFAULT_MODULE ON) + set(DEFAULT_MODULE ON) endif () # Spout is not supported on non-Windows machines if (NOT WIN32) - set(SUPPORTED OFF) -endif () \ No newline at end of file + set(SUPPORTED OFF) +endif () diff --git a/modules/touch/src/touchinteraction.cpp b/modules/touch/src/touchinteraction.cpp index 45f4faf2dd..65f6e5e6f5 100644 --- a/modules/touch/src/touchinteraction.cpp +++ b/modules/touch/src/touchinteraction.cpp @@ -25,9 +25,6 @@ #include #include #include -#ifdef OPENSPACE_MODULE_WEBBROWSER_ENABLED -#include -#endif #include #include @@ -49,6 +46,10 @@ #include #endif +#ifdef OPENSPACE_MODULE_WEBBROWSER_ENABLED +#include +#endif + #include #include #include @@ -432,13 +433,13 @@ void TouchInteraction::updateStateFromInput(const std::vector& list, } bool TouchInteraction::webContent(const std::vector& list) { +#ifdef OPENSPACE_MODULE_WEBBROWSER_ENABLED glm::ivec2 res = global::windowDelegate.currentWindowSize(); glm::dvec2 pos = glm::vec2( list.at(0).getScreenX(res.x), list.at(0).getScreenY(res.y) ); -#ifdef OPENSPACE_MODULE_WEBBROWSER_ENABLED WebBrowserModule& module = *(global::moduleEngine.module()); return module.eventHandler().hasContentCallback(pos.x, pos.y); #else diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 0ea302d3ea..4c59fffdfb 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -23,10 +23,8 @@ ****************************************************************************************/ #include -#ifdef OPENSPACE_MODULE_WEBBROWSER_ENABLED -#include -#endif +#include #include #include #include @@ -40,6 +38,10 @@ #include #include +#ifdef OPENSPACE_MODULE_WEBBROWSER_ENABLED +#include +#endif + using namespace TUIO; namespace openspace { diff --git a/modules/toyvolume/include.cmake b/modules/toyvolume/include.cmake index 1231f1db18..a746e4569e 100644 --- a/modules/toyvolume/include.cmake +++ b/modules/toyvolume/include.cmake @@ -1,3 +1,3 @@ set (OPENSPACE_DEPENDENCIES - space -) \ No newline at end of file + space +) diff --git a/modules/volume/include.cmake b/modules/volume/include.cmake index eb1651efed..a746e4569e 100644 --- a/modules/volume/include.cmake +++ b/modules/volume/include.cmake @@ -1,4 +1,3 @@ set (OPENSPACE_DEPENDENCIES -# kameleon - space + space ) diff --git a/modules/webbrowser/CMakeLists.txt b/modules/webbrowser/CMakeLists.txt index 2f464991ab..8dd1e2bf62 100644 --- a/modules/webbrowser/CMakeLists.txt +++ b/modules/webbrowser/CMakeLists.txt @@ -2,7 +2,7 @@ # # # OpenSpace # # # -# Copyright (c) 2014-2018 # +# Copyright (c) 2014-2019 # # # # Permission is hereby granted, free of charge, to any person obtaining a copy of this # # software and associated documentation files (the "Software"), to deal in the Software # @@ -22,6 +22,8 @@ # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # ########################################################################################## +cmake_minimum_required(VERSION 3.12 FATAL_ERROR) + include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) include(${GHOUL_BASE_DIR}/support/cmake/handle_external_library.cmake) @@ -49,7 +51,7 @@ set_property(GLOBAL PROPERTY OS_FOLDERS ON) cmake_policy(SET CMP0074 NEW) # Specify the CEF distribution version. -set(CEF_VERSION "3.3029.1617.gaf831b6") +set(CEF_VERSION "3.3578.1867.g0f6d65a") # Add this project's cmake/ directory to the module path. set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") @@ -131,8 +133,9 @@ set(WEBBROWSER_RESOURCES_SRCS ${WEBBROWSER_RESOURCES_MAC_ENGLISH_LPROJ_SRCS} ) -# place helper in separate executable -set(CEF_HELPER_TARGET "openspace_web_helper" CACHE INTERNAL "CEF_HELPER_TARGET") +# Place Helper in separate executable +# The naming style " Helper" is required by Chromium. +set(CEF_HELPER_TARGET "OpenSpace Helper" CACHE INTERNAL "CEF_HELPER_TARGET") # # CEF platform-specific config @@ -147,13 +150,16 @@ if(OS_MACOSX) SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_HELPER_TARGET}) add_cef_logical_target("libcef_lib" "${CEF_LIB_DEBUG}" "${CEF_LIB_RELEASE}") add_dependencies(${CEF_HELPER_TARGET} libcef_dll_wrapper) - target_link_libraries(${CEF_HELPER_TARGET} libcef_lib libcef_dll_wrapper ${CEF_STANDARD_LIBS}) + target_link_libraries(${CEF_HELPER_TARGET} libcef_dll_wrapper ${CEF_STANDARD_LIBS}) set_target_properties(${CEF_HELPER_TARGET} PROPERTIES - MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/mac/helper-Info.plist + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/mac/helper-Info.plist ) - # Fix the framework rpath in the helper executable. - FIX_MACOSX_HELPER_FRAMEWORK_RPATH(${CEF_HELPER_TARGET}) + if(USE_SANDBOX) + # Logical target used to link the cef_sandbox library. + ADD_LOGICAL_TARGET("cef_sandbox_lib" "${CEF_SANDBOX_LIB_DEBUG}" "${CEF_SANDBOX_LIB_RELEASE}") + target_link_libraries(${CEF_HELPER_TARGET} cef_sandbox_lib) + endif() endif() if (OS_WINDOWS) diff --git a/modules/webbrowser/cmake/patch/cmake/cef_variables.cmake b/modules/webbrowser/cmake/patch/cmake/cef_variables.cmake index 1ff09a7539..674f1e8ae2 100644 --- a/modules/webbrowser/cmake/patch/cmake/cef_variables.cmake +++ b/modules/webbrowser/cmake/patch/cmake/cef_variables.cmake @@ -36,9 +36,14 @@ if(NOT DEFINED PROJECT_ARCH) endif() endif() +if(${CMAKE_GENERATOR} STREQUAL "Ninja") + set(GEN_NINJA 1) +elseif(${CMAKE_GENERATOR} STREQUAL "Unix Makefiles") + set(GEN_MAKEFILES 1) +endif() + # Determine the build type. -if(NOT CMAKE_BUILD_TYPE AND - (${CMAKE_GENERATOR} STREQUAL "Ninja" OR ${CMAKE_GENERATOR} STREQUAL "Unix Makefiles")) +if(NOT CMAKE_BUILD_TYPE AND (GEN_NINJA OR GEN_MAKEFILES)) # CMAKE_BUILD_TYPE should be specified when using Ninja or Unix Makefiles. set(CMAKE_BUILD_TYPE Release) message(WARNING "No CMAKE_BUILD_TYPE value selected, using ${CMAKE_BUILD_TYPE}") @@ -60,6 +65,10 @@ list(APPEND CEF_COMPILER_DEFINES ) +# Configure use of the sandbox. +option(USE_SANDBOX "Enable or disable use of the sandbox." ON) + + # # Linux configuration. # @@ -80,6 +89,8 @@ if(OS_LINUX) #-Werror # Treat warnings as errors -Wno-missing-field-initializers # Don't warn about missing field initializers -Wno-unused-parameter # Don't warn about unused parameters + -Wno-error=comment # Don't warn about code in comments + -Wno-comment # Don't warn about code in comments ) list(APPEND CEF_C_COMPILER_FLAGS -std=c99 # Use the C99 language standard @@ -191,8 +202,12 @@ if(OS_LINUX) set(CEF_BINARY_FILES chrome-sandbox libcef.so + libEGL.so + libGLESv2.so natives_blob.bin snapshot_blob.bin + v8_context_snapshot.bin + swiftshader ) # List of CEF resource files. @@ -205,6 +220,12 @@ if(OS_LINUX) icudtl.dat locales ) + + if(USE_SANDBOX) + list(APPEND CEF_COMPILER_DEFINES + CEF_USE_SANDBOX # Used by apps to test if the sandbox is enabled + ) + endif() endif() @@ -302,9 +323,19 @@ if(OS_MACOSX) set(CEF_BINARY_DIR_DEBUG "${_CEF_ROOT}/Debug") set(CEF_BINARY_DIR_RELEASE "${_CEF_ROOT}/Release") - # CEF library paths. + # CEF library paths. # OpenSpace Patch set(CEF_LIB_DEBUG "${CEF_BINARY_DIR_DEBUG}/Chromium Embedded Framework.framework/Chromium Embedded Framework") set(CEF_LIB_RELEASE "${CEF_BINARY_DIR_RELEASE}/Chromium Embedded Framework.framework/Chromium Embedded Framework") + + if(USE_SANDBOX) + list(APPEND CEF_COMPILER_DEFINES + CEF_USE_SANDBOX # Used by apps to test if the sandbox is enabled + ) + + # CEF sandbox library paths. + set(CEF_SANDBOX_LIB_DEBUG "${CEF_BINARY_DIR_DEBUG}/cef_sandbox.a") + set(CEF_SANDBOX_LIB_RELEASE "${CEF_BINARY_DIR_RELEASE}/cef_sandbox.a") + endif() endif() @@ -313,35 +344,52 @@ endif() # if(OS_WINDOWS) - # Configure use of the sandbox. - option(USE_SANDBOX "Enable or disable use of the sandbox." ON) - if(USE_SANDBOX AND NOT MSVC_VERSION EQUAL 1900) - # The cef_sandbox.lib static library is currently built with VS2015. It will - # not link successfully with other VS versions. - set(USE_SANDBOX OFF) + if (GEN_NINJA) + # When using the Ninja generator clear the CMake defaults to avoid excessive + # console warnings (see issue #2120). + set(CMAKE_CXX_FLAGS "") + set(CMAKE_CXX_FLAGS_DEBUG "") + set(CMAKE_CXX_FLAGS_RELEASE "") endif() - # Configure use of official build compiler settings. - # When using an official build the "Debug" build is actually a Release build - # with DCHECKs enabled. In order to link the sandbox the Debug build must - # be configured with some Release-related compiler settings. - option(USE_OFFICIAL_BUILD_SANDBOX "Enable or disable use of an official build sandbox." ON) - if(NOT USE_SANDBOX) - # Don't need official build settings when the sandbox is off. - set(USE_OFFICIAL_BUILD_SANDBOX OFF) + if(USE_SANDBOX) + # Check if the current MSVC version is compatible with the cef_sandbox.lib + # static library. For a list of all version numbers see + # https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering + list(APPEND supported_msvc_versions + 1900 # VS2015 and updates 1, 2, & 3 + 1910 # VS2017 version 15.1 & 15.2 + 1911 # VS2017 version 15.3 & 15.4 + 1912 # VS2017 version 15.5 + 1913 # VS2017 version 15.6 + 1914 # VS2017 version 15.7 + 1915 # VS2017 version 15.8 + ) + list(FIND supported_msvc_versions ${MSVC_VERSION} _index) + if (${_index} EQUAL -1) + message(WARNING "CEF sandbox is not compatible with the current MSVC version (${MSVC_VERSION})") + set(USE_SANDBOX OFF) + endif() endif() # Consumers who run into LNK4099 warnings can pass /Z7 instead (see issue #385). set(CEF_DEBUG_INFO_FLAG "/Zi" CACHE STRING "Optional flag specifying specific /Z flag to use") + # Consumers using different runtime types may want to pass different flags + set(CEF_RUNTIME_LIBRARY_FLAG "/MD" CACHE STRING "Optional flag specifying which runtime to use") #OpenSpace patch, replace MT with MD + if (CEF_RUNTIME_LIBRARY_FLAG) + list(APPEND CEF_COMPILER_FLAGS_DEBUG ${CEF_RUNTIME_LIBRARY_FLAG}d) + list(APPEND CEF_COMPILER_FLAGS_RELEASE ${CEF_RUNTIME_LIBRARY_FLAG}) + endif() + # Platform-specific compiler/linker flags. set(CEF_LIBTYPE STATIC) list(APPEND CEF_COMPILER_FLAGS /MP # Multiprocess compilation /Gy # Enable function-level linking - # /GR- # Disable run-time type information + #/GR- # Disable run-time type information # OpenSpace patch /W4 # Warning level 4 - #/WX # Treat warnings as errors + #/WX # Treat warnings as errors # OpenSpace patch /wd4100 # Ignore "unreferenced formal parameter" warning /wd4127 # Ignore "conditional expression is constant" warning /wd4244 # Ignore "conversion possible loss of data" warning @@ -352,24 +400,11 @@ if(OS_WINDOWS) /wd4996 # Ignore "function or variable may be unsafe" warning ${CEF_DEBUG_INFO_FLAG} ) - if(USE_OFFICIAL_BUILD_SANDBOX) - # CMake adds /RTC1, /D"_DEBUG" and a few other values by default for Debug - # builds. We can't link the sandbox with those values so clear the CMake - # defaults here. - set(CMAKE_CXX_FLAGS_DEBUG "") - - #list(APPEND CEF_COMPILER_FLAGS_DEBUG - # /MT # Multithreaded release runtime - # ) - else() - list(APPEND CEF_COMPILER_FLAGS_DEBUG - #/MTd # Multithreaded debug runtime - /RTC1 # Disable optimizations - /Od # Enable basic run-time checks - ) - endif() + list(APPEND CEF_COMPILER_FLAGS_DEBUG + /RTC1 # Disable optimizations + /Od # Enable basic run-time checks + ) list(APPEND CEF_COMPILER_FLAGS_RELEASE - #/MT # Multithreaded release runtime /O2 # Optimize for maximum speed /Ob2 # Inline any suitable function /GF # Enable string pooling @@ -383,18 +418,12 @@ if(OS_WINDOWS) ) list(APPEND CEF_COMPILER_DEFINES WIN32 _WIN32 _WINDOWS # Windows platform - # UNICODE _UNICODE # Unicode build - # WINVER=0x0601 _WIN32_WINNT=0x601 # Targeting Windows 7 + UNICODE _UNICODE # Unicode build + WINVER=0x0601 _WIN32_WINNT=0x601 # Targeting Windows 7 NOMINMAX # Use the standard's templated min/max WIN32_LEAN_AND_MEAN # Exclude less common API declarations - # _HAS_EXCEPTIONS=0 # Disable exceptions + _HAS_EXCEPTIONS=0 # Disable exceptions ) - if(USE_OFFICIAL_BUILD_SANDBOX) - list(APPEND CEF_COMPILER_DEFINES_DEBUG - NDEBUG _NDEBUG # Not a debug build - DCHECK_ALWAYS_ON=1 # DCHECKs are enabled - ) - endif() list(APPEND CEF_COMPILER_DEFINES_RELEASE NDEBUG _NDEBUG # Not a debug build ) @@ -427,6 +456,8 @@ if(OS_WINDOWS) libGLESv2.dll natives_blob.bin snapshot_blob.bin + v8_context_snapshot.bin + swiftshader ) # List of CEF resource files. @@ -451,6 +482,7 @@ if(OS_WINDOWS) dbghelp.lib psapi.lib version.lib + wbemuuid.lib winmm.lib ) @@ -462,10 +494,26 @@ if(OS_WINDOWS) # Configure use of ATL. option(USE_ATL "Enable or disable use of ATL." ON) if(USE_ATL) + # Locate the atlmfc directory if it exists. It may be at any depth inside + # the VC directory. The cl.exe path returned by CMAKE_CXX_COMPILER may also + # be at different depths depending on the toolchain version + # (e.g. "VC/bin/cl.exe", "VC/bin/amd64_x86/cl.exe", + # "VC/Tools/MSVC/14.10.25017/bin/HostX86/x86/cl.exe", etc). + set(HAS_ATLMFC 0) + get_filename_component(VC_DIR ${CMAKE_CXX_COMPILER} DIRECTORY) + get_filename_component(VC_DIR_NAME ${VC_DIR} NAME) + while(NOT ${VC_DIR_NAME} STREQUAL "VC") + get_filename_component(VC_DIR ${VC_DIR} DIRECTORY) + if(IS_DIRECTORY "${VC_DIR}/atlmfc") + set(HAS_ATLMFC 1) + break() + endif() + get_filename_component(VC_DIR_NAME ${VC_DIR} NAME) + endwhile() + # Determine if the Visual Studio install supports ATL. - get_filename_component(VC_BIN_DIR ${CMAKE_CXX_COMPILER} DIRECTORY) - get_filename_component(VC_DIR ${VC_BIN_DIR} DIRECTORY) - if(NOT IS_DIRECTORY "${VC_DIR}/atlmfc") + if(NOT HAS_ATLMFC) + message(WARNING "ATL is not supported by your VC installation.") set(USE_ATL OFF) endif() endif() diff --git a/modules/webbrowser/cmake/webbrowser_helpers.cmake b/modules/webbrowser/cmake/webbrowser_helpers.cmake index b6406a396e..8094d20a27 100644 --- a/modules/webbrowser/cmake/webbrowser_helpers.cmake +++ b/modules/webbrowser/cmake/webbrowser_helpers.cmake @@ -63,7 +63,7 @@ endfunction() function(run_cef_macosx_config CEF_ROOT module_path) set(CEF_FINAL_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Debug/${CEF_TARGET}.app") - set(CEF_FINAL_HELPER_APP "${CEF_FINAL_APP}/Contents/${CEF_HELPER_TARGET}.app") + set(CEF_FINAL_HELPER_APP "${CEF_FINAL_APP}/Contents/Frameworks/${CEF_HELPER_TARGET}.app") set(CEF_FRAMEWORK_LOCATION "${CEF_BINARY_DIR}/Chromium Embedded Framework.framework") set(CEF_FRAMEWORK_FINAL_LOCATION "${CEF_FINAL_APP}/Contents/Frameworks/Chromium Embedded Framework.framework") @@ -98,9 +98,6 @@ function(run_cef_macosx_config CEF_ROOT module_path) ) endforeach () - # Fix the framework rpath in the main executable. - FIX_MACOSX_MAIN_FRAMEWORK_RPATH(${CEF_TARGET}) - if(NOT ${CMAKE_GENERATOR} STREQUAL "Xcode") # Manually process and copy over resource files. # The Xcode generator handles this via the set_target_properties RESOURCE directive. diff --git a/modules/webbrowser/include.cmake b/modules/webbrowser/include.cmake index 3d5ca687a5..93f5c13e4a 100644 --- a/modules/webbrowser/include.cmake +++ b/modules/webbrowser/include.cmake @@ -1 +1,6 @@ -set(DEFAULT_MODULE OFF) +if (APPLE OR WIN32) + set(DEFAULT_MODULE ON) +else () + # WebBrowser is not available on Linux + set(DEFAULT_MODULE OFF) +endif () diff --git a/modules/webbrowser/include/browserinstance.h b/modules/webbrowser/include/browserinstance.h index 38d440ef1e..537c371600 100644 --- a/modules/webbrowser/include/browserinstance.h +++ b/modules/webbrowser/include/browserinstance.h @@ -61,7 +61,7 @@ public: BrowserInstance(WebRenderHandler* renderer, WebKeyboardHandler* keyboardHandler); ~BrowserInstance(); - void loadUrl(const std::string& url); + void loadUrl(std::string url); /** * Load a local file. * @@ -114,6 +114,8 @@ public: void reloadBrowser(); + void selectAll(); + const CefRefPtr& getBrowser() const; bool hasContent(int x, int y); diff --git a/modules/webbrowser/include/cefhost.h b/modules/webbrowser/include/cefhost.h index dbad16105f..1665ebf893 100644 --- a/modules/webbrowser/include/cefhost.h +++ b/modules/webbrowser/include/cefhost.h @@ -25,6 +25,7 @@ #ifndef __OPENSPACE_MODULE_WEBBROWSER___CEF_HOST___H__ #define __OPENSPACE_MODULE_WEBBROWSER___CEF_HOST___H__ +#include #include struct CefSettingsTraits; diff --git a/modules/webbrowser/include/eventhandler.h b/modules/webbrowser/include/eventhandler.h index 70b5d1ebcc..1596a02cb0 100644 --- a/modules/webbrowser/include/eventhandler.h +++ b/modules/webbrowser/include/eventhandler.h @@ -78,7 +78,7 @@ private: * \param key the pressed key * \return true if event found, false otherwise */ - bool specialKeyEvent(Key key); + bool specialKeyEvent(Key key, KeyModifier mods, KeyAction action); /** * Create a mouse event on the current cursor position. diff --git a/modules/webbrowser/include/webrenderhandler.h b/modules/webbrowser/include/webrenderhandler.h index e7d446d1a2..2e85dcacbf 100644 --- a/modules/webbrowser/include/webrenderhandler.h +++ b/modules/webbrowser/include/webrenderhandler.h @@ -52,7 +52,7 @@ public: void reshape(int, int); - bool GetViewRect(CefRefPtr browser, CefRect &rect) override; + void GetViewRect(CefRefPtr browser, CefRect &rect) override; void OnPaint(CefRefPtr browser, PaintElementType type, const RectList &dirtyRects, const void* buffer, int width, int height) override; bool hasContent(int x, int y); diff --git a/modules/webbrowser/mac/Info.plist b/modules/webbrowser/mac/Info.plist index e9d6d962e7..3e0968ab22 100644 --- a/modules/webbrowser/mac/Info.plist +++ b/modules/webbrowser/mac/Info.plist @@ -28,5 +28,12 @@ NSApplication NSSupportsAutomaticGraphicsSwitching + NSAppleEventsUsageDescription + Send usage data to Apple + LSEnvironment + + MallocNanoZone + 0 + diff --git a/modules/webbrowser/mac/helper-Info.plist b/modules/webbrowser/mac/helper-Info.plist index 4696e6a582..99cce15dc9 100644 --- a/modules/webbrowser/mac/helper-Info.plist +++ b/modules/webbrowser/mac/helper-Info.plist @@ -26,5 +26,12 @@ 1 NSSupportsAutomaticGraphicsSwitching + NSAppleEventsUsageDescription + Send usage data to Apple + LSEnvironment + + MallocNanoZone + 0 + diff --git a/modules/webbrowser/openspace_web_helper.exe.manifest b/modules/webbrowser/openspace Helper.exe.manifest similarity index 100% rename from modules/webbrowser/openspace_web_helper.exe.manifest rename to modules/webbrowser/openspace Helper.exe.manifest diff --git a/modules/webbrowser/src/browserinstance.cpp b/modules/webbrowser/src/browserinstance.cpp index abefab4f20..f52c22a626 100644 --- a/modules/webbrowser/src/browserinstance.cpp +++ b/modules/webbrowser/src/browserinstance.cpp @@ -49,8 +49,7 @@ BrowserInstance::BrowserInstance(WebRenderHandler* renderer, _client = new BrowserClient(_renderHandler, _keyboardHandler); CefWindowInfo windowInfo; - const bool renderTransparent = true; - windowInfo.SetAsWindowless(0, renderTransparent); + windowInfo.SetAsWindowless(nullptr); CefBrowserSettings browserSettings; browserSettings.windowless_frame_rate = 60; @@ -63,6 +62,10 @@ BrowserInstance::BrowserInstance(WebRenderHandler* renderer, browserSettings, nullptr ); + + if (!_browser) { + LERROR("Error when creating browser"); + } } BrowserInstance::~BrowserInstance() { @@ -74,11 +77,12 @@ void BrowserInstance::initialize() { _isInitialized = true; } -void BrowserInstance::loadUrl(const std::string& url) { +void BrowserInstance::loadUrl(std::string url) { ghoul_assert(_isInitialized, "BrowserInstance should be initialized"); LDEBUG(fmt::format("Loading URL: {}", url)); - _browser->GetMainFrame()->LoadURL(url); + CefString cefUrl = std::move(url); + _browser->GetMainFrame()->LoadURL(cefUrl); } bool BrowserInstance::loadLocalPath(std::string path) { @@ -168,6 +172,12 @@ void BrowserInstance::reloadBrowser() { _browser->Reload(); } +void BrowserInstance::selectAll() { + if (_browser->GetFocusedFrame()) { + _browser->GetFocusedFrame()->SelectAll(); + } +} + bool BrowserInstance::hasContent(int x, int y) { return _renderHandler->hasContent(x, y); } diff --git a/modules/webbrowser/src/cefhost.cpp b/modules/webbrowser/src/cefhost.cpp index 3620112607..d7ddeda570 100644 --- a/modules/webbrowser/src/cefhost.cpp +++ b/modules/webbrowser/src/cefhost.cpp @@ -30,6 +30,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + namespace { constexpr const char* _loggerCat = "CefHost"; } // namespace @@ -40,13 +44,29 @@ CefHost::CefHost(const std::string& helperLocation) { LDEBUG("Initializing CEF..."); CefSettings settings; + +#ifndef __APPLE__ + // Apple will always look for helper in a fixed location. CefString(&settings.browser_subprocess_path).FromString(helperLocation); +#endif + + settings.windowless_rendering_enabled = true; attachDebugSettings(settings); #ifdef WIN32 // Enable High-DPI support on Windows 7 or newer. CefEnableHighDPISupport(); #endif + +#ifdef __APPLE__ + // Load the CEF framework library at runtime instead of linking directly + // as required by the macOS sandbox implementation. + CefScopedLibraryLoader library_loader; + if (!library_loader.LoadInMain()) { + return; + } +#endif + CefRefPtr app(new WebBrowserApp); CefMainArgs args; @@ -65,10 +85,6 @@ void CefHost::attachDebugSettings(CefSettings &settings) { "Remote WebBrowser debugging available on http://localhost:{}", settings.remote_debugging_port )); - -#ifdef __APPLE__ - settings.single_process = true; -#endif } void CefHost::doMessageLoopWork() { diff --git a/modules/webbrowser/src/eventhandler.cpp b/modules/webbrowser/src/eventhandler.cpp index 1f612dba0f..ef0073d7e4 100644 --- a/modules/webbrowser/src/eventhandler.cpp +++ b/modules/webbrowser/src/eventhandler.cpp @@ -34,13 +34,13 @@ namespace { constexpr const char* _loggerCat = "WebBrowser:EventHandler"; /** - * Map from GLFW key codes to "regular" key codes, supported by JS and CEF. + * Map from GLFW key codes to windows key codes, supported by JS and CEF. * See http://keycode.info/ for lookup * * \param key * \return the key code, if mapped or the GLFW key code */ - int mapFromGlfwToNative(openspace::Key key) { + int mapFromGlfwToWindows(openspace::Key key) { switch (key) { case openspace::Key::BackSpace: return 8; case openspace::Key::Tab: return 9; @@ -54,6 +54,51 @@ namespace { } } + // Map from GLFW key codes to native key codes for Mac. + // The keys inserted here are based from setting breakpoints in + // the CEF-bundled 'cefclient' (browser_window_osr_mac.mm) + // as well as trial and error. + // There is an issue for proper cross-platform key events in CEF: + // https://bitbucket.org/chromiumembedded/cef/issues/1750 + // For now, the 'important' keys are inserted here manually. + int mapFromGlfwToNative(openspace::Key key) { + switch (key) { + case openspace::Key::BackSpace: return 51; + case openspace::Key::LeftControl: return 59; + case openspace::Key::LeftSuper: return 55; + case openspace::Key::Enter: return 36; + case openspace::Key::Left: return 123; + case openspace::Key::Right: return 124; + case openspace::Key::Up: return 126; + case openspace::Key::Down: return 127; + case openspace::Key::A: return 97; + case openspace::Key::Num0: return 82; + case openspace::Key::Num1: return 83; + case openspace::Key::Num2: return 84; + case openspace::Key::Num3: return 85; + case openspace::Key::Num4: return 86; + case openspace::Key::Num5: return 87; + case openspace::Key::Num6: return 88; + case openspace::Key::Num7: return 89; + case openspace::Key::Num8: return 91; // Note: 91, not 90. + case openspace::Key::Num9: return 92; + default: return static_cast(key); + } + } + + int16_t mapFromGlfwToCharacter(openspace::Key key) { + return static_cast(key); + } + + // This is needed to avoid the backspace up event to trigger backspace. + int16_t mapFromGlfwToUnmodifiedCharacter(openspace::Key key) { + switch (key) { + case openspace::Key::BackSpace: return 127; + case openspace::Key::A: return 97; + default: return static_cast(key); + } + } + uint32_t mapToCefModifiers(openspace::KeyModifier modifiers) { uint32_t cefModifiers = 0; // Based on cef_event_flags_t in cef_types.h @@ -66,6 +111,9 @@ namespace { if (hasKeyModifier(modifiers, openspace::KeyModifier::Alt)) { cefModifiers |= 1 << 3; } + if (hasKeyModifier(modifiers, openspace::KeyModifier::Super)) { + cefModifiers |= 1 << 7; + } return cefModifiers; } @@ -238,33 +286,43 @@ bool EventHandler::mouseWheelCallback(glm::ivec2 delta) { bool EventHandler::charCallback(unsigned int charCode, KeyModifier modifier) { CefKeyEvent keyEvent; - keyEvent.windows_key_code = charCode; - keyEvent.character = charCode; + keyEvent.windows_key_code = mapFromGlfwToWindows(Key(charCode)); + keyEvent.character = mapFromGlfwToCharacter(Key(charCode)); + keyEvent.native_key_code = mapFromGlfwToNative(Key(charCode)); keyEvent.modifiers = static_cast(modifier); keyEvent.type = KEYEVENT_CHAR; - // TODO(klas): figure out when to block + return _browserInstance->sendKeyEvent(keyEvent); } bool EventHandler::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) { - if (specialKeyEvent(key)) { + if (specialKeyEvent(key, modifier, action)) { return true; } CefKeyEvent keyEvent; + // TODO(klas): Use something less platform specific? - keyEvent.windows_key_code = mapFromGlfwToNative(key); - keyEvent.modifiers = mapToCefModifiers(modifier); - keyEvent.type = keyEventType(action); - // TODO(klas): figure out when to block + keyEvent.windows_key_code = mapFromGlfwToWindows(key); + keyEvent.native_key_code = mapFromGlfwToNative(key); + keyEvent.unmodified_character = mapFromGlfwToUnmodifiedCharacter(key); + keyEvent.modifiers = mapToCefModifiers(modifier); + keyEvent.type = keyEventType(action); + return _browserInstance->sendKeyEvent(keyEvent); } -bool EventHandler::specialKeyEvent(Key key) { +bool EventHandler::specialKeyEvent(Key key, KeyModifier mod, KeyAction) { switch (key) { case Key::F5: _browserInstance->reloadBrowser(); return true; + case Key::A: + if (hasKeyModifier(mod, KeyModifier::Super)) { + _browserInstance->selectAll(); + return true; + } + return false; default: return false; } diff --git a/modules/webbrowser/src/processhelpermac.cpp b/modules/webbrowser/src/processhelpermac.cpp index dc386f32ad..b26788b629 100644 --- a/modules/webbrowser/src/processhelpermac.cpp +++ b/modules/webbrowser/src/processhelpermac.cpp @@ -28,9 +28,33 @@ #include "include/cef_app.h" #include "include/webbrowserapp.h" +#include "include/wrapper/cef_library_loader.h" + +// When generating projects with CMake the CEF_USE_SANDBOX value will be defined +// automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line to disable +// use of the sandbox. +#if defined(CEF_USE_SANDBOX) +#include "include/cef_sandbox_mac.h" +#endif // Entry point function for sub-processes. int main(int argc, char* argv[]) { + +#if defined(CEF_USE_SANDBOX) + // Initialize the macOS sandbox for this helper process. + CefScopedSandboxContext sandbox_context; + if (!sandbox_context.Initialize(argc, argv)) { + return 1; + } +#endif + + // Load the CEF framework library at runtime instead of linking directly + // as required by the macOS sandbox implementation. + CefScopedLibraryLoader library_loader; + if (!library_loader.LoadInHelper()) { + return 1; + } + // Provide CEF with command-line arguments. CefMainArgs main_args(argc, argv); diff --git a/modules/webbrowser/src/webrenderhandler.cpp b/modules/webbrowser/src/webrenderhandler.cpp index e901839bc7..555e88d721 100644 --- a/modules/webbrowser/src/webrenderhandler.cpp +++ b/modules/webbrowser/src/webrenderhandler.cpp @@ -38,9 +38,8 @@ void WebRenderHandler::reshape(int w, int h) { _needsRepaint = true; } -bool WebRenderHandler::GetViewRect(CefRefPtr, CefRect& rect) { +void WebRenderHandler::GetViewRect(CefRefPtr, CefRect& rect) { rect = CefRect(0, 0, _windowSize.x, _windowSize.y); - return true; } void WebRenderHandler::OnPaint(CefRefPtr, CefRenderHandler::PaintElementType, diff --git a/modules/webbrowser/webbrowsermodule.cpp b/modules/webbrowser/webbrowsermodule.cpp index 6c7e6ec855..c9181fa28c 100644 --- a/modules/webbrowser/webbrowsermodule.cpp +++ b/modules/webbrowser/webbrowsermodule.cpp @@ -25,8 +25,8 @@ #include #include -#include #include +#include #include #include #include @@ -40,18 +40,57 @@ namespace { constexpr const char* _loggerCat = "WebBrowser"; #ifdef _MSC_VER - constexpr const char* SubprocessSuf = ".exe"; + constexpr const char* SubprocessPath = "OpenSpace Helper.exe"; #elif __APPLE__ - constexpr const char* SubprocessSuf = ".app/Contents/MacOS/openspace_web_helper"; + constexpr const char* SubprocessPath = + "../Frameworks/OpenSpace Helper.app/Contents/MacOS/OpenSpace Helper"; #else - constexpr const char* SubprocessSuf = ""; + constexpr const char* SubprocessPath = ""; #endif + + constexpr openspace::properties::Property::PropertyInfo + UpdateBrowserBetweenRenderablesInfo = { + "UpdateBrowserBetweenRenderables", + "Update Browser Between Renderables", + "Run the message loop of the browser between calls to render individual " + "renderables. When disabled, the browser message loop only runs " + "once per frame." + }; + + constexpr openspace::properties::Property::PropertyInfo BrowserUpdateIntervalInfo = { + "BrowserUpdateInterval", + "Browser Update Interval", + "The time in microseconds between running the message loop of the browser. " + "Only used if UpdateBrowserBetweenRenderables is true." + }; } // namespace namespace openspace { -WebBrowserModule::WebBrowserModule() : OpenSpaceModule(WebBrowserModule::Name) { +WebBrowserModule::WebBrowserModule() + : OpenSpaceModule(WebBrowserModule::Name) + , _updateBrowserBetweenRenderables(UpdateBrowserBetweenRenderablesInfo, true) + , _browserUpdateInterval(BrowserUpdateIntervalInfo, 1.f, 1.0f, 1000.f) +{ global::callback::deinitialize.emplace_back([this]() { deinitialize(); }); + + _browserUpdateInterval.onChange([this]() { + webbrowser::interval = std::chrono::microseconds( + static_cast(_browserUpdateInterval) + ); + }); + + _updateBrowserBetweenRenderables.onChange([this]() { + if (_updateBrowserBetweenRenderables && !_browsers.empty()) { + global::callback::webBrowserPerformanceHotfix = webbrowser::update; + } + else { + global::callback::webBrowserPerformanceHotfix = nullptr; + } + }); + + addProperty(_updateBrowserBetweenRenderables); + addProperty(_browserUpdateInterval); } void WebBrowserModule::internalDeinitialize() { @@ -68,7 +107,7 @@ void WebBrowserModule::internalDeinitialize() { } std::string WebBrowserModule::findHelperExecutable() { - std::string execLocation = absPath(_webHelperLocation + SubprocessSuf); + std::string execLocation = absPath("${BIN}/" + std::string(SubprocessPath)); if (!FileSys.fileExists(execLocation)) { LERROR(fmt::format( "Could not find web helper executable at location: {}" , execLocation @@ -79,7 +118,12 @@ std::string WebBrowserModule::findHelperExecutable() { } void WebBrowserModule::internalInitialize(const ghoul::Dictionary& dictionary) { - _webHelperLocation = dictionary.value("WebHelperLocation"); + if (dictionary.hasKeyAndValue("WebHelperLocation")) { + _webHelperLocation = absPath(dictionary.value("WebHelperLocation")); + } else { + _webHelperLocation = findHelperExecutable(); + } + if (dictionary.hasKeyAndValue("Enabled")) { _enabled = dictionary.value("Enabled"); } @@ -94,18 +138,31 @@ void WebBrowserModule::internalInitialize(const ghoul::Dictionary& dictionary) { return; } - LDEBUG("Starting CEF..."); - std::string helperLocation = findHelperExecutable(); - LDEBUG("Using web helper executable: " + helperLocation); - _cefHost = std::make_unique(std::move(helperLocation)); + LDEBUG("CEF using web helper executable: " + _webHelperLocation); + _cefHost = std::make_unique(_webHelperLocation); LDEBUG("Starting CEF... done!"); global::callback::preSync.emplace_back([this]() { if (_cefHost && !_browsers.empty()) { _cefHost->doMessageLoopWork(); + + const std::chrono::time_point timeAfter = + std::chrono::high_resolution_clock::now(); + webbrowser::latestCall = timeAfter; } }); + if (dictionary.hasValue(UpdateBrowserBetweenRenderablesInfo.identifier)) { + _updateBrowserBetweenRenderables = + dictionary.value(UpdateBrowserBetweenRenderablesInfo.identifier); + } + + if (dictionary.hasValue(BrowserUpdateIntervalInfo.identifier)) { + _browserUpdateInterval = static_cast( + dictionary.value(BrowserUpdateIntervalInfo.identifier) + ); + } + _eventHandler.initialize(); // register ScreenSpaceBrowser @@ -117,6 +174,9 @@ void WebBrowserModule::internalInitialize(const ghoul::Dictionary& dictionary) { void WebBrowserModule::addBrowser(BrowserInstance* browser) { if (_enabled) { _browsers.push_back(browser); + if (_updateBrowserBetweenRenderables) { + global::callback::webBrowserPerformanceHotfix = webbrowser::update; + } } } @@ -131,6 +191,10 @@ void WebBrowserModule::removeBrowser(BrowserInstance* browser) { LWARNING("Could not find browser in list of browsers."); } + if (_browsers.empty()) { + global::callback::webBrowserPerformanceHotfix = nullptr; + } + LDEBUG(fmt::format("Number of browsers stored: {}", _browsers.size())); } @@ -154,4 +218,34 @@ bool WebBrowserModule::isEnabled() const { return _enabled; } +namespace webbrowser { + +/** + * Logic for the webbrowser performance hotfix, + * described in more detail in globalscallbacks.h. + */ + +std::chrono::microseconds interval = std::chrono::microseconds(1); +std::chrono::time_point latestCall; +CefHost* cefHost = nullptr; + +void update() { + const std::chrono::time_point timeBefore = + std::chrono::high_resolution_clock::now(); + + std::chrono::microseconds duration = + std::chrono::duration_cast(timeBefore - latestCall); + + if (duration > interval) { + cefHost->doMessageLoopWork(); + + const std::chrono::time_point timeAfter = + std::chrono::high_resolution_clock::now(); + + latestCall = timeAfter; + } +} +} + } // namespace openspace + diff --git a/modules/webbrowser/webbrowsermodule.h b/modules/webbrowser/webbrowsermodule.h index 8fb9c1f3d3..b42e968396 100644 --- a/modules/webbrowser/webbrowsermodule.h +++ b/modules/webbrowser/webbrowsermodule.h @@ -25,14 +25,23 @@ #ifndef __OPENSPACE_MODULE_WEBBROWSER___WEBBROWSERMODULE___H__ #define __OPENSPACE_MODULE_WEBBROWSER___WEBBROWSERMODULE___H__ -#include - #include +#include +#include +#include +#include namespace openspace { class CefHost; +namespace webbrowser { + extern std::chrono::microseconds interval; + extern std::chrono::time_point latestCall; + extern CefHost* cefHost; + void update(); +} + class WebBrowserModule : public OpenSpaceModule { public: static constexpr const char* Name = "WebBrowser"; @@ -60,6 +69,9 @@ private: */ std::string findHelperExecutable(); + properties::BoolProperty _updateBrowserBetweenRenderables; + properties::FloatProperty _browserUpdateInterval; + std::vector _browsers; EventHandler _eventHandler; std::unique_ptr _cefHost; diff --git a/modules/webgui/include.cmake b/modules/webgui/include.cmake index 51ba3c9497..448a857dfd 100644 --- a/modules/webgui/include.cmake +++ b/modules/webgui/include.cmake @@ -1,4 +1,4 @@ set (DEFAULT_MODULE ON) set (OPENSPACE_DEPENDENCIES - server -) \ No newline at end of file + server +) diff --git a/openspace.cfg b/openspace.cfg index 58e0446fca..f16cda6c48 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -111,8 +111,7 @@ ModuleConfigurations = { } }, WebBrowser = { - Enabled = true, - WebHelperLocation = "${BIN}/openspace_web_helper" + Enabled = true }, WebGui = { Address = "localhost", diff --git a/src/engine/globalscallbacks.cpp b/src/engine/globalscallbacks.cpp index 00ad0f6a1b..93f7fe0d0a 100644 --- a/src/engine/globalscallbacks.cpp +++ b/src/engine/globalscallbacks.cpp @@ -96,4 +96,10 @@ std::vector>& gMouseScrollWheel() { return g; } +} // namespace openspace::global::detail + +namespace openspace::global::callback { + +void(*webBrowserPerformanceHotfix)() = nullptr; + } // namespace openspace::global::callback diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index b3e722898f..dcb5be76ee 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -33,7 +34,6 @@ #include #include #include - #include #include @@ -313,6 +313,9 @@ void Scene::render(const RenderData& data, RendererTasks& tasks) { catch (const ghoul::RuntimeError& e) { LERRORC(e.component, e.what()); } + if (global::callback::webBrowserPerformanceHotfix) { + (*global::callback::webBrowserPerformanceHotfix)(); + } } }