Merge with CEF tip.

master
Nicky 2015-11-24 15:28:05 +01:00
commit 3f1a78cee9
24 changed files with 440 additions and 256 deletions

View File

@ -1698,11 +1698,11 @@
<key>archive</key>
<map>
<key>hash</key>
<string>f222975b084f8ef74b91fcca0c3ef922</string>
<string>bcc015c5943397b612da1cdc29df4340</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llceflib_3p-llceflib/rev/307407/arch/Darwin/installer/llceflib-1.3.1.307407-darwin-307407.tar.bz2</string>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llceflib_3p-llceflib/rev/308183/arch/Darwin/installer/llceflib-1.4.0.308183-darwin-308183.tar.bz2</string>
</map>
<key>name</key>
<string>darwin</string>
@ -1737,7 +1737,7 @@
</map>
</map>
<key>version</key>
<string>1.3.1.307407</string>
<string>1.4.0.308183</string>
</map>
<key>llphysicsextensions_source</key>
<map>

View File

@ -249,6 +249,10 @@ if (LINUX)
add_definitions(-std=gnu++11)
# </FS:ND>
# force this platform to accept TOS via external browser <FS:ND> No, do not.
# add_definitions(-DEXTERNAL_TOS)
add_definitions(-DAPPID=secondlife)
add_definitions(-fvisibility=hidden)
# don't catch SIGCHLD in our base application class for the viewer - some of our 3rd party libs may need their *own* SIGCHLD handler to work. Sigh! The viewer doesn't need to catch SIGCHLD anyway.

View File

@ -48,7 +48,6 @@ static int nextPowerOf2( int value )
LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner)
{
mOwner = owner;
mPlugin = NULL;
reset();
//debug use
@ -68,7 +67,7 @@ bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::s
LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL;
LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL;
mPlugin = new LLPluginProcessParent(this);
mPlugin = LLPluginProcessParent::create(this);
mPlugin->setSleepTime(mSleepTime);
// Queue up the media init message -- it will be sent after all the currently queued messages.
@ -84,10 +83,10 @@ bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::s
void LLPluginClassMedia::reset()
{
if(mPlugin != NULL)
if(mPlugin)
{
delete mPlugin;
mPlugin = NULL;
mPlugin->requestShutdown();
mPlugin.reset();
}
mTextureParamsReceived = false;
@ -674,7 +673,7 @@ bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD
return true;
}
void LLPluginClassMedia::setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path)
void LLPluginClassMedia::setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path, bool httponly, bool secure)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_cookie");
@ -683,6 +682,8 @@ void LLPluginClassMedia::setCookie(std::string uri, std::string name, std::strin
message.setValue("value", value);
message.setValue("domain", domain);
message.setValue("path", path);
message.setValueBoolean("httponly", httponly);
message.setValueBoolean("secure", secure);
sendMessage(message);
}

View File

@ -133,7 +133,7 @@ public:
// Text may be unicode (utf8 encoded)
bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data);
void setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path);
void setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path, bool httponly, bool secure);
void loadURI(const std::string &uri);
@ -374,7 +374,7 @@ protected:
int mPadding;
LLPluginProcessParent *mPlugin;
LLPluginProcessParent::ptr_t mPlugin;
LLRect mDirtyRect;

View File

@ -33,6 +33,7 @@
#include "llpluginmessagepipe.h"
#include "llpluginmessageclasses.h"
static const F32 GOODBYE_SECONDS = 20.0f;
static const F32 HEARTBEAT_SECONDS = 1.0f;
static const F32 PLUGIN_IDLE_SECONDS = 1.0f / 100.0f; // Each call to idle will give the plugin this much time.
@ -194,33 +195,43 @@ void LLPluginProcessChild::idle(void)
}
}
// receivePluginMessage will transition to STATE_UNLOADING
break;
break;
case STATE_SHUTDOWNREQ:
if (mInstance != NULL)
{
sendMessageToPlugin(LLPluginMessage("base", "cleanup"));
delete mInstance;
mInstance = NULL;
}
setState(STATE_UNLOADING);
mWaitGoodbye.setTimerExpirySec(GOODBYE_SECONDS);
break;
case STATE_UNLOADING:
if(mInstance != NULL)
{
sendMessageToPlugin(LLPluginMessage("base", "cleanup"));
delete mInstance;
mInstance = NULL;
}
setState(STATE_UNLOADED);
break;
// waiting for goodbye from plugin.
if (mWaitGoodbye.hasExpired())
{
LL_WARNS() << "Wait for goodbye expired. Advancing to UNLOADED" << LL_ENDL;
setState(STATE_UNLOADED);
}
break;
case STATE_UNLOADED:
killSockets();
setState(STATE_DONE);
break;
break;
case STATE_ERROR:
// Close the socket to the launcher
killSockets();
// TODO: Where do we go from here? Just exit()?
setState(STATE_DONE);
break;
break;
case STATE_DONE:
// just sit here.
break;
break;
}
} while (idle_again);
@ -350,6 +361,10 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)
mPluginFile = parsed.getValue("file");
mPluginDir = parsed.getValue("dir");
}
else if (message_name == "shutdown_plugin")
{
setState(STATE_SHUTDOWNREQ);
}
else if(message_name == "shm_add")
{
std::string name = parsed.getValue("name");
@ -495,6 +510,10 @@ void LLPluginProcessChild::receivePluginMessage(const std::string &message)
// Let the parent know it's loaded and initialized.
sendMessageToParent(new_message);
}
else if (message_name == "goodbye")
{
setState(STATE_UNLOADED);
}
else if(message_name == "shm_remove_response")
{
// Don't pass this message up to the parent

View File

@ -80,6 +80,7 @@ private:
STATE_PLUGIN_LOADED, // plugin library has been loaded
STATE_PLUGIN_INITIALIZING, // plugin is processing init message
STATE_RUNNING, // steady state (processing messages)
STATE_SHUTDOWNREQ, // Parent has requested a shutdown.
STATE_UNLOADING, // plugin has sent shutdown_response and needs to be unloaded
STATE_UNLOADED, // plugin has been unloaded
STATE_ERROR, // generic bailout state
@ -101,12 +102,12 @@ private:
sharedMemoryRegionsType mSharedMemoryRegions;
LLTimer mHeartbeat;
F64 mSleepTime;
F64 mCPUElapsed;
F64 mSleepTime;
F64 mCPUElapsed;
bool mBlockingRequest;
bool mBlockingResponseReceived;
std::queue<std::string> mMessageQueue;
LLTimer mWaitGoodbye;
void deliverQueuedMessages();
};

View File

@ -48,7 +48,7 @@ bool LLPluginProcessParent::sUseReadThread = false;
apr_pollset_t *LLPluginProcessParent::sPollSet = NULL;
bool LLPluginProcessParent::sPollsetNeedsRebuild = false;
LLMutex *LLPluginProcessParent::sInstancesMutex;
std::list<LLPluginProcessParent*> LLPluginProcessParent::sInstances;
LLPluginProcessParent::mapInstances_t LLPluginProcessParent::sInstances;
LLThread *LLPluginProcessParent::sReadThread = NULL;
@ -106,27 +106,12 @@ LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner):
// Don't start the timer here -- start it when we actually launch the plugin process.
mHeartbeat.stop();
// Don't add to the global list until fully constructed.
{
LLMutexLock lock(sInstancesMutex);
sInstances.push_back(this);
}
}
LLPluginProcessParent::~LLPluginProcessParent()
{
LL_DEBUGS("Plugin") << "destructor" << LL_ENDL;
// Remove from the global list before beginning destruction.
{
// Make sure to get the global mutex _first_ here, to avoid a possible deadlock against LLPluginProcessParent::poll()
LLMutexLock lock(sInstancesMutex);
{
LLMutexLock lock2(&mIncomingQueueMutex);
sInstances.remove(this);
}
}
// Destroy any remaining shared memory regions
sharedMemoryRegionsType::iterator iter;
while((iter = mSharedMemoryRegions.begin()) != mSharedMemoryRegions.end())
@ -141,9 +126,109 @@ LLPluginProcessParent::~LLPluginProcessParent()
}
LLProcess::kill(mProcess);
killSockets();
if (!LLApp::isQuitting())
{ // If we are quitting, the network sockets will already have been destroyed.
killSockets();
}
}
/*static*/
LLPluginProcessParent::ptr_t LLPluginProcessParent::create(LLPluginProcessParentOwner *owner)
{
ptr_t that(new LLPluginProcessParent(owner));
// Don't add to the global list until fully constructed.
{
LLMutexLock lock(sInstancesMutex);
sInstances.insert(mapInstances_t::value_type(that.get(), that));
}
return that;
}
/*static*/
void LLPluginProcessParent::shutdown()
{
LLMutexLock lock(sInstancesMutex);
mapInstances_t::iterator it;
for (it = sInstances.begin(); it != sInstances.end(); ++it)
{
(*it).second->setState(STATE_GOODBYE);
(*it).second->idle();
}
sInstances.clear();
}
void LLPluginProcessParent::requestShutdown()
{
setState(STATE_GOODBYE);
mOwner = NULL;
if (LLApp::isQuitting())
{ // if we're quitting, run the idle once more
idle();
removeFromProcessing();
return;
}
static uint32_t count = 0;
std::stringstream namestream;
namestream << "LLPluginProcessParentListener" << ++count;
//*HACK!*//
// After requestShutdown has been called our previous owner will no longer call
// our idle() method. Tie into the event loop here to do that until we are good
// and finished.
LL_DEBUGS("LLPluginProcessParent") << "listening on \"mainloop\"" << LL_ENDL;
mPolling = LLEventPumps::instance().obtain("mainloop")
.listen(namestream.str(), boost::bind(&LLPluginProcessParent::pollTick, this));
}
bool LLPluginProcessParent::pollTick()
{
if (isDone())
{
ptr_t that;
{
// this grabs a copy of the smart pointer to ourselves to ensure that we do not
// get destroyed until after this method returns.
LLMutexLock lock(sInstancesMutex);
mapInstances_t::iterator it = sInstances.find(this);
if (it != sInstances.end())
that = (*it).second;
}
removeFromProcessing();
return true;
}
idle();
return false;
}
void LLPluginProcessParent::removeFromProcessing()
{
// Remove from the global list before beginning destruction.
{
// Make sure to get the global mutex _first_ here, to avoid a possible deadlock against LLPluginProcessParent::poll()
LLMutexLock lock(sInstancesMutex);
{
LLMutexLock lock2(&mIncomingQueueMutex);
sInstances.erase(this);
}
}
}
bool LLPluginProcessParent::wantsPolling() const
{
return (mPollFD.client_data && (mState != STATE_DONE));
}
void LLPluginProcessParent::killSockets(void)
{
{
@ -390,48 +475,48 @@ void LLPluginProcessParent::idle(void)
break;
case STATE_LISTENING:
{
// Launch the plugin process.
{
// Launch the plugin process.
// Only argument to the launcher is the port number we're listening on
mProcessParams.args.add(stringize(mBoundPort));
if (! (mProcess = LLProcess::create(mProcessParams)))
{
errorState();
}
else
{
if(mDebug)
{
#if LL_DARWIN
// If we're set to debug, start up a gdb instance in a new terminal window and have it attach to the plugin process and continue.
// Only argument to the launcher is the port number we're listening on
mProcessParams.args.add(stringize(mBoundPort));
if (! (mProcess = LLProcess::create(mProcessParams)))
{
errorState();
}
else
{
if(mDebug)
{
#if LL_DARWIN
// If we're set to debug, start up a gdb instance in a new terminal window and have it attach to the plugin process and continue.
// The command we're constructing would look like this on the command line:
// osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell'
// The command we're constructing would look like this on the command line:
// osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell'
LLProcess::Params params;
params.executable = "/usr/bin/osascript";
params.args.add("-e");
params.args.add("tell application \"Terminal\"");
params.args.add("-e");
params.args.add(STRINGIZE("set win to do script \"gdb -pid "
<< mProcess->getProcessID() << "\""));
params.args.add("-e");
params.args.add("do script \"continue\" in win");
params.args.add("-e");
params.args.add("end tell");
mDebugger = LLProcess::create(params);
LLProcess::Params params;
params.executable = "/usr/bin/osascript";
params.args.add("-e");
params.args.add("tell application \"Terminal\"");
params.args.add("-e");
params.args.add(STRINGIZE("set win to do script \"gdb -pid "
<< mProcess->getProcessID() << "\""));
params.args.add("-e");
params.args.add("do script \"continue\" in win");
params.args.add("-e");
params.args.add("end tell");
mDebugger = LLProcess::create(params);
#endif
}
#endif
}
// This will allow us to time out if the process never starts.
mHeartbeat.start();
mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout);
setState(STATE_LAUNCHED);
}
}
break;
// This will allow us to time out if the process never starts.
mHeartbeat.start();
mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout);
setState(STATE_LAUNCHED);
}
}
break;
case STATE_LAUNCHED:
// waiting for the plugin to connect
@ -449,7 +534,7 @@ void LLPluginProcessParent::idle(void)
setState(STATE_CONNECTED);
}
}
break;
break;
case STATE_CONNECTED:
// waiting for hello message from the plugin
@ -458,7 +543,7 @@ void LLPluginProcessParent::idle(void)
{
errorState();
}
break;
break;
case STATE_HELLO:
LL_DEBUGS("Plugin") << "received hello message" << LL_ENDL;
@ -472,7 +557,7 @@ void LLPluginProcessParent::idle(void)
}
setState(STATE_LOADING);
break;
break;
case STATE_LOADING:
// The load_plugin_response message will kick us from here into STATE_RUNNING
@ -480,15 +565,23 @@ void LLPluginProcessParent::idle(void)
{
errorState();
}
break;
break;
case STATE_RUNNING:
if(pluginLockedUpOrQuit())
{
errorState();
}
break;
break;
case STATE_GOODBYE:
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shutdown_plugin");
sendMessage(message);
}
setState(STATE_EXITING);
break;
case STATE_EXITING:
if (! LLProcess::isRunning(mProcess))
{
@ -499,7 +592,7 @@ void LLPluginProcessParent::idle(void)
LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << LL_ENDL;
errorState();
}
break;
break;
case STATE_LAUNCH_FAILURE:
if(mOwner != NULL)
@ -507,7 +600,7 @@ void LLPluginProcessParent::idle(void)
mOwner->pluginLaunchFailed();
}
setState(STATE_CLEANUP);
break;
break;
case STATE_ERROR:
if(mOwner != NULL)
@ -515,19 +608,18 @@ void LLPluginProcessParent::idle(void)
mOwner->pluginDied();
}
setState(STATE_CLEANUP);
break;
break;
case STATE_CLEANUP:
LLProcess::kill(mProcess);
killSockets();
setState(STATE_DONE);
break;
dirtyPollSet();
break;
case STATE_DONE:
// just sit here.
break;
break;
}
} while (idle_again);
@ -670,14 +762,14 @@ void LLPluginProcessParent::updatePollset()
sPollSet = NULL;
}
std::list<LLPluginProcessParent*>::iterator iter;
mapInstances_t::iterator iter;
int count = 0;
// Count the number of instances that want to be in the pollset
for(iter = sInstances.begin(); iter != sInstances.end(); iter++)
{
(*iter)->mPolledInput = false;
if((*iter)->mPollFD.client_data)
(*iter).second->mPolledInput = false;
if ((*iter).second->wantsPolling())
{
// This instance has a socket that needs to be polled.
++count;
@ -705,12 +797,12 @@ void LLPluginProcessParent::updatePollset()
// Pollset was created, add all instances to it.
for(iter = sInstances.begin(); iter != sInstances.end(); iter++)
{
if((*iter)->mPollFD.client_data)
if ((*iter).second->wantsPolling())
{
status = apr_pollset_add(sPollSet, &((*iter)->mPollFD));
status = apr_pollset_add(sPollSet, &((*iter).second->mPollFD));
if(status == APR_SUCCESS)
{
(*iter)->mPolledInput = true;
(*iter).second->mPolledInput = true;
}
else
{
@ -775,45 +867,27 @@ void LLPluginProcessParent::poll(F64 timeout)
if(status == APR_SUCCESS)
{
// One or more of the descriptors signalled. Call them.
for(int i = 0; i < count; i++)
{
LLPluginProcessParent *self = (LLPluginProcessParent *)(descriptors[i].client_data);
// NOTE: the descriptor returned here is actually a COPY of the original (even though we create the pollset with APR_POLLSET_NOCOPY).
// This means that even if the parent has set its mPollFD.client_data to NULL, the old pointer may still there in this descriptor.
// It's even possible that the old pointer no longer points to a valid LLPluginProcessParent.
// This means that we can't safely dereference the 'self' pointer here without some extra steps...
if(self)
{
// Make sure this pointer is still in the instances list
bool valid = false;
{
LLMutexLock lock(sInstancesMutex);
for(std::list<LLPluginProcessParent*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
{
if(*iter == self)
{
// Lock the instance's mutex before unlocking the global mutex.
// This avoids a possible race condition where the instance gets deleted between this check and the servicePoll() call.
self->mIncomingQueueMutex.lock();
valid = true;
break;
}
}
}
if(valid)
{
// The instance is still valid.
// Pull incoming messages off the socket
self->servicePoll();
self->mIncomingQueueMutex.unlock();
}
else
{
LL_DEBUGS("PluginPoll") << "detected deleted instance " << self << LL_ENDL;
}
for (int i = 0; i < count; i++)
{
void *thatId = descriptors[i].client_data;
ptr_t that;
mapInstances_t::iterator it;
{
LLMutexLock lock(sInstancesMutex);
it = sInstances.find(thatId);
if (it != sInstances.end())
that = (*it).second;
}
if (that)
{
that->mIncomingQueueMutex.lock();
that->servicePoll();
that->mIncomingQueueMutex.unlock();
}
}
}
}
else if(APR_STATUS_IS_TIMEUP(status))
@ -831,6 +905,16 @@ void LLPluginProcessParent::poll(F64 timeout)
LL_WARNS("PluginPoll") << "apr_pollset_poll failed with status " << status << LL_ENDL;
}
}
// Remove instances in the done state from the sInstances map.
mapInstances_t::iterator itClean = sInstances.begin();
while (itClean != sInstances.end())
{
if ((*itClean).second->isDone())
sInstances.erase(itClean++);
else
++itClean;
}
}
void LLPluginProcessParent::servicePoll()

View File

@ -30,6 +30,7 @@
#define LL_LLPLUGINPROCESSPARENT_H
#include <queue>
#include <boost/enable_shared_from_this.hpp>
#include "llapr.h"
#include "llprocess.h"
@ -40,8 +41,9 @@
#include "lliosocket.h"
#include "llthread.h"
#include "llsd.h"
#include "llevents.h"
class LLPluginProcessParentOwner
class LLPluginProcessParentOwner : public boost::enable_shared_from_this < LLPluginProcessParentOwner >
{
public:
virtual ~LLPluginProcessParentOwner();
@ -55,8 +57,11 @@ public:
class LLPluginProcessParent : public LLPluginMessagePipeOwner
{
LOG_CLASS(LLPluginProcessParent);
LLPluginProcessParent(LLPluginProcessParentOwner *owner);
public:
LLPluginProcessParent(LLPluginProcessParentOwner *owner);
typedef boost::shared_ptr<LLPluginProcessParent> ptr_t;
~LLPluginProcessParent();
void init(const std::string &launcher_filename,
@ -89,7 +94,10 @@ public:
void sendMessage(const LLPluginMessage &message);
void receiveMessage(const LLPluginMessage &message);
static ptr_t create(LLPluginProcessParentOwner *owner);
void requestShutdown();
// Inherited from LLPluginMessagePipeOwner
/*virtual*/ void receiveMessageRaw(const std::string &message);
/*virtual*/ void receiveMessageEarly(const LLPluginMessage &message);
@ -121,7 +129,10 @@ public:
static bool canPollThreadRun() { return (sPollSet || sPollsetNeedsRebuild || sUseReadThread); };
static void setUseReadThread(bool use_read_thread);
static bool getUseReadThread() { return sUseReadThread; };
static void shutdown();
private:
typedef std::map<void *, ptr_t> mapInstances_t;
enum EState
{
@ -133,6 +144,7 @@ private:
STATE_HELLO, // first message from the plugin process has been received
STATE_LOADING, // process has been asked to load the plugin
STATE_RUNNING, //
STATE_GOODBYE,
STATE_LAUNCH_FAILURE, // Failure before plugin loaded
STATE_ERROR, // generic bailout state
STATE_CLEANUP, // clean everything up
@ -143,6 +155,9 @@ private:
EState mState;
void setState(EState state);
bool wantsPolling() const;
void removeFromProcessing();
bool pluginLockedUp();
bool pluginLockedUpOrQuit();
@ -185,12 +200,15 @@ private:
static apr_pollset_t *sPollSet;
static bool sPollsetNeedsRebuild;
static LLMutex *sInstancesMutex;
static std::list<LLPluginProcessParent*> sInstances;
static mapInstances_t sInstances;
static void dirtyPollSet();
static void updatePollset();
void servicePoll();
static LLThread *sReadThread;
LLTempBoundListener mPolling;
bool pollTick();
LLMutex mIncomingQueueMutex;
std::queue<LLPluginMessage> mIncomingQueue;

View File

@ -28,6 +28,11 @@
#include "llwindowmacosx-objc.h"
#import "llappdelegate-objc.h"
//---------------------------
@implementation NSScreen (PointConversion)
+ (NSScreen *)currentScreenForMouseLocation
@ -60,19 +65,16 @@
void extractKeyDataFromEvent (NSEvent *theEvent, NativeKeyEventData * eventData)
{
if ([theEvent characters].length)
{
eventData->mCharacter = (wchar_t)[[theEvent characters] characterAtIndex:0];
}
else
{
eventData->mCharacter = [theEvent keyCode];
}
eventData->mKeyEvent = NativeKeyEventData::KEYUNKNOWN;
eventData->mKeyCode = [theEvent keyCode];
eventData->mKeyModifiers = [theEvent modifierFlags];
eventData->mScanCode = [theEvent keyCode ];
eventData->mKeyboardType = 0;
eventData->mEventType = [theEvent type];
eventData->mEventModifiers = [theEvent modifierFlags];
eventData->mEventKeyCode = [theEvent keyCode];
NSString *strEventChars = [theEvent characters];
eventData->mEventChars = (strEventChars.length) ? [strEventChars characterAtIndex:0] : 0;
NSString *strEventUChars = [theEvent charactersIgnoringModifiers];
eventData->mEventUnmodChars = (strEventUChars.length) ? [strEventUChars characterAtIndex:0] : 0;
eventData->mEventRepeat = [theEvent isARepeat];
}

View File

@ -56,11 +56,12 @@ struct NativeKeyEventData {
};
EventType mKeyEvent;
uint32_t mKeyCode;
uint32_t mScanCode;
uint32_t mKeyModifiers;
uint32_t mKeyboardType;
wchar_t mCharacter;
uint32_t mEventType;
uint32_t mEventModifiers;
uint32_t mEventKeyCode;
uint32_t mEventChars;
uint32_t mEventUnmodChars;
bool mEventRepeat;
};
typedef const NativeKeyEventData * NSKeyEventRef;

View File

@ -1779,38 +1779,12 @@ LLSD LLWindowMacOSX::getNativeKeyData()
#if 1
if(mRawKeyEvent)
{
result["char_code"] = (S32)(mRawKeyEvent)->mCharacter;
result["scan_code"] = (S32)(mRawKeyEvent)->mScanCode;
result["key_code"] = (S32)(mRawKeyEvent->mKeyCode);
result["modifiers"] = (S32)(mRawKeyEvent->mKeyModifiers);
result["keyboard_type"] = (S32)(mRawKeyEvent->mKeyboardType);
#if 0
// This causes trouble for control characters -- apparently character codes less than 32 (escape, control-A, etc)
// cause llsd serialization to create XML that the llsd deserializer won't parse!
std::string unicode;
S32 err = noErr;
EventParamType actualType = typeUTF8Text;
UInt32 actualSize = 0;
char *buffer = NULL;
err = GetEventParameter (mRawKeyEvent, kEventParamKeyUnicodes, typeUTF8Text, &actualType, 0, &actualSize, NULL);
if(err == noErr)
{
// allocate a buffer and get the actual data.
buffer = new char[actualSize];
err = GetEventParameter (mRawKeyEvent, kEventParamKeyUnicodes, typeUTF8Text, &actualType, actualSize, &actualSize, buffer);
if(err == noErr)
{
unicode.assign(buffer, actualSize);
}
delete[] buffer;
}
result["unicode"] = unicode;
#endif
result["event_type"] = LLSD::Integer(mRawKeyEvent->mEventType);
result["event_modifiers"] = LLSD::Integer(mRawKeyEvent->mEventModifiers);
result["event_keycode"] = LLSD::Integer(mRawKeyEvent->mEventKeyCode);
result["event_chars"] = (mRawKeyEvent->mEventChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventChars)) : LLSD();
result["event_umodchars"] = (mRawKeyEvent->mEventUnmodChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventUnmodChars)) : LLSD();
result["event_isrepeat"] = LLSD::Boolean(mRawKeyEvent->mEventRepeat);
}
#endif

View File

@ -111,7 +111,7 @@ if (WINDOWS)
set_target_properties(
media_plugin_cef
PROPERTIES
LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /NODEFAULTLIB:LIBCMT"
LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /LTCG /NODEFAULTLIB:LIBCMT"
LINK_FLAGS_DEBUG "/MANIFEST:NO /SAFESEH:NO /NODEFAULTLIB:LIBCMTD"
)
endif (WINDOWS)

View File

@ -56,12 +56,13 @@ public:
private:
bool init();
void onPageChangedCallback(unsigned char* pixels, int width, int height);
void onPageChangedCallback(unsigned char* pixels, int x, int y, int width, int height, bool is_popup);
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 onRequestExitCallback();
void onLoadEndCallback(int httpStatusCode);
void onAddressChangeCallback(std::string url);
void onNavigateURLCallback(std::string url, std::string target);
@ -136,7 +137,6 @@ MediaPluginBase(host_send_func, host_user_data)
//
MediaPluginCEF::~MediaPluginCEF()
{
mLLCEFLib->requestExit();
}
////////////////////////////////////////////////////////////////////////////////
@ -157,13 +157,31 @@ void MediaPluginCEF::postDebugMessage(const std::string& msg)
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginCEF::onPageChangedCallback(unsigned char* pixels, int width, int height)
void MediaPluginCEF::onPageChangedCallback(unsigned char* pixels, int x, int y, int width, int height, bool is_popup)
{
if (mPixels && pixels)
{
if (mWidth == width && mHeight == height)
if (is_popup)
{
memcpy(mPixels, pixels, mWidth * mHeight * mDepth);
for (int line = 0; line < height; ++line)
{
int inverted_y = mHeight - y - height;
int src = line * width * mDepth;
int dst = (inverted_y + line) * mWidth * mDepth + x * mDepth;
if (dst + width * mDepth < mWidth * mHeight * mDepth)
{
memcpy(mPixels + dst, pixels + src, width * mDepth);
}
}
}
else
{
if (mWidth == width && mHeight == height)
{
memcpy(mPixels, pixels, mWidth * mHeight * mDepth);
}
}
setDirty(0, 0, mWidth, mHeight);
}
@ -207,6 +225,16 @@ void MediaPluginCEF::onLoadStartCallback()
sendMessage(message);
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginCEF::onRequestExitCallback()
{
mLLCEFLib->shutdown();
LLPluginMessage message("base", "goodbye");
sendMessage(message);
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginCEF::onLoadEndCallback(int httpStatusCode)
@ -318,7 +346,7 @@ void MediaPluginCEF::authResponse(LLPluginMessage &message)
//
void MediaPluginCEF::receiveMessage(const char* message_string)
{
// std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
// std::cerr << "MediaPluginCEF::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
LLPluginMessage message_in;
if (message_in.parse(message_string) >= 0)
@ -336,7 +364,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
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";
std::string plugin_version = "CEF plugin 1.1.3";
message.setValue("plugin_version", plugin_version);
sendMessage(message);
}
@ -352,6 +380,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
}
else if (message_name == "cleanup")
{
mLLCEFLib->requestExit();
}
else if (message_name == "shm_added")
{
@ -379,7 +408,6 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
}
else
{
//std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl;
}
LLPluginMessage message("base", "shm_remove_response");
@ -388,7 +416,6 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
}
else
{
//std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl;
}
}
else if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
@ -402,7 +429,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
// </FS:ND>
// event callbacks from LLCefLib
mLLCEFLib->setOnPageChangedCallback(boost::bind(&MediaPluginCEF::onPageChangedCallback, this, _1, _2, _3));
mLLCEFLib->setOnPageChangedCallback(boost::bind(&MediaPluginCEF::onPageChangedCallback, this, _1, _2, _3, _4, _5, _6));
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));
@ -413,6 +440,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
mLLCEFLib->setOnNavigateURLCallback(boost::bind(&MediaPluginCEF::onNavigateURLCallback, this, _1, _2));
mLLCEFLib->setOnHTTPAuthCallback(boost::bind(&MediaPluginCEF::onHTTPAuthCallback, this, _1, _2, _3, _4));
mLLCEFLib->setOnCursorChangedCallback(boost::bind(&MediaPluginCEF::onCursorChangedCallback, this, _1, _2));
mLLCEFLib->setOnRequestExitCallback(boost::bind(&MediaPluginCEF::onRequestExitCallback, this));
LLCEFLib::LLCEFLibSettings settings;
settings.initial_width = 1024;
@ -424,7 +452,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
settings.cache_enabled = true;
settings.cache_path = mCachePath;
settings.accept_language_list = mHostLanguage;
settings.user_agent_substring = mUserAgentSubtring;
settings.user_agent_substring = mLLCEFLib->makeCompatibleUserAgentString(mUserAgentSubtring);
bool result = mLLCEFLib->init(settings);
if (!result)
@ -507,7 +535,9 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
std::string value = message_in.getValue("value");
std::string domain = message_in.getValue("domain");
std::string path = message_in.getValue("path");
mLLCEFLib->setCookie(uri, name, value, domain, path);
bool httponly = message_in.getValueBoolean("httponly");
bool secure = message_in.getValueBoolean("secure");
mLLCEFLib->setCookie(uri, name, value, domain, path, httponly, secure);
}
else if (message_name == "mouse_event")
{
@ -516,15 +546,13 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
S32 x = message_in.getValueS32("x");
S32 y = message_in.getValueS32("y");
//std::string modifiers = message_in.getValue("modifiers");
// only even send left mouse button events to LLCEFLib
// (partially prompted by crash in OS X 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");
LLCEFLib::EMouseButton btn = LLCEFLib::MB_MOUSE_BUTTON_LEFT;
if (button == 0) btn = LLCEFLib::MB_MOUSE_BUTTON_LEFT;
if (button == 1) btn = LLCEFLib::MB_MOUSE_BUTTON_RIGHT;
if (button == 2) btn = LLCEFLib::MB_MOUSE_BUTTON_MIDDLE;
if (event == "down")
if (event == "down" && button == 0)
{
mLLCEFLib->mouseButton(btn, LLCEFLib::ME_MOUSE_DOWN, x, y);
mLLCEFLib->setFocus(true);
@ -533,7 +561,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
str << "Mouse down at = " << x << ", " << y;
postDebugMessage(str.str());
}
else if (event == "up")
else if (event == "up" && button == 0)
{
mLLCEFLib->mouseButton(btn, LLCEFLib::ME_MOUSE_UP, x, y);
@ -552,7 +580,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
}
else if (message_name == "scroll_event")
{
S32 x = message_in.getValueS32("y");
S32 x = message_in.getValueS32("x");
S32 y = message_in.getValueS32("y");
const int scaling_factor = 40;
y *= -scaling_factor;
@ -597,9 +625,9 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
{
key_event = LLCEFLib::KE_KEY_REPEAT;
}
keyEvent(key_event, key, LLCEFLib::KM_MODIFIER_NONE, native_key_data);
#endif
#elif LL_WINDOWS
std::string event = message_in.getValue("event");
@ -674,6 +702,10 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
{
mUserAgentSubtring = message_in.getValue("user_agent");
}
else if (message_name == "show_web_inspector")
{
mLLCEFLib->showDevTools(true);
}
else if (message_name == "plugins_enabled")
{
mPluginsEnabled = message_in.getValueBoolean("enable");
@ -697,7 +729,6 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
}
else
{
//std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl;
};
}
}
@ -751,46 +782,32 @@ void MediaPluginCEF::deserializeKeyboardData(LLSD native_key_data, uint32_t& nat
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginCEF::keyEvent(LLCEFLib::EKeyEvent key_event, int key, LLCEFLib::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
void MediaPluginCEF::keyEvent(LLCEFLib::EKeyEvent key_event, int key, LLCEFLib::EKeyboardModifier modifiers_x, LLSD native_key_data = LLSD::emptyMap())
{
#if LL_DARWIN || LL_LINUX
std::string utf8_text;
uint32_t native_char_code = native_key_data["char_code"].asInteger();
uint32_t native_scan_code = native_key_data["scan_code"].asInteger();
uint32_t native_virtual_key = native_key_data["key_code"].asInteger();
uint32_t native_modifiers = native_key_data["modifiers"].asInteger();
if (key < 128)
{
utf8_text = (char)native_virtual_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;
}
mLLCEFLib->keyboardEvent(key_event, native_char_code,
utf8_text.c_str(), modifiers,
native_scan_code, native_virtual_key,
native_modifiers);
if (!native_key_data.has("event_type") ||
!native_key_data.has("event_modifiers") ||
!native_key_data.has("event_keycode") ||
!native_key_data.has("event_isrepeat"))
return;
uint32_t eventType = native_key_data["event_type"].asInteger();
uint32_t eventModifiers = native_key_data["event_modifiers"].asInteger();
uint32_t eventKeycode = native_key_data["event_keycode"].asInteger();
char eventChars = static_cast<char>(native_key_data["event_chars"].isUndefined() ? 0 : native_key_data["event_chars"].asInteger());
char eventUChars = static_cast<char>(native_key_data["event_umodchars"].isUndefined() ? 0 : native_key_data["event_umodchars"].asInteger());
bool eventIsRepeat = native_key_data["event_isrepeat"].asBoolean();
mLLCEFLib->keyboardEventOSX(eventType, eventModifiers, (eventChars) ? &eventChars : NULL,
(eventUChars) ? &eventUChars : NULL, eventIsRepeat, eventKeycode);
#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
};

View File

@ -837,7 +837,9 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string)
else if(message_name == "cleanup")
{
// TODO: clean up here
}
LLPluginMessage message("base", "goodbye");
sendMessage(message);
}
else if(message_name == "shm_added")
{
SharedSegmentInfo info;

View File

@ -3529,7 +3529,7 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
<integer>0</integer>
<key>Backup</key>
<integer>0</integer>
</map>
@ -10498,7 +10498,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>5.0</real>
<real>10.0</real>
</map>
<key>MediaRollOffMax</key>
<map>

View File

@ -2033,6 +2033,9 @@ bool LLAppViewer::cleanup()
// to ensure shutdown order
LLMortician::setZealous(TRUE);
// Give any remaining SLPlugin instances a chance to exit cleanly.
LLPluginProcessParent::shutdown();
LLVoiceClient::getInstance()->terminate();
disconnectViewer();

View File

@ -116,6 +116,7 @@
#include "llpluginclassmedia.h"
#include "llteleporthistorystorage.h"
#include "llproxy.h"
#include "llweb.h"
#include "lllogininstance.h" // to check if logged in yet
#include "llsdserialize.h"
@ -2930,6 +2931,16 @@ BOOL LLPanelPreference::postBuild()
//}
// </FS:Ansariel> Fix for visually broken browser choice radiobuttons
#ifdef EXTERNAL_TOS
LLRadioGroup* ext_browser_settings = getChild<LLRadioGroup>("preferred_browser_behavior");
if (ext_browser_settings)
{
// turn off ability to set external/internal browser
ext_browser_settings->setSelectedByValue(LLWeb::BROWSER_EXTERNAL_ONLY, true);
ext_browser_settings->setEnabled(false);
}
#endif
////////////////////// PanelAlerts ///////////////////
if (hasChild("OnlineOfflinetoNearbyChat", TRUE))
{

View File

@ -47,7 +47,6 @@
#include "llstartup.h" // login_alert_done
#include "llviewernetwork.h" // FIX FIRE 3143 SJ
LLFloaterTOS::LLFloaterTOS(const LLSD& data)
: LLModalDialog( data["message"].asString() ),
mMessage(data["message"].asString()),
@ -86,7 +85,7 @@ protected:
{
if ( mParent )
{
mParent->setSiteIsAlive( true );
mParent->setSiteIsAlive(true);
}
}
@ -160,6 +159,20 @@ BOOL LLFloaterTOS::postBuild()
if (web_browser && use_web_browser)
// </FS:CR>
{
// if we are forced to send users to an external site in their system browser
// (e.g.) Linux users because of lack of media support for HTML ToS page
// remove exisiting UI and replace with a link to external page where users can accept ToS
#ifdef EXTERNAL_TOS
LLTextBox* header = getChild<LLTextBox>("tos_heading");
if (header)
header->setVisible(false);
LLTextBox* external_prompt = getChild<LLTextBox>("external_tos_required");
if (external_prompt)
external_prompt->setVisible(true);
web_browser->setVisible(false);
#else
web_browser->addObserver(this);
// <FS:CR> FIRE-8063 - Aurora and OpenSim TOS
@ -185,6 +198,7 @@ BOOL LLFloaterTOS::postBuild()
media_plugin->setOverrideClickTarget("_external");
}
}
#endif
}
#ifdef OPENSIM
else if (LLGridManager::getInstance()->isInOpenSim())
@ -213,6 +227,13 @@ BOOL LLFloaterTOS::postBuild()
void LLFloaterTOS::setSiteIsAlive( bool alive )
{
// if we are forced to send users to an external site in their system browser
// (e.g.) Linux users because of lack of media support for HTML ToS page
// force the regular HTML UI to deactivate so alternative is rendered instead.
#ifdef EXTERNAL_TOS
mSiteAlive = false;
#else
mSiteAlive = alive;
// only do this for TOS pages
@ -241,6 +262,7 @@ void LLFloaterTOS::setSiteIsAlive( bool alive )
tos_agreement->setEnabled( true );
}
}
#endif
}
LLFloaterTOS::~LLFloaterTOS()

View File

@ -1418,7 +1418,7 @@ LLSD LLViewerMedia::getHeaders()
/////////////////////////////////////////////////////////////////////////////////////////
// static
bool LLViewerMedia::parseRawCookie(const std::string raw_cookie, std::string& name, std::string& value, std::string& path)
bool LLViewerMedia::parseRawCookie(const std::string raw_cookie, std::string& name, std::string& value, std::string& path, bool& httponly, bool& secure)
{
std::size_t name_pos = raw_cookie.find_first_of("=");
if (name_pos != std::string::npos)
@ -1430,6 +1430,9 @@ bool LLViewerMedia::parseRawCookie(const std::string raw_cookie, std::string& na
value = raw_cookie.substr(name_pos + 1, value_pos - name_pos - 1);
path = "/"; // assume root path for now
httponly = true; // hard coded for now
secure = true;
return true;
}
}
@ -1478,10 +1481,12 @@ void LLViewerMedia::setOpenIDCookie(const std::string& url)
std::string cookie_name = "";
std::string cookie_value = "";
std::string cookie_path = "";
if (parseRawCookie(sOpenIDCookie, cookie_name, cookie_value, cookie_path) &&
bool httponly = true;
bool secure = true;
if (parseRawCookie(sOpenIDCookie, cookie_name, cookie_value, cookie_path, httponly, secure) &&
media_instance->getMediaPlugin())
{
media_instance->getMediaPlugin()->setCookie(url, cookie_name, cookie_value, cookie_host, cookie_path);
media_instance->getMediaPlugin()->setCookie(url, cookie_name, cookie_value, cookie_host, cookie_path, httponly, secure);
}
}
}

View File

@ -163,7 +163,7 @@ public:
static LLSD getHeaders();
private:
static bool parseRawCookie(const std::string raw_cookie, std::string& name, std::string& value, std::string& path);
static bool parseRawCookie(const std::string raw_cookie, std::string& name, std::string& value, std::string& path, bool& httponly, bool& secure);
static void setOpenIDCookie(const std::string& url);
static void onTeleportFinished();

View File

@ -2186,6 +2186,7 @@ void LLViewerWindow::initWorldUI()
}
gHUDView = new LLHUDView(hud_rect);
getRootView()->addChild(gHUDView);
getRootView()->sendChildToBack(gHUDView);
}
LLPanel* panel_ssf_container = getRootView()->getChild<LLPanel>("state_management_buttons_container");

View File

@ -238,6 +238,9 @@ std::string LLWeb::expandURLSubstitutions(const std::string &url,
//static
bool LLWeb::useExternalBrowser(const std::string &url)
{
#ifdef EXTERNAL_TOS
return true;
#else
if (gSavedSettings.getU32("PreferredBrowserBehavior") == BROWSER_EXTERNAL_ONLY)
{
return true;
@ -254,4 +257,5 @@ bool LLWeb::useExternalBrowser(const std::string &url)
return !(boost::regex_search(uri_string, matches, pattern));
}
return false;
#endif
}

View File

@ -57,6 +57,21 @@
width="552">
Please read the following Terms of Service and Privacy Policy carefully. To continue logging in you must accept the agreement.
</text>
<text
type="string"
length="1"
follows="left|top"
font="SansSerif"
height="30"
layout="topleft"
left="16"
name="external_tos_required"
visible="false"
top="32"
word_wrap="true"
width="552">
To continue logging in to [SECOND_LIFE], you must accept the [https://id.secondlife.com/openid/login?return_to=https%3A%2F%2Fmy.secondlife.com%2Fopenid Terms of Service and Privacy Policy].
</text>
<web_browser
trusted_content="true"
follows="left|top"

View File

@ -26,7 +26,7 @@
#include "linden_common.h"
#include "../llviewerprecompiledheaders.h"
#include <iostream>
#include "../test/lltut.h"