From da967da9c7aa0d88f478d476e8bb059ba79ca818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Thu, 11 Jan 2024 11:32:15 +0100 Subject: Rename OS X to macOS, mostly in comments We only support 10.13+ now, and it's been called macOS since 10.12. References in code to older versions are unchanged. --- indra/media_plugins/cef/mac_volume_catcher.cpp | 2 +- indra/media_plugins/cef/media_plugin_cef.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/media_plugins/cef') diff --git a/indra/media_plugins/cef/mac_volume_catcher.cpp b/indra/media_plugins/cef/mac_volume_catcher.cpp index dddb9c2077..dafe545d09 100644 --- a/indra/media_plugins/cef/mac_volume_catcher.cpp +++ b/indra/media_plugins/cef/mac_volume_catcher.cpp @@ -1,6 +1,6 @@ /** * @file mac_volume_catcher.cpp - * @brief A Mac OS X specific hack to control the volume level of all audio channels opened by a process. + * @brief A macOS specific hack to control the volume level of all audio channels opened by a process. * * @cond * $LicenseInfo:firstyear=2010&license=viewerlgpl$ diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index 43d3a32e64..d5e17ba536 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -816,7 +816,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string) S32 y = message_in.getValueS32("y"); // only even send left mouse button events to the CEF library - // (partially prompted by crash in OS X CEF when sending right button events) + // (partially prompted by crash in macOS CEF when sending right button events) // we catch the right click in viewer and display our own context menu anyway S32 button = message_in.getValueS32("button"); dullahan::EMouseButton btn = dullahan::MB_MOUSE_BUTTON_LEFT; -- cgit v1.2.3 From e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 22 May 2024 21:25:21 +0200 Subject: Fix line endlings --- indra/media_plugins/cef/mac_volume_catcher.cpp | 550 +++--- indra/media_plugins/cef/media_plugin_cef.cpp | 2294 ++++++++++++------------ 2 files changed, 1422 insertions(+), 1422 deletions(-) (limited to 'indra/media_plugins/cef') diff --git a/indra/media_plugins/cef/mac_volume_catcher.cpp b/indra/media_plugins/cef/mac_volume_catcher.cpp index 26b1977e55..54ebbfe1c7 100644 --- a/indra/media_plugins/cef/mac_volume_catcher.cpp +++ b/indra/media_plugins/cef/mac_volume_catcher.cpp @@ -1,275 +1,275 @@ -/** - * @file mac_volume_catcher.cpp - * @brief A macOS specific hack to control the volume level of all audio channels opened by a process. - * - * @cond - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - * @endcond - */ - -/************************************************************************************************************** - This code works by using CaptureComponent to capture the "Default Output" audio component - (kAudioUnitType_Output/kAudioUnitSubType_DefaultOutput) and delegating all calls to the original component. - It does this just to keep track of all instances of the default output component, so that it can set the - kHALOutputParam_Volume parameter on all of them to adjust the output volume. -**************************************************************************************************************/ - -#include "volume_catcher.h" - -#include -#include -#include - -#if LL_DARWIN -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif - -struct VolumeCatcherStorage; - -class VolumeCatcherImpl -{ -public: - - void setVolume(F32 volume); - void setPan(F32 pan); - - void setInstanceVolume(VolumeCatcherStorage *instance); - - std::list mComponentInstances; - Component mOriginalDefaultOutput; - Component mVolumeAdjuster; - - static VolumeCatcherImpl *getInstance(); -private: - // This is a singleton class -- both callers and the component implementation should use getInstance() to find the instance. - VolumeCatcherImpl(); - static VolumeCatcherImpl *sInstance; - - // The singlar instance of this class is expected to last until the process exits. - // To ensure this, we declare the destructor here but never define it, so any code which attempts to destroy the instance will not link. - ~VolumeCatcherImpl(); - - F32 mVolume; - F32 mPan; -}; - -VolumeCatcherImpl *VolumeCatcherImpl::sInstance = NULL;; - -struct VolumeCatcherStorage -{ - ComponentInstance self; - ComponentInstance delegate; -}; - -static ComponentResult volume_catcher_component_entry(ComponentParameters *cp, Handle componentStorage); -static ComponentResult volume_catcher_component_open(VolumeCatcherStorage *storage, ComponentInstance self); -static ComponentResult volume_catcher_component_close(VolumeCatcherStorage *storage, ComponentInstance self); - -VolumeCatcherImpl *VolumeCatcherImpl::getInstance() -{ - if(!sInstance) - { - sInstance = new VolumeCatcherImpl; - } - - return sInstance; -} - -VolumeCatcherImpl::VolumeCatcherImpl() -{ - mVolume = 1.0; // default to full volume - mPan = 0.0; // and center pan - - ComponentDescription desc; - desc.componentType = kAudioUnitType_Output; - desc.componentSubType = kAudioUnitSubType_DefaultOutput; - desc.componentManufacturer = kAudioUnitManufacturer_Apple; - desc.componentFlags = 0; - desc.componentFlagsMask = 0; - - // Find the original default output component - mOriginalDefaultOutput = FindNextComponent(NULL, &desc); - - // Register our own output component with the same parameters - mVolumeAdjuster = RegisterComponent(&desc, NewComponentRoutineUPP(volume_catcher_component_entry), 0, NULL, NULL, NULL); - - // Capture the original component, so we always get found instead. - CaptureComponent(mOriginalDefaultOutput, mVolumeAdjuster); - -} - -static ComponentResult volume_catcher_component_entry(ComponentParameters *cp, Handle componentStorage) -{ - ComponentResult result = badComponentSelector; - VolumeCatcherStorage *storage = (VolumeCatcherStorage*)componentStorage; - - switch(cp->what) - { - case kComponentOpenSelect: -// std::cerr << "kComponentOpenSelect" << std::endl; - result = CallComponentFunctionWithStorageProcInfo((Handle)storage, cp, (ProcPtr)volume_catcher_component_open, uppCallComponentOpenProcInfo); - break; - - case kComponentCloseSelect: -// std::cerr << "kComponentCloseSelect" << std::endl; - result = CallComponentFunctionWithStorageProcInfo((Handle)storage, cp, (ProcPtr)volume_catcher_component_close, uppCallComponentCloseProcInfo); - // CallComponentFunctionWithStorageProcInfo - break; - - default: -// std::cerr << "Delegating selector: " << cp->what << " to component instance " << storage->delegate << std::endl; - result = DelegateComponentCall(cp, storage->delegate); - break; - } - - return result; -} - -static ComponentResult volume_catcher_component_open(VolumeCatcherStorage *storage, ComponentInstance self) -{ - ComponentResult result = noErr; - VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance(); - - storage = new VolumeCatcherStorage; - - storage->self = self; - storage->delegate = NULL; - - result = OpenAComponent(impl->mOriginalDefaultOutput, &(storage->delegate)); - - if(result != noErr) - { -// std::cerr << "OpenAComponent result = " << result << ", component ref = " << storage->delegate << std::endl; - - // If we failed to open the delagate component, our open is going to fail. Clean things up. - delete storage; - } - else - { - // Success -- set up this component's storage - SetComponentInstanceStorage(self, (Handle)storage); - - // add this instance to the global list - impl->mComponentInstances.push_back(storage); - - // and set up the initial volume - impl->setInstanceVolume(storage); - } - - return result; -} - -static ComponentResult volume_catcher_component_close(VolumeCatcherStorage *storage, ComponentInstance self) -{ - ComponentResult result = noErr; - - if(storage) - { - if(storage->delegate) - { - CloseComponent(storage->delegate); - storage->delegate = NULL; - } - - VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance(); - impl->mComponentInstances.remove(storage); - delete[] storage; - } - - return result; -} - -void VolumeCatcherImpl::setVolume(F32 volume) -{ - VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance(); - impl->mVolume = volume; - - // Iterate through all known instances, setting the volume on each. - for(std::list::iterator iter = mComponentInstances.begin(); iter != mComponentInstances.end(); ++iter) - { - impl->setInstanceVolume(*iter); - } -} - -void VolumeCatcherImpl::setPan(F32 pan) -{ - VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance(); - impl->mPan = pan; - - // TODO: implement this. - // This will probably require adding a "panner" audio unit to the chain somehow. - // There's also a "3d mixer" component that we might be able to use... -} - -void VolumeCatcherImpl::setInstanceVolume(VolumeCatcherStorage *instance) -{ -// std::cerr << "Setting volume on component instance: " << (instance->delegate) << " to " << mVolume << std::endl; - - OSStatus err = noErr; - - if(instance && instance->delegate) - { - err = AudioUnitSetParameter( - instance->delegate, - kHALOutputParam_Volume, - kAudioUnitScope_Global, - 0, - mVolume, - 0); - } - - if(err) - { -// std::cerr << " AudioUnitSetParameter returned " << err << std::endl; - } -} - -///////////////////////////////////////////////////// - -VolumeCatcher::VolumeCatcher() -{ - pimpl = VolumeCatcherImpl::getInstance(); -} - -VolumeCatcher::~VolumeCatcher() -{ - // Let the instance persist until exit. -} - -void VolumeCatcher::setVolume(F32 volume) -{ - pimpl->setVolume(volume); -} - -void VolumeCatcher::setPan(F32 pan) -{ - pimpl->setPan(pan); -} - -void VolumeCatcher::pump() -{ - // No periodic tasks are necessary for this implementation. -} - -#if LL_DARWIN -#pragma GCC diagnostic warning "-Wdeprecated-declarations" -#endif +/** + * @file mac_volume_catcher.cpp + * @brief A macOS specific hack to control the volume level of all audio channels opened by a process. + * + * @cond + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + * @endcond + */ + +/************************************************************************************************************** + This code works by using CaptureComponent to capture the "Default Output" audio component + (kAudioUnitType_Output/kAudioUnitSubType_DefaultOutput) and delegating all calls to the original component. + It does this just to keep track of all instances of the default output component, so that it can set the + kHALOutputParam_Volume parameter on all of them to adjust the output volume. +**************************************************************************************************************/ + +#include "volume_catcher.h" + +#include +#include +#include + +#if LL_DARWIN +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +struct VolumeCatcherStorage; + +class VolumeCatcherImpl +{ +public: + + void setVolume(F32 volume); + void setPan(F32 pan); + + void setInstanceVolume(VolumeCatcherStorage *instance); + + std::list mComponentInstances; + Component mOriginalDefaultOutput; + Component mVolumeAdjuster; + + static VolumeCatcherImpl *getInstance(); +private: + // This is a singleton class -- both callers and the component implementation should use getInstance() to find the instance. + VolumeCatcherImpl(); + static VolumeCatcherImpl *sInstance; + + // The singlar instance of this class is expected to last until the process exits. + // To ensure this, we declare the destructor here but never define it, so any code which attempts to destroy the instance will not link. + ~VolumeCatcherImpl(); + + F32 mVolume; + F32 mPan; +}; + +VolumeCatcherImpl *VolumeCatcherImpl::sInstance = NULL;; + +struct VolumeCatcherStorage +{ + ComponentInstance self; + ComponentInstance delegate; +}; + +static ComponentResult volume_catcher_component_entry(ComponentParameters *cp, Handle componentStorage); +static ComponentResult volume_catcher_component_open(VolumeCatcherStorage *storage, ComponentInstance self); +static ComponentResult volume_catcher_component_close(VolumeCatcherStorage *storage, ComponentInstance self); + +VolumeCatcherImpl *VolumeCatcherImpl::getInstance() +{ + if(!sInstance) + { + sInstance = new VolumeCatcherImpl; + } + + return sInstance; +} + +VolumeCatcherImpl::VolumeCatcherImpl() +{ + mVolume = 1.0; // default to full volume + mPan = 0.0; // and center pan + + ComponentDescription desc; + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_DefaultOutput; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + // Find the original default output component + mOriginalDefaultOutput = FindNextComponent(NULL, &desc); + + // Register our own output component with the same parameters + mVolumeAdjuster = RegisterComponent(&desc, NewComponentRoutineUPP(volume_catcher_component_entry), 0, NULL, NULL, NULL); + + // Capture the original component, so we always get found instead. + CaptureComponent(mOriginalDefaultOutput, mVolumeAdjuster); + +} + +static ComponentResult volume_catcher_component_entry(ComponentParameters *cp, Handle componentStorage) +{ + ComponentResult result = badComponentSelector; + VolumeCatcherStorage *storage = (VolumeCatcherStorage*)componentStorage; + + switch(cp->what) + { + case kComponentOpenSelect: +// std::cerr << "kComponentOpenSelect" << std::endl; + result = CallComponentFunctionWithStorageProcInfo((Handle)storage, cp, (ProcPtr)volume_catcher_component_open, uppCallComponentOpenProcInfo); + break; + + case kComponentCloseSelect: +// std::cerr << "kComponentCloseSelect" << std::endl; + result = CallComponentFunctionWithStorageProcInfo((Handle)storage, cp, (ProcPtr)volume_catcher_component_close, uppCallComponentCloseProcInfo); + // CallComponentFunctionWithStorageProcInfo + break; + + default: +// std::cerr << "Delegating selector: " << cp->what << " to component instance " << storage->delegate << std::endl; + result = DelegateComponentCall(cp, storage->delegate); + break; + } + + return result; +} + +static ComponentResult volume_catcher_component_open(VolumeCatcherStorage *storage, ComponentInstance self) +{ + ComponentResult result = noErr; + VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance(); + + storage = new VolumeCatcherStorage; + + storage->self = self; + storage->delegate = NULL; + + result = OpenAComponent(impl->mOriginalDefaultOutput, &(storage->delegate)); + + if(result != noErr) + { +// std::cerr << "OpenAComponent result = " << result << ", component ref = " << storage->delegate << std::endl; + + // If we failed to open the delagate component, our open is going to fail. Clean things up. + delete storage; + } + else + { + // Success -- set up this component's storage + SetComponentInstanceStorage(self, (Handle)storage); + + // add this instance to the global list + impl->mComponentInstances.push_back(storage); + + // and set up the initial volume + impl->setInstanceVolume(storage); + } + + return result; +} + +static ComponentResult volume_catcher_component_close(VolumeCatcherStorage *storage, ComponentInstance self) +{ + ComponentResult result = noErr; + + if(storage) + { + if(storage->delegate) + { + CloseComponent(storage->delegate); + storage->delegate = NULL; + } + + VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance(); + impl->mComponentInstances.remove(storage); + delete[] storage; + } + + return result; +} + +void VolumeCatcherImpl::setVolume(F32 volume) +{ + VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance(); + impl->mVolume = volume; + + // Iterate through all known instances, setting the volume on each. + for(std::list::iterator iter = mComponentInstances.begin(); iter != mComponentInstances.end(); ++iter) + { + impl->setInstanceVolume(*iter); + } +} + +void VolumeCatcherImpl::setPan(F32 pan) +{ + VolumeCatcherImpl *impl = VolumeCatcherImpl::getInstance(); + impl->mPan = pan; + + // TODO: implement this. + // This will probably require adding a "panner" audio unit to the chain somehow. + // There's also a "3d mixer" component that we might be able to use... +} + +void VolumeCatcherImpl::setInstanceVolume(VolumeCatcherStorage *instance) +{ +// std::cerr << "Setting volume on component instance: " << (instance->delegate) << " to " << mVolume << std::endl; + + OSStatus err = noErr; + + if(instance && instance->delegate) + { + err = AudioUnitSetParameter( + instance->delegate, + kHALOutputParam_Volume, + kAudioUnitScope_Global, + 0, + mVolume, + 0); + } + + if(err) + { +// std::cerr << " AudioUnitSetParameter returned " << err << std::endl; + } +} + +///////////////////////////////////////////////////// + +VolumeCatcher::VolumeCatcher() +{ + pimpl = VolumeCatcherImpl::getInstance(); +} + +VolumeCatcher::~VolumeCatcher() +{ + // Let the instance persist until exit. +} + +void VolumeCatcher::setVolume(F32 volume) +{ + pimpl->setVolume(volume); +} + +void VolumeCatcher::setPan(F32 pan) +{ + pimpl->setPan(pan); +} + +void VolumeCatcher::pump() +{ + // No periodic tasks are necessary for this implementation. +} + +#if LL_DARWIN +#pragma GCC diagnostic warning "-Wdeprecated-declarations" +#endif diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index 3aa73ed9a2..64fc7e452b 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -1,1147 +1,1147 @@ -/** -* @file media_plugin_cef.cpp -* @brief CEF (Chromium Embedding Framework) plugin for LLMedia API plugin system -* -* @cond -* $LicenseInfo:firstyear=2008&license=viewerlgpl$ -* Second Life Viewer Source Code -* Copyright (C) 2010, Linden Research, Inc. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; -* version 2.1 of the License only. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA -* $/LicenseInfo$ -* @endcond -*/ - -#include "linden_common.h" -#include "indra_constants.h" // for indra keyboard codes - -#include "llglheaders.h" // for GL_* constants -#include "llsdutil.h" -#include "llplugininstance.h" -#include "llpluginmessage.h" -#include "llpluginmessageclasses.h" -#include "llstring.h" -#include "volume_catcher.h" -#include "media_plugin_base.h" - -#include "dullahan.h" - -//////////////////////////////////////////////////////////////////////////////// -// -class MediaPluginCEF : - public MediaPluginBase -{ -public: - MediaPluginCEF(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); - ~MediaPluginCEF(); - - /*virtual*/ - void receiveMessage(const char* message_string); - -private: - bool init(); - - void onPageChangedCallback(const unsigned char* pixels, int x, int y, const int width, const int height); - void onCustomSchemeURLCallback(std::string url, bool user_gesture, bool is_redirect); - void onConsoleMessageCallback(std::string message, std::string source, int line); - void onStatusMessageCallback(std::string value); - void onTitleChangeCallback(std::string title); - void onTooltipCallback(std::string text); - void onLoadStartCallback(); - void onRequestExitCallback(); - void onLoadEndCallback(int httpStatusCode, std::string url); - void onLoadError(int status, const std::string error_text); - void onAddressChangeCallback(std::string url); - void onOpenPopupCallback(std::string url, std::string target); - bool onHTTPAuthCallback(const std::string host, const std::string realm, std::string& username, std::string& password); - void onCursorChangedCallback(dullahan::ECursorType type); - const std::vector onFileDialog(dullahan::EFileDialogType dialog_type, const std::string dialog_title, const std::string default_file, const std::string dialog_accept_filter, bool& use_default); - bool onJSDialogCallback(const std::string origin_url, const std::string message_text, const std::string default_prompt_text); - bool onJSBeforeUnloadCallback(); - - void postDebugMessage(const std::string& msg); - void authResponse(LLPluginMessage &message); - - void keyEvent(dullahan::EKeyEvent key_event, LLSD native_key_data); - void unicodeInput(std::string event, LLSD native_key_data); - - void checkEditState(); - void setVolume(); - - bool mEnableMediaPluginDebugging; - std::string mHostLanguage; - bool mCookiesEnabled; - bool mPluginsEnabled; - bool mJavascriptEnabled; - bool mProxyEnabled; - std::string mProxyHost; - int mProxyPort; - bool mDisableGPU; - bool mDisableNetworkService; - bool mUseMockKeyChain; - bool mDisableWebSecurity; - bool mFileAccessFromFileUrls; - std::string mUserAgentSubtring; - std::string mAuthUsername; - std::string mAuthPassword; - bool mAuthOK; - bool mCanCut; - bool mCanCopy; - bool mCanPaste; - std::string mRootCachePath; - std::string mCachePath; - std::string mContextCachePath; - std::string mCefLogFile; - bool mCefLogVerbose; - std::vector mPickedFiles; - VolumeCatcher mVolumeCatcher; - F32 mCurVolume; - dullahan* mCEFLib; -}; - -//////////////////////////////////////////////////////////////////////////////// -// -MediaPluginCEF::MediaPluginCEF(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) : -MediaPluginBase(host_send_func, host_user_data) -{ - mWidth = 0; - mHeight = 0; - mDepth = 4; - mPixels = 0; - mEnableMediaPluginDebugging = true; - mHostLanguage = "en"; - mCookiesEnabled = true; - mPluginsEnabled = false; - mJavascriptEnabled = true; - mProxyEnabled = false; - mProxyHost = ""; - mProxyPort = 0; - mDisableGPU = false; - mDisableNetworkService = true; - mUseMockKeyChain = true; - mDisableWebSecurity = false; - mFileAccessFromFileUrls = false; - mUserAgentSubtring = ""; - mAuthUsername = ""; - mAuthPassword = ""; - mAuthOK = false; - mCanCut = false; - mCanCopy = false; - mCanPaste = false; - mCachePath = ""; - mCefLogFile = ""; - mCefLogVerbose = false; - mPickedFiles.clear(); - mCurVolume = 0.0; - - mCEFLib = new dullahan(); - - setVolume(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -MediaPluginCEF::~MediaPluginCEF() -{ - mCEFLib->shutdown(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginCEF::postDebugMessage(const std::string& msg) -{ - if (mEnableMediaPluginDebugging) - { - std::stringstream str; - str << "@Media Msg> " << msg; - - LLPluginMessage debug_message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "debug_message"); - debug_message.setValue("message_text", str.str()); - debug_message.setValue("message_level", "info"); - sendMessage(debug_message); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginCEF::onPageChangedCallback(const unsigned char* pixels, int x, int y, const int width, const int height) -{ - if( mPixels && pixels ) - { - if (mWidth == width && mHeight == height) - { - memcpy(mPixels, pixels, mWidth * mHeight * mDepth); - } - else - { - mCEFLib->setSize(mWidth, mHeight); - } - setDirty(0, 0, mWidth, mHeight); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginCEF::onConsoleMessageCallback(std::string message, std::string source, int line) -{ - std::stringstream str; - str << "Console message: " << message << " in file(" << source << ") at line " << line; - postDebugMessage(str.str()); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginCEF::onStatusMessageCallback(std::string value) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text"); - message.setValue("status", value); - sendMessage(message); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginCEF::onTitleChangeCallback(std::string title) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); - message.setValue("name", title); - message.setValueBoolean("history_back_available", mCEFLib->canGoBack()); - message.setValueBoolean("history_forward_available", mCEFLib->canGoForward()); - sendMessage(message); -} - -void MediaPluginCEF::onTooltipCallback(std::string text) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "tooltip_text"); - message.setValue("tooltip", text); - sendMessage(message); -} -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginCEF::onLoadStartCallback() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin"); - //message.setValue("uri", event.getEventUri()); // not easily available here in CEF - needed? - message.setValueBoolean("history_back_available", mCEFLib->canGoBack()); - message.setValueBoolean("history_forward_available", mCEFLib->canGoForward()); - sendMessage(message); -} - -///////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginCEF::onLoadError(int status, const std::string error_text) -{ - std::stringstream msg; - - msg << "Loading error!"; - msg << "

"; - msg << "Message: " << error_text; - msg << "
"; - msg << "Code: " << status; - - mCEFLib->showBrowserMessage(msg.str()); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginCEF::onRequestExitCallback() -{ - LLPluginMessage message("base", "goodbye"); - sendMessage(message); - - // Will trigger delete on next staticReceiveMessage() - mDeleteMe = true; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginCEF::onLoadEndCallback(int httpStatusCode, std::string url) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete"); - //message.setValue("uri", event.getEventUri()); // not easily available here in CEF - needed? - message.setValueS32("result_code", httpStatusCode); - message.setValueBoolean("history_back_available", mCEFLib->canGoBack()); - message.setValueBoolean("history_forward_available", mCEFLib->canGoForward()); - message.setValue("uri", url); - sendMessage(message); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginCEF::onAddressChangeCallback(std::string url) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed"); - message.setValue("uri", url); - sendMessage(message); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginCEF::onOpenPopupCallback(std::string url, std::string target) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href"); - message.setValue("uri", url); - message.setValue("target", target); - sendMessage(message); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginCEF::onCustomSchemeURLCallback(std::string url, bool user_gesture, bool is_redirect) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow"); - message.setValue("uri", url); - - // indicate if this interaction was from a user click (okay on a SLAPP) or - // via a navigation (e.g. a data URL - see SL-18151) (not okay on a SLAPP) - const std::string nav_type = user_gesture ? "clicked" : "navigated"; - - message.setValue("nav_type", nav_type); - message.setValueBoolean("is_redirect", is_redirect); - - sendMessage(message); -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool MediaPluginCEF::onHTTPAuthCallback(const std::string host, const std::string realm, std::string& username, std::string& password) -{ - mAuthOK = false; - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_request"); - message.setValue("url", host); - message.setValue("realm", realm); - message.setValueBoolean("blocking_request", true); - - // The "blocking_request" key in the message means this sendMessage call will block until a response is received. - sendMessage(message); - - if (mAuthOK) - { - username = mAuthUsername; - password = mAuthPassword; - } - - return mAuthOK; -} - -//////////////////////////////////////////////////////////////////////////////// -// -const std::vector MediaPluginCEF::onFileDialog(dullahan::EFileDialogType dialog_type, const std::string dialog_title, const std::string default_file, std::string dialog_accept_filter, bool& use_default) -{ - // do not use the default CEF file picker - use_default = false; - - if (dialog_type == dullahan::FD_OPEN_FILE) - { - mPickedFiles.clear(); - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file"); - message.setValueBoolean("blocking_request", true); - message.setValueBoolean("multiple_files", false); - - sendMessage(message); - - return mPickedFiles; - } - else if (dialog_type == dullahan::FD_OPEN_MULTIPLE_FILES) - { - mPickedFiles.clear(); - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file"); - message.setValueBoolean("blocking_request", true); - message.setValueBoolean("multiple_files", true); - - sendMessage(message); - - return mPickedFiles; - } - else if (dialog_type == dullahan::FD_SAVE_FILE) - { - mPickedFiles.clear(); - mAuthOK = false; - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "file_download"); - message.setValueBoolean("blocking_request", true); - message.setValue("filename", default_file); - - sendMessage(message); - - return mPickedFiles; - } - - return std::vector(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool MediaPluginCEF::onJSDialogCallback(const std::string origin_url, const std::string message_text, const std::string default_prompt_text) -{ - // return true indicates we suppress the JavaScript alert UI entirely - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool MediaPluginCEF::onJSBeforeUnloadCallback() -{ - // return true indicates we suppress the JavaScript UI entirely - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginCEF::onCursorChangedCallback(dullahan::ECursorType type) -{ - std::string name = ""; - - switch (type) - { - case dullahan::CT_POINTER: - name = "UI_CURSOR_ARROW"; - break; - case dullahan::CT_CROSS: - name = "UI_CURSOR_CROSS"; - break; - case dullahan::CT_HAND: - name = "UI_CURSOR_HAND"; - break; - case dullahan::CT_IBEAM: - name = "UI_CURSOR_IBEAM"; - break; - case dullahan::CT_WAIT: - name = "UI_CURSOR_WAIT"; - break; - //case dullahan::CT_HELP: - case dullahan::CT_ROWRESIZE: - case dullahan::CT_NORTHRESIZE: - case dullahan::CT_SOUTHRESIZE: - case dullahan::CT_NORTHSOUTHRESIZE: - name = "UI_CURSOR_SIZENS"; - break; - case dullahan::CT_COLUMNRESIZE: - case dullahan::CT_EASTRESIZE: - case dullahan::CT_WESTRESIZE: - case dullahan::CT_EASTWESTRESIZE: - name = "UI_CURSOR_SIZEWE"; - break; - case dullahan::CT_NORTHEASTRESIZE: - case dullahan::CT_SOUTHWESTRESIZE: - case dullahan::CT_NORTHEASTSOUTHWESTRESIZE: - name = "UI_CURSOR_SIZENESW"; - break; - case dullahan::CT_SOUTHEASTRESIZE: - case dullahan::CT_NORTHWESTRESIZE: - case dullahan::CT_NORTHWESTSOUTHEASTRESIZE: - name = "UI_CURSOR_SIZENWSE"; - break; - case dullahan::CT_MOVE: - name = "UI_CURSOR_SIZEALL"; - break; - //case dullahan::CT_MIDDLEPANNING: - //case dullahan::CT_EASTPANNING: - //case dullahan::CT_NORTHPANNING: - //case dullahan::CT_NORTHEASTPANNING: - //case dullahan::CT_NORTHWESTPANNING: - //case dullahan::CT_SOUTHPANNING: - //case dullahan::CT_SOUTHEASTPANNING: - //case dullahan::CT_SOUTHWESTPANNING: - //case dullahan::CT_WESTPANNING: - //case dullahan::CT_VERTICALTEXT: - //case dullahan::CT_CELL: - //case dullahan::CT_CONTEXTMENU: - case dullahan::CT_ALIAS: - name = "UI_CURSOR_TOOLMEDIAOPEN"; - break; - case dullahan::CT_PROGRESS: - name = "UI_CURSOR_WORKING"; - break; - case dullahan::CT_COPY: - name = "UI_CURSOR_ARROWCOPY"; - break; - case dullahan::CT_NONE: - name = "UI_CURSOR_NO"; - break; - case dullahan::CT_NODROP: - case dullahan::CT_NOTALLOWED: - name = "UI_CURSOR_NOLOCKED"; - break; - case dullahan::CT_ZOOMIN: - name = "UI_CURSOR_TOOLZOOMIN"; - break; - case dullahan::CT_ZOOMOUT: - name = "UI_CURSOR_TOOLZOOMOUT"; - break; - case dullahan::CT_GRAB: - name = "UI_CURSOR_TOOLGRAB"; - break; - //case dullahan::CT_GRABING: - //case dullahan::CT_CUSTOM: - - default: - LL_WARNS() << "Unknown cursor ID: " << (int)type << LL_ENDL; - break; - } - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed"); - message.setValue("name", name); - sendMessage(message); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginCEF::authResponse(LLPluginMessage &message) -{ - mAuthOK = message.getValueBoolean("ok"); - if (mAuthOK) - { - mAuthUsername = message.getValue("username"); - mAuthPassword = message.getValue("password"); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginCEF::receiveMessage(const char* message_string) -{ - // std::cerr << "MediaPluginCEF::receiveMessage: received message: \"" << message_string << "\"" << std::endl; - LLPluginMessage message_in; - - if (message_in.parse(message_string) >= 0) - { - std::string message_class = message_in.getClass(); - std::string message_name = message_in.getName(); - if (message_class == LLPLUGIN_MESSAGE_CLASS_BASE) - { - if (message_name == "init") - { - LLPluginMessage message("base", "init_response"); - LLSD versions = LLSD::emptyMap(); - versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; - versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; - versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; - message.setValueLLSD("versions", versions); - - std::string plugin_version = "CEF plugin 1.1.412"; - message.setValue("plugin_version", plugin_version); - sendMessage(message); - } - else if (message_name == "idle") - { - mCEFLib->update(); - - mVolumeCatcher.pump(); - - // this seems bad but unless the state changes (it won't until we figure out - // how to get CEF to tell us if copy/cut/paste is available) then this function - // will return immediately - checkEditState(); - } - else if (message_name == "cleanup") - { - mCEFLib->requestExit(); - } - else if (message_name == "force_exit") - { - mDeleteMe = true; - } - else if (message_name == "shm_added") - { - SharedSegmentInfo info; - info.mAddress = message_in.getValuePointer("address"); - info.mSize = (size_t)message_in.getValueS32("size"); - std::string name = message_in.getValue("name"); - - mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); - - } - else if (message_name == "shm_remove") - { - std::string name = message_in.getValue("name"); - - SharedSegmentMap::iterator iter = mSharedSegments.find(name); - if (iter != mSharedSegments.end()) - { - if (mPixels == iter->second.mAddress) - { - mPixels = NULL; - mTextureSegmentName.clear(); - } - mSharedSegments.erase(iter); - } - else - { - } - - LLPluginMessage message("base", "shm_remove_response"); - message.setValue("name", name); - sendMessage(message); - } - else - { - } - } - else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) - { - if (message_name == "init") - { - // event callbacks from Dullahan - mCEFLib->setOnPageChangedCallback(std::bind(&MediaPluginCEF::onPageChangedCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); - mCEFLib->setOnCustomSchemeURLCallback(std::bind(&MediaPluginCEF::onCustomSchemeURLCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); - mCEFLib->setOnConsoleMessageCallback(std::bind(&MediaPluginCEF::onConsoleMessageCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); - mCEFLib->setOnStatusMessageCallback(std::bind(&MediaPluginCEF::onStatusMessageCallback, this, std::placeholders::_1)); - mCEFLib->setOnTitleChangeCallback(std::bind(&MediaPluginCEF::onTitleChangeCallback, this, std::placeholders::_1)); - mCEFLib->setOnTooltipCallback(std::bind(&MediaPluginCEF::onTooltipCallback, this, std::placeholders::_1)); - mCEFLib->setOnLoadStartCallback(std::bind(&MediaPluginCEF::onLoadStartCallback, this)); - mCEFLib->setOnLoadEndCallback(std::bind(&MediaPluginCEF::onLoadEndCallback, this, std::placeholders::_1, std::placeholders::_2)); - mCEFLib->setOnLoadErrorCallback(std::bind(&MediaPluginCEF::onLoadError, this, std::placeholders::_1, std::placeholders::_2)); - mCEFLib->setOnAddressChangeCallback(std::bind(&MediaPluginCEF::onAddressChangeCallback, this, std::placeholders::_1)); - mCEFLib->setOnOpenPopupCallback(std::bind(&MediaPluginCEF::onOpenPopupCallback, this, std::placeholders::_1, std::placeholders::_2)); - mCEFLib->setOnHTTPAuthCallback(std::bind(&MediaPluginCEF::onHTTPAuthCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); - mCEFLib->setOnFileDialogCallback(std::bind(&MediaPluginCEF::onFileDialog, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); - mCEFLib->setOnCursorChangedCallback(std::bind(&MediaPluginCEF::onCursorChangedCallback, this, std::placeholders::_1)); - mCEFLib->setOnRequestExitCallback(std::bind(&MediaPluginCEF::onRequestExitCallback, this)); - mCEFLib->setOnJSDialogCallback(std::bind(&MediaPluginCEF::onJSDialogCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); - mCEFLib->setOnJSBeforeUnloadCallback(std::bind(&MediaPluginCEF::onJSBeforeUnloadCallback, this)); - - dullahan::dullahan_settings settings; -#if LL_WINDOWS - // As of CEF version 83+, for Windows versions, we need to tell CEF - // where the host helper process is since this DLL is not in the same - // dir as the executable that loaded it (SLPlugin.exe). The code in - // Dullahan that tried to figure out the location automatically uses - // the location of the exe which isn't helpful so we tell it explicitly. - std::vector buffer(MAX_PATH + 1); - GetCurrentDirectoryW(MAX_PATH, &buffer[0]); - settings.host_process_path = ll_convert_wide_to_string(&buffer[0]); -#endif - settings.accept_language_list = mHostLanguage; - - // SL-15560: Product team overruled my change to set the default - // embedded background color to match the floater background - // and set it to white - settings.background_color = 0xffffffff; // white - - settings.cache_enabled = true; - settings.root_cache_path = mRootCachePath; - settings.cache_path = mCachePath; - settings.context_cache_path = mContextCachePath; - settings.cookies_enabled = mCookiesEnabled; - - // configure proxy argument if enabled and valid - if (mProxyEnabled && mProxyHost.length()) - { - std::ostringstream proxy_url; - proxy_url << mProxyHost << ":" << mProxyPort; - settings.proxy_host_port = proxy_url.str(); - } - settings.disable_gpu = mDisableGPU; -#if LL_DARWIN - settings.disable_network_service = mDisableNetworkService; - settings.use_mock_keychain = mUseMockKeyChain; -#endif - // these were added to facilitate loading images directly into a local - // web page for the prototype 360 project in 2017 - something that is - // disallowed normally by the browser security model. Now the the source - // (cubemap) images are stores as JavaScript, we can avoid opening up - // this security hole (it was only set for the 360 floater but still - // a concern). Leaving them here, explicitly turn off vs removing - // entirely from this source file so that others are aware of them - // in the future. - settings.disable_web_security = false; - settings.file_access_from_file_urls = false; - - settings.flash_enabled = mPluginsEnabled; - - // This setting applies to all plugins, not just Flash - // Regarding, SL-15559 PDF files do not load in CEF v91, - // it turns out that on Windows, PDF support is treated - // as a plugin on Windows only so turning all plugins - // off, disabled built in PDF support. (Works okay in - // macOS surprisingly). To mitigrate this, we set the global - // media enabled flag to whatever the consumer wants and - // explicitly disable Flash with a different setting (below) - settings.plugins_enabled = mPluginsEnabled; - - // SL-14897 Disable Flash support in the embedded browser - settings.flash_enabled = false; - - settings.flip_mouse_y = false; - settings.flip_pixels_y = true; - settings.frame_rate = 60; - settings.force_wave_audio = true; - settings.initial_height = 1024; - settings.initial_width = 1024; - settings.java_enabled = false; - settings.javascript_enabled = mJavascriptEnabled; - settings.media_stream_enabled = false; // MAINT-6060 - WebRTC media removed until we can add granularity/query UI - - settings.user_agent_substring = mCEFLib->makeCompatibleUserAgentString(mUserAgentSubtring); - settings.webgl_enabled = true; - settings.log_file = mCefLogFile; - settings.log_verbose = mCefLogVerbose; - settings.autoplay_without_gesture = true; - - std::vector custom_schemes(1, "secondlife"); - mCEFLib->setCustomSchemes(custom_schemes); - - bool result = mCEFLib->init(settings); - if (!result) - { - // if this fails, the media system in viewer will put up a message - } - - // now we can set page zoom factor - F32 factor = (F32)message_in.getValueReal("factor"); -#if LL_DARWIN - //temporary fix for SL-10473: issue with displaying checkboxes on Mojave - factor*=1.001; -#endif - mCEFLib->setPageZoom(factor); - - // Plugin gets to decide the texture parameters to use. - mDepth = 4; - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); - message.setValueS32("default_width", 1024); - message.setValueS32("default_height", 1024); - message.setValueS32("depth", mDepth); - message.setValueU32("internalformat", GL_RGB); - message.setValueU32("format", GL_BGRA); - message.setValueU32("type", GL_UNSIGNED_BYTE); - message.setValueBoolean("coords_opengl", true); - sendMessage(message); - } - else if (message_name == "set_user_data_path") - { - std::string user_data_path_cache = message_in.getValue("cache_path"); - std::string subfolder = message_in.getValue("username"); - - mRootCachePath = user_data_path_cache + "cef_cache"; - if (!subfolder.empty()) - { - std::string delim; -#if LL_WINDOWS - // media plugin doesn't have access to gDirUtilp - delim = "\\"; -#else - delim = "/"; -#endif - mCachePath = mRootCachePath + delim + subfolder; - } - else - { - mCachePath = mRootCachePath; - } - mContextCachePath = ""; // disabled by "" - mCefLogFile = message_in.getValue("cef_log_file"); - mCefLogVerbose = message_in.getValueBoolean("cef_verbose_log"); - } - else if (message_name == "size_change") - { - std::string name = message_in.getValue("name"); - S32 width = message_in.getValueS32("width"); - S32 height = message_in.getValueS32("height"); - S32 texture_width = message_in.getValueS32("texture_width"); - S32 texture_height = message_in.getValueS32("texture_height"); - - if (!name.empty()) - { - // Find the shared memory region with this name - SharedSegmentMap::iterator iter = mSharedSegments.find(name); - if (iter != mSharedSegments.end()) - { - mPixels = (unsigned char*)iter->second.mAddress; - mWidth = width; - mHeight = height; - - mTextureWidth = texture_width; - mTextureHeight = texture_height; - - mCEFLib->setSize(mWidth, mHeight); - }; - }; - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); - message.setValue("name", name); - message.setValueS32("width", width); - message.setValueS32("height", height); - message.setValueS32("texture_width", texture_width); - message.setValueS32("texture_height", texture_height); - sendMessage(message); - - } - else if (message_name == "set_language_code") - { - mHostLanguage = message_in.getValue("language"); - } - else if (message_name == "load_uri") - { - std::string uri = message_in.getValue("uri"); - mCEFLib->navigate(uri); - } - else if (message_name == "execute_javascript") - { - std::string code = message_in.getValue("code"); - mCEFLib->executeJavaScript(code); - } - else if (message_name == "set_cookie") - { - std::string uri = message_in.getValue("uri"); - std::string name = message_in.getValue("name"); - std::string value = message_in.getValue("value"); - std::string domain = message_in.getValue("domain"); - std::string path = message_in.getValue("path"); - bool httponly = message_in.getValueBoolean("httponly"); - bool secure = message_in.getValueBoolean("secure"); - mCEFLib->setCookie(uri, name, value, domain, path, httponly, secure); - } - else if (message_name == "mouse_event") - { - std::string event = message_in.getValue("event"); - - S32 x = message_in.getValueS32("x"); - S32 y = message_in.getValueS32("y"); - - // only even send left mouse button events to the CEF library - // (partially prompted by crash in macOS CEF when sending right button events) - // we catch the right click in viewer and display our own context menu anyway - S32 button = message_in.getValueS32("button"); - dullahan::EMouseButton btn = dullahan::MB_MOUSE_BUTTON_LEFT; - - if (event == "down" && button == 0) - { - mCEFLib->mouseButton(btn, dullahan::ME_MOUSE_DOWN, x, y); - mCEFLib->setFocus(); - - std::stringstream str; - str << "Mouse down at = " << x << ", " << y; - postDebugMessage(str.str()); - } - else if (event == "up" && button == 0) - { - mCEFLib->mouseButton(btn, dullahan::ME_MOUSE_UP, x, y); - - std::stringstream str; - str << "Mouse up at = " << x << ", " << y; - postDebugMessage(str.str()); - } - else if (event == "double_click") - { - mCEFLib->mouseButton(btn, dullahan::ME_MOUSE_DOUBLE_CLICK, x, y); - } - else - { - mCEFLib->mouseMove(x, y); - } - } - else if (message_name == "scroll_event") - { - // Mouse coordinates for cef to be able to scroll 'containers' - S32 x = message_in.getValueS32("x"); - S32 y = message_in.getValueS32("y"); - - // Wheel's clicks - S32 delta_x = message_in.getValueS32("clicks_x"); - S32 delta_y = message_in.getValueS32("clicks_y"); - const int scaling_factor = 40; - delta_x *= -scaling_factor; - delta_y *= -scaling_factor; - - mCEFLib->mouseWheel(x, y, delta_x, delta_y); - } - else if (message_name == "text_event") - { - std::string event = message_in.getValue("event"); - LLSD native_key_data = message_in.getValueLLSD("native_key_data"); - unicodeInput(event, native_key_data); - } - else if (message_name == "key_event") - { -#if LL_DARWIN - std::string event = message_in.getValue("event"); - LLSD native_key_data = message_in.getValueLLSD("native_key_data"); - - dullahan::EKeyEvent key_event = dullahan::KE_KEY_UP; - if (event == "down") - { - key_event = dullahan::KE_KEY_DOWN; - } - else if (event == "repeat") - { - key_event = dullahan::KE_KEY_REPEAT; - } - - keyEvent(key_event, native_key_data); - -#elif LL_WINDOWS - std::string event = message_in.getValue("event"); - LLSD native_key_data = message_in.getValueLLSD("native_key_data"); - - // Treat unknown events as key-up for safety. - dullahan::EKeyEvent key_event = dullahan::KE_KEY_UP; - if (event == "down") - { - key_event = dullahan::KE_KEY_DOWN; - } - else if (event == "repeat") - { - key_event = dullahan::KE_KEY_REPEAT; - } - - keyEvent(key_event, native_key_data); -#endif - } - else if (message_name == "enable_media_plugin_debugging") - { - mEnableMediaPluginDebugging = message_in.getValueBoolean("enable"); - } - if (message_name == "pick_file_response") - { - LLSD file_list_llsd = message_in.getValueLLSD("file_list"); - - LLSD::array_const_iterator iter = file_list_llsd.beginArray(); - LLSD::array_const_iterator end = file_list_llsd.endArray(); - for (; iter != end; ++iter) - { - mPickedFiles.push_back(((*iter).asString())); - } - } - if (message_name == "auth_response") - { - authResponse(message_in); - } - if (message_name == "edit_cut") - { - mCEFLib->editCut(); - } - if (message_name == "edit_copy") - { - mCEFLib->editCopy(); - } - if (message_name == "edit_paste") - { - mCEFLib->editPaste(); - } - } - else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) - { - if (message_name == "set_page_zoom_factor") - { - F32 factor = (F32)message_in.getValueReal("factor"); -#if LL_DARWIN - //temporary fix for SL-10473: issue with displaying checkboxes on Mojave - factor*=1.001; -#endif - mCEFLib->setPageZoom(factor); - } - if (message_name == "browse_stop") - { - mCEFLib->stop(); - } - else if (message_name == "browse_reload") - { - bool ignore_cache = true; - mCEFLib->reload(ignore_cache); - } - else if (message_name == "browse_forward") - { - mCEFLib->goForward(); - } - else if (message_name == "browse_back") - { - mCEFLib->goBack(); - } - else if (message_name == "cookies_enabled") - { - mCookiesEnabled = message_in.getValueBoolean("enable"); - } - else if (message_name == "clear_cookies") - { - mCEFLib->deleteAllCookies(); - } - else if (message_name == "set_user_agent") - { - mUserAgentSubtring = message_in.getValue("user_agent"); - } - else if (message_name == "show_web_inspector") - { - mCEFLib->showDevTools(); - } - else if (message_name == "plugins_enabled") - { - mPluginsEnabled = message_in.getValueBoolean("enable"); - } - else if (message_name == "javascript_enabled") - { - mJavascriptEnabled = message_in.getValueBoolean("enable"); - } - else if (message_name == "gpu_disabled") - { - mDisableGPU = message_in.getValueBoolean("disable"); - } - else if (message_name == "proxy_setup") - { - mProxyEnabled = message_in.getValueBoolean("enable"); - mProxyHost = message_in.getValue("host"); - mProxyPort = message_in.getValueS32("port"); - } - else if (message_name == "web_security_disabled") - { - mDisableWebSecurity = message_in.getValueBoolean("disabled"); - } - else if (message_name == "file_access_from_file_urls") - { - mFileAccessFromFileUrls = message_in.getValueBoolean("enabled"); - } - } - else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) - { - if (message_name == "set_volume") - { - F32 volume = (F32)message_in.getValueReal("volume"); - mCurVolume = volume; - setVolume(); - } - } - else - { - }; - } -} - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginCEF::keyEvent(dullahan::EKeyEvent key_event, LLSD native_key_data = LLSD::emptyMap()) -{ -#if LL_DARWIN - U32 event_modifiers = native_key_data["event_modifiers"].asInteger(); - U32 event_keycode = native_key_data["event_keycode"].asInteger(); - U32 event_chars = native_key_data["event_chars"].asInteger(); - U32 event_umodchars = native_key_data["event_umodchars"].asInteger(); - bool event_isrepeat = native_key_data["event_isrepeat"].asBoolean(); - - // adding new code below in unicodeInput means we don't send ascii chars - // here too or we get double key presses on a mac. - bool esc_key = (event_umodchars == 27); - bool tab_key_up = (event_umodchars == 9) && (key_event == dullahan::EKeyEvent::KE_KEY_UP); - if ((esc_key || ((unsigned char)event_chars < 0x10 || (unsigned char)event_chars >= 0x7f )) && !tab_key_up) - { - mCEFLib->nativeKeyboardEventOSX(key_event, event_modifiers, - event_keycode, event_chars, - event_umodchars, event_isrepeat); - } -#elif LL_WINDOWS - U32 msg = ll_U32_from_sd(native_key_data["msg"]); - U32 wparam = ll_U32_from_sd(native_key_data["w_param"]); - U64 lparam = ll_U32_from_sd(native_key_data["l_param"]); - - mCEFLib->nativeKeyboardEventWin(msg, wparam, lparam); -#endif -}; - -void MediaPluginCEF::unicodeInput(std::string event, LLSD native_key_data = LLSD::emptyMap()) -{ -#if LL_DARWIN - // i didn't think this code was needed for macOS but without it, the IME - // input in japanese (and likely others too) doesn't work correctly. - // see maint-7654 - U32 event_modifiers = native_key_data["event_modifiers"].asInteger(); - U32 event_keycode = native_key_data["event_keycode"].asInteger(); - U32 event_chars = native_key_data["event_chars"].asInteger(); - U32 event_umodchars = native_key_data["event_umodchars"].asInteger(); - bool event_isrepeat = native_key_data["event_isrepeat"].asBoolean(); - - dullahan::EKeyEvent key_event = dullahan::KE_KEY_UP; - if (event == "down") - { - key_event = dullahan::KE_KEY_DOWN; - } - - mCEFLib->nativeKeyboardEventOSX(key_event, event_modifiers, - event_keycode, event_chars, - event_umodchars, event_isrepeat); -#elif LL_WINDOWS - event = ""; // not needed here but prevents unused var warning as error - U32 msg = ll_U32_from_sd(native_key_data["msg"]); - U32 wparam = ll_U32_from_sd(native_key_data["w_param"]); - U64 lparam = ll_U32_from_sd(native_key_data["l_param"]); - mCEFLib->nativeKeyboardEventWin(msg, wparam, lparam); -#endif -}; - -//////////////////////////////////////////////////////////////////////////////// -// -void MediaPluginCEF::checkEditState() -{ - bool can_cut = mCEFLib->editCanCut(); - bool can_copy = mCEFLib->editCanCopy(); - bool can_paste = mCEFLib->editCanPaste(); - - if ((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste)) - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state"); - - if (can_cut != mCanCut) - { - mCanCut = can_cut; - message.setValueBoolean("cut", can_cut); - } - - if (can_copy != mCanCopy) - { - mCanCopy = can_copy; - message.setValueBoolean("copy", can_copy); - } - - if (can_paste != mCanPaste) - { - mCanPaste = can_paste; - message.setValueBoolean("paste", can_paste); - } - - sendMessage(message); - } -} - -void MediaPluginCEF::setVolume() -{ - mVolumeCatcher.setVolume(mCurVolume); -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool MediaPluginCEF::init() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); - message.setValue("name", "CEF Plugin"); - sendMessage(message); - - return true; -}; - -//////////////////////////////////////////////////////////////////////////////// -// -int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, - void* host_user_data, - LLPluginInstance::sendMessageFunction *plugin_send_func, - void **plugin_user_data) -{ - MediaPluginCEF* self = new MediaPluginCEF(host_send_func, host_user_data); - *plugin_send_func = MediaPluginCEF::staticReceiveMessage; - *plugin_user_data = (void*)self; - - return 0; -} +/** +* @file media_plugin_cef.cpp +* @brief CEF (Chromium Embedding Framework) plugin for LLMedia API plugin system +* +* @cond +* $LicenseInfo:firstyear=2008&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2010, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +* @endcond +*/ + +#include "linden_common.h" +#include "indra_constants.h" // for indra keyboard codes + +#include "llglheaders.h" // for GL_* constants +#include "llsdutil.h" +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" +#include "llstring.h" +#include "volume_catcher.h" +#include "media_plugin_base.h" + +#include "dullahan.h" + +//////////////////////////////////////////////////////////////////////////////// +// +class MediaPluginCEF : + public MediaPluginBase +{ +public: + MediaPluginCEF(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~MediaPluginCEF(); + + /*virtual*/ + void receiveMessage(const char* message_string); + +private: + bool init(); + + void onPageChangedCallback(const unsigned char* pixels, int x, int y, const int width, const int height); + void onCustomSchemeURLCallback(std::string url, bool user_gesture, bool is_redirect); + void onConsoleMessageCallback(std::string message, std::string source, int line); + void onStatusMessageCallback(std::string value); + void onTitleChangeCallback(std::string title); + void onTooltipCallback(std::string text); + void onLoadStartCallback(); + void onRequestExitCallback(); + void onLoadEndCallback(int httpStatusCode, std::string url); + void onLoadError(int status, const std::string error_text); + void onAddressChangeCallback(std::string url); + void onOpenPopupCallback(std::string url, std::string target); + bool onHTTPAuthCallback(const std::string host, const std::string realm, std::string& username, std::string& password); + void onCursorChangedCallback(dullahan::ECursorType type); + const std::vector onFileDialog(dullahan::EFileDialogType dialog_type, const std::string dialog_title, const std::string default_file, const std::string dialog_accept_filter, bool& use_default); + bool onJSDialogCallback(const std::string origin_url, const std::string message_text, const std::string default_prompt_text); + bool onJSBeforeUnloadCallback(); + + void postDebugMessage(const std::string& msg); + void authResponse(LLPluginMessage &message); + + void keyEvent(dullahan::EKeyEvent key_event, LLSD native_key_data); + void unicodeInput(std::string event, LLSD native_key_data); + + void checkEditState(); + void setVolume(); + + bool mEnableMediaPluginDebugging; + std::string mHostLanguage; + bool mCookiesEnabled; + bool mPluginsEnabled; + bool mJavascriptEnabled; + bool mProxyEnabled; + std::string mProxyHost; + int mProxyPort; + bool mDisableGPU; + bool mDisableNetworkService; + bool mUseMockKeyChain; + bool mDisableWebSecurity; + bool mFileAccessFromFileUrls; + std::string mUserAgentSubtring; + std::string mAuthUsername; + std::string mAuthPassword; + bool mAuthOK; + bool mCanCut; + bool mCanCopy; + bool mCanPaste; + std::string mRootCachePath; + std::string mCachePath; + std::string mContextCachePath; + std::string mCefLogFile; + bool mCefLogVerbose; + std::vector mPickedFiles; + VolumeCatcher mVolumeCatcher; + F32 mCurVolume; + dullahan* mCEFLib; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +MediaPluginCEF::MediaPluginCEF(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) : +MediaPluginBase(host_send_func, host_user_data) +{ + mWidth = 0; + mHeight = 0; + mDepth = 4; + mPixels = 0; + mEnableMediaPluginDebugging = true; + mHostLanguage = "en"; + mCookiesEnabled = true; + mPluginsEnabled = false; + mJavascriptEnabled = true; + mProxyEnabled = false; + mProxyHost = ""; + mProxyPort = 0; + mDisableGPU = false; + mDisableNetworkService = true; + mUseMockKeyChain = true; + mDisableWebSecurity = false; + mFileAccessFromFileUrls = false; + mUserAgentSubtring = ""; + mAuthUsername = ""; + mAuthPassword = ""; + mAuthOK = false; + mCanCut = false; + mCanCopy = false; + mCanPaste = false; + mCachePath = ""; + mCefLogFile = ""; + mCefLogVerbose = false; + mPickedFiles.clear(); + mCurVolume = 0.0; + + mCEFLib = new dullahan(); + + setVolume(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +MediaPluginCEF::~MediaPluginCEF() +{ + mCEFLib->shutdown(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginCEF::postDebugMessage(const std::string& msg) +{ + if (mEnableMediaPluginDebugging) + { + std::stringstream str; + str << "@Media Msg> " << msg; + + LLPluginMessage debug_message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "debug_message"); + debug_message.setValue("message_text", str.str()); + debug_message.setValue("message_level", "info"); + sendMessage(debug_message); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginCEF::onPageChangedCallback(const unsigned char* pixels, int x, int y, const int width, const int height) +{ + if( mPixels && pixels ) + { + if (mWidth == width && mHeight == height) + { + memcpy(mPixels, pixels, mWidth * mHeight * mDepth); + } + else + { + mCEFLib->setSize(mWidth, mHeight); + } + setDirty(0, 0, mWidth, mHeight); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginCEF::onConsoleMessageCallback(std::string message, std::string source, int line) +{ + std::stringstream str; + str << "Console message: " << message << " in file(" << source << ") at line " << line; + postDebugMessage(str.str()); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginCEF::onStatusMessageCallback(std::string value) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text"); + message.setValue("status", value); + sendMessage(message); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginCEF::onTitleChangeCallback(std::string title) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); + message.setValue("name", title); + message.setValueBoolean("history_back_available", mCEFLib->canGoBack()); + message.setValueBoolean("history_forward_available", mCEFLib->canGoForward()); + sendMessage(message); +} + +void MediaPluginCEF::onTooltipCallback(std::string text) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "tooltip_text"); + message.setValue("tooltip", text); + sendMessage(message); +} +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginCEF::onLoadStartCallback() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin"); + //message.setValue("uri", event.getEventUri()); // not easily available here in CEF - needed? + message.setValueBoolean("history_back_available", mCEFLib->canGoBack()); + message.setValueBoolean("history_forward_available", mCEFLib->canGoForward()); + sendMessage(message); +} + +///////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginCEF::onLoadError(int status, const std::string error_text) +{ + std::stringstream msg; + + msg << "Loading error!"; + msg << "

"; + msg << "Message: " << error_text; + msg << "
"; + msg << "Code: " << status; + + mCEFLib->showBrowserMessage(msg.str()); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginCEF::onRequestExitCallback() +{ + LLPluginMessage message("base", "goodbye"); + sendMessage(message); + + // Will trigger delete on next staticReceiveMessage() + mDeleteMe = true; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginCEF::onLoadEndCallback(int httpStatusCode, std::string url) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete"); + //message.setValue("uri", event.getEventUri()); // not easily available here in CEF - needed? + message.setValueS32("result_code", httpStatusCode); + message.setValueBoolean("history_back_available", mCEFLib->canGoBack()); + message.setValueBoolean("history_forward_available", mCEFLib->canGoForward()); + message.setValue("uri", url); + sendMessage(message); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginCEF::onAddressChangeCallback(std::string url) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed"); + message.setValue("uri", url); + sendMessage(message); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginCEF::onOpenPopupCallback(std::string url, std::string target) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href"); + message.setValue("uri", url); + message.setValue("target", target); + sendMessage(message); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginCEF::onCustomSchemeURLCallback(std::string url, bool user_gesture, bool is_redirect) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow"); + message.setValue("uri", url); + + // indicate if this interaction was from a user click (okay on a SLAPP) or + // via a navigation (e.g. a data URL - see SL-18151) (not okay on a SLAPP) + const std::string nav_type = user_gesture ? "clicked" : "navigated"; + + message.setValue("nav_type", nav_type); + message.setValueBoolean("is_redirect", is_redirect); + + sendMessage(message); +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool MediaPluginCEF::onHTTPAuthCallback(const std::string host, const std::string realm, std::string& username, std::string& password) +{ + mAuthOK = false; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_request"); + message.setValue("url", host); + message.setValue("realm", realm); + message.setValueBoolean("blocking_request", true); + + // The "blocking_request" key in the message means this sendMessage call will block until a response is received. + sendMessage(message); + + if (mAuthOK) + { + username = mAuthUsername; + password = mAuthPassword; + } + + return mAuthOK; +} + +//////////////////////////////////////////////////////////////////////////////// +// +const std::vector MediaPluginCEF::onFileDialog(dullahan::EFileDialogType dialog_type, const std::string dialog_title, const std::string default_file, std::string dialog_accept_filter, bool& use_default) +{ + // do not use the default CEF file picker + use_default = false; + + if (dialog_type == dullahan::FD_OPEN_FILE) + { + mPickedFiles.clear(); + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file"); + message.setValueBoolean("blocking_request", true); + message.setValueBoolean("multiple_files", false); + + sendMessage(message); + + return mPickedFiles; + } + else if (dialog_type == dullahan::FD_OPEN_MULTIPLE_FILES) + { + mPickedFiles.clear(); + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file"); + message.setValueBoolean("blocking_request", true); + message.setValueBoolean("multiple_files", true); + + sendMessage(message); + + return mPickedFiles; + } + else if (dialog_type == dullahan::FD_SAVE_FILE) + { + mPickedFiles.clear(); + mAuthOK = false; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "file_download"); + message.setValueBoolean("blocking_request", true); + message.setValue("filename", default_file); + + sendMessage(message); + + return mPickedFiles; + } + + return std::vector(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool MediaPluginCEF::onJSDialogCallback(const std::string origin_url, const std::string message_text, const std::string default_prompt_text) +{ + // return true indicates we suppress the JavaScript alert UI entirely + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool MediaPluginCEF::onJSBeforeUnloadCallback() +{ + // return true indicates we suppress the JavaScript UI entirely + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginCEF::onCursorChangedCallback(dullahan::ECursorType type) +{ + std::string name = ""; + + switch (type) + { + case dullahan::CT_POINTER: + name = "UI_CURSOR_ARROW"; + break; + case dullahan::CT_CROSS: + name = "UI_CURSOR_CROSS"; + break; + case dullahan::CT_HAND: + name = "UI_CURSOR_HAND"; + break; + case dullahan::CT_IBEAM: + name = "UI_CURSOR_IBEAM"; + break; + case dullahan::CT_WAIT: + name = "UI_CURSOR_WAIT"; + break; + //case dullahan::CT_HELP: + case dullahan::CT_ROWRESIZE: + case dullahan::CT_NORTHRESIZE: + case dullahan::CT_SOUTHRESIZE: + case dullahan::CT_NORTHSOUTHRESIZE: + name = "UI_CURSOR_SIZENS"; + break; + case dullahan::CT_COLUMNRESIZE: + case dullahan::CT_EASTRESIZE: + case dullahan::CT_WESTRESIZE: + case dullahan::CT_EASTWESTRESIZE: + name = "UI_CURSOR_SIZEWE"; + break; + case dullahan::CT_NORTHEASTRESIZE: + case dullahan::CT_SOUTHWESTRESIZE: + case dullahan::CT_NORTHEASTSOUTHWESTRESIZE: + name = "UI_CURSOR_SIZENESW"; + break; + case dullahan::CT_SOUTHEASTRESIZE: + case dullahan::CT_NORTHWESTRESIZE: + case dullahan::CT_NORTHWESTSOUTHEASTRESIZE: + name = "UI_CURSOR_SIZENWSE"; + break; + case dullahan::CT_MOVE: + name = "UI_CURSOR_SIZEALL"; + break; + //case dullahan::CT_MIDDLEPANNING: + //case dullahan::CT_EASTPANNING: + //case dullahan::CT_NORTHPANNING: + //case dullahan::CT_NORTHEASTPANNING: + //case dullahan::CT_NORTHWESTPANNING: + //case dullahan::CT_SOUTHPANNING: + //case dullahan::CT_SOUTHEASTPANNING: + //case dullahan::CT_SOUTHWESTPANNING: + //case dullahan::CT_WESTPANNING: + //case dullahan::CT_VERTICALTEXT: + //case dullahan::CT_CELL: + //case dullahan::CT_CONTEXTMENU: + case dullahan::CT_ALIAS: + name = "UI_CURSOR_TOOLMEDIAOPEN"; + break; + case dullahan::CT_PROGRESS: + name = "UI_CURSOR_WORKING"; + break; + case dullahan::CT_COPY: + name = "UI_CURSOR_ARROWCOPY"; + break; + case dullahan::CT_NONE: + name = "UI_CURSOR_NO"; + break; + case dullahan::CT_NODROP: + case dullahan::CT_NOTALLOWED: + name = "UI_CURSOR_NOLOCKED"; + break; + case dullahan::CT_ZOOMIN: + name = "UI_CURSOR_TOOLZOOMIN"; + break; + case dullahan::CT_ZOOMOUT: + name = "UI_CURSOR_TOOLZOOMOUT"; + break; + case dullahan::CT_GRAB: + name = "UI_CURSOR_TOOLGRAB"; + break; + //case dullahan::CT_GRABING: + //case dullahan::CT_CUSTOM: + + default: + LL_WARNS() << "Unknown cursor ID: " << (int)type << LL_ENDL; + break; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed"); + message.setValue("name", name); + sendMessage(message); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginCEF::authResponse(LLPluginMessage &message) +{ + mAuthOK = message.getValueBoolean("ok"); + if (mAuthOK) + { + mAuthUsername = message.getValue("username"); + mAuthPassword = message.getValue("password"); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginCEF::receiveMessage(const char* message_string) +{ + // std::cerr << "MediaPluginCEF::receiveMessage: received message: \"" << message_string << "\"" << std::endl; + LLPluginMessage message_in; + + if (message_in.parse(message_string) >= 0) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + if (message_class == LLPLUGIN_MESSAGE_CLASS_BASE) + { + if (message_name == "init") + { + LLPluginMessage message("base", "init_response"); + LLSD versions = LLSD::emptyMap(); + versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; + message.setValueLLSD("versions", versions); + + std::string plugin_version = "CEF plugin 1.1.412"; + message.setValue("plugin_version", plugin_version); + sendMessage(message); + } + else if (message_name == "idle") + { + mCEFLib->update(); + + mVolumeCatcher.pump(); + + // this seems bad but unless the state changes (it won't until we figure out + // how to get CEF to tell us if copy/cut/paste is available) then this function + // will return immediately + checkEditState(); + } + else if (message_name == "cleanup") + { + mCEFLib->requestExit(); + } + else if (message_name == "force_exit") + { + mDeleteMe = true; + } + else if (message_name == "shm_added") + { + SharedSegmentInfo info; + info.mAddress = message_in.getValuePointer("address"); + info.mSize = (size_t)message_in.getValueS32("size"); + std::string name = message_in.getValue("name"); + + mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); + + } + else if (message_name == "shm_remove") + { + std::string name = message_in.getValue("name"); + + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if (iter != mSharedSegments.end()) + { + if (mPixels == iter->second.mAddress) + { + mPixels = NULL; + mTextureSegmentName.clear(); + } + mSharedSegments.erase(iter); + } + else + { + } + + LLPluginMessage message("base", "shm_remove_response"); + message.setValue("name", name); + sendMessage(message); + } + else + { + } + } + else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + if (message_name == "init") + { + // event callbacks from Dullahan + mCEFLib->setOnPageChangedCallback(std::bind(&MediaPluginCEF::onPageChangedCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); + mCEFLib->setOnCustomSchemeURLCallback(std::bind(&MediaPluginCEF::onCustomSchemeURLCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + mCEFLib->setOnConsoleMessageCallback(std::bind(&MediaPluginCEF::onConsoleMessageCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + mCEFLib->setOnStatusMessageCallback(std::bind(&MediaPluginCEF::onStatusMessageCallback, this, std::placeholders::_1)); + mCEFLib->setOnTitleChangeCallback(std::bind(&MediaPluginCEF::onTitleChangeCallback, this, std::placeholders::_1)); + mCEFLib->setOnTooltipCallback(std::bind(&MediaPluginCEF::onTooltipCallback, this, std::placeholders::_1)); + mCEFLib->setOnLoadStartCallback(std::bind(&MediaPluginCEF::onLoadStartCallback, this)); + mCEFLib->setOnLoadEndCallback(std::bind(&MediaPluginCEF::onLoadEndCallback, this, std::placeholders::_1, std::placeholders::_2)); + mCEFLib->setOnLoadErrorCallback(std::bind(&MediaPluginCEF::onLoadError, this, std::placeholders::_1, std::placeholders::_2)); + mCEFLib->setOnAddressChangeCallback(std::bind(&MediaPluginCEF::onAddressChangeCallback, this, std::placeholders::_1)); + mCEFLib->setOnOpenPopupCallback(std::bind(&MediaPluginCEF::onOpenPopupCallback, this, std::placeholders::_1, std::placeholders::_2)); + mCEFLib->setOnHTTPAuthCallback(std::bind(&MediaPluginCEF::onHTTPAuthCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + mCEFLib->setOnFileDialogCallback(std::bind(&MediaPluginCEF::onFileDialog, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); + mCEFLib->setOnCursorChangedCallback(std::bind(&MediaPluginCEF::onCursorChangedCallback, this, std::placeholders::_1)); + mCEFLib->setOnRequestExitCallback(std::bind(&MediaPluginCEF::onRequestExitCallback, this)); + mCEFLib->setOnJSDialogCallback(std::bind(&MediaPluginCEF::onJSDialogCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + mCEFLib->setOnJSBeforeUnloadCallback(std::bind(&MediaPluginCEF::onJSBeforeUnloadCallback, this)); + + dullahan::dullahan_settings settings; +#if LL_WINDOWS + // As of CEF version 83+, for Windows versions, we need to tell CEF + // where the host helper process is since this DLL is not in the same + // dir as the executable that loaded it (SLPlugin.exe). The code in + // Dullahan that tried to figure out the location automatically uses + // the location of the exe which isn't helpful so we tell it explicitly. + std::vector buffer(MAX_PATH + 1); + GetCurrentDirectoryW(MAX_PATH, &buffer[0]); + settings.host_process_path = ll_convert_wide_to_string(&buffer[0]); +#endif + settings.accept_language_list = mHostLanguage; + + // SL-15560: Product team overruled my change to set the default + // embedded background color to match the floater background + // and set it to white + settings.background_color = 0xffffffff; // white + + settings.cache_enabled = true; + settings.root_cache_path = mRootCachePath; + settings.cache_path = mCachePath; + settings.context_cache_path = mContextCachePath; + settings.cookies_enabled = mCookiesEnabled; + + // configure proxy argument if enabled and valid + if (mProxyEnabled && mProxyHost.length()) + { + std::ostringstream proxy_url; + proxy_url << mProxyHost << ":" << mProxyPort; + settings.proxy_host_port = proxy_url.str(); + } + settings.disable_gpu = mDisableGPU; +#if LL_DARWIN + settings.disable_network_service = mDisableNetworkService; + settings.use_mock_keychain = mUseMockKeyChain; +#endif + // these were added to facilitate loading images directly into a local + // web page for the prototype 360 project in 2017 - something that is + // disallowed normally by the browser security model. Now the the source + // (cubemap) images are stores as JavaScript, we can avoid opening up + // this security hole (it was only set for the 360 floater but still + // a concern). Leaving them here, explicitly turn off vs removing + // entirely from this source file so that others are aware of them + // in the future. + settings.disable_web_security = false; + settings.file_access_from_file_urls = false; + + settings.flash_enabled = mPluginsEnabled; + + // This setting applies to all plugins, not just Flash + // Regarding, SL-15559 PDF files do not load in CEF v91, + // it turns out that on Windows, PDF support is treated + // as a plugin on Windows only so turning all plugins + // off, disabled built in PDF support. (Works okay in + // macOS surprisingly). To mitigrate this, we set the global + // media enabled flag to whatever the consumer wants and + // explicitly disable Flash with a different setting (below) + settings.plugins_enabled = mPluginsEnabled; + + // SL-14897 Disable Flash support in the embedded browser + settings.flash_enabled = false; + + settings.flip_mouse_y = false; + settings.flip_pixels_y = true; + settings.frame_rate = 60; + settings.force_wave_audio = true; + settings.initial_height = 1024; + settings.initial_width = 1024; + settings.java_enabled = false; + settings.javascript_enabled = mJavascriptEnabled; + settings.media_stream_enabled = false; // MAINT-6060 - WebRTC media removed until we can add granularity/query UI + + settings.user_agent_substring = mCEFLib->makeCompatibleUserAgentString(mUserAgentSubtring); + settings.webgl_enabled = true; + settings.log_file = mCefLogFile; + settings.log_verbose = mCefLogVerbose; + settings.autoplay_without_gesture = true; + + std::vector custom_schemes(1, "secondlife"); + mCEFLib->setCustomSchemes(custom_schemes); + + bool result = mCEFLib->init(settings); + if (!result) + { + // if this fails, the media system in viewer will put up a message + } + + // now we can set page zoom factor + F32 factor = (F32)message_in.getValueReal("factor"); +#if LL_DARWIN + //temporary fix for SL-10473: issue with displaying checkboxes on Mojave + factor*=1.001; +#endif + mCEFLib->setPageZoom(factor); + + // Plugin gets to decide the texture parameters to use. + mDepth = 4; + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); + message.setValueS32("default_width", 1024); + message.setValueS32("default_height", 1024); + message.setValueS32("depth", mDepth); + message.setValueU32("internalformat", GL_RGB); + message.setValueU32("format", GL_BGRA); + message.setValueU32("type", GL_UNSIGNED_BYTE); + message.setValueBoolean("coords_opengl", true); + sendMessage(message); + } + else if (message_name == "set_user_data_path") + { + std::string user_data_path_cache = message_in.getValue("cache_path"); + std::string subfolder = message_in.getValue("username"); + + mRootCachePath = user_data_path_cache + "cef_cache"; + if (!subfolder.empty()) + { + std::string delim; +#if LL_WINDOWS + // media plugin doesn't have access to gDirUtilp + delim = "\\"; +#else + delim = "/"; +#endif + mCachePath = mRootCachePath + delim + subfolder; + } + else + { + mCachePath = mRootCachePath; + } + mContextCachePath = ""; // disabled by "" + mCefLogFile = message_in.getValue("cef_log_file"); + mCefLogVerbose = message_in.getValueBoolean("cef_verbose_log"); + } + else if (message_name == "size_change") + { + std::string name = message_in.getValue("name"); + S32 width = message_in.getValueS32("width"); + S32 height = message_in.getValueS32("height"); + S32 texture_width = message_in.getValueS32("texture_width"); + S32 texture_height = message_in.getValueS32("texture_height"); + + if (!name.empty()) + { + // Find the shared memory region with this name + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if (iter != mSharedSegments.end()) + { + mPixels = (unsigned char*)iter->second.mAddress; + mWidth = width; + mHeight = height; + + mTextureWidth = texture_width; + mTextureHeight = texture_height; + + mCEFLib->setSize(mWidth, mHeight); + }; + }; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); + message.setValue("name", name); + message.setValueS32("width", width); + message.setValueS32("height", height); + message.setValueS32("texture_width", texture_width); + message.setValueS32("texture_height", texture_height); + sendMessage(message); + + } + else if (message_name == "set_language_code") + { + mHostLanguage = message_in.getValue("language"); + } + else if (message_name == "load_uri") + { + std::string uri = message_in.getValue("uri"); + mCEFLib->navigate(uri); + } + else if (message_name == "execute_javascript") + { + std::string code = message_in.getValue("code"); + mCEFLib->executeJavaScript(code); + } + else if (message_name == "set_cookie") + { + std::string uri = message_in.getValue("uri"); + std::string name = message_in.getValue("name"); + std::string value = message_in.getValue("value"); + std::string domain = message_in.getValue("domain"); + std::string path = message_in.getValue("path"); + bool httponly = message_in.getValueBoolean("httponly"); + bool secure = message_in.getValueBoolean("secure"); + mCEFLib->setCookie(uri, name, value, domain, path, httponly, secure); + } + else if (message_name == "mouse_event") + { + std::string event = message_in.getValue("event"); + + S32 x = message_in.getValueS32("x"); + S32 y = message_in.getValueS32("y"); + + // only even send left mouse button events to the CEF library + // (partially prompted by crash in macOS CEF when sending right button events) + // we catch the right click in viewer and display our own context menu anyway + S32 button = message_in.getValueS32("button"); + dullahan::EMouseButton btn = dullahan::MB_MOUSE_BUTTON_LEFT; + + if (event == "down" && button == 0) + { + mCEFLib->mouseButton(btn, dullahan::ME_MOUSE_DOWN, x, y); + mCEFLib->setFocus(); + + std::stringstream str; + str << "Mouse down at = " << x << ", " << y; + postDebugMessage(str.str()); + } + else if (event == "up" && button == 0) + { + mCEFLib->mouseButton(btn, dullahan::ME_MOUSE_UP, x, y); + + std::stringstream str; + str << "Mouse up at = " << x << ", " << y; + postDebugMessage(str.str()); + } + else if (event == "double_click") + { + mCEFLib->mouseButton(btn, dullahan::ME_MOUSE_DOUBLE_CLICK, x, y); + } + else + { + mCEFLib->mouseMove(x, y); + } + } + else if (message_name == "scroll_event") + { + // Mouse coordinates for cef to be able to scroll 'containers' + S32 x = message_in.getValueS32("x"); + S32 y = message_in.getValueS32("y"); + + // Wheel's clicks + S32 delta_x = message_in.getValueS32("clicks_x"); + S32 delta_y = message_in.getValueS32("clicks_y"); + const int scaling_factor = 40; + delta_x *= -scaling_factor; + delta_y *= -scaling_factor; + + mCEFLib->mouseWheel(x, y, delta_x, delta_y); + } + else if (message_name == "text_event") + { + std::string event = message_in.getValue("event"); + LLSD native_key_data = message_in.getValueLLSD("native_key_data"); + unicodeInput(event, native_key_data); + } + else if (message_name == "key_event") + { +#if LL_DARWIN + std::string event = message_in.getValue("event"); + LLSD native_key_data = message_in.getValueLLSD("native_key_data"); + + dullahan::EKeyEvent key_event = dullahan::KE_KEY_UP; + if (event == "down") + { + key_event = dullahan::KE_KEY_DOWN; + } + else if (event == "repeat") + { + key_event = dullahan::KE_KEY_REPEAT; + } + + keyEvent(key_event, native_key_data); + +#elif LL_WINDOWS + std::string event = message_in.getValue("event"); + LLSD native_key_data = message_in.getValueLLSD("native_key_data"); + + // Treat unknown events as key-up for safety. + dullahan::EKeyEvent key_event = dullahan::KE_KEY_UP; + if (event == "down") + { + key_event = dullahan::KE_KEY_DOWN; + } + else if (event == "repeat") + { + key_event = dullahan::KE_KEY_REPEAT; + } + + keyEvent(key_event, native_key_data); +#endif + } + else if (message_name == "enable_media_plugin_debugging") + { + mEnableMediaPluginDebugging = message_in.getValueBoolean("enable"); + } + if (message_name == "pick_file_response") + { + LLSD file_list_llsd = message_in.getValueLLSD("file_list"); + + LLSD::array_const_iterator iter = file_list_llsd.beginArray(); + LLSD::array_const_iterator end = file_list_llsd.endArray(); + for (; iter != end; ++iter) + { + mPickedFiles.push_back(((*iter).asString())); + } + } + if (message_name == "auth_response") + { + authResponse(message_in); + } + if (message_name == "edit_cut") + { + mCEFLib->editCut(); + } + if (message_name == "edit_copy") + { + mCEFLib->editCopy(); + } + if (message_name == "edit_paste") + { + mCEFLib->editPaste(); + } + } + else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) + { + if (message_name == "set_page_zoom_factor") + { + F32 factor = (F32)message_in.getValueReal("factor"); +#if LL_DARWIN + //temporary fix for SL-10473: issue with displaying checkboxes on Mojave + factor*=1.001; +#endif + mCEFLib->setPageZoom(factor); + } + if (message_name == "browse_stop") + { + mCEFLib->stop(); + } + else if (message_name == "browse_reload") + { + bool ignore_cache = true; + mCEFLib->reload(ignore_cache); + } + else if (message_name == "browse_forward") + { + mCEFLib->goForward(); + } + else if (message_name == "browse_back") + { + mCEFLib->goBack(); + } + else if (message_name == "cookies_enabled") + { + mCookiesEnabled = message_in.getValueBoolean("enable"); + } + else if (message_name == "clear_cookies") + { + mCEFLib->deleteAllCookies(); + } + else if (message_name == "set_user_agent") + { + mUserAgentSubtring = message_in.getValue("user_agent"); + } + else if (message_name == "show_web_inspector") + { + mCEFLib->showDevTools(); + } + else if (message_name == "plugins_enabled") + { + mPluginsEnabled = message_in.getValueBoolean("enable"); + } + else if (message_name == "javascript_enabled") + { + mJavascriptEnabled = message_in.getValueBoolean("enable"); + } + else if (message_name == "gpu_disabled") + { + mDisableGPU = message_in.getValueBoolean("disable"); + } + else if (message_name == "proxy_setup") + { + mProxyEnabled = message_in.getValueBoolean("enable"); + mProxyHost = message_in.getValue("host"); + mProxyPort = message_in.getValueS32("port"); + } + else if (message_name == "web_security_disabled") + { + mDisableWebSecurity = message_in.getValueBoolean("disabled"); + } + else if (message_name == "file_access_from_file_urls") + { + mFileAccessFromFileUrls = message_in.getValueBoolean("enabled"); + } + } + else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) + { + if (message_name == "set_volume") + { + F32 volume = (F32)message_in.getValueReal("volume"); + mCurVolume = volume; + setVolume(); + } + } + else + { + }; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginCEF::keyEvent(dullahan::EKeyEvent key_event, LLSD native_key_data = LLSD::emptyMap()) +{ +#if LL_DARWIN + U32 event_modifiers = native_key_data["event_modifiers"].asInteger(); + U32 event_keycode = native_key_data["event_keycode"].asInteger(); + U32 event_chars = native_key_data["event_chars"].asInteger(); + U32 event_umodchars = native_key_data["event_umodchars"].asInteger(); + bool event_isrepeat = native_key_data["event_isrepeat"].asBoolean(); + + // adding new code below in unicodeInput means we don't send ascii chars + // here too or we get double key presses on a mac. + bool esc_key = (event_umodchars == 27); + bool tab_key_up = (event_umodchars == 9) && (key_event == dullahan::EKeyEvent::KE_KEY_UP); + if ((esc_key || ((unsigned char)event_chars < 0x10 || (unsigned char)event_chars >= 0x7f )) && !tab_key_up) + { + mCEFLib->nativeKeyboardEventOSX(key_event, event_modifiers, + event_keycode, event_chars, + event_umodchars, event_isrepeat); + } +#elif LL_WINDOWS + U32 msg = ll_U32_from_sd(native_key_data["msg"]); + U32 wparam = ll_U32_from_sd(native_key_data["w_param"]); + U64 lparam = ll_U32_from_sd(native_key_data["l_param"]); + + mCEFLib->nativeKeyboardEventWin(msg, wparam, lparam); +#endif +}; + +void MediaPluginCEF::unicodeInput(std::string event, LLSD native_key_data = LLSD::emptyMap()) +{ +#if LL_DARWIN + // i didn't think this code was needed for macOS but without it, the IME + // input in japanese (and likely others too) doesn't work correctly. + // see maint-7654 + U32 event_modifiers = native_key_data["event_modifiers"].asInteger(); + U32 event_keycode = native_key_data["event_keycode"].asInteger(); + U32 event_chars = native_key_data["event_chars"].asInteger(); + U32 event_umodchars = native_key_data["event_umodchars"].asInteger(); + bool event_isrepeat = native_key_data["event_isrepeat"].asBoolean(); + + dullahan::EKeyEvent key_event = dullahan::KE_KEY_UP; + if (event == "down") + { + key_event = dullahan::KE_KEY_DOWN; + } + + mCEFLib->nativeKeyboardEventOSX(key_event, event_modifiers, + event_keycode, event_chars, + event_umodchars, event_isrepeat); +#elif LL_WINDOWS + event = ""; // not needed here but prevents unused var warning as error + U32 msg = ll_U32_from_sd(native_key_data["msg"]); + U32 wparam = ll_U32_from_sd(native_key_data["w_param"]); + U64 lparam = ll_U32_from_sd(native_key_data["l_param"]); + mCEFLib->nativeKeyboardEventWin(msg, wparam, lparam); +#endif +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void MediaPluginCEF::checkEditState() +{ + bool can_cut = mCEFLib->editCanCut(); + bool can_copy = mCEFLib->editCanCopy(); + bool can_paste = mCEFLib->editCanPaste(); + + if ((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste)) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state"); + + if (can_cut != mCanCut) + { + mCanCut = can_cut; + message.setValueBoolean("cut", can_cut); + } + + if (can_copy != mCanCopy) + { + mCanCopy = can_copy; + message.setValueBoolean("copy", can_copy); + } + + if (can_paste != mCanPaste) + { + mCanPaste = can_paste; + message.setValueBoolean("paste", can_paste); + } + + sendMessage(message); + } +} + +void MediaPluginCEF::setVolume() +{ + mVolumeCatcher.setVolume(mCurVolume); +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool MediaPluginCEF::init() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); + message.setValue("name", "CEF Plugin"); + sendMessage(message); + + return true; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, + void* host_user_data, + LLPluginInstance::sendMessageFunction *plugin_send_func, + void **plugin_user_data) +{ + MediaPluginCEF* self = new MediaPluginCEF(host_send_func, host_user_data); + *plugin_send_func = MediaPluginCEF::staticReceiveMessage; + *plugin_user_data = (void*)self; + + return 0; +} -- cgit v1.2.3