Skip to content
Snippets Groups Projects
Commit 0d6d281c authored by callum_linden's avatar callum_linden
Browse files

Point to LLCEFLib with updated 2357 version and support for setting language for embedded browser

parent af54cd28
No related branches found
No related tags found
No related merge requests found
......@@ -1550,18 +1550,18 @@
<key>archive</key>
<map>
<key>hash</key>
<string>d3532a19f33ba42cfcfc14a3889134ef</string>
<string>bae64d0e6d787daa6299079351ceacf8</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/llceflib_3p-llceflib/rev/303597/arch/CYGWIN/installer/llceflib-1.0.0.CEF-WIN-3.2272.gbda8dc7-32.303597-windows-303597.tar.bz2</string>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/llceflib_3p-llceflib/rev/303625/arch/CYGWIN/installer/llceflib-1.0.0.303625-windows-303625.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
</map>
</map>
<key>version</key>
<string>1.0.0.CEF-WIN-3.2272.gbda8dc7-32.303597</string>
<string>1.0.0.303625</string>
</map>
<key>llphysicsextensions_source</key>
<map>
......
/**
* @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 "llgl.h"
#include "llsdutil.h"
#include "llplugininstance.h"
#include "llpluginmessage.h"
#include "llpluginmessageclasses.h"
#include "media_plugin_base.h"
#include "boost/function.hpp"
#include "boost/bind.hpp"
#include "llCEFLib.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 pageChangedCallback(unsigned char* pixels, int width, int height);
void onCustomSchemeURLCallback(std::string url);
void onConsoleMessageCallback(std::string message, std::string source, int line);
void onStatusMessageCallback(std::string value);
void onTitleChangeCallback(std::string title);
void onLoadStartCallback();
void onLoadEndCallback(int httpStatusCode);
void onNavigateURLCallback(std::string url);
void postDebugMessage(const std::string& msg);
EKeyboardModifier decodeModifiers(std::string &modifiers);
void deserializeKeyboardData(LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers);
void keyEvent(EKeyEvent key_event, int key, EKeyboardModifier modifiers, LLSD native_key_data);
void unicodeInput(const std::string &utf8str, EKeyboardModifier modifiers, LLSD native_key_data);
bool mEnableMediaPluginDebugging;
LLCEFLib* mLLCEFLib;
};
////////////////////////////////////////////////////////////////////////////////
//
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;
mLLCEFLib = new LLCEFLib();
}
////////////////////////////////////////////////////////////////////////////////
//
MediaPluginCEF::~MediaPluginCEF()
{
mLLCEFLib->reset();
}
////////////////////////////////////////////////////////////////////////////////
//
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::pageChangedCallback(unsigned char* pixels, int width, int height)
{
if (mPixels && pixels)
{
if (mWidth == width && mHeight == height)
{
memcpy(mPixels, pixels, mWidth * mHeight * mDepth);
}
setDirty(0, 0, mWidth, mHeight);
}
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginCEF::onCustomSchemeURLCallback(std::string url)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
message.setValue("uri", url);
message.setValue("nav_type", "clicked"); // TODO: differentiate between click and navigate to
sendMessage(message);
}
////////////////////////////////////////////////////////////////////////////////
//
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);
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", mLLCEFLib->canGoBack());
message.setValueBoolean("history_forward_available", mLLCEFLib->canGoForward());
sendMessage(message);
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginCEF::onLoadEndCallback(int httpStatusCode)
{
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", mLLCEFLib->canGoBack());
message.setValueBoolean("history_forward_available", mLLCEFLib->canGoForward());
sendMessage(message);
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginCEF::onNavigateURLCallback(std::string url)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed");
message.setValue("uri", url);
sendMessage(message);
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginCEF::receiveMessage(const char* message_string)
{
// std::cerr << "MediaPluginWebKit::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.0.0";
message.setValue("plugin_version", plugin_version);
sendMessage(message);
}
else if (message_name == "idle")
{
mLLCEFLib->update();
}
else if (message_name == "cleanup")
{
}
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
{
//std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl;
}
LLPluginMessage message("base", "shm_remove_response");
message.setValue("name", name);
sendMessage(message);
}
else
{
//std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl;
}
}
else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
{
if (message_name == "init")
{
// event callbacks from LLCefLib
mLLCEFLib->setPageChangedCallback(boost::bind(&MediaPluginCEF::pageChangedCallback, this, _1, _2, _3));
mLLCEFLib->setOnCustomSchemeURLCallback(boost::bind(&MediaPluginCEF::onCustomSchemeURLCallback, this, _1));
mLLCEFLib->setOnConsoleMessageCallback(boost::bind(&MediaPluginCEF::onConsoleMessageCallback, this, _1, _2, _3));
mLLCEFLib->setOnStatusMessageCallback(boost::bind(&MediaPluginCEF::onStatusMessageCallback, this, _1));
mLLCEFLib->setOnTitleChangeCallback(boost::bind(&MediaPluginCEF::onTitleChangeCallback, this, _1));
mLLCEFLib->setOnLoadStartCallback(boost::bind(&MediaPluginCEF::onLoadStartCallback, this));
mLLCEFLib->setOnLoadEndCallback(boost::bind(&MediaPluginCEF::onLoadEndCallback, this, _1));
mLLCEFLib->setOnNavigateURLCallback(boost::bind(&MediaPluginCEF::onNavigateURLCallback, this, _1));
LLCEFLibSettings settings;
settings.inital_width = 1024;
settings.inital_height = 1024;
settings.javascript_enabled = true;
settings.cookies_enabled = true;
bool result = mLLCEFLib->init(settings);
if (!result)
{
// TODO - return something to indicate failure
//MessageBoxA(0, "FAIL INIT", 0, 0);
}
// 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", false);
sendMessage(message);
}
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;
};
};
mLLCEFLib->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 == "load_uri")
{
std::string uri = message_in.getValue("uri");
mLLCEFLib->navigate(uri);
}
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");
//std::string modifiers = message_in.getValue("modifiers");
S32 button = message_in.getValueS32("button");
EMouseButton btn = MB_MOUSE_BUTTON_LEFT;
if (button == 0) btn = MB_MOUSE_BUTTON_LEFT;
if (button == 1) btn = MB_MOUSE_BUTTON_RIGHT;
if (button == 2) btn = MB_MOUSE_BUTTON_MIDDLE;
if (event == "down")
{
mLLCEFLib->mouseButton(btn, ME_MOUSE_DOWN, x, y);
mLLCEFLib->setFocus(true);
std::stringstream str;
str << "Mouse down at = " << x << ", " << y;
postDebugMessage(str.str());
}
else if (event == "up")
{
mLLCEFLib->mouseButton(btn, ME_MOUSE_UP, x, y);
std::stringstream str;
str << "Mouse up at = " << x << ", " << y;
postDebugMessage(str.str());
}
else if (event == "double_click")
{
// TODO: do we need this ?
}
else
{
mLLCEFLib->mouseMove(x, y);
}
}
else if (message_name == "scroll_event")
{
S32 y = message_in.getValueS32("y");
const int scaling_factor = 40;
y *= -scaling_factor;
mLLCEFLib->mouseWheel(y);
}
else if (message_name == "text_event")
{
std::string text = message_in.getValue("text");
std::string modifiers = message_in.getValue("modifiers");
LLSD native_key_data = message_in.getValueLLSD("native_key_data");
unicodeInput(text, decodeModifiers(modifiers), native_key_data);
}
else if (message_name == "key_event")
{
#if LL_DARWIN
std::string event = message_in.getValue("event");
S32 key = message_in.getValueS32("key");
if (event == "down")
{
mLLCEFLib->keyPress(key, true);
}
else if (event == "up")
{
mLLCEFLib->keyPress(key, false);
}
#elif LL_WINDOWS
std::string event = message_in.getValue("event");
S32 key = message_in.getValueS32("key");
std::string modifiers = message_in.getValue("modifiers");
LLSD native_key_data = message_in.getValueLLSD("native_key_data");
// Treat unknown events as key-up for safety.
EKeyEvent key_event = KE_KEY_UP;
if (event == "down")
{
key_event = KE_KEY_DOWN;
}
else if (event == "repeat")
{
key_event = KE_KEY_REPEAT;
}
keyEvent(key_event, key, decodeModifiers(modifiers), native_key_data);
#endif
}
else if (message_name == "enable_media_plugin_debugging")
{
mEnableMediaPluginDebugging = message_in.getValueBoolean("enable");
}
}
else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
{
if (message_name == "set_page_zoom_factor")
{
F32 factor = (F32)message_in.getValueReal("factor");
mLLCEFLib->setPageZoom(factor);
}
if (message_name == "browse_stop")
{
mLLCEFLib->stop();
}
else if (message_name == "browse_reload")
{
bool ignore_cache = true;
mLLCEFLib->reload(ignore_cache);
}
else if (message_name == "browse_forward")
{
mLLCEFLib->goForward();
}
else if (message_name == "browse_back")
{
mLLCEFLib->goBack();
}
}
else
{
//std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl;
};
}
}
EKeyboardModifier MediaPluginCEF::decodeModifiers(std::string &modifiers)
{
int result = 0;
if (modifiers.find("shift") != std::string::npos)
result |= KM_MODIFIER_SHIFT;
if (modifiers.find("alt") != std::string::npos)
result |= KM_MODIFIER_ALT;
if (modifiers.find("control") != std::string::npos)
result |= KM_MODIFIER_CONTROL;
if (modifiers.find("meta") != std::string::npos)
result |= KM_MODIFIER_META;
return (EKeyboardModifier)result;
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginCEF::deserializeKeyboardData(LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers)
{
native_scan_code = 0;
native_virtual_key = 0;
native_modifiers = 0;
if (native_key_data.isMap())
{
#if LL_DARWIN
native_scan_code = (uint32_t)(native_key_data["char_code"].asInteger());
native_virtual_key = (uint32_t)(native_key_data["key_code"].asInteger());
native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger());
#elif LL_WINDOWS
native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger());
native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());
// TODO: I don't think we need to do anything with native modifiers here -- please verify
#endif
};
};
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginCEF::keyEvent(EKeyEvent key_event, int key, EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
{
#if LL_DARWIN
std::string utf8_text;
if (key < 128)
{
utf8_text = (char)key;
}
switch ((KEY)key)
{
case KEY_BACKSPACE: utf8_text = (char)8; break;
case KEY_TAB: utf8_text = (char)9; break;
case KEY_RETURN: utf8_text = (char)13; break;
case KEY_PAD_RETURN: utf8_text = (char)13; break;
case KEY_ESCAPE: utf8_text = (char)27; break;
default:
break;
}
uint32_t native_scan_code = 0;
uint32_t native_virtual_key = 0;
uint32_t native_modifiers = 0;
deserializeKeyboardData(native_key_data, native_scan_code, native_virtual_key, native_modifiers);
mLLCEFLib->keyboardEvent(key_event, (uint32_t)key, utf8_text.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
#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"]);
mLLCEFLib->nativeKeyboardEvent(msg, wparam, lparam);
#endif
};
void MediaPluginCEF::unicodeInput(const std::string &utf8str, EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
{
#if LL_DARWIN
mLLCEFLib->keyPress(utf8str[0], true);
#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"]);
mLLCEFLib->nativeKeyboardEvent(msg, wparam, lparam);
#endif
};
////////////////////////////////////////////////////////////////////////////////
//
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 "llgl.h"
#include "llsdutil.h"
#include "llplugininstance.h"
#include "llpluginmessage.h"
#include "llpluginmessageclasses.h"
#include "media_plugin_base.h"
#include "boost/function.hpp"
#include "boost/bind.hpp"
#include "llCEFLib.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 pageChangedCallback(unsigned char* pixels, int width, int height);
void onCustomSchemeURLCallback(std::string url);
void onConsoleMessageCallback(std::string message, std::string source, int line);
void onStatusMessageCallback(std::string value);
void onTitleChangeCallback(std::string title);
void onLoadStartCallback();
void onLoadEndCallback(int httpStatusCode);
void onNavigateURLCallback(std::string url);
void postDebugMessage(const std::string& msg);
EKeyboardModifier decodeModifiers(std::string &modifiers);
void deserializeKeyboardData(LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers);
void keyEvent(EKeyEvent key_event, int key, EKeyboardModifier modifiers, LLSD native_key_data);
void unicodeInput(const std::string &utf8str, EKeyboardModifier modifiers, LLSD native_key_data);
bool mEnableMediaPluginDebugging;
std::string mHostLanguage;
LLCEFLib* mLLCEFLib;
};
////////////////////////////////////////////////////////////////////////////////
//
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";
mLLCEFLib = new LLCEFLib();
}
////////////////////////////////////////////////////////////////////////////////
//
MediaPluginCEF::~MediaPluginCEF()
{
mLLCEFLib->reset();
}
////////////////////////////////////////////////////////////////////////////////
//
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::pageChangedCallback(unsigned char* pixels, int width, int height)
{
if (mPixels && pixels)
{
if (mWidth == width && mHeight == height)
{
memcpy(mPixels, pixels, mWidth * mHeight * mDepth);
}
setDirty(0, 0, mWidth, mHeight);
}
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginCEF::onCustomSchemeURLCallback(std::string url)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
message.setValue("uri", url);
message.setValue("nav_type", "clicked"); // TODO: differentiate between click and navigate to
sendMessage(message);
}
////////////////////////////////////////////////////////////////////////////////
//
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);
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", mLLCEFLib->canGoBack());
message.setValueBoolean("history_forward_available", mLLCEFLib->canGoForward());
sendMessage(message);
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginCEF::onLoadEndCallback(int httpStatusCode)
{
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", mLLCEFLib->canGoBack());
message.setValueBoolean("history_forward_available", mLLCEFLib->canGoForward());
sendMessage(message);
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginCEF::onNavigateURLCallback(std::string url)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed");
message.setValue("uri", url);
sendMessage(message);
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginCEF::receiveMessage(const char* message_string)
{
// std::cerr << "MediaPluginWebKit::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.0.0";
message.setValue("plugin_version", plugin_version);
sendMessage(message);
}
else if (message_name == "idle")
{
mLLCEFLib->update();
}
else if (message_name == "cleanup")
{
}
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
{
//std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl;
}
LLPluginMessage message("base", "shm_remove_response");
message.setValue("name", name);
sendMessage(message);
}
else
{
//std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl;
}
}
else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
{
if (message_name == "init")
{
// event callbacks from LLCefLib
mLLCEFLib->setPageChangedCallback(boost::bind(&MediaPluginCEF::pageChangedCallback, this, _1, _2, _3));
mLLCEFLib->setOnCustomSchemeURLCallback(boost::bind(&MediaPluginCEF::onCustomSchemeURLCallback, this, _1));
mLLCEFLib->setOnConsoleMessageCallback(boost::bind(&MediaPluginCEF::onConsoleMessageCallback, this, _1, _2, _3));
mLLCEFLib->setOnStatusMessageCallback(boost::bind(&MediaPluginCEF::onStatusMessageCallback, this, _1));
mLLCEFLib->setOnTitleChangeCallback(boost::bind(&MediaPluginCEF::onTitleChangeCallback, this, _1));
mLLCEFLib->setOnLoadStartCallback(boost::bind(&MediaPluginCEF::onLoadStartCallback, this));
mLLCEFLib->setOnLoadEndCallback(boost::bind(&MediaPluginCEF::onLoadEndCallback, this, _1));
mLLCEFLib->setOnNavigateURLCallback(boost::bind(&MediaPluginCEF::onNavigateURLCallback, this, _1));
LLCEFLibSettings settings;
settings.inital_width = 1024;
settings.inital_height = 1024;
settings.javascript_enabled = true;
settings.cookies_enabled = true;
settings.accept_language_list = mHostLanguage;
bool result = mLLCEFLib->init(settings);
if (!result)
{
// TODO - return something to indicate failure
//MessageBoxA(0, "FAIL INIT", 0, 0);
}
// 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", false);
sendMessage(message);
}
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;
};
};
mLLCEFLib->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");
mLLCEFLib->navigate(uri);
}
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");
//std::string modifiers = message_in.getValue("modifiers");
S32 button = message_in.getValueS32("button");
EMouseButton btn = MB_MOUSE_BUTTON_LEFT;
if (button == 0) btn = MB_MOUSE_BUTTON_LEFT;
if (button == 1) btn = MB_MOUSE_BUTTON_RIGHT;
if (button == 2) btn = MB_MOUSE_BUTTON_MIDDLE;
if (event == "down")
{
mLLCEFLib->mouseButton(btn, ME_MOUSE_DOWN, x, y);
mLLCEFLib->setFocus(true);
std::stringstream str;
str << "Mouse down at = " << x << ", " << y;
postDebugMessage(str.str());
}
else if (event == "up")
{
mLLCEFLib->mouseButton(btn, ME_MOUSE_UP, x, y);
std::stringstream str;
str << "Mouse up at = " << x << ", " << y;
postDebugMessage(str.str());
}
else if (event == "double_click")
{
// TODO: do we need this ?
}
else
{
mLLCEFLib->mouseMove(x, y);
}
}
else if (message_name == "scroll_event")
{
S32 y = message_in.getValueS32("y");
const int scaling_factor = 40;
y *= -scaling_factor;
mLLCEFLib->mouseWheel(y);
}
else if (message_name == "text_event")
{
std::string text = message_in.getValue("text");
std::string modifiers = message_in.getValue("modifiers");
LLSD native_key_data = message_in.getValueLLSD("native_key_data");
unicodeInput(text, decodeModifiers(modifiers), native_key_data);
}
else if (message_name == "key_event")
{
#if LL_DARWIN
std::string event = message_in.getValue("event");
S32 key = message_in.getValueS32("key");
if (event == "down")
{
mLLCEFLib->keyPress(key, true);
}
else if (event == "up")
{
mLLCEFLib->keyPress(key, false);
}
#elif LL_WINDOWS
std::string event = message_in.getValue("event");
S32 key = message_in.getValueS32("key");
std::string modifiers = message_in.getValue("modifiers");
LLSD native_key_data = message_in.getValueLLSD("native_key_data");
// Treat unknown events as key-up for safety.
EKeyEvent key_event = KE_KEY_UP;
if (event == "down")
{
key_event = KE_KEY_DOWN;
}
else if (event == "repeat")
{
key_event = KE_KEY_REPEAT;
}
keyEvent(key_event, key, decodeModifiers(modifiers), native_key_data);
#endif
}
else if (message_name == "enable_media_plugin_debugging")
{
mEnableMediaPluginDebugging = message_in.getValueBoolean("enable");
}
}
else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
{
if (message_name == "set_page_zoom_factor")
{
F32 factor = (F32)message_in.getValueReal("factor");
mLLCEFLib->setPageZoom(factor);
}
if (message_name == "browse_stop")
{
mLLCEFLib->stop();
}
else if (message_name == "browse_reload")
{
bool ignore_cache = true;
mLLCEFLib->reload(ignore_cache);
}
else if (message_name == "browse_forward")
{
mLLCEFLib->goForward();
}
else if (message_name == "browse_back")
{
mLLCEFLib->goBack();
}
}
else
{
//std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl;
};
}
}
EKeyboardModifier MediaPluginCEF::decodeModifiers(std::string &modifiers)
{
int result = 0;
if (modifiers.find("shift") != std::string::npos)
result |= KM_MODIFIER_SHIFT;
if (modifiers.find("alt") != std::string::npos)
result |= KM_MODIFIER_ALT;
if (modifiers.find("control") != std::string::npos)
result |= KM_MODIFIER_CONTROL;
if (modifiers.find("meta") != std::string::npos)
result |= KM_MODIFIER_META;
return (EKeyboardModifier)result;
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginCEF::deserializeKeyboardData(LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers)
{
native_scan_code = 0;
native_virtual_key = 0;
native_modifiers = 0;
if (native_key_data.isMap())
{
#if LL_DARWIN
native_scan_code = (uint32_t)(native_key_data["char_code"].asInteger());
native_virtual_key = (uint32_t)(native_key_data["key_code"].asInteger());
native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger());
#elif LL_WINDOWS
native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger());
native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());
// TODO: I don't think we need to do anything with native modifiers here -- please verify
#endif
};
};
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginCEF::keyEvent(EKeyEvent key_event, int key, EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
{
#if LL_DARWIN
std::string utf8_text;
if (key < 128)
{
utf8_text = (char)key;
}
switch ((KEY)key)
{
case KEY_BACKSPACE: utf8_text = (char)8; break;
case KEY_TAB: utf8_text = (char)9; break;
case KEY_RETURN: utf8_text = (char)13; break;
case KEY_PAD_RETURN: utf8_text = (char)13; break;
case KEY_ESCAPE: utf8_text = (char)27; break;
default:
break;
}
uint32_t native_scan_code = 0;
uint32_t native_virtual_key = 0;
uint32_t native_modifiers = 0;
deserializeKeyboardData(native_key_data, native_scan_code, native_virtual_key, native_modifiers);
mLLCEFLib->keyboardEvent(key_event, (uint32_t)key, utf8_text.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
#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"]);
mLLCEFLib->nativeKeyboardEvent(msg, wparam, lparam);
#endif
};
void MediaPluginCEF::unicodeInput(const std::string &utf8str, EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
{
#if LL_DARWIN
mLLCEFLib->keyPress(utf8str[0], true);
#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"]);
mLLCEFLib->nativeKeyboardEvent(msg, wparam, lparam);
#endif
};
////////////////////////////////////////////////////////////////////////////////
//
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;
}
......@@ -452,7 +452,8 @@ def construct(self):
self.path("libEGL.dll")
self.path("libGLESv2.dll")
self.path("llceflib_host.exe")
self.path("pdf.dll")
self.path("natives_blob.bin")
self.path("snapshot_blob.bin")
self.path("wow_helper.exe")
self.end_prefix()
else:
......@@ -465,7 +466,8 @@ def construct(self):
self.path("libEGL.dll")
self.path("libGLESv2.dll")
self.path("llceflib_host.exe")
self.path("pdf.dll")
self.path("natives_blob.bin")
self.path("snapshot_blob.bin")
self.path("wow_helper.exe")
self.end_prefix()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment