From 52f1830821859379a6dad8fb6d2cb140f7fe939e Mon Sep 17 00:00:00 2001 From: Leslie Linden Date: Fri, 13 May 2011 11:32:59 -0700 Subject: Updating to remove spam associated with the search for the [MacLocale] string. The change of OS version from "Darwin" to "Mac OS X" changed the name of the string the code is looking for. Reviewed by Richard. --- indra/newview/skins/default/xui/da/language_settings.xml | 1 + indra/newview/skins/default/xui/de/language_settings.xml | 1 + indra/newview/skins/default/xui/en/language_settings.xml | 1 + indra/newview/skins/default/xui/es/language_settings.xml | 1 + indra/newview/skins/default/xui/fr/language_settings.xml | 1 + indra/newview/skins/default/xui/it/language_settings.xml | 1 + indra/newview/skins/default/xui/ja/language_settings.xml | 1 + indra/newview/skins/default/xui/nl/language_settings.xml | 1 + indra/newview/skins/default/xui/pl/language_settings.xml | 1 + indra/newview/skins/default/xui/pt/language_settings.xml | 1 + 10 files changed, 10 insertions(+) diff --git a/indra/newview/skins/default/xui/da/language_settings.xml b/indra/newview/skins/default/xui/da/language_settings.xml index 3e46f69af1..0e3cbfd2d2 100644 --- a/indra/newview/skins/default/xui/da/language_settings.xml +++ b/indra/newview/skins/default/xui/da/language_settings.xml @@ -4,6 +4,7 @@ danish + da_DK.UTF-8 da_DK.UTF-8 da_DK.UTF-8 diff --git a/indra/newview/skins/default/xui/de/language_settings.xml b/indra/newview/skins/default/xui/de/language_settings.xml index d54f548fe1..f9346eef7d 100644 --- a/indra/newview/skins/default/xui/de/language_settings.xml +++ b/indra/newview/skins/default/xui/de/language_settings.xml @@ -4,6 +4,7 @@ german + de_DE.UTF-8 de_DE.UTF-8 de_DE.UTF-8 diff --git a/indra/newview/skins/default/xui/en/language_settings.xml b/indra/newview/skins/default/xui/en/language_settings.xml index c8a06fe401..51779e4bfd 100644 --- a/indra/newview/skins/default/xui/en/language_settings.xml +++ b/indra/newview/skins/default/xui/en/language_settings.xml @@ -4,6 +4,7 @@ english + C C C diff --git a/indra/newview/skins/default/xui/es/language_settings.xml b/indra/newview/skins/default/xui/es/language_settings.xml index f172994077..997293a741 100644 --- a/indra/newview/skins/default/xui/es/language_settings.xml +++ b/indra/newview/skins/default/xui/es/language_settings.xml @@ -4,6 +4,7 @@ spanish + es_ES.UTF-8 es_ES.UTF-8 es_ES.UTF-8 diff --git a/indra/newview/skins/default/xui/fr/language_settings.xml b/indra/newview/skins/default/xui/fr/language_settings.xml index bd272e1f28..fdac9d65a7 100644 --- a/indra/newview/skins/default/xui/fr/language_settings.xml +++ b/indra/newview/skins/default/xui/fr/language_settings.xml @@ -4,6 +4,7 @@ french + fr_FR.UTF-8 fr_FR.UTF-8 fr_FR.UTF-8 diff --git a/indra/newview/skins/default/xui/it/language_settings.xml b/indra/newview/skins/default/xui/it/language_settings.xml index 312b8e21aa..5f448fa828 100644 --- a/indra/newview/skins/default/xui/it/language_settings.xml +++ b/indra/newview/skins/default/xui/it/language_settings.xml @@ -4,6 +4,7 @@ italian + it_IT.UTF-8 it_IT.UTF-8 it_IT.UTF-8 diff --git a/indra/newview/skins/default/xui/ja/language_settings.xml b/indra/newview/skins/default/xui/ja/language_settings.xml index a6023f9b56..91e8f4be7c 100644 --- a/indra/newview/skins/default/xui/ja/language_settings.xml +++ b/indra/newview/skins/default/xui/ja/language_settings.xml @@ -4,6 +4,7 @@ japanese + ja_JP.UTF-8 ja_JP.UTF-8 ja_JP.UTF-8 diff --git a/indra/newview/skins/default/xui/nl/language_settings.xml b/indra/newview/skins/default/xui/nl/language_settings.xml index 53501d5dcb..40f4d9178a 100644 --- a/indra/newview/skins/default/xui/nl/language_settings.xml +++ b/indra/newview/skins/default/xui/nl/language_settings.xml @@ -4,6 +4,7 @@ dutch + nl_NL.UTF-8 nl_NL.UTF-8 nl_NL.UTF-8 diff --git a/indra/newview/skins/default/xui/pl/language_settings.xml b/indra/newview/skins/default/xui/pl/language_settings.xml index 681b38e9cf..93051d1317 100644 --- a/indra/newview/skins/default/xui/pl/language_settings.xml +++ b/indra/newview/skins/default/xui/pl/language_settings.xml @@ -4,6 +4,7 @@ polish + pl_PL.UTF-8 pl_PL.UTF-8 pl_PL.UTF-8 diff --git a/indra/newview/skins/default/xui/pt/language_settings.xml b/indra/newview/skins/default/xui/pt/language_settings.xml index e1de6ffea7..8799475ace 100644 --- a/indra/newview/skins/default/xui/pt/language_settings.xml +++ b/indra/newview/skins/default/xui/pt/language_settings.xml @@ -4,6 +4,7 @@ portuguese + pt_PT.UTF-8 pt_PT.UTF-8 pt_PT.UTF-8 -- cgit v1.2.3 From e4a9704d4157151442accca1116ad70f7f63ae95 Mon Sep 17 00:00:00 2001 From: callum Date: Fri, 13 May 2011 17:08:43 -0700 Subject: EXP-676 FIX As a web developer, I want to access information about the current state of the SL client, such as avatar location --- autobuild.xml | 12 +- indra/llplugin/llpluginclassmedia.cpp | 2744 ++++---- indra/llplugin/llpluginclassmedia.h | 840 +-- indra/media_plugins/webkit/media_plugin_webkit.cpp | 51 +- indra/newview/app_settings/settings.xml | 11 + indra/newview/llviewermedia.cpp | 7434 ++++++++++---------- indra/newview/llviewermedia.h | 5 +- indra/newview/skins/default/xui/en/menu_login.xml | 6 +- install.xml | 1851 ----- 9 files changed, 5649 insertions(+), 7305 deletions(-) delete mode 100644 install.xml diff --git a/autobuild.xml b/autobuild.xml index d72846b8fe..9d4fe8382b 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1062,9 +1062,9 @@ archive hash - 76c1015eafcba5ca9932c3009533b51c + 1aec55e90d510ffa3beb83c427af8312 url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/225273/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20110329.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/229944/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20110513.tar.bz2 name darwin @@ -1074,9 +1074,9 @@ archive hash - c05a33ee8b6f253b5a744596dfc3707d + 834215a2a004efb983e318d9c458d112 url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-linux-qt4.6-20101013.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/229944/arch/Linux/installer/llqtwebkit-4.7.1-linux-20110513.tar.bz2 name linux @@ -1086,9 +1086,9 @@ archive hash - 1b1b8e104e39c542d69eb37b5ee81818 + 4442288be66754063f7dbc53b9b4a9a9 url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/225249/arch/CYGWIN/installer/llqtwebkit-4.7.1-windows-20110329.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/229944/arch/CYGWIN/installer/llqtwebkit-4.7.1-windows-20110513.tar.bz2 name windows diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 2103216536..cc8fe53c3b 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -1,1335 +1,1409 @@ -/** - * @file llpluginclassmedia.cpp - * @brief LLPluginClassMedia handles a plugin which knows about the "media" message class. - * - * @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" - -#include "llpluginclassmedia.h" -#include "llpluginmessageclasses.h" - -#include "llqtwebkit.h" - -static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256; - -static int nextPowerOf2( int value ) -{ - int next_power_of_2 = 1; - while ( next_power_of_2 < value ) - { - next_power_of_2 <<= 1; - } - - return next_power_of_2; -} - -LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner) -{ - mOwner = owner; - mPlugin = NULL; - reset(); - - //debug use - mDeleteOK = true ; -} - - -LLPluginClassMedia::~LLPluginClassMedia() -{ - llassert_always(mDeleteOK) ; - reset(); -} - -bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug) -{ - LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL; - LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL; - LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL; - - mPlugin = new LLPluginProcessParent(this); - mPlugin->setSleepTime(mSleepTime); - - // Queue up the media init message -- it will be sent after all the currently queued messages. - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init"); - message.setValue("target", mTarget); - sendMessage(message); - - mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug); - - return true; -} - - -void LLPluginClassMedia::reset() -{ - if(mPlugin != NULL) - { - delete mPlugin; - mPlugin = NULL; - } - - mTextureParamsReceived = false; - mRequestedTextureDepth = 0; - mRequestedTextureInternalFormat = 0; - mRequestedTextureFormat = 0; - mRequestedTextureType = 0; - mRequestedTextureSwapBytes = false; - mRequestedTextureCoordsOpenGL = false; - mTextureSharedMemorySize = 0; - mTextureSharedMemoryName.clear(); - mDefaultMediaWidth = 0; - mDefaultMediaHeight = 0; - mNaturalMediaWidth = 0; - mNaturalMediaHeight = 0; - mSetMediaWidth = -1; - mSetMediaHeight = -1; - mRequestedMediaWidth = 0; - mRequestedMediaHeight = 0; - mRequestedTextureWidth = 0; - mRequestedTextureHeight = 0; - mFullMediaWidth = 0; - mFullMediaHeight = 0; - mTextureWidth = 0; - mTextureHeight = 0; - mMediaWidth = 0; - mMediaHeight = 0; - mDirtyRect = LLRect::null; - mAutoScaleMedia = false; - mRequestedVolume = 1.0f; - mPriority = PRIORITY_NORMAL; - mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT; - mAllowDownsample = false; - mPadding = 0; - mLastMouseX = 0; - mLastMouseY = 0; - mStatus = LLPluginClassMediaOwner::MEDIA_NONE; - mSleepTime = 1.0f / 100.0f; - mCanCut = false; - mCanCopy = false; - mCanPaste = false; - mMediaName.clear(); - mMediaDescription.clear(); - mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f); - - // media_browser class - mNavigateURI.clear(); - mNavigateResultCode = -1; - mNavigateResultString.clear(); - mHistoryBackAvailable = false; - mHistoryForwardAvailable = false; - mStatusText.clear(); - mProgressPercent = 0; - mClickURL.clear(); - mClickNavType.clear(); - mClickTarget.clear(); - mClickUUID.clear(); - mStatusCode = 0; - - // media_time class - mCurrentTime = 0.0f; - mDuration = 0.0f; - mCurrentRate = 0.0f; - mLoadedDuration = 0.0f; -} - -void LLPluginClassMedia::idle(void) -{ - if(mPlugin) - { - mPlugin->idle(); - } - - if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL)) - { - // Can't process a size change at this time - } - else if((mRequestedMediaWidth != mMediaWidth) || (mRequestedMediaHeight != mMediaHeight)) - { - // Calculate the correct size for the media texture - mRequestedTextureHeight = mRequestedMediaHeight; - if(mPadding < 0) - { - // negative values indicate the plugin wants a power of 2 - mRequestedTextureWidth = nextPowerOf2(mRequestedMediaWidth); - } - else - { - mRequestedTextureWidth = mRequestedMediaWidth; - - if(mPadding > 1) - { - // Pad up to a multiple of the specified number of bytes per row - int rowbytes = mRequestedTextureWidth * mRequestedTextureDepth; - int pad = rowbytes % mPadding; - if(pad != 0) - { - rowbytes += mPadding - pad; - } - - if(rowbytes % mRequestedTextureDepth == 0) - { - mRequestedTextureWidth = rowbytes / mRequestedTextureDepth; - } - else - { - LL_WARNS("Plugin") << "Unable to pad texture width, padding size " << mPadding << "is not a multiple of pixel size " << mRequestedTextureDepth << LL_ENDL; - } - } - } - - - // Size change has been requested but not initiated yet. - size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth; - - // Add an extra line for padding, just in case. - newsize += mRequestedTextureWidth * mRequestedTextureDepth; - - if(newsize != mTextureSharedMemorySize) - { - if(!mTextureSharedMemoryName.empty()) - { - // Tell the plugin to remove the old memory segment - mPlugin->removeSharedMemory(mTextureSharedMemoryName); - mTextureSharedMemoryName.clear(); - } - - mTextureSharedMemorySize = newsize; - mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize); - if(!mTextureSharedMemoryName.empty()) - { - void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); - - // clear texture memory to avoid random screen visual fuzz from uninitialized texture data - memset( addr, 0x00, newsize ); - - // We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin, - // so it may not be worthwhile. - // mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight); - } - } - - // This is our local indicator that a change is in progress. - mTextureWidth = -1; - mTextureHeight = -1; - mMediaWidth = -1; - mMediaHeight = -1; - - // This invalidates any existing dirty rect. - resetDirty(); - - // Send a size change message to the plugin - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change"); - message.setValue("name", mTextureSharedMemoryName); - message.setValueS32("width", mRequestedMediaWidth); - message.setValueS32("height", mRequestedMediaHeight); - message.setValueS32("texture_width", mRequestedTextureWidth); - message.setValueS32("texture_height", mRequestedTextureHeight); - message.setValueReal("background_r", mBackgroundColor.mV[VX]); - message.setValueReal("background_g", mBackgroundColor.mV[VY]); - message.setValueReal("background_b", mBackgroundColor.mV[VZ]); - message.setValueReal("background_a", mBackgroundColor.mV[VW]); - mPlugin->sendMessage(message); // DO NOT just use sendMessage() here -- we want this to jump ahead of the queue. - - LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL; - } - } - - if(mPlugin && mPlugin->isRunning()) - { - // Send queued messages - while(!mSendQueue.empty()) - { - LLPluginMessage message = mSendQueue.front(); - mSendQueue.pop(); - mPlugin->sendMessage(message); - } - } -} - -int LLPluginClassMedia::getTextureWidth() const -{ - return nextPowerOf2(mTextureWidth); -} - -int LLPluginClassMedia::getTextureHeight() const -{ - return nextPowerOf2(mTextureHeight); -} - -unsigned char* LLPluginClassMedia::getBitsData() -{ - unsigned char *result = NULL; - if((mPlugin != NULL) && !mTextureSharedMemoryName.empty()) - { - result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); - } - return result; -} - -void LLPluginClassMedia::setSize(int width, int height) -{ - if((width > 0) && (height > 0)) - { - mSetMediaWidth = width; - mSetMediaHeight = height; - } - else - { - mSetMediaWidth = -1; - mSetMediaHeight = -1; - } - - setSizeInternal(); -} - -void LLPluginClassMedia::setSizeInternal(void) -{ - if((mSetMediaWidth > 0) && (mSetMediaHeight > 0)) - { - mRequestedMediaWidth = mSetMediaWidth; - mRequestedMediaHeight = mSetMediaHeight; - } - else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0)) - { - mRequestedMediaWidth = mNaturalMediaWidth; - mRequestedMediaHeight = mNaturalMediaHeight; - } - else - { - mRequestedMediaWidth = mDefaultMediaWidth; - mRequestedMediaHeight = mDefaultMediaHeight; - } - - // Save these for size/interest calculations - mFullMediaWidth = mRequestedMediaWidth; - mFullMediaHeight = mRequestedMediaHeight; - - if(mAllowDownsample) - { - switch(mPriority) - { - case PRIORITY_SLIDESHOW: - case PRIORITY_LOW: - // Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit - while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit)) - { - mRequestedMediaWidth /= 2; - mRequestedMediaHeight /= 2; - } - break; - - default: - // Don't adjust texture size - break; - } - } - - if(mAutoScaleMedia) - { - mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth); - mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight); - } - - if(mRequestedMediaWidth > 2048) - mRequestedMediaWidth = 2048; - - if(mRequestedMediaHeight > 2048) - mRequestedMediaHeight = 2048; -} - -void LLPluginClassMedia::setAutoScale(bool auto_scale) -{ - if(auto_scale != mAutoScaleMedia) - { - mAutoScaleMedia = auto_scale; - setSizeInternal(); - } -} - -bool LLPluginClassMedia::textureValid(void) -{ - if( - !mTextureParamsReceived || - mTextureWidth <= 0 || - mTextureHeight <= 0 || - mMediaWidth <= 0 || - mMediaHeight <= 0 || - mRequestedMediaWidth != mMediaWidth || - mRequestedMediaHeight != mMediaHeight || - getBitsData() == NULL - ) - return false; - - return true; -} - -bool LLPluginClassMedia::getDirty(LLRect *dirty_rect) -{ - bool result = !mDirtyRect.isEmpty(); - - if(dirty_rect != NULL) - { - *dirty_rect = mDirtyRect; - } - - return result; -} - -void LLPluginClassMedia::resetDirty(void) -{ - mDirtyRect = LLRect::null; -} - -std::string LLPluginClassMedia::translateModifiers(MASK modifiers) -{ - std::string result; - - - if(modifiers & MASK_CONTROL) - { - result += "control|"; - } - - if(modifiers & MASK_ALT) - { - result += "alt|"; - } - - if(modifiers & MASK_SHIFT) - { - result += "shift|"; - } - - // TODO: should I deal with platform differences here or in callers? - // TODO: how do we deal with the Mac "command" key? -/* - if(modifiers & MASK_SOMETHING) - { - result += "meta|"; - } -*/ - return result; -} - -void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers) -{ - if(type == MOUSE_EVENT_MOVE) - { - if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked()) - { - // Don't queue up mouse move events that can't be delivered. - return; - } - - if((x == mLastMouseX) && (y == mLastMouseY)) - { - // Don't spam unnecessary mouse move events. - return; - } - - mLastMouseX = x; - mLastMouseY = y; - } - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event"); - std::string temp; - switch(type) - { - case MOUSE_EVENT_DOWN: temp = "down"; break; - case MOUSE_EVENT_UP: temp = "up"; break; - case MOUSE_EVENT_MOVE: temp = "move"; break; - case MOUSE_EVENT_DOUBLE_CLICK: temp = "double_click"; break; - } - message.setValue("event", temp); - - message.setValueS32("button", button); - - message.setValueS32("x", x); - - // Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it. - if(!mRequestedTextureCoordsOpenGL) - { - // TODO: Should I use mMediaHeight or mRequestedMediaHeight here? - y = mMediaHeight - y; - } - message.setValueS32("y", y); - - message.setValue("modifiers", translateModifiers(modifiers)); - - sendMessage(message); -} - -bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data) -{ - bool result = true; - - // FIXME: - // HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode. - // For now, return false for the ones the webkit plugin won't handle properly. - - switch(key_code) - { - case KEY_BACKSPACE: - case KEY_TAB: - case KEY_RETURN: - case KEY_PAD_RETURN: - case KEY_SHIFT: - case KEY_CONTROL: - case KEY_ALT: - case KEY_CAPSLOCK: - case KEY_ESCAPE: - case KEY_PAGE_UP: - case KEY_PAGE_DOWN: - case KEY_END: - case KEY_HOME: - case KEY_LEFT: - case KEY_UP: - case KEY_RIGHT: - case KEY_DOWN: - case KEY_INSERT: - case KEY_DELETE: - // These will be handled - break; - - default: - // regular ASCII characters will also be handled - if(key_code >= KEY_SPECIAL) - { - // Other "special" codes will not work properly. - result = false; - } - break; - } - -#if LL_DARWIN - if(modifiers & MASK_ALT) - { - // Option-key modified characters should be handled by the unicode input path instead of this one. - result = false; - } -#endif - - if(result) - { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event"); - std::string temp; - switch(type) - { - case KEY_EVENT_DOWN: temp = "down"; break; - case KEY_EVENT_UP: temp = "up"; break; - case KEY_EVENT_REPEAT: temp = "repeat"; break; - } - message.setValue("event", temp); - - message.setValueS32("key", key_code); - - message.setValue("modifiers", translateModifiers(modifiers)); - message.setValueLLSD("native_key_data", native_key_data); - - sendMessage(message); - } - - return result; -} - -void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event"); - - message.setValueS32("x", x); - message.setValueS32("y", y); - message.setValue("modifiers", translateModifiers(modifiers)); - - sendMessage(message); -} - -bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event"); - - message.setValue("text", text); - message.setValue("modifiers", translateModifiers(modifiers)); - message.setValueLLSD("native_key_data", native_key_data); - - sendMessage(message); - - return true; -} - -void LLPluginClassMedia::loadURI(const std::string &uri) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri"); - - message.setValue("uri", uri); - - sendMessage(message); -} - -const char* LLPluginClassMedia::priorityToString(EPriority priority) -{ - const char* result = "UNKNOWN"; - switch(priority) - { - case PRIORITY_UNLOADED: result = "unloaded"; break; - case PRIORITY_STOPPED: result = "stopped"; break; - case PRIORITY_HIDDEN: result = "hidden"; break; - case PRIORITY_SLIDESHOW: result = "slideshow"; break; - case PRIORITY_LOW: result = "low"; break; - case PRIORITY_NORMAL: result = "normal"; break; - case PRIORITY_HIGH: result = "high"; break; - } - - return result; -} - -void LLPluginClassMedia::setPriority(EPriority priority) -{ - if(mPriority != priority) - { - mPriority = priority; - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority"); - - std::string priority_string = priorityToString(priority); - switch(priority) - { - case PRIORITY_UNLOADED: - mSleepTime = 1.0f; - break; - case PRIORITY_STOPPED: - mSleepTime = 1.0f; - break; - case PRIORITY_HIDDEN: - mSleepTime = 1.0f; - break; - case PRIORITY_SLIDESHOW: - mSleepTime = 1.0f; - break; - case PRIORITY_LOW: - mSleepTime = 1.0f / 25.0f; - break; - case PRIORITY_NORMAL: - mSleepTime = 1.0f / 50.0f; - break; - case PRIORITY_HIGH: - mSleepTime = 1.0f / 100.0f; - break; - } - - message.setValue("priority", priority_string); - - sendMessage(message); - - if(mPlugin) - { - mPlugin->setSleepTime(mSleepTime); - } - - LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL; - - // This may affect the calculated size, so recalculate it here. - setSizeInternal(); - } -} - -void LLPluginClassMedia::setLowPrioritySizeLimit(int size) -{ - int power = nextPowerOf2(size); - if(mLowPrioritySizeLimit != power) - { - mLowPrioritySizeLimit = power; - - // This may affect the calculated size, so recalculate it here. - setSizeInternal(); - } -} - -F64 LLPluginClassMedia::getCPUUsage() -{ - F64 result = 0.0f; - - if(mPlugin) - { - result = mPlugin->getCPUUsage(); - } - - return result; -} - -void LLPluginClassMedia::sendPickFileResponse(const std::string &file) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response"); - message.setValue("file", file); - if(mPlugin && mPlugin->isBlocked()) - { - // If the plugin sent a blocking pick-file request, the response should unblock it. - message.setValueBoolean("blocking_response", true); - } - sendMessage(message); -} - -void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, const std::string &password) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response"); - message.setValueBoolean("ok", ok); - message.setValue("username", username); - message.setValue("password", password); - if(mPlugin && mPlugin->isBlocked()) - { - // If the plugin sent a blocking pick-file request, the response should unblock it. - message.setValueBoolean("blocking_response", true); - } - sendMessage(message); -} - -void LLPluginClassMedia::cut() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut"); - sendMessage(message); -} - -void LLPluginClassMedia::copy() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_copy"); - sendMessage(message); -} - -void LLPluginClassMedia::paste() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_paste"); - sendMessage(message); -} - -void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path"); - message.setValue("path", user_data_path); - sendMessage(message); -} - -void LLPluginClassMedia::setLanguageCode(const std::string &language_code) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_language_code"); - message.setValue("language", language_code); - sendMessage(message); -} - -void LLPluginClassMedia::setPluginsEnabled(const bool enabled) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled"); - message.setValueBoolean("enable", enabled); - sendMessage(message); -} - -void LLPluginClassMedia::setJavascriptEnabled(const bool enabled) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled"); - message.setValueBoolean("enable", enabled); - sendMessage(message); -} - -void LLPluginClassMedia::setTarget(const std::string &target) -{ - mTarget = target; -} - -/* virtual */ -void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) -{ - std::string message_class = message.getClass(); - - if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) - { - std::string message_name = message.getName(); - if(message_name == "texture_params") - { - mRequestedTextureDepth = message.getValueS32("depth"); - mRequestedTextureInternalFormat = message.getValueU32("internalformat"); - mRequestedTextureFormat = message.getValueU32("format"); - mRequestedTextureType = message.getValueU32("type"); - mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes"); - mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl"); - - // These two are optional, and will default to 0 if they're not specified. - mDefaultMediaWidth = message.getValueS32("default_width"); - mDefaultMediaHeight = message.getValueS32("default_height"); - - mAllowDownsample = message.getValueBoolean("allow_downsample"); - mPadding = message.getValueS32("padding"); - - setSizeInternal(); - - mTextureParamsReceived = true; - } - else if(message_name == "updated") - { - if(message.hasValue("left")) - { - LLRect newDirtyRect; - newDirtyRect.mLeft = message.getValueS32("left"); - newDirtyRect.mTop = message.getValueS32("top"); - newDirtyRect.mRight = message.getValueS32("right"); - newDirtyRect.mBottom = message.getValueS32("bottom"); - - // The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion. - // If they're backwards, swap them. - if(newDirtyRect.mTop < newDirtyRect.mBottom) - { - S32 temp = newDirtyRect.mTop; - newDirtyRect.mTop = newDirtyRect.mBottom; - newDirtyRect.mBottom = temp; - } - - if(mDirtyRect.isEmpty()) - { - mDirtyRect = newDirtyRect; - } - else - { - mDirtyRect.unionWith(newDirtyRect); - } - - LL_DEBUGS("Plugin") << "adjusted incoming rect is: (" - << newDirtyRect.mLeft << ", " - << newDirtyRect.mTop << ", " - << newDirtyRect.mRight << ", " - << newDirtyRect.mBottom << "), new dirty rect is: (" - << mDirtyRect.mLeft << ", " - << mDirtyRect.mTop << ", " - << mDirtyRect.mRight << ", " - << mDirtyRect.mBottom << ")" - << LL_ENDL; - - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED); - } - - - bool time_duration_updated = false; - int previous_percent = mProgressPercent; - - if(message.hasValue("current_time")) - { - mCurrentTime = message.getValueReal("current_time"); - time_duration_updated = true; - } - if(message.hasValue("duration")) - { - mDuration = message.getValueReal("duration"); - time_duration_updated = true; - } - - if(message.hasValue("current_rate")) - { - mCurrentRate = message.getValueReal("current_rate"); - } - - if(message.hasValue("loaded_duration")) - { - mLoadedDuration = message.getValueReal("loaded_duration"); - time_duration_updated = true; - } - else - { - // If the message doesn't contain a loaded_duration param, assume it's equal to duration - mLoadedDuration = mDuration; - } - - // Calculate a percentage based on the loaded duration and total duration. - if(mDuration != 0.0f) // Don't divide by zero. - { - mProgressPercent = (int)((mLoadedDuration * 100.0f)/mDuration); - } - - if(time_duration_updated) - { - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED); - } - - if(previous_percent != mProgressPercent) - { - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED); - } - } - else if(message_name == "media_status") - { - std::string status = message.getValue("status"); - - LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL; - - if(status == "loading") - { - mStatus = LLPluginClassMediaOwner::MEDIA_LOADING; - } - else if(status == "loaded") - { - mStatus = LLPluginClassMediaOwner::MEDIA_LOADED; - } - else if(status == "error") - { - mStatus = LLPluginClassMediaOwner::MEDIA_ERROR; - } - else if(status == "playing") - { - mStatus = LLPluginClassMediaOwner::MEDIA_PLAYING; - } - else if(status == "paused") - { - mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED; - } - else if(status == "done") - { - mStatus = LLPluginClassMediaOwner::MEDIA_DONE; - } - else - { - // empty string or any unknown string - mStatus = LLPluginClassMediaOwner::MEDIA_NONE; - } - } - else if(message_name == "size_change_request") - { - S32 width = message.getValueS32("width"); - S32 height = message.getValueS32("height"); - std::string name = message.getValue("name"); - - // TODO: check that name matches? - mNaturalMediaWidth = width; - mNaturalMediaHeight = height; - - setSizeInternal(); - } - else if(message_name == "size_change_response") - { - std::string name = message.getValue("name"); - - // TODO: check that name matches? - - mTextureWidth = message.getValueS32("texture_width"); - mTextureHeight = message.getValueS32("texture_height"); - mMediaWidth = message.getValueS32("width"); - mMediaHeight = message.getValueS32("height"); - - // This invalidates any existing dirty rect. - resetDirty(); - - // TODO: should we verify that the plugin sent back the right values? - // Two size changes in a row may cause them to not match, due to queueing, etc. - - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED); - } - else if(message_name == "cursor_changed") - { - mCursorName = message.getValue("name"); - - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CURSOR_CHANGED); - } - else if(message_name == "edit_state") - { - if(message.hasValue("cut")) - { - mCanCut = message.getValueBoolean("cut"); - } - if(message.hasValue("copy")) - { - mCanCopy = message.getValueBoolean("copy"); - } - if(message.hasValue("paste")) - { - mCanPaste = message.getValueBoolean("paste"); - } - } - else if(message_name == "name_text") - { - mMediaName = message.getValue("name"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED); - } - else if(message_name == "pick_file") - { - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST); - } - else if(message_name == "auth_request") - { - mAuthURL = message.getValue("url"); - mAuthRealm = message.getValue("realm"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST); - } - else - { - LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; - } - } - else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) - { - std::string message_name = message.getName(); - if(message_name == "navigate_begin") - { - mNavigateURI = message.getValue("uri"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_BEGIN); - } - else if(message_name == "navigate_complete") - { - mNavigateURI = message.getValue("uri"); - mNavigateResultCode = message.getValueS32("result_code"); - mNavigateResultString = message.getValue("result_string"); - mHistoryBackAvailable = message.getValueBoolean("history_back_available"); - mHistoryForwardAvailable = message.getValueBoolean("history_forward_available"); - - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE); - } - else if(message_name == "progress") - { - mProgressPercent = message.getValueS32("percent"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED); - } - else if(message_name == "status_text") - { - mStatusText = message.getValue("status"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_STATUS_TEXT_CHANGED); - } - else if(message_name == "location_changed") - { - mLocation = message.getValue("uri"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LOCATION_CHANGED); - } - else if(message_name == "click_href") - { - mClickURL = message.getValue("uri"); - mClickTarget = message.getValue("target"); - mClickUUID = message.getValue("uuid"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF); - } - else if(message_name == "click_nofollow") - { - mClickURL = message.getValue("uri"); - mClickNavType = message.getValue("nav_type"); - mClickTarget.clear(); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW); - } - else if(message_name == "navigate_error_page") - { - mStatusCode = message.getValueS32("status_code"); - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_ERROR_PAGE); - } - else if(message_name == "cookie_set") - { - if(mOwner) - { - mOwner->handleCookieSet(this, message.getValue("cookie")); - } - } - else if(message_name == "close_request") - { - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLOSE_REQUEST); - } - else if(message_name == "geometry_change") - { - mClickUUID = message.getValue("uuid"); - mGeometryX = message.getValueS32("x"); - mGeometryY = message.getValueS32("y"); - mGeometryWidth = message.getValueS32("width"); - mGeometryHeight = message.getValueS32("height"); - - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE); - } - else if(message_name == "link_hovered") - { - // text is not currently used -- the tooltip hover text is taken from the "title". - mHoverLink = message.getValue("link"); - mHoverText = message.getValue("title"); - // message.getValue("text"); - - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED); - } - else - { - LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; - } - } - else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) - { - std::string message_name = message.getName(); - - // This class hasn't defined any incoming messages yet. -// if(message_name == "message_name") -// { -// } -// else - { - LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; - } - } - -} - -/* virtual */ -void LLPluginClassMedia::pluginLaunchFailed() -{ - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH); -} - -/* virtual */ -void LLPluginClassMedia::pluginDied() -{ - mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED); -} - -void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event) -{ - if(mOwner) - { - mOwner->handleMediaEvent(this, event); - } -} - -void LLPluginClassMedia::sendMessage(const LLPluginMessage &message) -{ - if(mPlugin && mPlugin->isRunning()) - { - mPlugin->sendMessage(message); - } - else - { - // The plugin isn't set up yet -- queue this message to be sent after initialization. - mSendQueue.push(message); - } -} - -//////////////////////////////////////////////////////////// -// MARK: media_browser class functions -bool LLPluginClassMedia::pluginSupportsMediaBrowser(void) -{ - std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER); - return !version.empty(); -} - -void LLPluginClassMedia::focus(bool focused) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus"); - - message.setValueBoolean("focused", focused); - - sendMessage(message); -} - -void LLPluginClassMedia::clear_cache() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache"); - sendMessage(message); -} - -void LLPluginClassMedia::clear_cookies() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cookies"); - sendMessage(message); -} - -void LLPluginClassMedia::set_cookies(const std::string &cookies) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies"); - message.setValue("cookies", cookies); - sendMessage(message); -} - -void LLPluginClassMedia::enable_cookies(bool enable) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies"); - message.setValueBoolean("enable", enable); - sendMessage(message); -} - -void LLPluginClassMedia::proxy_setup(bool enable, const std::string &host, int port) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup"); - - message.setValueBoolean("enable", enable); - message.setValue("host", host); - message.setValueS32("port", port); - - sendMessage(message); -} - -void LLPluginClassMedia::browse_stop() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_stop"); - sendMessage(message); -} - -void LLPluginClassMedia::browse_reload(bool ignore_cache) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload"); - - message.setValueBoolean("ignore_cache", ignore_cache); - - sendMessage(message); -} - -void LLPluginClassMedia::browse_forward() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_forward"); - sendMessage(message); -} - -void LLPluginClassMedia::browse_back() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_back"); - sendMessage(message); -} - -void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent"); - - message.setValue("user_agent", user_agent); - - sendMessage(message); -} - -void LLPluginClassMedia::proxyWindowOpened(const std::string &target, const std::string &uuid) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_opened"); - - message.setValue("target", target); - message.setValue("uuid", uuid); - - sendMessage(message); -} - -void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_closed"); - - message.setValue("uuid", uuid); - - sendMessage(message); -} - -void LLPluginClassMedia::ignore_ssl_cert_errors(bool ignore) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors"); - message.setValueBoolean("ignore", ignore); - sendMessage(message); -} - -void LLPluginClassMedia::addCertificateFilePath(const std::string& path) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "add_certificate_file_path"); - message.setValue("path", path); - sendMessage(message); -} - -void LLPluginClassMedia::crashPlugin() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash"); - - sendMessage(message); -} - -void LLPluginClassMedia::hangPlugin() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hang"); - - sendMessage(message); -} - - -//////////////////////////////////////////////////////////// -// MARK: media_time class functions -bool LLPluginClassMedia::pluginSupportsMediaTime(void) -{ - std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME); - return !version.empty(); -} - -void LLPluginClassMedia::stop() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "stop"); - sendMessage(message); -} - -void LLPluginClassMedia::start(float rate) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "start"); - - message.setValueReal("rate", rate); - - sendMessage(message); -} - -void LLPluginClassMedia::pause() -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "pause"); - sendMessage(message); -} - -void LLPluginClassMedia::seek(float time) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek"); - - message.setValueReal("time", time); - - sendMessage(message); -} - -void LLPluginClassMedia::setLoop(bool loop) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_loop"); - - message.setValueBoolean("loop", loop); - - sendMessage(message); -} - -void LLPluginClassMedia::setVolume(float volume) -{ - if(volume != mRequestedVolume) - { - mRequestedVolume = volume; - - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume"); - - message.setValueReal("volume", volume); - - sendMessage(message); - } -} - -float LLPluginClassMedia::getVolume() -{ - return mRequestedVolume; -} - -void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history) -{ - // Send URL history to plugin - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "init_history"); - message.setValueLLSD("history", url_history); - sendMessage(message); - - LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL; -} - +/** + * @file llpluginclassmedia.cpp + * @brief LLPluginClassMedia handles a plugin which knows about the "media" message class. + * + * @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" + +#include "llpluginclassmedia.h" +#include "llpluginmessageclasses.h" + +#include "llqtwebkit.h" + +static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256; + +static int nextPowerOf2( int value ) +{ + int next_power_of_2 = 1; + while ( next_power_of_2 < value ) + { + next_power_of_2 <<= 1; + } + + return next_power_of_2; +} + +LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner) +{ + mOwner = owner; + mPlugin = NULL; + reset(); + + //debug use + mDeleteOK = true ; +} + + +LLPluginClassMedia::~LLPluginClassMedia() +{ + llassert_always(mDeleteOK) ; + reset(); +} + +bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug) +{ + LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL; + LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL; + LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL; + + mPlugin = new LLPluginProcessParent(this); + mPlugin->setSleepTime(mSleepTime); + + // Queue up the media init message -- it will be sent after all the currently queued messages. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init"); + message.setValue("target", mTarget); + sendMessage(message); + + mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug); + + return true; +} + + +void LLPluginClassMedia::reset() +{ + if(mPlugin != NULL) + { + delete mPlugin; + mPlugin = NULL; + } + + mTextureParamsReceived = false; + mRequestedTextureDepth = 0; + mRequestedTextureInternalFormat = 0; + mRequestedTextureFormat = 0; + mRequestedTextureType = 0; + mRequestedTextureSwapBytes = false; + mRequestedTextureCoordsOpenGL = false; + mTextureSharedMemorySize = 0; + mTextureSharedMemoryName.clear(); + mDefaultMediaWidth = 0; + mDefaultMediaHeight = 0; + mNaturalMediaWidth = 0; + mNaturalMediaHeight = 0; + mSetMediaWidth = -1; + mSetMediaHeight = -1; + mRequestedMediaWidth = 0; + mRequestedMediaHeight = 0; + mRequestedTextureWidth = 0; + mRequestedTextureHeight = 0; + mFullMediaWidth = 0; + mFullMediaHeight = 0; + mTextureWidth = 0; + mTextureHeight = 0; + mMediaWidth = 0; + mMediaHeight = 0; + mDirtyRect = LLRect::null; + mAutoScaleMedia = false; + mRequestedVolume = 1.0f; + mPriority = PRIORITY_NORMAL; + mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT; + mAllowDownsample = false; + mPadding = 0; + mLastMouseX = 0; + mLastMouseY = 0; + mStatus = LLPluginClassMediaOwner::MEDIA_NONE; + mSleepTime = 1.0f / 100.0f; + mCanCut = false; + mCanCopy = false; + mCanPaste = false; + mMediaName.clear(); + mMediaDescription.clear(); + mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f); + + // media_browser class + mNavigateURI.clear(); + mNavigateResultCode = -1; + mNavigateResultString.clear(); + mHistoryBackAvailable = false; + mHistoryForwardAvailable = false; + mStatusText.clear(); + mProgressPercent = 0; + mClickURL.clear(); + mClickNavType.clear(); + mClickTarget.clear(); + mClickUUID.clear(); + mStatusCode = 0; + + // media_time class + mCurrentTime = 0.0f; + mDuration = 0.0f; + mCurrentRate = 0.0f; + mLoadedDuration = 0.0f; +} + +void LLPluginClassMedia::idle(void) +{ + if(mPlugin) + { + mPlugin->idle(); + } + + if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL)) + { + // Can't process a size change at this time + } + else if((mRequestedMediaWidth != mMediaWidth) || (mRequestedMediaHeight != mMediaHeight)) + { + // Calculate the correct size for the media texture + mRequestedTextureHeight = mRequestedMediaHeight; + if(mPadding < 0) + { + // negative values indicate the plugin wants a power of 2 + mRequestedTextureWidth = nextPowerOf2(mRequestedMediaWidth); + } + else + { + mRequestedTextureWidth = mRequestedMediaWidth; + + if(mPadding > 1) + { + // Pad up to a multiple of the specified number of bytes per row + int rowbytes = mRequestedTextureWidth * mRequestedTextureDepth; + int pad = rowbytes % mPadding; + if(pad != 0) + { + rowbytes += mPadding - pad; + } + + if(rowbytes % mRequestedTextureDepth == 0) + { + mRequestedTextureWidth = rowbytes / mRequestedTextureDepth; + } + else + { + LL_WARNS("Plugin") << "Unable to pad texture width, padding size " << mPadding << "is not a multiple of pixel size " << mRequestedTextureDepth << LL_ENDL; + } + } + } + + + // Size change has been requested but not initiated yet. + size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth; + + // Add an extra line for padding, just in case. + newsize += mRequestedTextureWidth * mRequestedTextureDepth; + + if(newsize != mTextureSharedMemorySize) + { + if(!mTextureSharedMemoryName.empty()) + { + // Tell the plugin to remove the old memory segment + mPlugin->removeSharedMemory(mTextureSharedMemoryName); + mTextureSharedMemoryName.clear(); + } + + mTextureSharedMemorySize = newsize; + mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize); + if(!mTextureSharedMemoryName.empty()) + { + void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); + + // clear texture memory to avoid random screen visual fuzz from uninitialized texture data + memset( addr, 0x00, newsize ); + + // We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin, + // so it may not be worthwhile. + // mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight); + } + } + + // This is our local indicator that a change is in progress. + mTextureWidth = -1; + mTextureHeight = -1; + mMediaWidth = -1; + mMediaHeight = -1; + + // This invalidates any existing dirty rect. + resetDirty(); + + // Send a size change message to the plugin + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change"); + message.setValue("name", mTextureSharedMemoryName); + message.setValueS32("width", mRequestedMediaWidth); + message.setValueS32("height", mRequestedMediaHeight); + message.setValueS32("texture_width", mRequestedTextureWidth); + message.setValueS32("texture_height", mRequestedTextureHeight); + message.setValueReal("background_r", mBackgroundColor.mV[VX]); + message.setValueReal("background_g", mBackgroundColor.mV[VY]); + message.setValueReal("background_b", mBackgroundColor.mV[VZ]); + message.setValueReal("background_a", mBackgroundColor.mV[VW]); + mPlugin->sendMessage(message); // DO NOT just use sendMessage() here -- we want this to jump ahead of the queue. + + LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL; + } + } + + if(mPlugin && mPlugin->isRunning()) + { + // Send queued messages + while(!mSendQueue.empty()) + { + LLPluginMessage message = mSendQueue.front(); + mSendQueue.pop(); + mPlugin->sendMessage(message); + } + } +} + +int LLPluginClassMedia::getTextureWidth() const +{ + return nextPowerOf2(mTextureWidth); +} + +int LLPluginClassMedia::getTextureHeight() const +{ + return nextPowerOf2(mTextureHeight); +} + +unsigned char* LLPluginClassMedia::getBitsData() +{ + unsigned char *result = NULL; + if((mPlugin != NULL) && !mTextureSharedMemoryName.empty()) + { + result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); + } + return result; +} + +void LLPluginClassMedia::setSize(int width, int height) +{ + if((width > 0) && (height > 0)) + { + mSetMediaWidth = width; + mSetMediaHeight = height; + } + else + { + mSetMediaWidth = -1; + mSetMediaHeight = -1; + } + + setSizeInternal(); +} + +void LLPluginClassMedia::setSizeInternal(void) +{ + if((mSetMediaWidth > 0) && (mSetMediaHeight > 0)) + { + mRequestedMediaWidth = mSetMediaWidth; + mRequestedMediaHeight = mSetMediaHeight; + } + else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0)) + { + mRequestedMediaWidth = mNaturalMediaWidth; + mRequestedMediaHeight = mNaturalMediaHeight; + } + else + { + mRequestedMediaWidth = mDefaultMediaWidth; + mRequestedMediaHeight = mDefaultMediaHeight; + } + + // Save these for size/interest calculations + mFullMediaWidth = mRequestedMediaWidth; + mFullMediaHeight = mRequestedMediaHeight; + + if(mAllowDownsample) + { + switch(mPriority) + { + case PRIORITY_SLIDESHOW: + case PRIORITY_LOW: + // Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit + while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit)) + { + mRequestedMediaWidth /= 2; + mRequestedMediaHeight /= 2; + } + break; + + default: + // Don't adjust texture size + break; + } + } + + if(mAutoScaleMedia) + { + mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth); + mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight); + } + + if(mRequestedMediaWidth > 2048) + mRequestedMediaWidth = 2048; + + if(mRequestedMediaHeight > 2048) + mRequestedMediaHeight = 2048; +} + +void LLPluginClassMedia::setAutoScale(bool auto_scale) +{ + if(auto_scale != mAutoScaleMedia) + { + mAutoScaleMedia = auto_scale; + setSizeInternal(); + } +} + +bool LLPluginClassMedia::textureValid(void) +{ + if( + !mTextureParamsReceived || + mTextureWidth <= 0 || + mTextureHeight <= 0 || + mMediaWidth <= 0 || + mMediaHeight <= 0 || + mRequestedMediaWidth != mMediaWidth || + mRequestedMediaHeight != mMediaHeight || + getBitsData() == NULL + ) + return false; + + return true; +} + +bool LLPluginClassMedia::getDirty(LLRect *dirty_rect) +{ + bool result = !mDirtyRect.isEmpty(); + + if(dirty_rect != NULL) + { + *dirty_rect = mDirtyRect; + } + + return result; +} + +void LLPluginClassMedia::resetDirty(void) +{ + mDirtyRect = LLRect::null; +} + +std::string LLPluginClassMedia::translateModifiers(MASK modifiers) +{ + std::string result; + + + if(modifiers & MASK_CONTROL) + { + result += "control|"; + } + + if(modifiers & MASK_ALT) + { + result += "alt|"; + } + + if(modifiers & MASK_SHIFT) + { + result += "shift|"; + } + + // TODO: should I deal with platform differences here or in callers? + // TODO: how do we deal with the Mac "command" key? +/* + if(modifiers & MASK_SOMETHING) + { + result += "meta|"; + } +*/ + return result; +} + +void LLPluginClassMedia::jsExposeObjectEvent( bool expose ) +{ + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_expose_object"); + message.setValueBoolean( "expose", expose ); + sendMessage( message ); +} + +void LLPluginClassMedia::jsValuesValidEvent( bool valid ) +{ + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_values_valid"); + message.setValueBoolean( "valid", valid ); + sendMessage( message ); +} + +void LLPluginClassMedia::jsAgentLocationEvent( double x, double y, double z ) +{ + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_location"); + message.setValueReal( "x", x ); + message.setValueReal( "y", y ); + message.setValueReal( "z", z ); + sendMessage( message ); +} + +void LLPluginClassMedia::jsAgentLanguageEvent( const std::string& language ) +{ + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_language"); + message.setValue( "language", language ); + sendMessage( message ); +} + +void LLPluginClassMedia::jsAgentRegionEvent( const std::string& region ) +{ + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_region"); + message.setValue( "region", region ); + sendMessage( message ); +} + +void LLPluginClassMedia::jsAgentMaturityEvent( const std::string& maturity ) +{ + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_maturity"); + message.setValue( "maturity", maturity ); + sendMessage( message ); +} + +void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers) +{ + if(type == MOUSE_EVENT_MOVE) + { + if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked()) + { + // Don't queue up mouse move events that can't be delivered. + return; + } + + if((x == mLastMouseX) && (y == mLastMouseY)) + { + // Don't spam unnecessary mouse move events. + return; + } + + mLastMouseX = x; + mLastMouseY = y; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event"); + std::string temp; + switch(type) + { + case MOUSE_EVENT_DOWN: temp = "down"; break; + case MOUSE_EVENT_UP: temp = "up"; break; + case MOUSE_EVENT_MOVE: temp = "move"; break; + case MOUSE_EVENT_DOUBLE_CLICK: temp = "double_click"; break; + } + message.setValue("event", temp); + + message.setValueS32("button", button); + + message.setValueS32("x", x); + + // Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it. + if(!mRequestedTextureCoordsOpenGL) + { + // TODO: Should I use mMediaHeight or mRequestedMediaHeight here? + y = mMediaHeight - y; + } + message.setValueS32("y", y); + + message.setValue("modifiers", translateModifiers(modifiers)); + + sendMessage(message); +} + +bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data) +{ + bool result = true; + + // FIXME: + // HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode. + // For now, return false for the ones the webkit plugin won't handle properly. + + switch(key_code) + { + case KEY_BACKSPACE: + case KEY_TAB: + case KEY_RETURN: + case KEY_PAD_RETURN: + case KEY_SHIFT: + case KEY_CONTROL: + case KEY_ALT: + case KEY_CAPSLOCK: + case KEY_ESCAPE: + case KEY_PAGE_UP: + case KEY_PAGE_DOWN: + case KEY_END: + case KEY_HOME: + case KEY_LEFT: + case KEY_UP: + case KEY_RIGHT: + case KEY_DOWN: + case KEY_INSERT: + case KEY_DELETE: + // These will be handled + break; + + default: + // regular ASCII characters will also be handled + if(key_code >= KEY_SPECIAL) + { + // Other "special" codes will not work properly. + result = false; + } + break; + } + +#if LL_DARWIN + if(modifiers & MASK_ALT) + { + // Option-key modified characters should be handled by the unicode input path instead of this one. + result = false; + } +#endif + + if(result) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event"); + std::string temp; + switch(type) + { + case KEY_EVENT_DOWN: temp = "down"; break; + case KEY_EVENT_UP: temp = "up"; break; + case KEY_EVENT_REPEAT: temp = "repeat"; break; + } + message.setValue("event", temp); + + message.setValueS32("key", key_code); + + message.setValue("modifiers", translateModifiers(modifiers)); + message.setValueLLSD("native_key_data", native_key_data); + + sendMessage(message); + } + + return result; +} + +void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event"); + + message.setValueS32("x", x); + message.setValueS32("y", y); + message.setValue("modifiers", translateModifiers(modifiers)); + + sendMessage(message); +} + +bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event"); + + message.setValue("text", text); + message.setValue("modifiers", translateModifiers(modifiers)); + message.setValueLLSD("native_key_data", native_key_data); + + sendMessage(message); + + return true; +} + +void LLPluginClassMedia::loadURI(const std::string &uri) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri"); + + message.setValue("uri", uri); + + sendMessage(message); +} + +const char* LLPluginClassMedia::priorityToString(EPriority priority) +{ + const char* result = "UNKNOWN"; + switch(priority) + { + case PRIORITY_UNLOADED: result = "unloaded"; break; + case PRIORITY_STOPPED: result = "stopped"; break; + case PRIORITY_HIDDEN: result = "hidden"; break; + case PRIORITY_SLIDESHOW: result = "slideshow"; break; + case PRIORITY_LOW: result = "low"; break; + case PRIORITY_NORMAL: result = "normal"; break; + case PRIORITY_HIGH: result = "high"; break; + } + + return result; +} + +void LLPluginClassMedia::setPriority(EPriority priority) +{ + if(mPriority != priority) + { + mPriority = priority; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority"); + + std::string priority_string = priorityToString(priority); + switch(priority) + { + case PRIORITY_UNLOADED: + mSleepTime = 1.0f; + break; + case PRIORITY_STOPPED: + mSleepTime = 1.0f; + break; + case PRIORITY_HIDDEN: + mSleepTime = 1.0f; + break; + case PRIORITY_SLIDESHOW: + mSleepTime = 1.0f; + break; + case PRIORITY_LOW: + mSleepTime = 1.0f / 25.0f; + break; + case PRIORITY_NORMAL: + mSleepTime = 1.0f / 50.0f; + break; + case PRIORITY_HIGH: + mSleepTime = 1.0f / 100.0f; + break; + } + + message.setValue("priority", priority_string); + + sendMessage(message); + + if(mPlugin) + { + mPlugin->setSleepTime(mSleepTime); + } + + LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL; + + // This may affect the calculated size, so recalculate it here. + setSizeInternal(); + } +} + +void LLPluginClassMedia::setLowPrioritySizeLimit(int size) +{ + int power = nextPowerOf2(size); + if(mLowPrioritySizeLimit != power) + { + mLowPrioritySizeLimit = power; + + // This may affect the calculated size, so recalculate it here. + setSizeInternal(); + } +} + +F64 LLPluginClassMedia::getCPUUsage() +{ + F64 result = 0.0f; + + if(mPlugin) + { + result = mPlugin->getCPUUsage(); + } + + return result; +} + +void LLPluginClassMedia::sendPickFileResponse(const std::string &file) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response"); + message.setValue("file", file); + if(mPlugin && mPlugin->isBlocked()) + { + // If the plugin sent a blocking pick-file request, the response should unblock it. + message.setValueBoolean("blocking_response", true); + } + sendMessage(message); +} + +void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, const std::string &password) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response"); + message.setValueBoolean("ok", ok); + message.setValue("username", username); + message.setValue("password", password); + if(mPlugin && mPlugin->isBlocked()) + { + // If the plugin sent a blocking pick-file request, the response should unblock it. + message.setValueBoolean("blocking_response", true); + } + sendMessage(message); +} + +void LLPluginClassMedia::cut() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut"); + sendMessage(message); +} + +void LLPluginClassMedia::copy() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_copy"); + sendMessage(message); +} + +void LLPluginClassMedia::paste() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_paste"); + sendMessage(message); +} + +void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path"); + message.setValue("path", user_data_path); + sendMessage(message); +} + +void LLPluginClassMedia::setLanguageCode(const std::string &language_code) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_language_code"); + message.setValue("language", language_code); + sendMessage(message); +} + +void LLPluginClassMedia::setPluginsEnabled(const bool enabled) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled"); + message.setValueBoolean("enable", enabled); + sendMessage(message); +} + +void LLPluginClassMedia::setJavascriptEnabled(const bool enabled) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled"); + message.setValueBoolean("enable", enabled); + sendMessage(message); +} + +void LLPluginClassMedia::setTarget(const std::string &target) +{ + mTarget = target; +} + +/* virtual */ +void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) +{ + std::string message_class = message.getClass(); + + if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + std::string message_name = message.getName(); + if(message_name == "texture_params") + { + mRequestedTextureDepth = message.getValueS32("depth"); + mRequestedTextureInternalFormat = message.getValueU32("internalformat"); + mRequestedTextureFormat = message.getValueU32("format"); + mRequestedTextureType = message.getValueU32("type"); + mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes"); + mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl"); + + // These two are optional, and will default to 0 if they're not specified. + mDefaultMediaWidth = message.getValueS32("default_width"); + mDefaultMediaHeight = message.getValueS32("default_height"); + + mAllowDownsample = message.getValueBoolean("allow_downsample"); + mPadding = message.getValueS32("padding"); + + setSizeInternal(); + + mTextureParamsReceived = true; + } + else if(message_name == "updated") + { + if(message.hasValue("left")) + { + LLRect newDirtyRect; + newDirtyRect.mLeft = message.getValueS32("left"); + newDirtyRect.mTop = message.getValueS32("top"); + newDirtyRect.mRight = message.getValueS32("right"); + newDirtyRect.mBottom = message.getValueS32("bottom"); + + // The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion. + // If they're backwards, swap them. + if(newDirtyRect.mTop < newDirtyRect.mBottom) + { + S32 temp = newDirtyRect.mTop; + newDirtyRect.mTop = newDirtyRect.mBottom; + newDirtyRect.mBottom = temp; + } + + if(mDirtyRect.isEmpty()) + { + mDirtyRect = newDirtyRect; + } + else + { + mDirtyRect.unionWith(newDirtyRect); + } + + LL_DEBUGS("Plugin") << "adjusted incoming rect is: (" + << newDirtyRect.mLeft << ", " + << newDirtyRect.mTop << ", " + << newDirtyRect.mRight << ", " + << newDirtyRect.mBottom << "), new dirty rect is: (" + << mDirtyRect.mLeft << ", " + << mDirtyRect.mTop << ", " + << mDirtyRect.mRight << ", " + << mDirtyRect.mBottom << ")" + << LL_ENDL; + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED); + } + + + bool time_duration_updated = false; + int previous_percent = mProgressPercent; + + if(message.hasValue("current_time")) + { + mCurrentTime = message.getValueReal("current_time"); + time_duration_updated = true; + } + if(message.hasValue("duration")) + { + mDuration = message.getValueReal("duration"); + time_duration_updated = true; + } + + if(message.hasValue("current_rate")) + { + mCurrentRate = message.getValueReal("current_rate"); + } + + if(message.hasValue("loaded_duration")) + { + mLoadedDuration = message.getValueReal("loaded_duration"); + time_duration_updated = true; + } + else + { + // If the message doesn't contain a loaded_duration param, assume it's equal to duration + mLoadedDuration = mDuration; + } + + // Calculate a percentage based on the loaded duration and total duration. + if(mDuration != 0.0f) // Don't divide by zero. + { + mProgressPercent = (int)((mLoadedDuration * 100.0f)/mDuration); + } + + if(time_duration_updated) + { + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED); + } + + if(previous_percent != mProgressPercent) + { + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED); + } + } + else if(message_name == "media_status") + { + std::string status = message.getValue("status"); + + LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL; + + if(status == "loading") + { + mStatus = LLPluginClassMediaOwner::MEDIA_LOADING; + } + else if(status == "loaded") + { + mStatus = LLPluginClassMediaOwner::MEDIA_LOADED; + } + else if(status == "error") + { + mStatus = LLPluginClassMediaOwner::MEDIA_ERROR; + } + else if(status == "playing") + { + mStatus = LLPluginClassMediaOwner::MEDIA_PLAYING; + } + else if(status == "paused") + { + mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED; + } + else if(status == "done") + { + mStatus = LLPluginClassMediaOwner::MEDIA_DONE; + } + else + { + // empty string or any unknown string + mStatus = LLPluginClassMediaOwner::MEDIA_NONE; + } + } + else if(message_name == "size_change_request") + { + S32 width = message.getValueS32("width"); + S32 height = message.getValueS32("height"); + std::string name = message.getValue("name"); + + // TODO: check that name matches? + mNaturalMediaWidth = width; + mNaturalMediaHeight = height; + + setSizeInternal(); + } + else if(message_name == "size_change_response") + { + std::string name = message.getValue("name"); + + // TODO: check that name matches? + + mTextureWidth = message.getValueS32("texture_width"); + mTextureHeight = message.getValueS32("texture_height"); + mMediaWidth = message.getValueS32("width"); + mMediaHeight = message.getValueS32("height"); + + // This invalidates any existing dirty rect. + resetDirty(); + + // TODO: should we verify that the plugin sent back the right values? + // Two size changes in a row may cause them to not match, due to queueing, etc. + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED); + } + else if(message_name == "cursor_changed") + { + mCursorName = message.getValue("name"); + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CURSOR_CHANGED); + } + else if(message_name == "edit_state") + { + if(message.hasValue("cut")) + { + mCanCut = message.getValueBoolean("cut"); + } + if(message.hasValue("copy")) + { + mCanCopy = message.getValueBoolean("copy"); + } + if(message.hasValue("paste")) + { + mCanPaste = message.getValueBoolean("paste"); + } + } + else if(message_name == "name_text") + { + mMediaName = message.getValue("name"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED); + } + else if(message_name == "pick_file") + { + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST); + } + else if(message_name == "auth_request") + { + mAuthURL = message.getValue("url"); + mAuthRealm = message.getValue("realm"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST); + } + else + { + LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) + { + std::string message_name = message.getName(); + if(message_name == "navigate_begin") + { + mNavigateURI = message.getValue("uri"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_BEGIN); + } + else if(message_name == "navigate_complete") + { + mNavigateURI = message.getValue("uri"); + mNavigateResultCode = message.getValueS32("result_code"); + mNavigateResultString = message.getValue("result_string"); + mHistoryBackAvailable = message.getValueBoolean("history_back_available"); + mHistoryForwardAvailable = message.getValueBoolean("history_forward_available"); + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE); + } + else if(message_name == "progress") + { + mProgressPercent = message.getValueS32("percent"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED); + } + else if(message_name == "status_text") + { + mStatusText = message.getValue("status"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_STATUS_TEXT_CHANGED); + } + else if(message_name == "location_changed") + { + mLocation = message.getValue("uri"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LOCATION_CHANGED); + } + else if(message_name == "click_href") + { + mClickURL = message.getValue("uri"); + mClickTarget = message.getValue("target"); + mClickUUID = message.getValue("uuid"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF); + } + else if(message_name == "click_nofollow") + { + mClickURL = message.getValue("uri"); + mClickNavType = message.getValue("nav_type"); + mClickTarget.clear(); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW); + } + else if(message_name == "navigate_error_page") + { + mStatusCode = message.getValueS32("status_code"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_ERROR_PAGE); + } + else if(message_name == "cookie_set") + { + if(mOwner) + { + mOwner->handleCookieSet(this, message.getValue("cookie")); + } + } + else if(message_name == "close_request") + { + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLOSE_REQUEST); + } + else if(message_name == "geometry_change") + { + mClickUUID = message.getValue("uuid"); + mGeometryX = message.getValueS32("x"); + mGeometryY = message.getValueS32("y"); + mGeometryWidth = message.getValueS32("width"); + mGeometryHeight = message.getValueS32("height"); + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE); + } + else if(message_name == "link_hovered") + { + // text is not currently used -- the tooltip hover text is taken from the "title". + mHoverLink = message.getValue("link"); + mHoverText = message.getValue("title"); + // message.getValue("text"); + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED); + } + else + { + LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) + { + std::string message_name = message.getName(); + + // This class hasn't defined any incoming messages yet. +// if(message_name == "message_name") +// { +// } +// else + { + LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; + } + } + +} + +/* virtual */ +void LLPluginClassMedia::pluginLaunchFailed() +{ + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH); +} + +/* virtual */ +void LLPluginClassMedia::pluginDied() +{ + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED); +} + +void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event) +{ + if(mOwner) + { + mOwner->handleMediaEvent(this, event); + } +} + +void LLPluginClassMedia::sendMessage(const LLPluginMessage &message) +{ + if(mPlugin && mPlugin->isRunning()) + { + mPlugin->sendMessage(message); + } + else + { + // The plugin isn't set up yet -- queue this message to be sent after initialization. + mSendQueue.push(message); + } +} + +//////////////////////////////////////////////////////////// +// MARK: media_browser class functions +bool LLPluginClassMedia::pluginSupportsMediaBrowser(void) +{ + std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER); + return !version.empty(); +} + +void LLPluginClassMedia::focus(bool focused) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus"); + + message.setValueBoolean("focused", focused); + + sendMessage(message); +} + +void LLPluginClassMedia::clear_cache() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache"); + sendMessage(message); +} + +void LLPluginClassMedia::clear_cookies() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cookies"); + sendMessage(message); +} + +void LLPluginClassMedia::set_cookies(const std::string &cookies) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies"); + message.setValue("cookies", cookies); + sendMessage(message); +} + +void LLPluginClassMedia::enable_cookies(bool enable) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies"); + message.setValueBoolean("enable", enable); + sendMessage(message); +} + +void LLPluginClassMedia::proxy_setup(bool enable, const std::string &host, int port) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup"); + + message.setValueBoolean("enable", enable); + message.setValue("host", host); + message.setValueS32("port", port); + + sendMessage(message); +} + +void LLPluginClassMedia::browse_stop() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_stop"); + sendMessage(message); +} + +void LLPluginClassMedia::browse_reload(bool ignore_cache) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload"); + + message.setValueBoolean("ignore_cache", ignore_cache); + + sendMessage(message); +} + +void LLPluginClassMedia::browse_forward() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_forward"); + sendMessage(message); +} + +void LLPluginClassMedia::browse_back() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_back"); + sendMessage(message); +} + +void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent"); + + message.setValue("user_agent", user_agent); + + sendMessage(message); +} + +void LLPluginClassMedia::proxyWindowOpened(const std::string &target, const std::string &uuid) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_opened"); + + message.setValue("target", target); + message.setValue("uuid", uuid); + + sendMessage(message); +} + +void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_closed"); + + message.setValue("uuid", uuid); + + sendMessage(message); +} + +void LLPluginClassMedia::ignore_ssl_cert_errors(bool ignore) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors"); + message.setValueBoolean("ignore", ignore); + sendMessage(message); +} + +void LLPluginClassMedia::addCertificateFilePath(const std::string& path) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "add_certificate_file_path"); + message.setValue("path", path); + sendMessage(message); +} + +void LLPluginClassMedia::crashPlugin() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash"); + + sendMessage(message); +} + +void LLPluginClassMedia::hangPlugin() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hang"); + + sendMessage(message); +} + + +//////////////////////////////////////////////////////////// +// MARK: media_time class functions +bool LLPluginClassMedia::pluginSupportsMediaTime(void) +{ + std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME); + return !version.empty(); +} + +void LLPluginClassMedia::stop() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "stop"); + sendMessage(message); +} + +void LLPluginClassMedia::start(float rate) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "start"); + + message.setValueReal("rate", rate); + + sendMessage(message); +} + +void LLPluginClassMedia::pause() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "pause"); + sendMessage(message); +} + +void LLPluginClassMedia::seek(float time) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek"); + + message.setValueReal("time", time); + + sendMessage(message); +} + +void LLPluginClassMedia::setLoop(bool loop) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_loop"); + + message.setValueBoolean("loop", loop); + + sendMessage(message); +} + +void LLPluginClassMedia::setVolume(float volume) +{ + if(volume != mRequestedVolume) + { + mRequestedVolume = volume; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume"); + + message.setValueReal("volume", volume); + + sendMessage(message); + } +} + +float LLPluginClassMedia::getVolume() +{ + return mRequestedVolume; +} + +void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history) +{ + // Send URL history to plugin + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "init_history"); + message.setValueLLSD("history", url_history); + sendMessage(message); + + LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL; +} + diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index cf8d8b26b9..015fb31252 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -1,416 +1,424 @@ -/** - * @file llpluginclassmedia.h - * @brief LLPluginClassMedia handles interaction with a plugin which knows about the "media" message class. - * - * @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 - */ - -#ifndef LL_LLPLUGINCLASSMEDIA_H -#define LL_LLPLUGINCLASSMEDIA_H - -#include "llgltypes.h" -#include "llpluginprocessparent.h" -#include "llrect.h" -#include "llpluginclassmediaowner.h" -#include -#include "v4color.h" - -class LLPluginClassMedia : public LLPluginProcessParentOwner -{ - LOG_CLASS(LLPluginClassMedia); -public: - LLPluginClassMedia(LLPluginClassMediaOwner *owner); - virtual ~LLPluginClassMedia(); - - // local initialization, called by the media manager when creating a source - virtual bool init(const std::string &launcher_filename, - const std::string &plugin_dir, - const std::string &plugin_filename, - bool debug); - - // undoes everything init() didm called by the media manager when destroying a source - virtual void reset(); - - void idle(void); - - // All of these may return 0 or an actual valid value. - // Callers need to check the return for 0, and not use the values in that case. - int getWidth() const { return (mMediaWidth > 0) ? mMediaWidth : 0; }; - int getHeight() const { return (mMediaHeight > 0) ? mMediaHeight : 0; }; - int getNaturalWidth() const { return mNaturalMediaWidth; }; - int getNaturalHeight() const { return mNaturalMediaHeight; }; - int getSetWidth() const { return mSetMediaWidth; }; - int getSetHeight() const { return mSetMediaHeight; }; - int getBitsWidth() const { return (mTextureWidth > 0) ? mTextureWidth : 0; }; - int getBitsHeight() const { return (mTextureHeight > 0) ? mTextureHeight : 0; }; - int getTextureWidth() const; - int getTextureHeight() const; - int getFullWidth() const { return mFullMediaWidth; }; - int getFullHeight() const { return mFullMediaHeight; }; - - // This may return NULL. Callers need to check for and handle this case. - unsigned char* getBitsData(); - - // gets the format details of the texture data - // These may return 0 if they haven't been set up yet. The caller needs to detect this case. - int getTextureDepth() const { return mRequestedTextureDepth; }; - int getTextureFormatInternal() const { return mRequestedTextureInternalFormat; }; - int getTextureFormatPrimary() const { return mRequestedTextureFormat; }; - int getTextureFormatType() const { return mRequestedTextureType; }; - bool getTextureFormatSwapBytes() const { return mRequestedTextureSwapBytes; }; - bool getTextureCoordsOpenGL() const { return mRequestedTextureCoordsOpenGL; }; - - void setSize(int width, int height); - void setAutoScale(bool auto_scale); - - void setBackgroundColor(LLColor4 color) { mBackgroundColor = color; }; - - void setOwner(LLPluginClassMediaOwner *owner) { mOwner = owner; }; - - // Returns true if all of the texture parameters (depth, format, size, and texture size) are set up and consistent. - // This will initially be false, and will also be false for some time after setSize while the resize is processed. - // Note that if this returns true, it is safe to use all the get() functions above without checking for invalid return values - // until you call idle() again. - bool textureValid(void); - - bool getDirty(LLRect *dirty_rect = NULL); - void resetDirty(void); - - typedef enum - { - MOUSE_EVENT_DOWN, - MOUSE_EVENT_UP, - MOUSE_EVENT_MOVE, - MOUSE_EVENT_DOUBLE_CLICK - }EMouseEventType; - - void mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers); - - typedef enum - { - KEY_EVENT_DOWN, - KEY_EVENT_UP, - KEY_EVENT_REPEAT - }EKeyEventType; - - bool keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data); - - void scrollEvent(int x, int y, MASK modifiers); - - // Text may be unicode (utf8 encoded) - bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data); - - void loadURI(const std::string &uri); - - // "Loading" means uninitialized or any state prior to fully running (processing commands) - bool isPluginLoading(void) { return mPlugin?mPlugin->isLoading():false; }; - - // "Running" means the steady state -- i.e. processing messages - bool isPluginRunning(void) { return mPlugin?mPlugin->isRunning():false; }; - - // "Exited" means any regular or error state after "Running" (plugin may have crashed or exited normally) - bool isPluginExited(void) { return mPlugin?mPlugin->isDone():false; }; - - std::string getPluginVersion() { return mPlugin?mPlugin->getPluginVersion():std::string(""); }; - - bool getDisableTimeout() { return mPlugin?mPlugin->getDisableTimeout():false; }; - void setDisableTimeout(bool disable) { if(mPlugin) mPlugin->setDisableTimeout(disable); }; - - // Inherited from LLPluginProcessParentOwner - /* virtual */ void receivePluginMessage(const LLPluginMessage &message); - /* virtual */ void pluginLaunchFailed(); - /* virtual */ void pluginDied(); - - - typedef enum - { - PRIORITY_UNLOADED, // media plugin isn't even loaded. - PRIORITY_STOPPED, // media is not playing, shouldn't need to update at all. - PRIORITY_HIDDEN, // media is not being displayed or is out of view, don't need to do graphic updates, but may still update audio, playhead, etc. - PRIORITY_SLIDESHOW, // media is in the far distance, updates very infrequently - PRIORITY_LOW, // media is in the distance, may be rendered at reduced size - PRIORITY_NORMAL, // normal (default) priority - PRIORITY_HIGH // media has user focus and/or is taking up most of the screen - }EPriority; - - static const char* priorityToString(EPriority priority); - void setPriority(EPriority priority); - void setLowPrioritySizeLimit(int size); - - F64 getCPUUsage(); - - void sendPickFileResponse(const std::string &file); - - void sendAuthResponse(bool ok, const std::string &username, const std::string &password); - - // Valid after a MEDIA_EVENT_CURSOR_CHANGED event - std::string getCursorName() const { return mCursorName; }; - - LLPluginClassMediaOwner::EMediaStatus getStatus() const { return mStatus; } - - void cut(); - bool canCut() const { return mCanCut; }; - - void copy(); - bool canCopy() const { return mCanCopy; }; - - void paste(); - bool canPaste() const { return mCanPaste; }; - - // These can be called before init(), and they will be queued and sent before the media init message. - void setUserDataPath(const std::string &user_data_path); - void setLanguageCode(const std::string &language_code); - void setPluginsEnabled(const bool enabled); - void setJavascriptEnabled(const bool enabled); - void setTarget(const std::string &target); - - /////////////////////////////////// - // media browser class functions - bool pluginSupportsMediaBrowser(void); - - void focus(bool focused); - void clear_cache(); - void clear_cookies(); - void set_cookies(const std::string &cookies); - void enable_cookies(bool enable); - void proxy_setup(bool enable, const std::string &host = LLStringUtil::null, int port = 0); - void browse_stop(); - void browse_reload(bool ignore_cache = false); - void browse_forward(); - void browse_back(); - void setBrowserUserAgent(const std::string& user_agent); - void proxyWindowOpened(const std::string &target, const std::string &uuid); - void proxyWindowClosed(const std::string &uuid); - void ignore_ssl_cert_errors(bool ignore); - void addCertificateFilePath(const std::string& path); - - // This is valid after MEDIA_EVENT_NAVIGATE_BEGIN or MEDIA_EVENT_NAVIGATE_COMPLETE - std::string getNavigateURI() const { return mNavigateURI; }; - - // These are valid after MEDIA_EVENT_NAVIGATE_COMPLETE - S32 getNavigateResultCode() const { return mNavigateResultCode; }; - std::string getNavigateResultString() const { return mNavigateResultString; }; - bool getHistoryBackAvailable() const { return mHistoryBackAvailable; }; - bool getHistoryForwardAvailable() const { return mHistoryForwardAvailable; }; - - // This is valid after MEDIA_EVENT_PROGRESS_UPDATED - int getProgressPercent() const { return mProgressPercent; }; - - // This is valid after MEDIA_EVENT_STATUS_TEXT_CHANGED - std::string getStatusText() const { return mStatusText; }; - - // This is valid after MEDIA_EVENT_LOCATION_CHANGED - std::string getLocation() const { return mLocation; }; - - // This is valid after MEDIA_EVENT_CLICK_LINK_HREF or MEDIA_EVENT_CLICK_LINK_NOFOLLOW - std::string getClickURL() const { return mClickURL; }; - - // This is valid after MEDIA_EVENT_CLICK_LINK_NOFOLLOW - std::string getClickNavType() const { return mClickNavType; }; - - // This is valid after MEDIA_EVENT_CLICK_LINK_HREF - std::string getClickTarget() const { return mClickTarget; }; - - // This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE - std::string getClickUUID() const { return mClickUUID; }; - - // This is valid after MEDIA_EVENT_NAVIGATE_ERROR_PAGE - S32 getStatusCode() const { return mStatusCode; }; - - // These are valid during MEDIA_EVENT_GEOMETRY_CHANGE - S32 getGeometryX() const { return mGeometryX; }; - S32 getGeometryY() const { return mGeometryY; }; - S32 getGeometryWidth() const { return mGeometryWidth; }; - S32 getGeometryHeight() const { return mGeometryHeight; }; - - // These are valid during MEDIA_EVENT_AUTH_REQUEST - std::string getAuthURL() const { return mAuthURL; }; - std::string getAuthRealm() const { return mAuthRealm; }; - - // These are valid during MEDIA_EVENT_LINK_HOVERED - std::string getHoverText() const { return mHoverText; }; - std::string getHoverLink() const { return mHoverLink; }; - - std::string getMediaName() const { return mMediaName; }; - std::string getMediaDescription() const { return mMediaDescription; }; - - // Crash the plugin. If you use this outside of a testbed, you will be punished. - void crashPlugin(); - - // Hang the plugin. If you use this outside of a testbed, you will be punished. - void hangPlugin(); - - /////////////////////////////////// - // media time class functions - bool pluginSupportsMediaTime(void); - void stop(); - void start(float rate = 0.0f); - void pause(); - void seek(float time); - void setLoop(bool loop); - void setVolume(float volume); - float getVolume(); - - F64 getCurrentTime(void) const { return mCurrentTime; }; - F64 getDuration(void) const { return mDuration; }; - F64 getCurrentPlayRate(void) { return mCurrentRate; }; - F64 getLoadedDuration(void) const { return mLoadedDuration; }; - - // Initialize the URL history of the plugin by sending - // "init_history" message - void initializeUrlHistory(const LLSD& url_history); - -protected: - - LLPluginClassMediaOwner *mOwner; - - // Notify this object's owner that an event has occurred. - void mediaEvent(LLPluginClassMediaOwner::EMediaEvent event); - - void sendMessage(const LLPluginMessage &message); // Send message internally, either queueing or sending directly. - std::queue mSendQueue; // Used to queue messages while the plugin initializes. - - void setSizeInternal(void); - - bool mTextureParamsReceived; // the mRequestedTexture* fields are only valid when this is true - S32 mRequestedTextureDepth; - LLGLenum mRequestedTextureInternalFormat; - LLGLenum mRequestedTextureFormat; - LLGLenum mRequestedTextureType; - bool mRequestedTextureSwapBytes; - bool mRequestedTextureCoordsOpenGL; - - std::string mTextureSharedMemoryName; - size_t mTextureSharedMemorySize; - - // True to scale requested media up to the full size of the texture (i.e. next power of two) - bool mAutoScaleMedia; - - // default media size for the plugin, from the texture_params message. - int mDefaultMediaWidth; - int mDefaultMediaHeight; - - // Size that has been requested by the plugin itself - int mNaturalMediaWidth; - int mNaturalMediaHeight; - - // Size that has been requested with setSize() - int mSetMediaWidth; - int mSetMediaHeight; - - // Full calculated media size (before auto-scale and downsample calculations) - int mFullMediaWidth; - int mFullMediaHeight; - - // Actual media size being set (after auto-scale) - int mRequestedMediaWidth; - int mRequestedMediaHeight; - - // Texture size calculated from actual media size - int mRequestedTextureWidth; - int mRequestedTextureHeight; - - // Size that the plugin has acknowledged - int mTextureWidth; - int mTextureHeight; - int mMediaWidth; - int mMediaHeight; - - float mRequestedVolume; - - // Priority of this media stream - EPriority mPriority; - int mLowPrioritySizeLimit; - - bool mAllowDownsample; - int mPadding; - - - LLPluginProcessParent *mPlugin; - - LLRect mDirtyRect; - - std::string translateModifiers(MASK modifiers); - - std::string mCursorName; - int mLastMouseX; - int mLastMouseY; - - LLPluginClassMediaOwner::EMediaStatus mStatus; - - F64 mSleepTime; - - bool mCanCut; - bool mCanCopy; - bool mCanPaste; - - std::string mMediaName; - std::string mMediaDescription; - - LLColor4 mBackgroundColor; - - std::string mTarget; - - ///////////////////////////////////////// - // media_browser class - std::string mNavigateURI; - S32 mNavigateResultCode; - std::string mNavigateResultString; - bool mHistoryBackAvailable; - bool mHistoryForwardAvailable; - std::string mStatusText; - int mProgressPercent; - std::string mLocation; - std::string mClickURL; - std::string mClickNavType; - std::string mClickTarget; - std::string mClickUUID; - S32 mGeometryX; - S32 mGeometryY; - S32 mGeometryWidth; - S32 mGeometryHeight; - S32 mStatusCode; - std::string mAuthURL; - std::string mAuthRealm; - std::string mHoverText; - std::string mHoverLink; - - ///////////////////////////////////////// - // media_time class - F64 mCurrentTime; - F64 mDuration; - F64 mCurrentRate; - F64 mLoadedDuration; - -//-------------------------------------- - //debug use only - // -private: - bool mDeleteOK ; -public: - void setDeleteOK(bool flag) { mDeleteOK = flag ;} -//-------------------------------------- -}; - -#endif // LL_LLPLUGINCLASSMEDIA_H +/** + * @file llpluginclassmedia.h + * @brief LLPluginClassMedia handles interaction with a plugin which knows about the "media" message class. + * + * @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 + */ + +#ifndef LL_LLPLUGINCLASSMEDIA_H +#define LL_LLPLUGINCLASSMEDIA_H + +#include "llgltypes.h" +#include "llpluginprocessparent.h" +#include "llrect.h" +#include "llpluginclassmediaowner.h" +#include +#include "v4color.h" + +class LLPluginClassMedia : public LLPluginProcessParentOwner +{ + LOG_CLASS(LLPluginClassMedia); +public: + LLPluginClassMedia(LLPluginClassMediaOwner *owner); + virtual ~LLPluginClassMedia(); + + // local initialization, called by the media manager when creating a source + virtual bool init(const std::string &launcher_filename, + const std::string &plugin_dir, + const std::string &plugin_filename, + bool debug); + + // undoes everything init() didm called by the media manager when destroying a source + virtual void reset(); + + void idle(void); + + // All of these may return 0 or an actual valid value. + // Callers need to check the return for 0, and not use the values in that case. + int getWidth() const { return (mMediaWidth > 0) ? mMediaWidth : 0; }; + int getHeight() const { return (mMediaHeight > 0) ? mMediaHeight : 0; }; + int getNaturalWidth() const { return mNaturalMediaWidth; }; + int getNaturalHeight() const { return mNaturalMediaHeight; }; + int getSetWidth() const { return mSetMediaWidth; }; + int getSetHeight() const { return mSetMediaHeight; }; + int getBitsWidth() const { return (mTextureWidth > 0) ? mTextureWidth : 0; }; + int getBitsHeight() const { return (mTextureHeight > 0) ? mTextureHeight : 0; }; + int getTextureWidth() const; + int getTextureHeight() const; + int getFullWidth() const { return mFullMediaWidth; }; + int getFullHeight() const { return mFullMediaHeight; }; + + // This may return NULL. Callers need to check for and handle this case. + unsigned char* getBitsData(); + + // gets the format details of the texture data + // These may return 0 if they haven't been set up yet. The caller needs to detect this case. + int getTextureDepth() const { return mRequestedTextureDepth; }; + int getTextureFormatInternal() const { return mRequestedTextureInternalFormat; }; + int getTextureFormatPrimary() const { return mRequestedTextureFormat; }; + int getTextureFormatType() const { return mRequestedTextureType; }; + bool getTextureFormatSwapBytes() const { return mRequestedTextureSwapBytes; }; + bool getTextureCoordsOpenGL() const { return mRequestedTextureCoordsOpenGL; }; + + void setSize(int width, int height); + void setAutoScale(bool auto_scale); + + void setBackgroundColor(LLColor4 color) { mBackgroundColor = color; }; + + void setOwner(LLPluginClassMediaOwner *owner) { mOwner = owner; }; + + // Returns true if all of the texture parameters (depth, format, size, and texture size) are set up and consistent. + // This will initially be false, and will also be false for some time after setSize while the resize is processed. + // Note that if this returns true, it is safe to use all the get() functions above without checking for invalid return values + // until you call idle() again. + bool textureValid(void); + + bool getDirty(LLRect *dirty_rect = NULL); + void resetDirty(void); + + typedef enum + { + MOUSE_EVENT_DOWN, + MOUSE_EVENT_UP, + MOUSE_EVENT_MOVE, + MOUSE_EVENT_DOUBLE_CLICK + }EMouseEventType; + + void mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers); + + typedef enum + { + KEY_EVENT_DOWN, + KEY_EVENT_UP, + KEY_EVENT_REPEAT + }EKeyEventType; + + bool keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data); + + void scrollEvent(int x, int y, MASK modifiers); + + // Javascript <-> viewer events + void jsExposeObjectEvent( bool expose ); + void jsValuesValidEvent( bool valid ); + void jsAgentLocationEvent( double x, double y, double z ); + void jsAgentLanguageEvent( const std::string& language ); + void jsAgentRegionEvent( const std::string& region_name ); + void jsAgentMaturityEvent( const std::string& maturity ); + + // Text may be unicode (utf8 encoded) + bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data); + + void loadURI(const std::string &uri); + + // "Loading" means uninitialized or any state prior to fully running (processing commands) + bool isPluginLoading(void) { return mPlugin?mPlugin->isLoading():false; }; + + // "Running" means the steady state -- i.e. processing messages + bool isPluginRunning(void) { return mPlugin?mPlugin->isRunning():false; }; + + // "Exited" means any regular or error state after "Running" (plugin may have crashed or exited normally) + bool isPluginExited(void) { return mPlugin?mPlugin->isDone():false; }; + + std::string getPluginVersion() { return mPlugin?mPlugin->getPluginVersion():std::string(""); }; + + bool getDisableTimeout() { return mPlugin?mPlugin->getDisableTimeout():false; }; + void setDisableTimeout(bool disable) { if(mPlugin) mPlugin->setDisableTimeout(disable); }; + + // Inherited from LLPluginProcessParentOwner + /* virtual */ void receivePluginMessage(const LLPluginMessage &message); + /* virtual */ void pluginLaunchFailed(); + /* virtual */ void pluginDied(); + + + typedef enum + { + PRIORITY_UNLOADED, // media plugin isn't even loaded. + PRIORITY_STOPPED, // media is not playing, shouldn't need to update at all. + PRIORITY_HIDDEN, // media is not being displayed or is out of view, don't need to do graphic updates, but may still update audio, playhead, etc. + PRIORITY_SLIDESHOW, // media is in the far distance, updates very infrequently + PRIORITY_LOW, // media is in the distance, may be rendered at reduced size + PRIORITY_NORMAL, // normal (default) priority + PRIORITY_HIGH // media has user focus and/or is taking up most of the screen + }EPriority; + + static const char* priorityToString(EPriority priority); + void setPriority(EPriority priority); + void setLowPrioritySizeLimit(int size); + + F64 getCPUUsage(); + + void sendPickFileResponse(const std::string &file); + + void sendAuthResponse(bool ok, const std::string &username, const std::string &password); + + // Valid after a MEDIA_EVENT_CURSOR_CHANGED event + std::string getCursorName() const { return mCursorName; }; + + LLPluginClassMediaOwner::EMediaStatus getStatus() const { return mStatus; } + + void cut(); + bool canCut() const { return mCanCut; }; + + void copy(); + bool canCopy() const { return mCanCopy; }; + + void paste(); + bool canPaste() const { return mCanPaste; }; + + // These can be called before init(), and they will be queued and sent before the media init message. + void setUserDataPath(const std::string &user_data_path); + void setLanguageCode(const std::string &language_code); + void setPluginsEnabled(const bool enabled); + void setJavascriptEnabled(const bool enabled); + void setTarget(const std::string &target); + + /////////////////////////////////// + // media browser class functions + bool pluginSupportsMediaBrowser(void); + + void focus(bool focused); + void clear_cache(); + void clear_cookies(); + void set_cookies(const std::string &cookies); + void enable_cookies(bool enable); + void proxy_setup(bool enable, const std::string &host = LLStringUtil::null, int port = 0); + void browse_stop(); + void browse_reload(bool ignore_cache = false); + void browse_forward(); + void browse_back(); + void setBrowserUserAgent(const std::string& user_agent); + void proxyWindowOpened(const std::string &target, const std::string &uuid); + void proxyWindowClosed(const std::string &uuid); + void ignore_ssl_cert_errors(bool ignore); + void addCertificateFilePath(const std::string& path); + + // This is valid after MEDIA_EVENT_NAVIGATE_BEGIN or MEDIA_EVENT_NAVIGATE_COMPLETE + std::string getNavigateURI() const { return mNavigateURI; }; + + // These are valid after MEDIA_EVENT_NAVIGATE_COMPLETE + S32 getNavigateResultCode() const { return mNavigateResultCode; }; + std::string getNavigateResultString() const { return mNavigateResultString; }; + bool getHistoryBackAvailable() const { return mHistoryBackAvailable; }; + bool getHistoryForwardAvailable() const { return mHistoryForwardAvailable; }; + + // This is valid after MEDIA_EVENT_PROGRESS_UPDATED + int getProgressPercent() const { return mProgressPercent; }; + + // This is valid after MEDIA_EVENT_STATUS_TEXT_CHANGED + std::string getStatusText() const { return mStatusText; }; + + // This is valid after MEDIA_EVENT_LOCATION_CHANGED + std::string getLocation() const { return mLocation; }; + + // This is valid after MEDIA_EVENT_CLICK_LINK_HREF or MEDIA_EVENT_CLICK_LINK_NOFOLLOW + std::string getClickURL() const { return mClickURL; }; + + // This is valid after MEDIA_EVENT_CLICK_LINK_NOFOLLOW + std::string getClickNavType() const { return mClickNavType; }; + + // This is valid after MEDIA_EVENT_CLICK_LINK_HREF + std::string getClickTarget() const { return mClickTarget; }; + + // This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE + std::string getClickUUID() const { return mClickUUID; }; + + // This is valid after MEDIA_EVENT_NAVIGATE_ERROR_PAGE + S32 getStatusCode() const { return mStatusCode; }; + + // These are valid during MEDIA_EVENT_GEOMETRY_CHANGE + S32 getGeometryX() const { return mGeometryX; }; + S32 getGeometryY() const { return mGeometryY; }; + S32 getGeometryWidth() const { return mGeometryWidth; }; + S32 getGeometryHeight() const { return mGeometryHeight; }; + + // These are valid during MEDIA_EVENT_AUTH_REQUEST + std::string getAuthURL() const { return mAuthURL; }; + std::string getAuthRealm() const { return mAuthRealm; }; + + // These are valid during MEDIA_EVENT_LINK_HOVERED + std::string getHoverText() const { return mHoverText; }; + std::string getHoverLink() const { return mHoverLink; }; + + std::string getMediaName() const { return mMediaName; }; + std::string getMediaDescription() const { return mMediaDescription; }; + + // Crash the plugin. If you use this outside of a testbed, you will be punished. + void crashPlugin(); + + // Hang the plugin. If you use this outside of a testbed, you will be punished. + void hangPlugin(); + + /////////////////////////////////// + // media time class functions + bool pluginSupportsMediaTime(void); + void stop(); + void start(float rate = 0.0f); + void pause(); + void seek(float time); + void setLoop(bool loop); + void setVolume(float volume); + float getVolume(); + + F64 getCurrentTime(void) const { return mCurrentTime; }; + F64 getDuration(void) const { return mDuration; }; + F64 getCurrentPlayRate(void) { return mCurrentRate; }; + F64 getLoadedDuration(void) const { return mLoadedDuration; }; + + // Initialize the URL history of the plugin by sending + // "init_history" message + void initializeUrlHistory(const LLSD& url_history); + +protected: + + LLPluginClassMediaOwner *mOwner; + + // Notify this object's owner that an event has occurred. + void mediaEvent(LLPluginClassMediaOwner::EMediaEvent event); + + void sendMessage(const LLPluginMessage &message); // Send message internally, either queueing or sending directly. + std::queue mSendQueue; // Used to queue messages while the plugin initializes. + + void setSizeInternal(void); + + bool mTextureParamsReceived; // the mRequestedTexture* fields are only valid when this is true + S32 mRequestedTextureDepth; + LLGLenum mRequestedTextureInternalFormat; + LLGLenum mRequestedTextureFormat; + LLGLenum mRequestedTextureType; + bool mRequestedTextureSwapBytes; + bool mRequestedTextureCoordsOpenGL; + + std::string mTextureSharedMemoryName; + size_t mTextureSharedMemorySize; + + // True to scale requested media up to the full size of the texture (i.e. next power of two) + bool mAutoScaleMedia; + + // default media size for the plugin, from the texture_params message. + int mDefaultMediaWidth; + int mDefaultMediaHeight; + + // Size that has been requested by the plugin itself + int mNaturalMediaWidth; + int mNaturalMediaHeight; + + // Size that has been requested with setSize() + int mSetMediaWidth; + int mSetMediaHeight; + + // Full calculated media size (before auto-scale and downsample calculations) + int mFullMediaWidth; + int mFullMediaHeight; + + // Actual media size being set (after auto-scale) + int mRequestedMediaWidth; + int mRequestedMediaHeight; + + // Texture size calculated from actual media size + int mRequestedTextureWidth; + int mRequestedTextureHeight; + + // Size that the plugin has acknowledged + int mTextureWidth; + int mTextureHeight; + int mMediaWidth; + int mMediaHeight; + + float mRequestedVolume; + + // Priority of this media stream + EPriority mPriority; + int mLowPrioritySizeLimit; + + bool mAllowDownsample; + int mPadding; + + + LLPluginProcessParent *mPlugin; + + LLRect mDirtyRect; + + std::string translateModifiers(MASK modifiers); + + std::string mCursorName; + int mLastMouseX; + int mLastMouseY; + + LLPluginClassMediaOwner::EMediaStatus mStatus; + + F64 mSleepTime; + + bool mCanCut; + bool mCanCopy; + bool mCanPaste; + + std::string mMediaName; + std::string mMediaDescription; + + LLColor4 mBackgroundColor; + + std::string mTarget; + + ///////////////////////////////////////// + // media_browser class + std::string mNavigateURI; + S32 mNavigateResultCode; + std::string mNavigateResultString; + bool mHistoryBackAvailable; + bool mHistoryForwardAvailable; + std::string mStatusText; + int mProgressPercent; + std::string mLocation; + std::string mClickURL; + std::string mClickNavType; + std::string mClickTarget; + std::string mClickUUID; + S32 mGeometryX; + S32 mGeometryY; + S32 mGeometryWidth; + S32 mGeometryHeight; + S32 mStatusCode; + std::string mAuthURL; + std::string mAuthRealm; + std::string mHoverText; + std::string mHoverLink; + + ///////////////////////////////////////// + // media_time class + F64 mCurrentTime; + F64 mDuration; + F64 mCurrentRate; + F64 mLoadedDuration; + +//-------------------------------------- + //debug use only + // +private: + bool mDeleteOK ; +public: + void setDeleteOK(bool flag) { mDeleteOK = flag ;} +//-------------------------------------- +}; + +#endif // LL_LLPLUGINCLASSMEDIA_H diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index 9ba8edbb59..b22dbc6604 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -1168,6 +1168,56 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) authResponse(message_in); } else + if(message_name == "js_expose_object") + { + bool expose_object = message_in.getValueBoolean( "expose" ); +#if LLQTWEBKIT_API_VERSION >= 9 + LLQtWebKit::getInstance()->setExposeObject( expose_object ); +#endif + } + else + if(message_name == "js_values_valid") + { + bool valid = message_in.getValueBoolean( "valid" ); +#if LLQTWEBKIT_API_VERSION >= 9 + LLQtWebKit::getInstance()->setValuesValid( valid ); +#endif + } + else + if(message_name == "js_agent_location") + { + F32 x = message_in.getValueReal("x"); + F32 y = message_in.getValueReal("y"); + F32 z = message_in.getValueReal("z"); +#if LLQTWEBKIT_API_VERSION >= 9 + LLQtWebKit::getInstance()->setAgentLocation( x, y, z ); +#endif + } + else + if(message_name == "js_agent_language") + { + const std::string& language = message_in.getValue("language"); +#if LLQTWEBKIT_API_VERSION >= 9 + LLQtWebKit::getInstance()->setAgentLanguage( language ); +#endif + } + else + if(message_name == "js_agent_region") + { + const std::string& region = message_in.getValue("region"); +#if LLQTWEBKIT_API_VERSION >= 9 + LLQtWebKit::getInstance()->setAgentRegion( region ); +#endif + } + else + if(message_name == "js_agent_maturity") + { + const std::string& maturity = message_in.getValue("maturity"); +#if LLQTWEBKIT_API_VERSION >= 9 + LLQtWebKit::getInstance()->setAgentMaturity( maturity ); +#endif + } + else { // std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl; } @@ -1324,4 +1374,3 @@ int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void return 0; } - diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index e6c2dc4413..8ecfccf727 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -708,6 +708,17 @@ Value 0 + BrowserEnableJSObject + + Comment + Enable or disable the viewer to Javascript bridge object. + Persist + 1 + Type + Boolean + Value + 0 + BlockAvatarAppearanceMessages Comment diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 037e22584f..62ae7ac6e2 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1,3692 +1,3742 @@ -/** - * @file llviewermedia.cpp - * @brief Client interface to the media engine - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llagent.h" -#include "llagentcamera.h" -#include "llviewermedia.h" -#include "llviewermediafocus.h" -#include "llmimetypes.h" -#include "llmediaentry.h" -#include "llversioninfo.h" -#include "llviewercontrol.h" -#include "llviewertexture.h" -#include "llviewerparcelmedia.h" -#include "llviewerparcelmgr.h" -#include "llviewertexturelist.h" -#include "llvovolume.h" -#include "llpluginclassmedia.h" -#include "llplugincookiestore.h" -#include "llviewerwindow.h" -#include "llfocusmgr.h" -#include "llcallbacklist.h" -#include "llparcel.h" -#include "llaudioengine.h" // for gAudiop -#include "llurldispatcher.h" -#include "llvoavatar.h" -#include "llvoavatarself.h" -#include "llviewerregion.h" -#include "llwebsharing.h" // For LLWebSharing::setOpenIDCookie(), *TODO: find a better way to do this! -#include "llfilepicker.h" -#include "llnotifications.h" -#include "lldir.h" -#include "llevent.h" // LLSimpleListener -#include "llnotificationsutil.h" -#include "lluuid.h" -#include "llkeyboard.h" -#include "llmutelist.h" -#include "llpanelprofile.h" -#include "llappviewer.h" -//#include "llfirstuse.h" -#include "llwindow.h" - -#include "llfloatermediabrowser.h" // for handling window close requests and geometry change requests in media browser windows. -#include "llfloaterwebcontent.h" // for handling window close requests and geometry change requests in media browser windows. - -#include // for SkinFolder listener -#include - -/*static*/ const char* LLViewerMedia::AUTO_PLAY_MEDIA_SETTING = "ParcelMediaAutoPlayEnable"; -/*static*/ const char* LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING = "MediaShowOnOthers"; -/*static*/ const char* LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING = "MediaShowWithinParcel"; -/*static*/ const char* LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING = "MediaShowOutsideParcel"; - - -// Move this to its own file. - -LLViewerMediaEventEmitter::~LLViewerMediaEventEmitter() -{ - observerListType::iterator iter = mObservers.begin(); - - while( iter != mObservers.end() ) - { - LLViewerMediaObserver *self = *iter; - iter++; - remObserver(self); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaEventEmitter::addObserver( LLViewerMediaObserver* observer ) -{ - if ( ! observer ) - return false; - - if ( std::find( mObservers.begin(), mObservers.end(), observer ) != mObservers.end() ) - return false; - - mObservers.push_back( observer ); - observer->mEmitters.push_back( this ); - - return true; -} - -/////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaEventEmitter::remObserver( LLViewerMediaObserver* observer ) -{ - if ( ! observer ) - return false; - - mObservers.remove( observer ); - observer->mEmitters.remove(this); - - return true; -} - -/////////////////////////////////////////////////////////////////////////////// -// -void LLViewerMediaEventEmitter::emitEvent( LLPluginClassMedia* media, LLViewerMediaObserver::EMediaEvent event ) -{ - // Broadcast the event to any observers. - observerListType::iterator iter = mObservers.begin(); - while( iter != mObservers.end() ) - { - LLViewerMediaObserver *self = *iter; - ++iter; - self->handleMediaEvent( media, event ); - } -} - -// Move this to its own file. -LLViewerMediaObserver::~LLViewerMediaObserver() -{ - std::list::iterator iter = mEmitters.begin(); - - while( iter != mEmitters.end() ) - { - LLViewerMediaEventEmitter *self = *iter; - iter++; - self->remObserver( this ); - } -} - - -// Move this to its own file. -// helper class that tries to download a URL from a web site and calls a method -// on the Panel Land Media and to discover the MIME type -class LLMimeDiscoveryResponder : public LLHTTPClient::Responder -{ -LOG_CLASS(LLMimeDiscoveryResponder); -public: - LLMimeDiscoveryResponder( viewer_media_t media_impl) - : mMediaImpl(media_impl), - mInitialized(false) - { - if(mMediaImpl->mMimeTypeProbe != NULL) - { - llerrs << "impl already has an outstanding responder" << llendl; - } - - mMediaImpl->mMimeTypeProbe = this; - } - - ~LLMimeDiscoveryResponder() - { - disconnectOwner(); - } - - virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) - { - std::string media_type = content["content-type"].asString(); - std::string::size_type idx1 = media_type.find_first_of(";"); - std::string mime_type = media_type.substr(0, idx1); - - lldebugs << "status is " << status << ", media type \"" << media_type << "\"" << llendl; - - // 2xx status codes indicate success. - // Most 4xx status codes are successful enough for our purposes. - // 499 is the error code for host not found, timeout, etc. - // 500 means "Internal Server error" but we decided it's okay to - // accept this and go past it in the MIME type probe - // 302 means the resource can be found temporarily in a different place - added this for join.secondlife.com - // 499 is a code specifc to join.secondlife.com (????) apparently safe to ignore -// if( ((status >= 200) && (status < 300)) || -// ((status >= 400) && (status < 499)) || -// (status == 500) || -// (status == 302) || -// (status == 499) -// ) - // We now no longer check the error code returned from the probe. - // If we have a mime type, use it. If not, default to the web plugin and let it handle error reporting. - if(1) - { - // The probe was successful. - if(mime_type.empty()) - { - // Some sites don't return any content-type header at all. - // Treat an empty mime type as text/html. - mime_type = "text/html"; - } - - completeAny(status, mime_type); - } - else - { - llwarns << "responder failed with status " << status << ", reason " << reason << llendl; - - if(mMediaImpl) - { - mMediaImpl->mMediaSourceFailed = true; - } - } - - } - - void completeAny(U32 status, const std::string& mime_type) - { - // the call to initializeMedia may disconnect the responder, which will clear mMediaImpl. - // Make a local copy so we can call loadURI() afterwards. - LLViewerMediaImpl *impl = mMediaImpl; - - if(impl && !mInitialized && ! mime_type.empty()) - { - if(impl->initializeMedia(mime_type)) - { - mInitialized = true; - impl->loadURI(); - disconnectOwner(); - } - } - } - - void cancelRequest() - { - disconnectOwner(); - } - -private: - void disconnectOwner() - { - if(mMediaImpl) - { - if(mMediaImpl->mMimeTypeProbe != this) - { - llerrs << "internal error: mMediaImpl->mMimeTypeProbe != this" << llendl; - } - - mMediaImpl->mMimeTypeProbe = NULL; - } - mMediaImpl = NULL; - } - - -public: - LLViewerMediaImpl *mMediaImpl; - bool mInitialized; -}; - -class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder -{ -LOG_CLASS(LLViewerMediaOpenIDResponder); -public: - LLViewerMediaOpenIDResponder( ) - { - } - - ~LLViewerMediaOpenIDResponder() - { - } - - /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) - { - LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; - LL_DEBUGS("MediaAuth") << content << LL_ENDL; - std::string cookie = content["set-cookie"].asString(); - - LLViewerMedia::openIDCookieResponse(cookie); - } - - /* virtual */ void completedRaw( - U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - // This is just here to disable the default behavior (attempting to parse the response as llsd). - // We don't care about the content of the response, only the set-cookie header. - } - -}; - -class LLViewerMediaWebProfileResponder : public LLHTTPClient::Responder -{ -LOG_CLASS(LLViewerMediaWebProfileResponder); -public: - LLViewerMediaWebProfileResponder(std::string host) - { - mHost = host; - } - - ~LLViewerMediaWebProfileResponder() - { - } - - /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) - { - LL_WARNS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; - LL_WARNS("MediaAuth") << content << LL_ENDL; - - std::string cookie = content["set-cookie"].asString(); - - LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost); - } - - void completedRaw( - U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - // This is just here to disable the default behavior (attempting to parse the response as llsd). - // We don't care about the content of the response, only the set-cookie header. - } - - std::string mHost; -}; - - -LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL; -LLURL LLViewerMedia::sOpenIDURL; -std::string LLViewerMedia::sOpenIDCookie; -LLPluginClassMedia* LLViewerMedia::sSpareBrowserMediaSource = NULL; -static LLViewerMedia::impl_list sViewerMediaImplList; -static LLViewerMedia::impl_id_map sViewerMediaTextureIDMap; -static LLTimer sMediaCreateTimer; -static const F32 LLVIEWERMEDIA_CREATE_DELAY = 1.0f; -static F32 sGlobalVolume = 1.0f; -static F64 sLowestLoadableImplInterest = 0.0f; -static bool sAnyMediaShowing = false; -static boost::signals2::connection sTeleportFinishConnection; -static std::string sUpdatedCookies; -static const char *PLUGIN_COOKIE_FILE_NAME = "plugin_cookies.txt"; - -////////////////////////////////////////////////////////////////////////////////////////// -static void add_media_impl(LLViewerMediaImpl* media) -{ - sViewerMediaImplList.push_back(media); -} - -////////////////////////////////////////////////////////////////////////////////////////// -static void remove_media_impl(LLViewerMediaImpl* media) -{ - LLViewerMedia::impl_list::iterator iter = sViewerMediaImplList.begin(); - LLViewerMedia::impl_list::iterator end = sViewerMediaImplList.end(); - - for(; iter != end; iter++) - { - if(media == *iter) - { - sViewerMediaImplList.erase(iter); - return; - } - } -} - -class LLViewerMediaMuteListObserver : public LLMuteListObserver -{ - /* virtual */ void onChange() { LLViewerMedia::muteListChanged();} -}; - -static LLViewerMediaMuteListObserver sViewerMediaMuteListObserver; -static bool sViewerMediaMuteListObserverInitialized = false; -static bool sInWorldMediaDisabled = false; - - -////////////////////////////////////////////////////////////////////////////////////////// -// LLViewerMedia - -////////////////////////////////////////////////////////////////////////////////////////// -// static -viewer_media_t LLViewerMedia::newMediaImpl( - const LLUUID& texture_id, - S32 media_width, - S32 media_height, - U8 media_auto_scale, - U8 media_loop) -{ - LLViewerMediaImpl* media_impl = getMediaImplFromTextureID(texture_id); - if(media_impl == NULL || texture_id.isNull()) - { - // Create the media impl - media_impl = new LLViewerMediaImpl(texture_id, media_width, media_height, media_auto_scale, media_loop); - } - else - { - media_impl->unload(); - media_impl->setTextureID(texture_id); - media_impl->mMediaWidth = media_width; - media_impl->mMediaHeight = media_height; - media_impl->mMediaAutoScale = media_auto_scale; - media_impl->mMediaLoop = media_loop; - } - - return media_impl; -} - -viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const std::string& previous_url, bool update_from_self) -{ - // Try to find media with the same media ID - viewer_media_t media_impl = getMediaImplFromTextureID(media_entry->getMediaID()); - - lldebugs << "called, current URL is \"" << media_entry->getCurrentURL() - << "\", previous URL is \"" << previous_url - << "\", update_from_self is " << (update_from_self?"true":"false") - << llendl; - - bool was_loaded = false; - bool needs_navigate = false; - - if(media_impl) - { - was_loaded = media_impl->hasMedia(); - - media_impl->setHomeURL(media_entry->getHomeURL()); - - media_impl->mMediaAutoScale = media_entry->getAutoScale(); - media_impl->mMediaLoop = media_entry->getAutoLoop(); - media_impl->mMediaWidth = media_entry->getWidthPixels(); - media_impl->mMediaHeight = media_entry->getHeightPixels(); - media_impl->mMediaAutoPlay = media_entry->getAutoPlay(); - media_impl->mMediaEntryURL = media_entry->getCurrentURL(); - if (media_impl->mMediaSource) - { - media_impl->mMediaSource->setAutoScale(media_impl->mMediaAutoScale); - media_impl->mMediaSource->setLoop(media_impl->mMediaLoop); - media_impl->mMediaSource->setSize(media_entry->getWidthPixels(), media_entry->getHeightPixels()); - } - - bool url_changed = (media_impl->mMediaEntryURL != previous_url); - if(media_impl->mMediaEntryURL.empty()) - { - if(url_changed) - { - // The current media URL is now empty. Unload the media source. - media_impl->unload(); - - lldebugs << "Unloading media instance (new current URL is empty)." << llendl; - } - } - else - { - // The current media URL is not empty. - // If (the media was already loaded OR the media was set to autoplay) AND this update didn't come from this agent, - // do a navigate. - bool auto_play = media_impl->isAutoPlayable(); - if((was_loaded || auto_play) && !update_from_self) - { - needs_navigate = url_changed; - } - - lldebugs << "was_loaded is " << (was_loaded?"true":"false") - << ", auto_play is " << (auto_play?"true":"false") - << ", needs_navigate is " << (needs_navigate?"true":"false") << llendl; - } - } - else - { - media_impl = newMediaImpl( - media_entry->getMediaID(), - media_entry->getWidthPixels(), - media_entry->getHeightPixels(), - media_entry->getAutoScale(), - media_entry->getAutoLoop()); - - media_impl->setHomeURL(media_entry->getHomeURL()); - media_impl->mMediaAutoPlay = media_entry->getAutoPlay(); - media_impl->mMediaEntryURL = media_entry->getCurrentURL(); - if(media_impl->isAutoPlayable()) - { - needs_navigate = true; - } - } - - if(media_impl) - { - if(needs_navigate) - { - media_impl->navigateTo(media_impl->mMediaEntryURL, "", true, true); - lldebugs << "navigating to URL " << media_impl->mMediaEntryURL << llendl; - } - else if(!media_impl->mMediaURL.empty() && (media_impl->mMediaURL != media_impl->mMediaEntryURL)) - { - // If we already have a non-empty media URL set and we aren't doing a navigate, update the media URL to match the media entry. - media_impl->mMediaURL = media_impl->mMediaEntryURL; - - // If this causes a navigate at some point (such as after a reload), it should be considered server-driven so it isn't broadcast. - media_impl->mNavigateServerRequest = true; - - lldebugs << "updating URL in the media impl to " << media_impl->mMediaEntryURL << llendl; - } - } - - return media_impl; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -LLViewerMediaImpl* LLViewerMedia::getMediaImplFromTextureID(const LLUUID& texture_id) -{ - LLViewerMediaImpl* result = NULL; - - // Look up the texture ID in the texture id->impl map. - impl_id_map::iterator iter = sViewerMediaTextureIDMap.find(texture_id); - if(iter != sViewerMediaTextureIDMap.end()) - { - result = iter->second; - } - - return result; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -std::string LLViewerMedia::getCurrentUserAgent() -{ - // Don't use user-visible string to avoid - // punctuation and strange characters. - std::string skin_name = gSavedSettings.getString("SkinCurrent"); - - // Just in case we need to check browser differences in A/B test - // builds. - std::string channel = LLVersionInfo::getChannel(); - - // append our magic version number string to the browser user agent id - // See the HTTP 1.0 and 1.1 specifications for allowed formats: - // http://www.ietf.org/rfc/rfc1945.txt section 10.15 - // http://www.ietf.org/rfc/rfc2068.txt section 3.8 - // This was also helpful: - // http://www.mozilla.org/build/revised-user-agent-strings.html - std::ostringstream codec; - codec << "SecondLife/"; - codec << LLVersionInfo::getVersion(); - codec << " (" << channel << "; " << skin_name << " skin)"; - llinfos << codec.str() << llendl; - - return codec.str(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::updateBrowserUserAgent() -{ - std::string user_agent = getCurrentUserAgent(); - - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - - for(; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - if(pimpl->mMediaSource && pimpl->mMediaSource->pluginSupportsMediaBrowser()) - { - pimpl->mMediaSource->setBrowserUserAgent(user_agent); - } - } - -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::handleSkinCurrentChanged(const LLSD& /*newvalue*/) -{ - // gSavedSettings is already updated when this function is called. - updateBrowserUserAgent(); - return true; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::textureHasMedia(const LLUUID& texture_id) -{ - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - - for(; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - if(pimpl->getMediaTextureID() == texture_id) - { - return true; - } - } - return false; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::setVolume(F32 volume) -{ - if(volume != sGlobalVolume) - { - sGlobalVolume = volume; - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - - for(; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - pimpl->updateVolume(); - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -F32 LLViewerMedia::getVolume() -{ - return sGlobalVolume; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::muteListChanged() -{ - // When the mute list changes, we need to check mute status on all impls. - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - - for(; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - pimpl->mNeedsMuteCheck = true; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::setInWorldMediaDisabled(bool disabled) -{ - sInWorldMediaDisabled = disabled; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::getInWorldMediaDisabled() -{ - return sInWorldMediaDisabled; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::isInterestingEnough(const LLVOVolume *object, const F64 &object_interest) -{ - bool result = false; - - if (NULL == object) - { - result = false; - } - // Focused? Then it is interesting! - else if (LLViewerMediaFocus::getInstance()->getFocusedObjectID() == object->getID()) - { - result = true; - } - // Selected? Then it is interesting! - // XXX Sadly, 'contains()' doesn't take a const :( - else if (LLSelectMgr::getInstance()->getSelection()->contains(const_cast(object))) - { - result = true; - } - else - { - lldebugs << "object interest = " << object_interest << ", lowest loadable = " << sLowestLoadableImplInterest << llendl; - if(object_interest >= sLowestLoadableImplInterest) - result = true; - } - - return result; -} - -LLViewerMedia::impl_list &LLViewerMedia::getPriorityList() -{ - return sViewerMediaImplList; -} - -// This is the predicate function used to sort sViewerMediaImplList by priority. -bool LLViewerMedia::priorityComparitor(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2) -{ - if(i1->isForcedUnloaded() && !i2->isForcedUnloaded()) - { - // Muted or failed items always go to the end of the list, period. - return false; - } - else if(i2->isForcedUnloaded() && !i1->isForcedUnloaded()) - { - // Muted or failed items always go to the end of the list, period. - return true; - } - else if(i1->hasFocus()) - { - // The item with user focus always comes to the front of the list, period. - return true; - } - else if(i2->hasFocus()) - { - // The item with user focus always comes to the front of the list, period. - return false; - } - else if(i1->isParcelMedia()) - { - // The parcel media impl sorts above all other inworld media, unless one has focus. - return true; - } - else if(i2->isParcelMedia()) - { - // The parcel media impl sorts above all other inworld media, unless one has focus. - return false; - } - else if(i1->getUsedInUI() && !i2->getUsedInUI()) - { - // i1 is a UI element, i2 is not. This makes i1 "less than" i2, so it sorts earlier in our list. - return true; - } - else if(i2->getUsedInUI() && !i1->getUsedInUI()) - { - // i2 is a UI element, i1 is not. This makes i2 "less than" i1, so it sorts earlier in our list. - return false; - } - else if(i1->isPlayable() && !i2->isPlayable()) - { - // Playable items sort above ones that wouldn't play even if they got high enough priority - return true; - } - else if(!i1->isPlayable() && i2->isPlayable()) - { - // Playable items sort above ones that wouldn't play even if they got high enough priority - return false; - } - else if(i1->getInterest() == i2->getInterest()) - { - // Generally this will mean both objects have zero interest. In this case, sort on distance. - return (i1->getProximityDistance() < i2->getProximityDistance()); - } - else - { - // The object with the larger interest value should be earlier in the list, so we reverse the sense of the comparison here. - return (i1->getInterest() > i2->getInterest()); - } -} - -static bool proximity_comparitor(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2) -{ - if(i1->getProximityDistance() < i2->getProximityDistance()) - { - return true; - } - else if(i1->getProximityDistance() > i2->getProximityDistance()) - { - return false; - } - else - { - // Both objects have the same distance. This most likely means they're two faces of the same object. - // They may also be faces on different objects with exactly the same distance (like HUD objects). - // We don't actually care what the sort order is for this case, as long as it's stable and doesn't change when you enable/disable media. - // Comparing the impl pointers gives a completely arbitrary ordering, but it will be stable. - return (i1 < i2); - } -} - -static LLFastTimer::DeclareTimer FTM_MEDIA_UPDATE("Update Media"); - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::updateMedia(void *dummy_arg) -{ - LLFastTimer t1(FTM_MEDIA_UPDATE); - - // Enable/disable the plugin read thread - LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread")); - - // HACK: we always try to keep a spare running webkit plugin around to improve launch times. - createSpareBrowserMediaSource(); - - sAnyMediaShowing = false; - sUpdatedCookies = getCookieStore()->getChangedCookies(); - if(!sUpdatedCookies.empty()) - { - lldebugs << "updated cookies will be sent to all loaded plugins: " << llendl; - lldebugs << sUpdatedCookies << llendl; - } - - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - - for(; iter != end;) - { - LLViewerMediaImpl* pimpl = *iter++; - pimpl->update(); - pimpl->calculateInterest(); - } - - // Let the spare media source actually launch - if(sSpareBrowserMediaSource) - { - sSpareBrowserMediaSource->idle(); - } - - // Sort the static instance list using our interest criteria - sViewerMediaImplList.sort(priorityComparitor); - - // Go through the list again and adjust according to priority. - iter = sViewerMediaImplList.begin(); - end = sViewerMediaImplList.end(); - - F64 total_cpu = 0.0f; - int impl_count_total = 0; - int impl_count_interest_low = 0; - int impl_count_interest_normal = 0; - - std::vector proximity_order; - - bool inworld_media_enabled = gSavedSettings.getBOOL("AudioStreamingMedia"); - bool inworld_audio_enabled = gSavedSettings.getBOOL("AudioStreamingMusic"); - U32 max_instances = gSavedSettings.getU32("PluginInstancesTotal"); - U32 max_normal = gSavedSettings.getU32("PluginInstancesNormal"); - U32 max_low = gSavedSettings.getU32("PluginInstancesLow"); - F32 max_cpu = gSavedSettings.getF32("PluginInstancesCPULimit"); - // Setting max_cpu to 0.0 disables CPU usage checking. - bool check_cpu_usage = (max_cpu != 0.0f); - - LLViewerMediaImpl* lowest_interest_loadable = NULL; - - // Notes on tweakable params: - // max_instances must be set high enough to allow the various instances used in the UI (for the help browser, search, etc.) to be loaded. - // If max_normal + max_low is less than max_instances, things will tend to get unloaded instead of being set to slideshow. - - for(; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - - LLPluginClassMedia::EPriority new_priority = LLPluginClassMedia::PRIORITY_NORMAL; - - if(pimpl->isForcedUnloaded() || (impl_count_total >= (int)max_instances)) - { - // Never load muted or failed impls. - // Hard limit on the number of instances that will be loaded at one time - new_priority = LLPluginClassMedia::PRIORITY_UNLOADED; - } - else if(!pimpl->getVisible()) - { - new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; - } - else if(pimpl->hasFocus()) - { - new_priority = LLPluginClassMedia::PRIORITY_HIGH; - impl_count_interest_normal++; // count this against the count of "normal" instances for priority purposes - } - else if(pimpl->getUsedInUI()) - { - new_priority = LLPluginClassMedia::PRIORITY_NORMAL; - impl_count_interest_normal++; - } - else if(pimpl->isParcelMedia()) - { - new_priority = LLPluginClassMedia::PRIORITY_NORMAL; - impl_count_interest_normal++; - } - else - { - // Look at interest and CPU usage for instances that aren't in any of the above states. - - // Heuristic -- if the media texture's approximate screen area is less than 1/4 of the native area of the texture, - // turn it down to low instead of normal. This may downsample for plugins that support it. - bool media_is_small = false; - F64 approximate_interest = pimpl->getApproximateTextureInterest(); - if(approximate_interest == 0.0f) - { - // this media has no current size, which probably means it's not loaded. - media_is_small = true; - } - else if(pimpl->getInterest() < (approximate_interest / 4)) - { - media_is_small = true; - } - - if(pimpl->getInterest() == 0.0f) - { - // This media is completely invisible, due to being outside the view frustrum or out of range. - new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; - } - else if(check_cpu_usage && (total_cpu > max_cpu)) - { - // Higher priority plugins have already used up the CPU budget. Set remaining ones to slideshow priority. - new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW; - } - else if((impl_count_interest_normal < (int)max_normal) && !media_is_small) - { - // Up to max_normal inworld get normal priority - new_priority = LLPluginClassMedia::PRIORITY_NORMAL; - impl_count_interest_normal++; - } - else if (impl_count_interest_low + impl_count_interest_normal < (int)max_low + (int)max_normal) - { - // The next max_low inworld get turned down - new_priority = LLPluginClassMedia::PRIORITY_LOW; - impl_count_interest_low++; - - // Set the low priority size for downsampling to approximately the size the texture is displayed at. - { - F32 approximate_interest_dimension = fsqrtf(pimpl->getInterest()); - - pimpl->setLowPrioritySizeLimit(llround(approximate_interest_dimension)); - } - } - else - { - // Any additional impls (up to max_instances) get very infrequent time - new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW; - } - } - - if(!pimpl->getUsedInUI() && (new_priority != LLPluginClassMedia::PRIORITY_UNLOADED)) - { - // This is a loadable inworld impl -- the last one in the list in this class defines the lowest loadable interest. - lowest_interest_loadable = pimpl; - - impl_count_total++; - } - - // Overrides if the window is minimized or we lost focus (taking care - // not to accidentally "raise" the priority either) - if (!gViewerWindow->getActive() /* viewer window minimized? */ - && new_priority > LLPluginClassMedia::PRIORITY_HIDDEN) - { - new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; - } - else if (!gFocusMgr.getAppHasFocus() /* viewer window lost focus? */ - && new_priority > LLPluginClassMedia::PRIORITY_LOW) - { - new_priority = LLPluginClassMedia::PRIORITY_LOW; - } - - if(!inworld_media_enabled) - { - // If inworld media is locked out, force all inworld media to stay unloaded. - if(!pimpl->getUsedInUI()) - { - new_priority = LLPluginClassMedia::PRIORITY_UNLOADED; - } - } - // update the audio stream here as well - if( !inworld_audio_enabled) - { - if(LLViewerMedia::isParcelAudioPlaying() && gAudiop && LLViewerMedia::hasParcelAudio()) - { - gAudiop->stopInternetStream(); - } - } - pimpl->setPriority(new_priority); - - if(pimpl->getUsedInUI()) - { - // Any impls used in the UI should not be in the proximity list. - pimpl->mProximity = -1; - } - else - { - proximity_order.push_back(pimpl); - } - - total_cpu += pimpl->getCPUUsage(); - - if (!pimpl->getUsedInUI() && pimpl->hasMedia()) - { - sAnyMediaShowing = true; - } - - } - - // Re-calculate this every time. - sLowestLoadableImplInterest = 0.0f; - - // Only do this calculation if we've hit the impl count limit -- up until that point we always need to load media data. - if(lowest_interest_loadable && (impl_count_total >= (int)max_instances)) - { - // Get the interest value of this impl's object for use by isInterestingEnough - LLVOVolume *object = lowest_interest_loadable->getSomeObject(); - if(object) - { - // NOTE: Don't use getMediaInterest() here. We want the pixel area, not the total media interest, - // so that we match up with the calculation done in LLMediaDataClient. - sLowestLoadableImplInterest = object->getPixelArea(); - } - } - - if(gSavedSettings.getBOOL("MediaPerformanceManagerDebug")) - { - // Give impls the same ordering as the priority list - // they're already in the right order for this. - } - else - { - // Use a distance-based sort for proximity values. - std::stable_sort(proximity_order.begin(), proximity_order.end(), proximity_comparitor); - } - - // Transfer the proximity order to the proximity fields in the objects. - for(int i = 0; i < (int)proximity_order.size(); i++) - { - proximity_order[i]->mProximity = i; - } - - LL_DEBUGS("PluginPriority") << "Total reported CPU usage is " << total_cpu << llendl; - -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::isAnyMediaShowing() -{ - return sAnyMediaShowing; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::setAllMediaEnabled(bool val) -{ - // Set "tentative" autoplay first. We need to do this here or else - // re-enabling won't start up the media below. - gSavedSettings.setBOOL("MediaTentativeAutoPlay", val); - - // Then - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - - for(; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - if (!pimpl->getUsedInUI()) - { - pimpl->setDisabled(!val); - } - } - - // Also do Parcel Media and Parcel Audio - if (val) - { - if (!LLViewerMedia::isParcelMediaPlaying() && LLViewerMedia::hasParcelMedia()) - { - LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel()); - } - - if (gSavedSettings.getBOOL("AudioStreamingMusic") && - !LLViewerMedia::isParcelAudioPlaying() && - gAudiop && - LLViewerMedia::hasParcelAudio()) - { - gAudiop->startInternetStream(LLViewerMedia::getParcelAudioURL()); - } - } - else { - // This actually unloads the impl, as opposed to "stop"ping the media - LLViewerParcelMedia::stop(); - if (gAudiop) gAudiop->stopInternetStream(); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::isParcelMediaPlaying() -{ - return (LLViewerMedia::hasParcelMedia() && LLViewerParcelMedia::getParcelMedia() && LLViewerParcelMedia::getParcelMedia()->hasMedia()); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::isParcelAudioPlaying() -{ - return (LLViewerMedia::hasParcelAudio() && gAudiop && LLAudioEngine::AUDIO_PLAYING == gAudiop->isInternetStreamPlaying()); -} - -void LLViewerMedia::onAuthSubmit(const LLSD& notification, const LLSD& response) -{ - LLViewerMediaImpl *impl = LLViewerMedia::getMediaImplFromTextureID(notification["payload"]["media_id"]); - if(impl) - { - LLPluginClassMedia* media = impl->getMediaPlugin(); - if(media) - { - if (response["ok"]) - { - media->sendAuthResponse(true, response["username"], response["password"]); - } - else - { - media->sendAuthResponse(false, "", ""); - } - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::clearAllCookies() -{ - // Clear all cookies for all plugins - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - for (; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - if(pimpl->mMediaSource) - { - pimpl->mMediaSource->clear_cookies(); - } - } - - // Clear all cookies from the cookie store - getCookieStore()->setAllCookies(""); - - // FIXME: this may not be sufficient, since the on-disk cookie file won't get written until some browser instance exits cleanly. - // It also won't clear cookies for other accounts, or for any account if we're not logged in, and won't do anything at all if there are no webkit plugins loaded. - // Until such time as we can centralize cookie storage, the following hack should cover these cases: - - // HACK: Look for cookie files in all possible places and delete them. - // NOTE: this assumes knowledge of what happens inside the webkit plugin (it's what adds 'browser_profile' to the path and names the cookie file) - - // Places that cookie files can be: - // /browser_profile/cookies - // /first_last/browser_profile/cookies (note that there may be any number of these!) - // /first_last/plugin_cookies.txt (note that there may be any number of these!) - - std::string base_dir = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter(); - std::string target; - std::string filename; - - lldebugs << "base dir = " << base_dir << llendl; - - // The non-logged-in version is easy - target = base_dir; - target += "browser_profile"; - target += gDirUtilp->getDirDelimiter(); - target += "cookies"; - lldebugs << "target = " << target << llendl; - if(LLFile::isfile(target)) - { - LLFile::remove(target); - } - - // the hard part: iterate over all user directories and delete the cookie file from each one - while(gDirUtilp->getNextFileInDir(base_dir, "*_*", filename)) - { - target = base_dir; - target += filename; - target += gDirUtilp->getDirDelimiter(); - target += "browser_profile"; - target += gDirUtilp->getDirDelimiter(); - target += "cookies"; - lldebugs << "target = " << target << llendl; - if(LLFile::isfile(target)) - { - LLFile::remove(target); - } - - // Other accounts may have new-style cookie files too -- delete them as well - target = base_dir; - target += filename; - target += gDirUtilp->getDirDelimiter(); - target += PLUGIN_COOKIE_FILE_NAME; - lldebugs << "target = " << target << llendl; - if(LLFile::isfile(target)) - { - LLFile::remove(target); - } - } - - // If we have an OpenID cookie, re-add it to the cookie store. - setOpenIDCookie(); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::clearAllCaches() -{ - // Clear all plugins' caches - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - for (; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - pimpl->clearCache(); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::setCookiesEnabled(bool enabled) -{ - // Set the "cookies enabled" flag for all loaded plugins - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - for (; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - if(pimpl->mMediaSource) - { - pimpl->mMediaSource->enable_cookies(enabled); - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::setProxyConfig(bool enable, const std::string &host, int port) -{ - // Set the proxy config for all loaded plugins - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - for (; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - if(pimpl->mMediaSource) - { - pimpl->mMediaSource->proxy_setup(enable, host, port); - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -///////////////////////////////////////////////////////////////////////////////////////// -// static -LLPluginCookieStore *LLViewerMedia::getCookieStore() -{ - if(sCookieStore == NULL) - { - sCookieStore = new LLPluginCookieStore; - } - - return sCookieStore; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::loadCookieFile() -{ - // build filename for each user - std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME); - - if (resolved_filename.empty()) - { - llinfos << "can't get path to plugin cookie file - probably not logged in yet." << llendl; - return; - } - - // open the file for reading - llifstream file(resolved_filename); - if (!file.is_open()) - { - llwarns << "can't load plugin cookies from file \"" << PLUGIN_COOKIE_FILE_NAME << "\"" << llendl; - return; - } - - getCookieStore()->readAllCookies(file, true); - - file.close(); - - // send the clear_cookies message to all loaded plugins - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - for (; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - if(pimpl->mMediaSource) - { - pimpl->mMediaSource->clear_cookies(); - } - } - - // If we have an OpenID cookie, re-add it to the cookie store. - setOpenIDCookie(); -} - - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::saveCookieFile() -{ - // build filename for each user - std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME); - - if (resolved_filename.empty()) - { - llinfos << "can't get path to plugin cookie file - probably not logged in yet." << llendl; - return; - } - - // open a file for writing - llofstream file (resolved_filename); - if (!file.is_open()) - { - llwarns << "can't open plugin cookie file \"" << PLUGIN_COOKIE_FILE_NAME << "\" for writing" << llendl; - return; - } - - getCookieStore()->writePersistentCookies(file); - - file.close(); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::addCookie(const std::string &name, const std::string &value, const std::string &domain, const LLDate &expires, const std::string &path, bool secure) -{ - std::stringstream cookie; - - cookie << name << "=" << LLPluginCookieStore::quoteString(value); - - if(expires.notNull()) - { - cookie << "; expires=" << expires.asRFC1123(); - } - - cookie << "; domain=" << domain; - - cookie << "; path=" << path; - - if(secure) - { - cookie << "; secure"; - } - - getCookieStore()->setCookies(cookie.str()); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::addSessionCookie(const std::string &name, const std::string &value, const std::string &domain, const std::string &path, bool secure) -{ - // A session cookie just has a NULL date. - addCookie(name, value, domain, LLDate(), path, secure); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::removeCookie(const std::string &name, const std::string &domain, const std::string &path ) -{ - // To remove a cookie, add one with the same name, domain, and path that expires in the past. - - addCookie(name, "", domain, LLDate(LLDate::now().secondsSinceEpoch() - 1.0), path); -} - - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::setOpenIDCookie() -{ - if(!sOpenIDCookie.empty()) - { - // The LLURL can give me the 'authority', which is of the form: [username[:password]@]hostname[:port] - // We want just the hostname for the cookie code, but LLURL doesn't seem to have a way to extract that. - // We therefore do it here. - std::string authority = sOpenIDURL.mAuthority; - std::string::size_type host_start = authority.find('@'); - if(host_start == std::string::npos) - { - // no username/password - host_start = 0; - } - else - { - // Hostname starts after the @. - // (If the hostname part is empty, this may put host_start at the end of the string. In that case, it will end up passing through an empty hostname, which is correct.) - ++host_start; - } - std::string::size_type host_end = authority.rfind(':'); - if((host_end == std::string::npos) || (host_end < host_start)) - { - // no port - host_end = authority.size(); - } - - getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(host_start, host_end - host_start)); - - // *HACK: Doing this here is nasty, find a better way. - LLWebSharing::instance().setOpenIDCookie(sOpenIDCookie); - - // Do a web profile get so we can store the cookie - LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "*/*"; - headers["Cookie"] = sOpenIDCookie; - headers["User-Agent"] = getCurrentUserAgent(); - - std::string profile_url = getProfileURL(""); - LLURL raw_profile_url( profile_url.c_str() ); - - LLHTTPClient::get(profile_url, - new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()), - headers); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string &openid_token) -{ - LL_DEBUGS("MediaAuth") << "url = \"" << openid_url << "\", token = \"" << openid_token << "\"" << LL_ENDL; - - // post the token to the url - // the responder will need to extract the cookie(s). - - // Save the OpenID URL for later -- we may need the host when adding the cookie. - sOpenIDURL.init(openid_url.c_str()); - - // We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies. - sOpenIDCookie.clear(); - - LLSD headers = LLSD::emptyMap(); - // Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header - headers["Accept"] = "*/*"; - // and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream" - headers["Content-Type"] = "application/x-www-form-urlencoded"; - - // postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here. - size_t size = openid_token.size(); - U8 *data = new U8[size]; - memcpy(data, openid_token.data(), size); - - LLHTTPClient::postRaw( - openid_url, - data, - size, - new LLViewerMediaOpenIDResponder(), - headers); - -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::openIDCookieResponse(const std::string &cookie) -{ - LL_DEBUGS("MediaAuth") << "Cookie received: \"" << cookie << "\"" << LL_ENDL; - - sOpenIDCookie += cookie; - - setOpenIDCookie(); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::proxyWindowOpened(const std::string &target, const std::string &uuid) -{ - if(uuid.empty()) - return; - - for (impl_list::iterator iter = sViewerMediaImplList.begin(); iter != sViewerMediaImplList.end(); iter++) - { - if((*iter)->mMediaSource && (*iter)->mMediaSource->pluginSupportsMediaBrowser()) - { - (*iter)->mMediaSource->proxyWindowOpened(target, uuid); - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::proxyWindowClosed(const std::string &uuid) -{ - if(uuid.empty()) - return; - - for (impl_list::iterator iter = sViewerMediaImplList.begin(); iter != sViewerMediaImplList.end(); iter++) - { - if((*iter)->mMediaSource && (*iter)->mMediaSource->pluginSupportsMediaBrowser()) - { - (*iter)->mMediaSource->proxyWindowClosed(uuid); - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::createSpareBrowserMediaSource() -{ - // If we don't have a spare browser media source, create one. - // However, if PluginAttachDebuggerToPlugins is set then don't spawn a spare - // SLPlugin process in order to not be confused by an unrelated gdb terminal - // popping up at the moment we start a media plugin. - if (!sSpareBrowserMediaSource && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")) - { - // The null owner will keep the browser plugin from fully initializing - // (specifically, it keeps LLPluginClassMedia from negotiating a size change, - // which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color) - sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource() -{ - LLPluginClassMedia* result = sSpareBrowserMediaSource; - sSpareBrowserMediaSource = NULL; - return result; -}; - -bool LLViewerMedia::hasInWorldMedia() -{ - if (sInWorldMediaDisabled) return false; - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - // This should be quick, because there should be very few non-in-world-media impls - for (; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - if (!pimpl->getUsedInUI() && !pimpl->isParcelMedia()) - { - // Found an in-world media impl - return true; - } - } - return false; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::hasParcelMedia() -{ - return !LLViewerParcelMedia::getURL().empty(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::hasParcelAudio() -{ - return !LLViewerMedia::getParcelAudioURL().empty(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -std::string LLViewerMedia::getParcelAudioURL() -{ - return LLViewerParcelMgr::getInstance()->getAgentParcel()->getMusicURL(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::initClass() -{ - gIdleCallbacks.addFunction(LLViewerMedia::updateMedia, NULL); - sTeleportFinishConnection = LLViewerParcelMgr::getInstance()-> - setTeleportFinishedCallback(boost::bind(&LLViewerMedia::onTeleportFinished)); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::cleanupClass() -{ - gIdleCallbacks.deleteFunction(LLViewerMedia::updateMedia, NULL); - sTeleportFinishConnection.disconnect(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::onTeleportFinished() -{ - // On teleport, clear this setting (i.e. set it to true) - gSavedSettings.setBOOL("MediaTentativeAutoPlay", true); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// LLViewerMediaImpl -////////////////////////////////////////////////////////////////////////////////////////// -LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id, - S32 media_width, - S32 media_height, - U8 media_auto_scale, - U8 media_loop) -: - mMediaSource( NULL ), - mMovieImageHasMips(false), - mMediaWidth(media_width), - mMediaHeight(media_height), - mMediaAutoScale(media_auto_scale), - mMediaLoop(media_loop), - mNeedsNewTexture(true), - mTextureUsedWidth(0), - mTextureUsedHeight(0), - mSuspendUpdates(false), - mVisible(true), - mLastSetCursor( UI_CURSOR_ARROW ), - mMediaNavState( MEDIANAVSTATE_NONE ), - mInterest(0.0f), - mUsedInUI(false), - mHasFocus(false), - mPriority(LLPluginClassMedia::PRIORITY_UNLOADED), - mNavigateRediscoverType(false), - mNavigateServerRequest(false), - mMediaSourceFailed(false), - mRequestedVolume(1.0f), - mIsMuted(false), - mNeedsMuteCheck(false), - mPreviousMediaState(MEDIA_NONE), - mPreviousMediaTime(0.0f), - mIsDisabled(false), - mIsParcelMedia(false), - mProximity(-1), - mProximityDistance(0.0f), - mMimeTypeProbe(NULL), - mMediaAutoPlay(false), - mInNearbyMediaList(false), - mClearCache(false), - mBackgroundColor(LLColor4::white), - mNavigateSuspended(false), - mNavigateSuspendedDeferred(false), - mIsUpdated(false), - mTrustedBrowser(false) -{ - - // Set up the mute list observer if it hasn't been set up already. - if(!sViewerMediaMuteListObserverInitialized) - { - LLMuteList::getInstance()->addObserver(&sViewerMediaMuteListObserver); - sViewerMediaMuteListObserverInitialized = true; - } - - add_media_impl(this); - - setTextureID(texture_id); - - // connect this media_impl to the media texture, creating it if it doesn't exist.0 - // This is necessary because we need to be able to use getMaxVirtualSize() even if the media plugin is not loaded. - LLViewerMediaTexture* media_tex = LLViewerTextureManager::getMediaTexture(mTextureId); - if(media_tex) - { - media_tex->setMediaImpl(); - } - -} - -////////////////////////////////////////////////////////////////////////////////////////// -LLViewerMediaImpl::~LLViewerMediaImpl() -{ - destroyMediaSource(); - - LLViewerMediaTexture::removeMediaImplFromTexture(mTextureId) ; - - setTextureID(); - remove_media_impl(this); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::emitEvent(LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event) -{ - // Broadcast to observers using the superclass version - LLViewerMediaEventEmitter::emitEvent(plugin, event); - - // If this media is on one or more LLVOVolume objects, tell them about the event as well. - std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; - while(iter != mObjectList.end()) - { - LLVOVolume *self = *iter; - ++iter; - self->mediaEvent(this, plugin, event); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type) -{ - bool mimeTypeChanged = (mMimeType != mime_type); - bool pluginChanged = (LLMIMETypes::implType(mCurrentMimeType) != LLMIMETypes::implType(mime_type)); - - if(!mMediaSource || pluginChanged) - { - // We don't have a plugin at all, or the new mime type is handled by a different plugin than the old mime type. - (void)initializePlugin(mime_type); - } - else if(mimeTypeChanged) - { - // The same plugin should be able to handle the new media -- just update the stored mime type. - mMimeType = mime_type; - } - - return (mMediaSource != NULL); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::createMediaSource() -{ - if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) - { - // This media shouldn't be created yet. - return; - } - - if(! mMediaURL.empty()) - { - navigateInternal(); - } - else if(! mMimeType.empty()) - { - if (!initializeMedia(mMimeType)) - { - LL_WARNS("Media") << "Failed to initialize media for mime type " << mMimeType << LL_ENDL; - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::destroyMediaSource() -{ - mNeedsNewTexture = true; - - // Tell the viewer media texture it's no longer active - LLViewerMediaTexture* oldImage = LLViewerTextureManager::findMediaTexture( mTextureId ); - if (oldImage) - { - oldImage->setPlaying(FALSE) ; - } - - cancelMimeTypeProbe(); - - if(mMediaSource) - { - mMediaSource->setDeleteOK(true) ; - delete mMediaSource; - mMediaSource = NULL; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::setMediaType(const std::string& media_type) -{ - mMimeType = media_type; -} - -////////////////////////////////////////////////////////////////////////////////////////// -/*static*/ -LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target) -{ - std::string plugin_basename = LLMIMETypes::implType(media_type); - LLPluginClassMedia* media_source = NULL; - - // HACK: we always try to keep a spare running webkit plugin around to improve launch times. - // If a spare was already created before PluginAttachDebuggerToPlugins was set, don't use it. - if(plugin_basename == "media_plugin_webkit" && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")) - { - media_source = LLViewerMedia::getSpareBrowserMediaSource(); - if(media_source) - { - media_source->setOwner(owner); - media_source->setTarget(target); - media_source->setSize(default_width, default_height); - - return media_source; - } - } - - if(plugin_basename.empty()) - { - LL_WARNS("Media") << "Couldn't find plugin for media type " << media_type << LL_ENDL; - } - else - { - std::string launcher_name = gDirUtilp->getLLPluginLauncher(); - std::string plugin_name = gDirUtilp->getLLPluginFilename(plugin_basename); - std::string user_data_path = gDirUtilp->getOSUserAppDir(); - user_data_path += gDirUtilp->getDirDelimiter(); - - // Fix for EXT-5960 - make browser profile specific to user (cache, cookies etc.) - // If the linden username returned is blank, that can only mean we are - // at the login page displaying login Web page or Web browser test via Develop menu. - // In this case we just use whatever gDirUtilp->getOSUserAppDir() gives us (this - // is what we always used before this change) - std::string linden_user_dir = gDirUtilp->getLindenUserDir(); - if ( ! linden_user_dir.empty() ) - { - // gDirUtilp->getLindenUserDir() is whole path, not just Linden name - user_data_path = linden_user_dir; - user_data_path += gDirUtilp->getDirDelimiter(); - }; - - // See if the plugin executable exists - llstat s; - if(LLFile::stat(launcher_name, &s)) - { - LL_WARNS("Media") << "Couldn't find launcher at " << launcher_name << LL_ENDL; - } - else if(LLFile::stat(plugin_name, &s)) - { - LL_WARNS("Media") << "Couldn't find plugin at " << plugin_name << LL_ENDL; - } - else - { - media_source = new LLPluginClassMedia(owner); - media_source->setSize(default_width, default_height); - media_source->setUserDataPath(user_data_path); - media_source->setLanguageCode(LLUI::getLanguage()); - - // collect 'cookies enabled' setting from prefs and send to embedded browser - bool cookies_enabled = gSavedSettings.getBOOL( "CookiesEnabled" ); - media_source->enable_cookies( cookies_enabled ); - - // collect 'plugins enabled' setting from prefs and send to embedded browser - bool plugins_enabled = gSavedSettings.getBOOL( "BrowserPluginsEnabled" ); - media_source->setPluginsEnabled( plugins_enabled ); - - // collect 'javascript enabled' setting from prefs and send to embedded browser - bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" ); - media_source->setJavascriptEnabled( javascript_enabled ); - - media_source->setTarget(target); - - const std::string plugin_dir = gDirUtilp->getLLPluginDir(); - if (media_source->init(launcher_name, plugin_dir, plugin_name, gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))) - { - return media_source; - } - else - { - LL_WARNS("Media") << "Failed to init plugin. Destroying." << LL_ENDL; - delete media_source; - } - } - } - - LL_WARNS("Plugin") << "plugin intialization failed for mime type: " << media_type << LL_ENDL; - LLSD args; - args["MIME_TYPE"] = media_type; - LLNotificationsUtil::add("NoPlugin", args); - - return NULL; -} - -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) -{ - if(mMediaSource) - { - // Save the previous media source's last set size before destroying it. - mMediaWidth = mMediaSource->getSetWidth(); - mMediaHeight = mMediaSource->getSetHeight(); - } - - // Always delete the old media impl first. - destroyMediaSource(); - - // and unconditionally set the mime type - mMimeType = media_type; - - if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) - { - // This impl should not be loaded at this time. - LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL; - - return false; - } - - // If we got here, we want to ignore previous init failures. - mMediaSourceFailed = false; - - // Save the MIME type that really caused the plugin to load - mCurrentMimeType = mMimeType; - - LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight, mTarget); - - if (media_source) - { - media_source->setDisableTimeout(gSavedSettings.getBOOL("DebugPluginDisableTimeout")); - media_source->setLoop(mMediaLoop); - media_source->setAutoScale(mMediaAutoScale); - media_source->setBrowserUserAgent(LLViewerMedia::getCurrentUserAgent()); - media_source->focus(mHasFocus); - media_source->setBackgroundColor(mBackgroundColor); - - if(gSavedSettings.getBOOL("BrowserIgnoreSSLCertErrors")) - { - media_source->ignore_ssl_cert_errors(true); - } - - // the correct way to deal with certs it to load ours from CA.pem and append them to the ones - // Qt/WebKit loads from your system location. - // Note: This needs the new CA.pem file with the Equifax Secure Certificate Authority - // cert at the bottom: (MIIDIDCCAomgAwIBAgIENd70zzANBg) - std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "CA.pem" ); - media_source->addCertificateFilePath( ca_path ); - - media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort")); - - if(mClearCache) - { - mClearCache = false; - media_source->clear_cache(); - } - - // TODO: Only send cookies to plugins that need them - // Ideally, the plugin should tell us whether it handles cookies or not -- either via the init response or through a separate message. - // Due to the ordering of messages, it's possible we wouldn't get that information back in time to send cookies before sending a navigate message, - // which could cause odd race conditions. - std::string all_cookies = LLViewerMedia::getCookieStore()->getAllCookies(); - lldebugs << "setting cookies: " << all_cookies << llendl; - if(!all_cookies.empty()) - { - media_source->set_cookies(all_cookies); - } - - mMediaSource = media_source; - mMediaSource->setDeleteOK(false) ; - updateVolume(); - - return true; - } - - // Make sure the timer doesn't try re-initing this plugin repeatedly until something else changes. - mMediaSourceFailed = true; - - return false; -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::loadURI() -{ - if(mMediaSource) - { - // trim whitespace from front and back of URL - fixes EXT-5363 - LLStringUtil::trim( mMediaURL ); - - // *HACK: we don't know if the URI coming in is properly escaped - // (the contract doesn't specify whether it is escaped or not. - // but LLQtWebKit expects it to be, so we do our best to encode - // special characters) - // The strings below were taken right from http://www.ietf.org/rfc/rfc1738.txt - // Note especially that '%' and '/' are there. - std::string uri = LLURI::escape(mMediaURL, - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - "0123456789" - "$-_.+" - "!*'()," - "{}|\\^~[]`" - "<>#%" - ";/?:@&=", - false); - llinfos << "Asking media source to load URI: " << uri << llendl; - - mMediaSource->loadURI( uri ); - - // A non-zero mPreviousMediaTime means that either this media was previously unloaded by the priority code while playing/paused, - // or a seek happened before the media loaded. In either case, seek to the saved time. - if(mPreviousMediaTime != 0.0f) - { - seek(mPreviousMediaTime); - } - - if(mPreviousMediaState == MEDIA_PLAYING) - { - // This media was playing before this instance was unloaded. - start(); - } - else if(mPreviousMediaState == MEDIA_PAUSED) - { - // This media was paused before this instance was unloaded. - pause(); - } - else - { - // No relevant previous media play state -- if we're loading the URL, we want to start playing. - start(); - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::setSize(int width, int height) -{ - mMediaWidth = width; - mMediaHeight = height; - if(mMediaSource) - { - mMediaSource->setSize(width, height); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::showNotification(LLNotificationPtr notify) -{ - mNotification = notify; -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::hideNotification() -{ - mNotification.reset(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::play() -{ - // If the media source isn't there, try to initialize it and load an URL. - if(mMediaSource == NULL) - { - if(!initializeMedia(mMimeType)) - { - // This may be the case where the plugin's priority is PRIORITY_UNLOADED - return; - } - - // Only do this if the media source was just loaded. - loadURI(); - } - - // always start the media - start(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::stop() -{ - if(mMediaSource) - { - mMediaSource->stop(); - // destroyMediaSource(); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::pause() -{ - if(mMediaSource) - { - mMediaSource->pause(); - } - else - { - mPreviousMediaState = MEDIA_PAUSED; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::start() -{ - if(mMediaSource) - { - mMediaSource->start(); - } - else - { - mPreviousMediaState = MEDIA_PLAYING; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::seek(F32 time) -{ - if(mMediaSource) - { - mMediaSource->seek(time); - } - else - { - // Save the seek time to be set when the media is loaded. - mPreviousMediaTime = time; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::skipBack(F32 step_scale) -{ - if(mMediaSource) - { - if(mMediaSource->pluginSupportsMediaTime()) - { - F64 back_step = mMediaSource->getCurrentTime() - (mMediaSource->getDuration()*step_scale); - if(back_step < 0.0) - { - back_step = 0.0; - } - mMediaSource->seek(back_step); - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::skipForward(F32 step_scale) -{ - if(mMediaSource) - { - if(mMediaSource->pluginSupportsMediaTime()) - { - F64 forward_step = mMediaSource->getCurrentTime() + (mMediaSource->getDuration()*step_scale); - if(forward_step > mMediaSource->getDuration()) - { - forward_step = mMediaSource->getDuration(); - } - mMediaSource->seek(forward_step); - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::setVolume(F32 volume) -{ - mRequestedVolume = volume; - updateVolume(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::updateVolume() -{ - if(mMediaSource) - { - // always scale the volume by the global media volume - F32 volume = mRequestedVolume * LLViewerMedia::getVolume(); - - if (mProximityCamera > 0) - { - if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMax")) - { - volume = 0; - } - else if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMin")) - { - // attenuated_volume = 1 / (roll_off_rate * (d - min))^2 - // the +1 is there so that for distance 0 the volume stays the same - F64 adjusted_distance = mProximityCamera - gSavedSettings.getF32("MediaRollOffMin"); - F64 attenuation = 1.0 + (gSavedSettings.getF32("MediaRollOffRate") * adjusted_distance); - attenuation = 1.0 / (attenuation * attenuation); - // the attenuation multiplier should never be more than one since that would increase volume - volume = volume * llmin(1.0, attenuation); - } - } - - mMediaSource->setVolume(volume); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -F32 LLViewerMediaImpl::getVolume() -{ - return mRequestedVolume; -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::focus(bool focus) -{ - mHasFocus = focus; - - if (mMediaSource) - { - // call focus just for the hell of it, even though this apopears to be a nop - mMediaSource->focus(focus); - if (focus) - { - // spoof a mouse click to *actually* pass focus - // Don't do this anymore -- it actually clicks through now. -// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, 1, 1, 0); -// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 1, 1, 0); - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::hasFocus() const -{ - // FIXME: This might be able to be a bit smarter by hooking into LLViewerMediaFocus, etc. - return mHasFocus; -} - -std::string LLViewerMediaImpl::getCurrentMediaURL() -{ - if(!mCurrentMediaURL.empty()) - { - return mCurrentMediaURL; - } - - return mMediaURL; -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::clearCache() -{ - if(mMediaSource) - { - mMediaSource->clear_cache(); - } - else - { - mClearCache = true; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::mouseDown(S32 x, S32 y, MASK mask, S32 button) -{ - scaleMouse(&x, &y); - mLastMouseX = x; - mLastMouseY = y; -// llinfos << "mouse down (" << x << ", " << y << ")" << llendl; - if (mMediaSource) - { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, button, x, y, mask); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::mouseUp(S32 x, S32 y, MASK mask, S32 button) -{ - scaleMouse(&x, &y); - mLastMouseX = x; - mLastMouseY = y; -// llinfos << "mouse up (" << x << ", " << y << ")" << llendl; - if (mMediaSource) - { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, button, x, y, mask); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::mouseMove(S32 x, S32 y, MASK mask) -{ - scaleMouse(&x, &y); - mLastMouseX = x; - mLastMouseY = y; -// llinfos << "mouse move (" << x << ", " << y << ")" << llendl; - if (mMediaSource) - { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, x, y, mask); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -//static -void LLViewerMediaImpl::scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y) -{ - F32 texture_x = texture_coords.mV[VX]; - F32 texture_y = texture_coords.mV[VY]; - - // Deal with repeating textures by wrapping the coordinates into the range [0, 1.0) - texture_x = fmodf(texture_x, 1.0f); - if(texture_x < 0.0f) - texture_x = 1.0 + texture_x; - - texture_y = fmodf(texture_y, 1.0f); - if(texture_y < 0.0f) - texture_y = 1.0 + texture_y; - - // scale x and y to texel units. - *x = llround(texture_x * mMediaSource->getTextureWidth()); - *y = llround((1.0f - texture_y) * mMediaSource->getTextureHeight()); - - // Adjust for the difference between the actual texture height and the amount of the texture in use. - *y -= (mMediaSource->getTextureHeight() - mMediaSource->getHeight()); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::mouseDown(const LLVector2& texture_coords, MASK mask, S32 button) -{ - if(mMediaSource) - { - S32 x, y; - scaleTextureCoords(texture_coords, &x, &y); - - mouseDown(x, y, mask, button); - } -} - -void LLViewerMediaImpl::mouseUp(const LLVector2& texture_coords, MASK mask, S32 button) -{ - if(mMediaSource) - { - S32 x, y; - scaleTextureCoords(texture_coords, &x, &y); - - mouseUp(x, y, mask, button); - } -} - -void LLViewerMediaImpl::mouseMove(const LLVector2& texture_coords, MASK mask) -{ - if(mMediaSource) - { - S32 x, y; - scaleTextureCoords(texture_coords, &x, &y); - - mouseMove(x, y, mask); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button) -{ - scaleMouse(&x, &y); - mLastMouseX = x; - mLastMouseY = y; - if (mMediaSource) - { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOUBLE_CLICK, button, x, y, mask); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::scrollWheel(S32 x, S32 y, MASK mask) -{ - scaleMouse(&x, &y); - mLastMouseX = x; - mLastMouseY = y; - if (mMediaSource) - { - mMediaSource->scrollEvent(x, y, mask); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::onMouseCaptureLost() -{ - if (mMediaSource) - { - mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 0, mLastMouseX, mLastMouseY, 0); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -BOOL LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask) -{ - // NOTE: this is called when the mouse is released when we have capture. - // Due to the way mouse coordinates are mapped to the object, we can't use the x and y coordinates that come in with the event. - - if(hasMouseCapture()) - { - // Release the mouse -- this will also send a mouseup to the media - gFocusMgr.setMouseCapture( FALSE ); - } - - return TRUE; -} - -////////////////////////////////////////////////////////////////////////////////////////// -std::string LLViewerMediaImpl::getName() const -{ - if (mMediaSource) - { - return mMediaSource->getMediaName(); - } - - return LLStringUtil::null; -}; - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::navigateBack() -{ - if (mMediaSource) - { - mMediaSource->browse_back(); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::navigateForward() -{ - if (mMediaSource) - { - mMediaSource->browse_forward(); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::navigateReload() -{ - navigateTo(getCurrentMediaURL(), "", true, false); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::navigateHome() -{ - bool rediscover_mimetype = mHomeMimeType.empty(); - navigateTo(mHomeURL, mHomeMimeType, rediscover_mimetype, false); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::unload() -{ - // Unload the media impl and clear its state. - destroyMediaSource(); - resetPreviousMediaState(); - mMediaURL.clear(); - mMimeType.clear(); - mCurrentMediaURL.clear(); - mCurrentMimeType.clear(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type, bool server_request) -{ - cancelMimeTypeProbe(); - - if(mMediaURL != url) - { - // Don't carry media play state across distinct URLs. - resetPreviousMediaState(); - } - - // Always set the current URL and MIME type. - mMediaURL = url; - mMimeType = mime_type; - - // Clear the current media URL, since it will no longer be correct. - mCurrentMediaURL.clear(); - - // if mime type discovery was requested, we'll need to do it when the media loads - mNavigateRediscoverType = rediscover_type; - - // and if this was a server request, the navigate on load will also need to be one. - mNavigateServerRequest = server_request; - - // An explicit navigate resets the "failed" flag. - mMediaSourceFailed = false; - - if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) - { - // Helpful to have media urls in log file. Shouldn't be spammy. - llinfos << "NOT LOADING media id= " << mTextureId << " url=" << url << " mime_type=" << mime_type << llendl; - - // This impl should not be loaded at this time. - LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL; - - return; - } - - navigateInternal(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::navigateInternal() -{ - // Helpful to have media urls in log file. Shouldn't be spammy. - llinfos << "media id= " << mTextureId << " url=" << mMediaURL << " mime_type=" << mMimeType << llendl; - - if(mNavigateSuspended) - { - llwarns << "Deferring navigate." << llendl; - mNavigateSuspendedDeferred = true; - return; - } - - if(mMimeTypeProbe != NULL) - { - llwarns << "MIME type probe already in progress -- bailing out." << llendl; - return; - } - - if(mNavigateServerRequest) - { - setNavState(MEDIANAVSTATE_SERVER_SENT); - } - else - { - setNavState(MEDIANAVSTATE_NONE); - } - - // If the caller has specified a non-empty MIME type, look that up in our MIME types list. - // If we have a plugin for that MIME type, use that instead of attempting auto-discovery. - // This helps in supporting legacy media content where the server the media resides on returns a bogus MIME type - // but the parcel owner has correctly set the MIME type in the parcel media settings. - - if(!mMimeType.empty() && (mMimeType != LLMIMETypes::getDefaultMimeType())) - { - std::string plugin_basename = LLMIMETypes::implType(mMimeType); - if(!plugin_basename.empty()) - { - // We have a plugin for this mime type - mNavigateRediscoverType = false; - } - } - - if(mNavigateRediscoverType) - { - - LLURI uri(mMediaURL); - std::string scheme = uri.scheme(); - - if(scheme.empty() || "http" == scheme || "https" == scheme) - { - // If we don't set an Accept header, LLHTTPClient will add one like this: - // Accept: application/llsd+xml - // which is really not what we want. - LLSD headers = LLSD::emptyMap(); - headers["Accept"] = "*/*"; - // Allow cookies in the response, to prevent a redirect loop when accessing join.secondlife.com - headers["Cookie"] = ""; - LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this), headers, 10.0f); - } - else if("data" == scheme || "file" == scheme || "about" == scheme) - { - // FIXME: figure out how to really discover the type for these schemes - // We use "data" internally for a text/html url for loading the login screen - if(initializeMedia("text/html")) - { - loadURI(); - } - } - else - { - // This catches 'rtsp://' urls - if(initializeMedia(scheme)) - { - loadURI(); - } - } - } - else if(initializeMedia(mMimeType)) - { - loadURI(); - } - else - { - LL_WARNS("Media") << "Couldn't navigate to: " << mMediaURL << " as there is no media type for: " << mMimeType << LL_ENDL; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::navigateStop() -{ - if(mMediaSource) - { - mMediaSource->browse_stop(); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask) -{ - bool result = false; - - if (mMediaSource) - { - // FIXME: THIS IS SO WRONG. - // Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it... - if( MASK_CONTROL & mask ) - { - result = true; - } - - if(!result) - { - - LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData(); - - result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask, native_key_data); - // Since the viewer internal event dispatching doesn't give us key-up events, simulate one here. - (void)mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP ,key, mask, native_key_data); - } - } - - return result; -} - -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char) -{ - bool result = false; - - if (mMediaSource) - { - // only accept 'printable' characters, sigh... - if (uni_char >= 32 // discard 'control' characters - && uni_char != 127) // SDL thinks this is 'delete' - yuck. - { - LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData(); - - mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE), native_key_data); - } - } - - return result; -} - -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::canNavigateForward() -{ - BOOL result = FALSE; - if (mMediaSource) - { - result = mMediaSource->getHistoryForwardAvailable(); - } - return result; -} - -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::canNavigateBack() -{ - BOOL result = FALSE; - if (mMediaSource) - { - result = mMediaSource->getHistoryBackAvailable(); - } - return result; -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::update() -{ - if(mMediaSource == NULL) - { - if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) - { - // This media source should not be loaded. - } - else if(mPriority <= LLPluginClassMedia::PRIORITY_SLIDESHOW) - { - // Don't load new instances that are at PRIORITY_SLIDESHOW or below. They're just kept around to preserve state. - } - else if(mMimeTypeProbe != NULL) - { - // this media source is doing a MIME type probe -- don't try loading it again. - } - else - { - // This media may need to be loaded. - if(sMediaCreateTimer.hasExpired()) - { - LL_DEBUGS("PluginPriority") << this << ": creating media based on timer expiration" << LL_ENDL; - createMediaSource(); - sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY); - } - else - { - LL_DEBUGS("PluginPriority") << this << ": NOT creating media (waiting on timer)" << LL_ENDL; - } - } - } - else - { - updateVolume(); - - // If we didn't just create the impl, it may need to get cookie updates. - if(!sUpdatedCookies.empty()) - { - // TODO: Only send cookies to plugins that need them - mMediaSource->set_cookies(sUpdatedCookies); - } - } - - - if(mMediaSource == NULL) - { - return; - } - - // Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash. - setNavigateSuspended(true); - - mMediaSource->idle(); - - setNavigateSuspended(false); - - if(mMediaSource == NULL) - { - return; - } - - if(mMediaSource->isPluginExited()) - { - resetPreviousMediaState(); - destroyMediaSource(); - return; - } - - if(!mMediaSource->textureValid()) - { - return; - } - - if(mSuspendUpdates || !mVisible) - { - return; - } - - LLViewerMediaTexture* placeholder_image = updatePlaceholderImage(); - - if(placeholder_image) - { - LLRect dirty_rect; - - // Since we're updating this texture, we know it's playing. Tell the texture to do its replacement magic so it gets rendered. - placeholder_image->setPlaying(TRUE); - - if(mMediaSource->getDirty(&dirty_rect)) - { - // Constrain the dirty rect to be inside the texture - S32 x_pos = llmax(dirty_rect.mLeft, 0); - S32 y_pos = llmax(dirty_rect.mBottom, 0); - S32 width = llmin(dirty_rect.mRight, placeholder_image->getWidth()) - x_pos; - S32 height = llmin(dirty_rect.mTop, placeholder_image->getHeight()) - y_pos; - - if(width > 0 && height > 0) - { - - U8* data = mMediaSource->getBitsData(); - - // Offset the pixels pointer to match x_pos and y_pos - data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() ); - data += ( y_pos * mMediaSource->getTextureDepth() ); - - placeholder_image->setSubImage( - data, - mMediaSource->getBitsWidth(), - mMediaSource->getBitsHeight(), - x_pos, - y_pos, - width, - height); - - } - - mMediaSource->resetDirty(); - } - } -} - - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::updateImagesMediaStreams() -{ -} - - -////////////////////////////////////////////////////////////////////////////////////////// -LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() -{ - if(mTextureId.isNull()) - { - // The code that created this instance will read from the plugin's bits. - return NULL; - } - - LLViewerMediaTexture* placeholder_image = LLViewerTextureManager::getMediaTexture( mTextureId ); - - if (mNeedsNewTexture - || placeholder_image->getUseMipMaps() - || (placeholder_image->getWidth() != mMediaSource->getTextureWidth()) - || (placeholder_image->getHeight() != mMediaSource->getTextureHeight()) - || (mTextureUsedWidth != mMediaSource->getWidth()) - || (mTextureUsedHeight != mMediaSource->getHeight()) - ) - { - LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL; - LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL; - - int texture_width = mMediaSource->getTextureWidth(); - int texture_height = mMediaSource->getTextureHeight(); - int texture_depth = mMediaSource->getTextureDepth(); - - // MEDIAOPT: check to see if size actually changed before doing work - placeholder_image->destroyGLTexture(); - // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work? - placeholder_image->reinit(FALSE); // probably not needed - - // MEDIAOPT: seems insane that we actually have to make an imageraw then - // immediately discard it - LLPointer raw = new LLImageRaw(texture_width, texture_height, texture_depth); - // Clear the texture to the background color, ignoring alpha. - // convert background color channels from [0.0, 1.0] to [0, 255]; - raw->clear(int(mBackgroundColor.mV[VX] * 255.0f), int(mBackgroundColor.mV[VY] * 255.0f), int(mBackgroundColor.mV[VZ] * 255.0f), 0xff); - int discard_level = 0; - - // ask media source for correct GL image format constants - placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(), - mMediaSource->getTextureFormatPrimary(), - mMediaSource->getTextureFormatType(), - mMediaSource->getTextureFormatSwapBytes()); - - placeholder_image->createGLTexture(discard_level, raw); - - // MEDIAOPT: set this dynamically on play/stop - // FIXME -// placeholder_image->mIsMediaTexture = true; - mNeedsNewTexture = false; - - // If the amount of the texture being drawn by the media goes down in either width or height, - // recreate the texture to avoid leaving parts of the old image behind. - mTextureUsedWidth = mMediaSource->getWidth(); - mTextureUsedHeight = mMediaSource->getHeight(); - } - - return placeholder_image; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -LLUUID LLViewerMediaImpl::getMediaTextureID() const -{ - return mTextureId; -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::setVisible(bool visible) -{ - mVisible = visible; - - if(mVisible) - { - if(mMediaSource && mMediaSource->isPluginExited()) - { - destroyMediaSource(); - } - - if(!mMediaSource) - { - createMediaSource(); - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::mouseCapture() -{ - gFocusMgr.setMouseCapture(this); -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::scaleMouse(S32 *mouse_x, S32 *mouse_y) -{ -#if 0 - S32 media_width, media_height; - S32 texture_width, texture_height; - getMediaSize( &media_width, &media_height ); - getTextureSize( &texture_width, &texture_height ); - S32 y_delta = texture_height - media_height; - - *mouse_y -= y_delta; -#endif -} - - - -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::isMediaTimeBased() -{ - bool result = false; - - if(mMediaSource) - { - result = mMediaSource->pluginSupportsMediaTime(); - } - - return result; -} - -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::isMediaPlaying() -{ - bool result = false; - - if(mMediaSource) - { - EMediaStatus status = mMediaSource->getStatus(); - if(status == MEDIA_PLAYING || status == MEDIA_LOADING) - result = true; - } - - return result; -} -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::isMediaPaused() -{ - bool result = false; - - if(mMediaSource) - { - if(mMediaSource->getStatus() == MEDIA_PAUSED) - result = true; - } - - return result; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaImpl::hasMedia() const -{ - return mMediaSource != NULL; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// -void LLViewerMediaImpl::resetPreviousMediaState() -{ - mPreviousMediaState = MEDIA_NONE; - mPreviousMediaTime = 0.0f; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// -void LLViewerMediaImpl::setDisabled(bool disabled, bool forcePlayOnEnable) -{ - if(mIsDisabled != disabled) - { - // Only do this on actual state transitions. - mIsDisabled = disabled; - - if(mIsDisabled) - { - // We just disabled this media. Clear all state. - unload(); - } - else - { - // We just (re)enabled this media. Do a navigate if auto-play is in order. - if(isAutoPlayable() || forcePlayOnEnable) - { - navigateTo(mMediaEntryURL, "", true, true); - } - } - - } -}; - -////////////////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaImpl::isForcedUnloaded() const -{ - if(mIsMuted || mMediaSourceFailed || mIsDisabled) - { - return true; - } - - if(sInWorldMediaDisabled) - { - // When inworld media is disabled, all instances that aren't marked as "used in UI" will not be loaded. - if(!mUsedInUI) - { - return true; - } - } - - // If this media's class is not supposed to be shown, unload - if (!shouldShowBasedOnClass()) - { - return true; - } - - return false; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaImpl::isPlayable() const -{ - if(isForcedUnloaded()) - { - // All of the forced-unloaded criteria also imply not playable. - return false; - } - - if(hasMedia()) - { - // Anything that's already playing is, by definition, playable. - return true; - } - - if(!mMediaURL.empty()) - { - // If something has navigated the instance, it's ready to be played. - return true; - } - - return false; -} - -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginClassMediaOwner::EMediaEvent event) -{ - bool pass_through = true; - switch(event) - { - case MEDIA_EVENT_CLICK_LINK_NOFOLLOW: - { - LL_DEBUGS("Media") << "MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is: " << plugin->getClickURL() << LL_ENDL; - std::string url = plugin->getClickURL(); - std::string nav_type = plugin->getClickNavType(); - LLURLDispatcher::dispatch(url, nav_type, NULL, mTrustedBrowser); - } - break; - case MEDIA_EVENT_CLICK_LINK_HREF: - { - LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << plugin->getClickTarget() << "\", uri is " << plugin->getClickURL() << LL_ENDL; - }; - break; - case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH: - { - // The plugin failed to load properly. Make sure the timer doesn't retry. - // TODO: maybe mark this plugin as not loadable somehow? - mMediaSourceFailed = true; - - // Reset the last known state of the media to defaults. - resetPreviousMediaState(); - - // TODO: may want a different message for this case? - LLSD args; - args["PLUGIN"] = LLMIMETypes::implType(mCurrentMimeType); - LLNotificationsUtil::add("MediaPluginFailed", args); - } - break; - - case MEDIA_EVENT_PLUGIN_FAILED: - { - // The plugin crashed. - mMediaSourceFailed = true; - - // Reset the last known state of the media to defaults. - resetPreviousMediaState(); - - LLSD args; - args["PLUGIN"] = LLMIMETypes::implType(mCurrentMimeType); - // SJB: This is getting called every frame if the plugin fails to load, continuously respawining the alert! - //LLNotificationsUtil::add("MediaPluginFailed", args); - } - break; - - case MEDIA_EVENT_CURSOR_CHANGED: - { - LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << plugin->getCursorName() << LL_ENDL; - - std::string cursor = plugin->getCursorName(); - - if(cursor == "arrow") - mLastSetCursor = UI_CURSOR_ARROW; - else if(cursor == "ibeam") - mLastSetCursor = UI_CURSOR_IBEAM; - else if(cursor == "splith") - mLastSetCursor = UI_CURSOR_SIZEWE; - else if(cursor == "splitv") - mLastSetCursor = UI_CURSOR_SIZENS; - else if(cursor == "hand") - mLastSetCursor = UI_CURSOR_HAND; - else // for anything else, default to the arrow - mLastSetCursor = UI_CURSOR_ARROW; - } - break; - - case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_BEGIN: - { - LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_BEGIN, uri is: " << plugin->getNavigateURI() << LL_ENDL; - hideNotification(); - - if(getNavState() == MEDIANAVSTATE_SERVER_SENT) - { - setNavState(MEDIANAVSTATE_SERVER_BEGUN); - } - else - { - setNavState(MEDIANAVSTATE_BEGUN); - } - } - break; - - case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE: - { - LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_COMPLETE, uri is: " << plugin->getNavigateURI() << LL_ENDL; - - std::string url = plugin->getNavigateURI(); - if(getNavState() == MEDIANAVSTATE_BEGUN) - { - if(mCurrentMediaURL == url) - { - // This is a navigate that takes us to the same url as the previous navigate. - setNavState(MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS); - } - else - { - mCurrentMediaURL = url; - setNavState(MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED); - } - } - else if(getNavState() == MEDIANAVSTATE_SERVER_BEGUN) - { - mCurrentMediaURL = url; - setNavState(MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED); - } - else - { - // all other cases need to leave the state alone. - } - } - break; - - case LLViewerMediaObserver::MEDIA_EVENT_LOCATION_CHANGED: - { - LL_DEBUGS("Media") << "MEDIA_EVENT_LOCATION_CHANGED, uri is: " << plugin->getLocation() << LL_ENDL; - - std::string url = plugin->getLocation(); - - if(getNavState() == MEDIANAVSTATE_BEGUN) - { - if(mCurrentMediaURL == url) - { - // This is a navigate that takes us to the same url as the previous navigate. - setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS); - } - else - { - mCurrentMediaURL = url; - setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED); - } - } - else if(getNavState() == MEDIANAVSTATE_SERVER_BEGUN) - { - mCurrentMediaURL = url; - setNavState(MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED); - } - else - { - // Don't track redirects. - setNavState(MEDIANAVSTATE_NONE); - } - } - break; - - case LLViewerMediaObserver::MEDIA_EVENT_PICK_FILE_REQUEST: - { - // Display a file picker - std::string response; - - LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getOpenFile(LLFilePicker::FFLOAD_ALL)) - { - // The user didn't pick a file -- the empty response string will indicate this. - } - - response = picker.getFirstFile(); - - plugin->sendPickFileResponse(response); - } - break; - - - case LLViewerMediaObserver::MEDIA_EVENT_AUTH_REQUEST: - { - LLNotification::Params auth_request_params; - auth_request_params.name = "AuthRequest"; - - // pass in host name and realm for site (may be zero length but will always exist) - LLSD args; - LLURL raw_url( plugin->getAuthURL().c_str() ); - args["HOST_NAME"] = raw_url.getAuthority(); - args["REALM"] = plugin->getAuthRealm(); - auth_request_params.substitutions = args; - - auth_request_params.payload = LLSD().with("media_id", mTextureId); - auth_request_params.functor.function = boost::bind(&LLViewerMedia::onAuthSubmit, _1, _2); - LLNotifications::instance().add(auth_request_params); - }; - break; - - case LLViewerMediaObserver::MEDIA_EVENT_CLOSE_REQUEST: - { - std::string uuid = plugin->getClickUUID(); - - llinfos << "MEDIA_EVENT_CLOSE_REQUEST for uuid " << uuid << llendl; - - if(uuid.empty()) - { - // This close request is directed at this instance, let it fall through. - } - else - { - // This close request is directed at another instance - pass_through = false; - LLFloaterMediaBrowser::closeRequest(uuid); - LLFloaterWebContent::closeRequest(uuid); - } - } - break; - - case LLViewerMediaObserver::MEDIA_EVENT_GEOMETRY_CHANGE: - { - std::string uuid = plugin->getClickUUID(); - - llinfos << "MEDIA_EVENT_GEOMETRY_CHANGE for uuid " << uuid << llendl; - - if(uuid.empty()) - { - // This geometry change request is directed at this instance, let it fall through. - } - else - { - // This request is directed at another instance - pass_through = false; - LLFloaterMediaBrowser::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight()); - LLFloaterWebContent::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight()); - } - } - break; - - default: - break; - } - - if(pass_through) - { - // Just chain the event to observers. - emitEvent(plugin, event); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void LLViewerMediaImpl::handleCookieSet(LLPluginClassMedia* self, const std::string &cookie) -{ - LLViewerMedia::getCookieStore()->setCookies(cookie); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void -LLViewerMediaImpl::cut() -{ - if (mMediaSource) - mMediaSource->cut(); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -BOOL -LLViewerMediaImpl::canCut() const -{ - if (mMediaSource) - return mMediaSource->canCut(); - else - return FALSE; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void -LLViewerMediaImpl::copy() -{ - if (mMediaSource) - mMediaSource->copy(); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -BOOL -LLViewerMediaImpl::canCopy() const -{ - if (mMediaSource) - return mMediaSource->canCopy(); - else - return FALSE; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -void -LLViewerMediaImpl::paste() -{ - if (mMediaSource) - mMediaSource->paste(); -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -BOOL -LLViewerMediaImpl::canPaste() const -{ - if (mMediaSource) - return mMediaSource->canPaste(); - else - return FALSE; -} - -void LLViewerMediaImpl::setUpdated(BOOL updated) -{ - mIsUpdated = updated ; -} - -BOOL LLViewerMediaImpl::isUpdated() -{ - return mIsUpdated ; -} - -void LLViewerMediaImpl::calculateInterest() -{ - LLViewerMediaTexture* texture = LLViewerTextureManager::findMediaTexture( mTextureId ); - - if(texture != NULL) - { - mInterest = texture->getMaxVirtualSize(); - } - else - { - // This will be a relatively common case now, since it will always be true for unloaded media. - mInterest = 0.0f; - } - - // Calculate distance from the avatar, for use in the proximity calculation. - mProximityDistance = 0.0f; - mProximityCamera = 0.0f; - if(!mObjectList.empty()) - { - // Just use the first object in the list. We could go through the list and find the closest object, but this should work well enough. - std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; - LLVOVolume* objp = *iter ; - llassert_always(objp != NULL) ; - - // The distance calculation is invalid for HUD attachments -- leave both mProximityDistance and mProximityCamera at 0 for them. - if(!objp->isHUDAttachment()) - { - LLVector3d obj_global = objp->getPositionGlobal() ; - LLVector3d agent_global = gAgent.getPositionGlobal() ; - LLVector3d global_delta = agent_global - obj_global ; - mProximityDistance = global_delta.magVecSquared(); // use distance-squared because it's cheaper and sorts the same. - - LLVector3d camera_delta = gAgentCamera.getCameraPositionGlobal() - obj_global; - mProximityCamera = camera_delta.magVec(); - } - } - - if(mNeedsMuteCheck) - { - // Check all objects this instance is associated with, and those objects' owners, against the mute list - mIsMuted = false; - - std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; - for(; iter != mObjectList.end() ; ++iter) - { - LLVOVolume *obj = *iter; - llassert(obj); - if (!obj) continue; - if(LLMuteList::getInstance() && - LLMuteList::getInstance()->isMuted(obj->getID())) - { - mIsMuted = true; - } - else - { - // We won't have full permissions data for all objects. Attempt to mute objects when we can tell their owners are muted. - if (LLSelectMgr::getInstance()) - { - LLPermissions* obj_perm = LLSelectMgr::getInstance()->findObjectPermissions(obj); - if(obj_perm) - { - if(LLMuteList::getInstance() && - LLMuteList::getInstance()->isMuted(obj_perm->getOwner())) - mIsMuted = true; - } - } - } - } - - mNeedsMuteCheck = false; - } -} - -F64 LLViewerMediaImpl::getApproximateTextureInterest() -{ - F64 result = 0.0f; - - if(mMediaSource) - { - result = mMediaSource->getFullWidth(); - result *= mMediaSource->getFullHeight(); - } - else - { - // No media source is loaded -- all we have to go on is the texture size that has been set on the impl, if any. - result = mMediaWidth; - result *= mMediaHeight; - } - - return result; -} - -void LLViewerMediaImpl::setUsedInUI(bool used_in_ui) -{ - mUsedInUI = used_in_ui; - - // HACK: Force elements used in UI to load right away. - // This fixes some issues where UI code that uses the browser instance doesn't expect it to be unloaded. - if(mUsedInUI && (mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)) - { - if(getVisible()) - { - setPriority(LLPluginClassMedia::PRIORITY_NORMAL); - } - else - { - setPriority(LLPluginClassMedia::PRIORITY_HIDDEN); - } - - createMediaSource(); - } -}; - -void LLViewerMediaImpl::setBackgroundColor(LLColor4 color) -{ - mBackgroundColor = color; - - if(mMediaSource) - { - mMediaSource->setBackgroundColor(mBackgroundColor); - } -}; - -F64 LLViewerMediaImpl::getCPUUsage() const -{ - F64 result = 0.0f; - - if(mMediaSource) - { - result = mMediaSource->getCPUUsage(); - } - - return result; -} - -void LLViewerMediaImpl::setPriority(LLPluginClassMedia::EPriority priority) -{ - if(mPriority != priority) - { - LL_DEBUGS("PluginPriority") - << "changing priority of media id " << mTextureId - << " from " << LLPluginClassMedia::priorityToString(mPriority) - << " to " << LLPluginClassMedia::priorityToString(priority) - << LL_ENDL; - } - - mPriority = priority; - - if(priority == LLPluginClassMedia::PRIORITY_UNLOADED) - { - if(mMediaSource) - { - // Need to unload the media source - - // First, save off previous media state - mPreviousMediaState = mMediaSource->getStatus(); - mPreviousMediaTime = mMediaSource->getCurrentTime(); - - destroyMediaSource(); - } - } - - if(mMediaSource) - { - mMediaSource->setPriority(mPriority); - } - - // NOTE: loading (or reloading) media sources whose priority has risen above PRIORITY_UNLOADED is done in update(). -} - -void LLViewerMediaImpl::setLowPrioritySizeLimit(int size) -{ - if(mMediaSource) - { - mMediaSource->setLowPrioritySizeLimit(size); - } -} - -void LLViewerMediaImpl::setNavState(EMediaNavState state) -{ - mMediaNavState = state; - - switch (state) - { - case MEDIANAVSTATE_NONE: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_NONE" << llendl; break; - case MEDIANAVSTATE_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_BEGUN" << llendl; break; - case MEDIANAVSTATE_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED" << llendl; break; - case MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS" << llendl; break; - case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED" << llendl; break; - case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS" << llendl; break; - case MEDIANAVSTATE_SERVER_SENT: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_SENT" << llendl; break; - case MEDIANAVSTATE_SERVER_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_BEGUN" << llendl; break; - case MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED" << llendl; break; - case MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED" << llendl; break; - } -} - -void LLViewerMediaImpl::setNavigateSuspended(bool suspend) -{ - if(mNavigateSuspended != suspend) - { - mNavigateSuspended = suspend; - if(!suspend) - { - // We're coming out of suspend. If someone tried to do a navigate while suspended, do one now instead. - if(mNavigateSuspendedDeferred) - { - mNavigateSuspendedDeferred = false; - navigateInternal(); - } - } - } -} - -void LLViewerMediaImpl::cancelMimeTypeProbe() -{ - if(mMimeTypeProbe != NULL) - { - // There doesn't seem to be a way to actually cancel an outstanding request. - // Simulate it by telling the LLMimeDiscoveryResponder not to write back any results. - mMimeTypeProbe->cancelRequest(); - - // The above should already have set mMimeTypeProbe to NULL. - if(mMimeTypeProbe != NULL) - { - llerrs << "internal error: mMimeTypeProbe is not NULL after cancelling request." << llendl; - } - } -} - -void LLViewerMediaImpl::addObject(LLVOVolume* obj) -{ - std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; - for(; iter != mObjectList.end() ; ++iter) - { - if(*iter == obj) - { - return ; //already in the list. - } - } - - mObjectList.push_back(obj) ; - mNeedsMuteCheck = true; -} - -void LLViewerMediaImpl::removeObject(LLVOVolume* obj) -{ - mObjectList.remove(obj) ; - mNeedsMuteCheck = true; -} - -const std::list< LLVOVolume* >* LLViewerMediaImpl::getObjectList() const -{ - return &mObjectList ; -} - -LLVOVolume *LLViewerMediaImpl::getSomeObject() -{ - LLVOVolume *result = NULL; - - std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; - if(iter != mObjectList.end()) - { - result = *iter; - } - - return result; -} - -void LLViewerMediaImpl::setTextureID(LLUUID id) -{ - if(id != mTextureId) - { - if(mTextureId.notNull()) - { - // Remove this item's entry from the map - sViewerMediaTextureIDMap.erase(mTextureId); - } - - if(id.notNull()) - { - sViewerMediaTextureIDMap.insert(LLViewerMedia::impl_id_map::value_type(id, this)); - } - - mTextureId = id; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaImpl::isAutoPlayable() const -{ - return (mMediaAutoPlay && - gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && - gSavedSettings.getBOOL("MediaTentativeAutoPlay")); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaImpl::shouldShowBasedOnClass() const -{ - // If this is parcel media or in the UI, return true always - if (getUsedInUI() || isParcelMedia()) return true; - - bool attached_to_another_avatar = isAttachedToAnotherAvatar(); - bool inside_parcel = isInAgentParcel(); - - // llinfos << " hasFocus = " << hasFocus() << - // " others = " << (attached_to_another_avatar && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING)) << - // " within = " << (inside_parcel && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING)) << - // " outside = " << (!inside_parcel && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING)) << llendl; - - // If it has focus, we should show it - // This is incorrect, and causes EXT-6750 (disabled attachment media still plays) -// if (hasFocus()) -// return true; - - // If it is attached to an avatar and the pref is off, we shouldn't show it - if (attached_to_another_avatar) - return gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING); - - if (inside_parcel) - return gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING); - else - return gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaImpl::isAttachedToAnotherAvatar() const -{ - bool result = false; - - std::list< LLVOVolume* >::const_iterator iter = mObjectList.begin(); - std::list< LLVOVolume* >::const_iterator end = mObjectList.end(); - for ( ; iter != end; iter++) - { - if (isObjectAttachedToAnotherAvatar(*iter)) - { - result = true; - break; - } - } - return result; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// -//static -bool LLViewerMediaImpl::isObjectAttachedToAnotherAvatar(LLVOVolume *obj) -{ - bool result = false; - LLXform *xform = obj; - // Walk up parent chain - while (NULL != xform) - { - LLViewerObject *object = dynamic_cast (xform); - if (NULL != object) - { - LLVOAvatar *avatar = object->asAvatar(); - if ((NULL != avatar) && (avatar != gAgentAvatarp)) - { - result = true; - break; - } - } - xform = xform->getParent(); - } - return result; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// -bool LLViewerMediaImpl::isInAgentParcel() const -{ - bool result = false; - - std::list< LLVOVolume* >::const_iterator iter = mObjectList.begin(); - std::list< LLVOVolume* >::const_iterator end = mObjectList.end(); - for ( ; iter != end; iter++) - { - LLVOVolume *object = *iter; - if (LLViewerMediaImpl::isObjectInAgentParcel(object)) - { - result = true; - break; - } - } - return result; -} - -LLNotificationPtr LLViewerMediaImpl::getCurrentNotification() const -{ - return mNotification; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// -// static -bool LLViewerMediaImpl::isObjectInAgentParcel(LLVOVolume *obj) -{ - return (LLViewerParcelMgr::getInstance()->inAgentParcel(obj->getPositionGlobal())); -} +/** + * @file llviewermedia.cpp + * @brief Client interface to the media engine + * + * $LicenseInfo:firstyear=2007&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$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llagent.h" +#include "llagentcamera.h" +#include "llviewermedia.h" +#include "llviewermediafocus.h" +#include "llmimetypes.h" +#include "llmediaentry.h" +#include "llversioninfo.h" +#include "llviewercontrol.h" +#include "llviewertexture.h" +#include "llviewerparcelmedia.h" +#include "llviewerparcelmgr.h" +#include "llviewertexturelist.h" +#include "llvovolume.h" +#include "llpluginclassmedia.h" +#include "llplugincookiestore.h" +#include "llviewerwindow.h" +#include "llfocusmgr.h" +#include "llcallbacklist.h" +#include "llparcel.h" +#include "llaudioengine.h" // for gAudiop +#include "llurldispatcher.h" +#include "llvoavatar.h" +#include "llvoavatarself.h" +#include "llviewerregion.h" +#include "llwebsharing.h" // For LLWebSharing::setOpenIDCookie(), *TODO: find a better way to do this! +#include "llfilepicker.h" +#include "llnotifications.h" +#include "lldir.h" +#include "llevent.h" // LLSimpleListener +#include "llnotificationsutil.h" +#include "lluuid.h" +#include "llkeyboard.h" +#include "llmutelist.h" +#include "llpanelprofile.h" +#include "llappviewer.h" +#include "lllogininstance.h" +//#include "llfirstuse.h" +#include "llwindow.h" + +#include "llfloatermediabrowser.h" // for handling window close requests and geometry change requests in media browser windows. +#include "llfloaterwebcontent.h" // for handling window close requests and geometry change requests in media browser windows. + +#include // for SkinFolder listener +#include + +/*static*/ const char* LLViewerMedia::AUTO_PLAY_MEDIA_SETTING = "ParcelMediaAutoPlayEnable"; +/*static*/ const char* LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING = "MediaShowOnOthers"; +/*static*/ const char* LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING = "MediaShowWithinParcel"; +/*static*/ const char* LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING = "MediaShowOutsideParcel"; + + +// Move this to its own file. + +LLViewerMediaEventEmitter::~LLViewerMediaEventEmitter() +{ + observerListType::iterator iter = mObservers.begin(); + + while( iter != mObservers.end() ) + { + LLViewerMediaObserver *self = *iter; + iter++; + remObserver(self); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaEventEmitter::addObserver( LLViewerMediaObserver* observer ) +{ + if ( ! observer ) + return false; + + if ( std::find( mObservers.begin(), mObservers.end(), observer ) != mObservers.end() ) + return false; + + mObservers.push_back( observer ); + observer->mEmitters.push_back( this ); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaEventEmitter::remObserver( LLViewerMediaObserver* observer ) +{ + if ( ! observer ) + return false; + + mObservers.remove( observer ); + observer->mEmitters.remove(this); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// +void LLViewerMediaEventEmitter::emitEvent( LLPluginClassMedia* media, LLViewerMediaObserver::EMediaEvent event ) +{ + // Broadcast the event to any observers. + observerListType::iterator iter = mObservers.begin(); + while( iter != mObservers.end() ) + { + LLViewerMediaObserver *self = *iter; + ++iter; + self->handleMediaEvent( media, event ); + } +} + +// Move this to its own file. +LLViewerMediaObserver::~LLViewerMediaObserver() +{ + std::list::iterator iter = mEmitters.begin(); + + while( iter != mEmitters.end() ) + { + LLViewerMediaEventEmitter *self = *iter; + iter++; + self->remObserver( this ); + } +} + + +// Move this to its own file. +// helper class that tries to download a URL from a web site and calls a method +// on the Panel Land Media and to discover the MIME type +class LLMimeDiscoveryResponder : public LLHTTPClient::Responder +{ +LOG_CLASS(LLMimeDiscoveryResponder); +public: + LLMimeDiscoveryResponder( viewer_media_t media_impl) + : mMediaImpl(media_impl), + mInitialized(false) + { + if(mMediaImpl->mMimeTypeProbe != NULL) + { + llerrs << "impl already has an outstanding responder" << llendl; + } + + mMediaImpl->mMimeTypeProbe = this; + } + + ~LLMimeDiscoveryResponder() + { + disconnectOwner(); + } + + virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) + { + std::string media_type = content["content-type"].asString(); + std::string::size_type idx1 = media_type.find_first_of(";"); + std::string mime_type = media_type.substr(0, idx1); + + lldebugs << "status is " << status << ", media type \"" << media_type << "\"" << llendl; + + // 2xx status codes indicate success. + // Most 4xx status codes are successful enough for our purposes. + // 499 is the error code for host not found, timeout, etc. + // 500 means "Internal Server error" but we decided it's okay to + // accept this and go past it in the MIME type probe + // 302 means the resource can be found temporarily in a different place - added this for join.secondlife.com + // 499 is a code specifc to join.secondlife.com (????) apparently safe to ignore +// if( ((status >= 200) && (status < 300)) || +// ((status >= 400) && (status < 499)) || +// (status == 500) || +// (status == 302) || +// (status == 499) +// ) + // We now no longer check the error code returned from the probe. + // If we have a mime type, use it. If not, default to the web plugin and let it handle error reporting. + if(1) + { + // The probe was successful. + if(mime_type.empty()) + { + // Some sites don't return any content-type header at all. + // Treat an empty mime type as text/html. + mime_type = "text/html"; + } + + completeAny(status, mime_type); + } + else + { + llwarns << "responder failed with status " << status << ", reason " << reason << llendl; + + if(mMediaImpl) + { + mMediaImpl->mMediaSourceFailed = true; + } + } + + } + + void completeAny(U32 status, const std::string& mime_type) + { + // the call to initializeMedia may disconnect the responder, which will clear mMediaImpl. + // Make a local copy so we can call loadURI() afterwards. + LLViewerMediaImpl *impl = mMediaImpl; + + if(impl && !mInitialized && ! mime_type.empty()) + { + if(impl->initializeMedia(mime_type)) + { + mInitialized = true; + impl->loadURI(); + disconnectOwner(); + } + } + } + + void cancelRequest() + { + disconnectOwner(); + } + +private: + void disconnectOwner() + { + if(mMediaImpl) + { + if(mMediaImpl->mMimeTypeProbe != this) + { + llerrs << "internal error: mMediaImpl->mMimeTypeProbe != this" << llendl; + } + + mMediaImpl->mMimeTypeProbe = NULL; + } + mMediaImpl = NULL; + } + + +public: + LLViewerMediaImpl *mMediaImpl; + bool mInitialized; +}; + +class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder +{ +LOG_CLASS(LLViewerMediaOpenIDResponder); +public: + LLViewerMediaOpenIDResponder( ) + { + } + + ~LLViewerMediaOpenIDResponder() + { + } + + /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) + { + LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; + LL_DEBUGS("MediaAuth") << content << LL_ENDL; + std::string cookie = content["set-cookie"].asString(); + + LLViewerMedia::openIDCookieResponse(cookie); + } + + /* virtual */ void completedRaw( + U32 status, + const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + // This is just here to disable the default behavior (attempting to parse the response as llsd). + // We don't care about the content of the response, only the set-cookie header. + } + +}; + +class LLViewerMediaWebProfileResponder : public LLHTTPClient::Responder +{ +LOG_CLASS(LLViewerMediaWebProfileResponder); +public: + LLViewerMediaWebProfileResponder(std::string host) + { + mHost = host; + } + + ~LLViewerMediaWebProfileResponder() + { + } + + /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) + { + LL_WARNS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; + LL_WARNS("MediaAuth") << content << LL_ENDL; + + std::string cookie = content["set-cookie"].asString(); + + LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost); + } + + void completedRaw( + U32 status, + const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + // This is just here to disable the default behavior (attempting to parse the response as llsd). + // We don't care about the content of the response, only the set-cookie header. + } + + std::string mHost; +}; + + +LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL; +LLURL LLViewerMedia::sOpenIDURL; +std::string LLViewerMedia::sOpenIDCookie; +LLPluginClassMedia* LLViewerMedia::sSpareBrowserMediaSource = NULL; +static LLViewerMedia::impl_list sViewerMediaImplList; +static LLViewerMedia::impl_id_map sViewerMediaTextureIDMap; +static LLTimer sMediaCreateTimer; +static const F32 LLVIEWERMEDIA_CREATE_DELAY = 1.0f; +static F32 sGlobalVolume = 1.0f; +static F64 sLowestLoadableImplInterest = 0.0f; +static bool sAnyMediaShowing = false; +static boost::signals2::connection sTeleportFinishConnection; +static std::string sUpdatedCookies; +static const char *PLUGIN_COOKIE_FILE_NAME = "plugin_cookies.txt"; + +////////////////////////////////////////////////////////////////////////////////////////// +static void add_media_impl(LLViewerMediaImpl* media) +{ + sViewerMediaImplList.push_back(media); +} + +////////////////////////////////////////////////////////////////////////////////////////// +static void remove_media_impl(LLViewerMediaImpl* media) +{ + LLViewerMedia::impl_list::iterator iter = sViewerMediaImplList.begin(); + LLViewerMedia::impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + if(media == *iter) + { + sViewerMediaImplList.erase(iter); + return; + } + } +} + +class LLViewerMediaMuteListObserver : public LLMuteListObserver +{ + /* virtual */ void onChange() { LLViewerMedia::muteListChanged();} +}; + +static LLViewerMediaMuteListObserver sViewerMediaMuteListObserver; +static bool sViewerMediaMuteListObserverInitialized = false; +static bool sInWorldMediaDisabled = false; + + +////////////////////////////////////////////////////////////////////////////////////////// +// LLViewerMedia + +////////////////////////////////////////////////////////////////////////////////////////// +// static +viewer_media_t LLViewerMedia::newMediaImpl( + const LLUUID& texture_id, + S32 media_width, + S32 media_height, + U8 media_auto_scale, + U8 media_loop) +{ + LLViewerMediaImpl* media_impl = getMediaImplFromTextureID(texture_id); + if(media_impl == NULL || texture_id.isNull()) + { + // Create the media impl + media_impl = new LLViewerMediaImpl(texture_id, media_width, media_height, media_auto_scale, media_loop); + } + else + { + media_impl->unload(); + media_impl->setTextureID(texture_id); + media_impl->mMediaWidth = media_width; + media_impl->mMediaHeight = media_height; + media_impl->mMediaAutoScale = media_auto_scale; + media_impl->mMediaLoop = media_loop; + } + + return media_impl; +} + +viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const std::string& previous_url, bool update_from_self) +{ + // Try to find media with the same media ID + viewer_media_t media_impl = getMediaImplFromTextureID(media_entry->getMediaID()); + + lldebugs << "called, current URL is \"" << media_entry->getCurrentURL() + << "\", previous URL is \"" << previous_url + << "\", update_from_self is " << (update_from_self?"true":"false") + << llendl; + + bool was_loaded = false; + bool needs_navigate = false; + + if(media_impl) + { + was_loaded = media_impl->hasMedia(); + + media_impl->setHomeURL(media_entry->getHomeURL()); + + media_impl->mMediaAutoScale = media_entry->getAutoScale(); + media_impl->mMediaLoop = media_entry->getAutoLoop(); + media_impl->mMediaWidth = media_entry->getWidthPixels(); + media_impl->mMediaHeight = media_entry->getHeightPixels(); + media_impl->mMediaAutoPlay = media_entry->getAutoPlay(); + media_impl->mMediaEntryURL = media_entry->getCurrentURL(); + if (media_impl->mMediaSource) + { + media_impl->mMediaSource->setAutoScale(media_impl->mMediaAutoScale); + media_impl->mMediaSource->setLoop(media_impl->mMediaLoop); + media_impl->mMediaSource->setSize(media_entry->getWidthPixels(), media_entry->getHeightPixels()); + } + + bool url_changed = (media_impl->mMediaEntryURL != previous_url); + if(media_impl->mMediaEntryURL.empty()) + { + if(url_changed) + { + // The current media URL is now empty. Unload the media source. + media_impl->unload(); + + lldebugs << "Unloading media instance (new current URL is empty)." << llendl; + } + } + else + { + // The current media URL is not empty. + // If (the media was already loaded OR the media was set to autoplay) AND this update didn't come from this agent, + // do a navigate. + bool auto_play = media_impl->isAutoPlayable(); + if((was_loaded || auto_play) && !update_from_self) + { + needs_navigate = url_changed; + } + + lldebugs << "was_loaded is " << (was_loaded?"true":"false") + << ", auto_play is " << (auto_play?"true":"false") + << ", needs_navigate is " << (needs_navigate?"true":"false") << llendl; + } + } + else + { + media_impl = newMediaImpl( + media_entry->getMediaID(), + media_entry->getWidthPixels(), + media_entry->getHeightPixels(), + media_entry->getAutoScale(), + media_entry->getAutoLoop()); + + media_impl->setHomeURL(media_entry->getHomeURL()); + media_impl->mMediaAutoPlay = media_entry->getAutoPlay(); + media_impl->mMediaEntryURL = media_entry->getCurrentURL(); + if(media_impl->isAutoPlayable()) + { + needs_navigate = true; + } + } + + if(media_impl) + { + if(needs_navigate) + { + media_impl->navigateTo(media_impl->mMediaEntryURL, "", true, true); + lldebugs << "navigating to URL " << media_impl->mMediaEntryURL << llendl; + } + else if(!media_impl->mMediaURL.empty() && (media_impl->mMediaURL != media_impl->mMediaEntryURL)) + { + // If we already have a non-empty media URL set and we aren't doing a navigate, update the media URL to match the media entry. + media_impl->mMediaURL = media_impl->mMediaEntryURL; + + // If this causes a navigate at some point (such as after a reload), it should be considered server-driven so it isn't broadcast. + media_impl->mNavigateServerRequest = true; + + lldebugs << "updating URL in the media impl to " << media_impl->mMediaEntryURL << llendl; + } + } + + return media_impl; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +LLViewerMediaImpl* LLViewerMedia::getMediaImplFromTextureID(const LLUUID& texture_id) +{ + LLViewerMediaImpl* result = NULL; + + // Look up the texture ID in the texture id->impl map. + impl_id_map::iterator iter = sViewerMediaTextureIDMap.find(texture_id); + if(iter != sViewerMediaTextureIDMap.end()) + { + result = iter->second; + } + + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +std::string LLViewerMedia::getCurrentUserAgent() +{ + // Don't use user-visible string to avoid + // punctuation and strange characters. + std::string skin_name = gSavedSettings.getString("SkinCurrent"); + + // Just in case we need to check browser differences in A/B test + // builds. + std::string channel = LLVersionInfo::getChannel(); + + // append our magic version number string to the browser user agent id + // See the HTTP 1.0 and 1.1 specifications for allowed formats: + // http://www.ietf.org/rfc/rfc1945.txt section 10.15 + // http://www.ietf.org/rfc/rfc2068.txt section 3.8 + // This was also helpful: + // http://www.mozilla.org/build/revised-user-agent-strings.html + std::ostringstream codec; + codec << "SecondLife/"; + codec << LLVersionInfo::getVersion(); + codec << " (" << channel << "; " << skin_name << " skin)"; + llinfos << codec.str() << llendl; + + return codec.str(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::updateBrowserUserAgent() +{ + std::string user_agent = getCurrentUserAgent(); + + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->mMediaSource && pimpl->mMediaSource->pluginSupportsMediaBrowser()) + { + pimpl->mMediaSource->setBrowserUserAgent(user_agent); + } + } + +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::handleSkinCurrentChanged(const LLSD& /*newvalue*/) +{ + // gSavedSettings is already updated when this function is called. + updateBrowserUserAgent(); + return true; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::textureHasMedia(const LLUUID& texture_id) +{ + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->getMediaTextureID() == texture_id) + { + return true; + } + } + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setVolume(F32 volume) +{ + if(volume != sGlobalVolume) + { + sGlobalVolume = volume; + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + pimpl->updateVolume(); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +F32 LLViewerMedia::getVolume() +{ + return sGlobalVolume; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::muteListChanged() +{ + // When the mute list changes, we need to check mute status on all impls. + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + pimpl->mNeedsMuteCheck = true; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setInWorldMediaDisabled(bool disabled) +{ + sInWorldMediaDisabled = disabled; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::getInWorldMediaDisabled() +{ + return sInWorldMediaDisabled; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::isInterestingEnough(const LLVOVolume *object, const F64 &object_interest) +{ + bool result = false; + + if (NULL == object) + { + result = false; + } + // Focused? Then it is interesting! + else if (LLViewerMediaFocus::getInstance()->getFocusedObjectID() == object->getID()) + { + result = true; + } + // Selected? Then it is interesting! + // XXX Sadly, 'contains()' doesn't take a const :( + else if (LLSelectMgr::getInstance()->getSelection()->contains(const_cast(object))) + { + result = true; + } + else + { + lldebugs << "object interest = " << object_interest << ", lowest loadable = " << sLowestLoadableImplInterest << llendl; + if(object_interest >= sLowestLoadableImplInterest) + result = true; + } + + return result; +} + +LLViewerMedia::impl_list &LLViewerMedia::getPriorityList() +{ + return sViewerMediaImplList; +} + +// This is the predicate function used to sort sViewerMediaImplList by priority. +bool LLViewerMedia::priorityComparitor(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2) +{ + if(i1->isForcedUnloaded() && !i2->isForcedUnloaded()) + { + // Muted or failed items always go to the end of the list, period. + return false; + } + else if(i2->isForcedUnloaded() && !i1->isForcedUnloaded()) + { + // Muted or failed items always go to the end of the list, period. + return true; + } + else if(i1->hasFocus()) + { + // The item with user focus always comes to the front of the list, period. + return true; + } + else if(i2->hasFocus()) + { + // The item with user focus always comes to the front of the list, period. + return false; + } + else if(i1->isParcelMedia()) + { + // The parcel media impl sorts above all other inworld media, unless one has focus. + return true; + } + else if(i2->isParcelMedia()) + { + // The parcel media impl sorts above all other inworld media, unless one has focus. + return false; + } + else if(i1->getUsedInUI() && !i2->getUsedInUI()) + { + // i1 is a UI element, i2 is not. This makes i1 "less than" i2, so it sorts earlier in our list. + return true; + } + else if(i2->getUsedInUI() && !i1->getUsedInUI()) + { + // i2 is a UI element, i1 is not. This makes i2 "less than" i1, so it sorts earlier in our list. + return false; + } + else if(i1->isPlayable() && !i2->isPlayable()) + { + // Playable items sort above ones that wouldn't play even if they got high enough priority + return true; + } + else if(!i1->isPlayable() && i2->isPlayable()) + { + // Playable items sort above ones that wouldn't play even if they got high enough priority + return false; + } + else if(i1->getInterest() == i2->getInterest()) + { + // Generally this will mean both objects have zero interest. In this case, sort on distance. + return (i1->getProximityDistance() < i2->getProximityDistance()); + } + else + { + // The object with the larger interest value should be earlier in the list, so we reverse the sense of the comparison here. + return (i1->getInterest() > i2->getInterest()); + } +} + +static bool proximity_comparitor(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2) +{ + if(i1->getProximityDistance() < i2->getProximityDistance()) + { + return true; + } + else if(i1->getProximityDistance() > i2->getProximityDistance()) + { + return false; + } + else + { + // Both objects have the same distance. This most likely means they're two faces of the same object. + // They may also be faces on different objects with exactly the same distance (like HUD objects). + // We don't actually care what the sort order is for this case, as long as it's stable and doesn't change when you enable/disable media. + // Comparing the impl pointers gives a completely arbitrary ordering, but it will be stable. + return (i1 < i2); + } +} + +static LLFastTimer::DeclareTimer FTM_MEDIA_UPDATE("Update Media"); + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::updateMedia(void *dummy_arg) +{ + LLFastTimer t1(FTM_MEDIA_UPDATE); + + // Enable/disable the plugin read thread + LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread")); + + // HACK: we always try to keep a spare running webkit plugin around to improve launch times. + createSpareBrowserMediaSource(); + + sAnyMediaShowing = false; + sUpdatedCookies = getCookieStore()->getChangedCookies(); + if(!sUpdatedCookies.empty()) + { + lldebugs << "updated cookies will be sent to all loaded plugins: " << llendl; + lldebugs << sUpdatedCookies << llendl; + } + + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end;) + { + LLViewerMediaImpl* pimpl = *iter++; + pimpl->update(); + pimpl->calculateInterest(); + } + + // Let the spare media source actually launch + if(sSpareBrowserMediaSource) + { + sSpareBrowserMediaSource->idle(); + } + + // Sort the static instance list using our interest criteria + sViewerMediaImplList.sort(priorityComparitor); + + // Go through the list again and adjust according to priority. + iter = sViewerMediaImplList.begin(); + end = sViewerMediaImplList.end(); + + F64 total_cpu = 0.0f; + int impl_count_total = 0; + int impl_count_interest_low = 0; + int impl_count_interest_normal = 0; + + std::vector proximity_order; + + bool inworld_media_enabled = gSavedSettings.getBOOL("AudioStreamingMedia"); + bool inworld_audio_enabled = gSavedSettings.getBOOL("AudioStreamingMusic"); + U32 max_instances = gSavedSettings.getU32("PluginInstancesTotal"); + U32 max_normal = gSavedSettings.getU32("PluginInstancesNormal"); + U32 max_low = gSavedSettings.getU32("PluginInstancesLow"); + F32 max_cpu = gSavedSettings.getF32("PluginInstancesCPULimit"); + // Setting max_cpu to 0.0 disables CPU usage checking. + bool check_cpu_usage = (max_cpu != 0.0f); + + LLViewerMediaImpl* lowest_interest_loadable = NULL; + + // Notes on tweakable params: + // max_instances must be set high enough to allow the various instances used in the UI (for the help browser, search, etc.) to be loaded. + // If max_normal + max_low is less than max_instances, things will tend to get unloaded instead of being set to slideshow. + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + + LLPluginClassMedia::EPriority new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + + if(pimpl->isForcedUnloaded() || (impl_count_total >= (int)max_instances)) + { + // Never load muted or failed impls. + // Hard limit on the number of instances that will be loaded at one time + new_priority = LLPluginClassMedia::PRIORITY_UNLOADED; + } + else if(!pimpl->getVisible()) + { + new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; + } + else if(pimpl->hasFocus()) + { + new_priority = LLPluginClassMedia::PRIORITY_HIGH; + impl_count_interest_normal++; // count this against the count of "normal" instances for priority purposes + } + else if(pimpl->getUsedInUI()) + { + new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + impl_count_interest_normal++; + } + else if(pimpl->isParcelMedia()) + { + new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + impl_count_interest_normal++; + } + else + { + // Look at interest and CPU usage for instances that aren't in any of the above states. + + // Heuristic -- if the media texture's approximate screen area is less than 1/4 of the native area of the texture, + // turn it down to low instead of normal. This may downsample for plugins that support it. + bool media_is_small = false; + F64 approximate_interest = pimpl->getApproximateTextureInterest(); + if(approximate_interest == 0.0f) + { + // this media has no current size, which probably means it's not loaded. + media_is_small = true; + } + else if(pimpl->getInterest() < (approximate_interest / 4)) + { + media_is_small = true; + } + + if(pimpl->getInterest() == 0.0f) + { + // This media is completely invisible, due to being outside the view frustrum or out of range. + new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; + } + else if(check_cpu_usage && (total_cpu > max_cpu)) + { + // Higher priority plugins have already used up the CPU budget. Set remaining ones to slideshow priority. + new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW; + } + else if((impl_count_interest_normal < (int)max_normal) && !media_is_small) + { + // Up to max_normal inworld get normal priority + new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + impl_count_interest_normal++; + } + else if (impl_count_interest_low + impl_count_interest_normal < (int)max_low + (int)max_normal) + { + // The next max_low inworld get turned down + new_priority = LLPluginClassMedia::PRIORITY_LOW; + impl_count_interest_low++; + + // Set the low priority size for downsampling to approximately the size the texture is displayed at. + { + F32 approximate_interest_dimension = fsqrtf(pimpl->getInterest()); + + pimpl->setLowPrioritySizeLimit(llround(approximate_interest_dimension)); + } + } + else + { + // Any additional impls (up to max_instances) get very infrequent time + new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW; + } + } + + if(!pimpl->getUsedInUI() && (new_priority != LLPluginClassMedia::PRIORITY_UNLOADED)) + { + // This is a loadable inworld impl -- the last one in the list in this class defines the lowest loadable interest. + lowest_interest_loadable = pimpl; + + impl_count_total++; + } + + // Overrides if the window is minimized or we lost focus (taking care + // not to accidentally "raise" the priority either) + if (!gViewerWindow->getActive() /* viewer window minimized? */ + && new_priority > LLPluginClassMedia::PRIORITY_HIDDEN) + { + new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; + } + else if (!gFocusMgr.getAppHasFocus() /* viewer window lost focus? */ + && new_priority > LLPluginClassMedia::PRIORITY_LOW) + { + new_priority = LLPluginClassMedia::PRIORITY_LOW; + } + + if(!inworld_media_enabled) + { + // If inworld media is locked out, force all inworld media to stay unloaded. + if(!pimpl->getUsedInUI()) + { + new_priority = LLPluginClassMedia::PRIORITY_UNLOADED; + } + } + // update the audio stream here as well + if( !inworld_audio_enabled) + { + if(LLViewerMedia::isParcelAudioPlaying() && gAudiop && LLViewerMedia::hasParcelAudio()) + { + gAudiop->stopInternetStream(); + } + } + pimpl->setPriority(new_priority); + + if(pimpl->getUsedInUI()) + { + // Any impls used in the UI should not be in the proximity list. + pimpl->mProximity = -1; + } + else + { + proximity_order.push_back(pimpl); + } + + total_cpu += pimpl->getCPUUsage(); + + if (!pimpl->getUsedInUI() && pimpl->hasMedia()) + { + sAnyMediaShowing = true; + } + + } + + // Re-calculate this every time. + sLowestLoadableImplInterest = 0.0f; + + // Only do this calculation if we've hit the impl count limit -- up until that point we always need to load media data. + if(lowest_interest_loadable && (impl_count_total >= (int)max_instances)) + { + // Get the interest value of this impl's object for use by isInterestingEnough + LLVOVolume *object = lowest_interest_loadable->getSomeObject(); + if(object) + { + // NOTE: Don't use getMediaInterest() here. We want the pixel area, not the total media interest, + // so that we match up with the calculation done in LLMediaDataClient. + sLowestLoadableImplInterest = object->getPixelArea(); + } + } + + if(gSavedSettings.getBOOL("MediaPerformanceManagerDebug")) + { + // Give impls the same ordering as the priority list + // they're already in the right order for this. + } + else + { + // Use a distance-based sort for proximity values. + std::stable_sort(proximity_order.begin(), proximity_order.end(), proximity_comparitor); + } + + // Transfer the proximity order to the proximity fields in the objects. + for(int i = 0; i < (int)proximity_order.size(); i++) + { + proximity_order[i]->mProximity = i; + } + + LL_DEBUGS("PluginPriority") << "Total reported CPU usage is " << total_cpu << llendl; + +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::isAnyMediaShowing() +{ + return sAnyMediaShowing; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setAllMediaEnabled(bool val) +{ + // Set "tentative" autoplay first. We need to do this here or else + // re-enabling won't start up the media below. + gSavedSettings.setBOOL("MediaTentativeAutoPlay", val); + + // Then + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if (!pimpl->getUsedInUI()) + { + pimpl->setDisabled(!val); + } + } + + // Also do Parcel Media and Parcel Audio + if (val) + { + if (!LLViewerMedia::isParcelMediaPlaying() && LLViewerMedia::hasParcelMedia()) + { + LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel()); + } + + if (gSavedSettings.getBOOL("AudioStreamingMusic") && + !LLViewerMedia::isParcelAudioPlaying() && + gAudiop && + LLViewerMedia::hasParcelAudio()) + { + gAudiop->startInternetStream(LLViewerMedia::getParcelAudioURL()); + } + } + else { + // This actually unloads the impl, as opposed to "stop"ping the media + LLViewerParcelMedia::stop(); + if (gAudiop) gAudiop->stopInternetStream(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::isParcelMediaPlaying() +{ + return (LLViewerMedia::hasParcelMedia() && LLViewerParcelMedia::getParcelMedia() && LLViewerParcelMedia::getParcelMedia()->hasMedia()); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::isParcelAudioPlaying() +{ + return (LLViewerMedia::hasParcelAudio() && gAudiop && LLAudioEngine::AUDIO_PLAYING == gAudiop->isInternetStreamPlaying()); +} + +void LLViewerMedia::onAuthSubmit(const LLSD& notification, const LLSD& response) +{ + LLViewerMediaImpl *impl = LLViewerMedia::getMediaImplFromTextureID(notification["payload"]["media_id"]); + if(impl) + { + LLPluginClassMedia* media = impl->getMediaPlugin(); + if(media) + { + if (response["ok"]) + { + media->sendAuthResponse(true, response["username"], response["password"]); + } + else + { + media->sendAuthResponse(false, "", ""); + } + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::clearAllCookies() +{ + // Clear all cookies for all plugins + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->mMediaSource) + { + pimpl->mMediaSource->clear_cookies(); + } + } + + // Clear all cookies from the cookie store + getCookieStore()->setAllCookies(""); + + // FIXME: this may not be sufficient, since the on-disk cookie file won't get written until some browser instance exits cleanly. + // It also won't clear cookies for other accounts, or for any account if we're not logged in, and won't do anything at all if there are no webkit plugins loaded. + // Until such time as we can centralize cookie storage, the following hack should cover these cases: + + // HACK: Look for cookie files in all possible places and delete them. + // NOTE: this assumes knowledge of what happens inside the webkit plugin (it's what adds 'browser_profile' to the path and names the cookie file) + + // Places that cookie files can be: + // /browser_profile/cookies + // /first_last/browser_profile/cookies (note that there may be any number of these!) + // /first_last/plugin_cookies.txt (note that there may be any number of these!) + + std::string base_dir = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter(); + std::string target; + std::string filename; + + lldebugs << "base dir = " << base_dir << llendl; + + // The non-logged-in version is easy + target = base_dir; + target += "browser_profile"; + target += gDirUtilp->getDirDelimiter(); + target += "cookies"; + lldebugs << "target = " << target << llendl; + if(LLFile::isfile(target)) + { + LLFile::remove(target); + } + + // the hard part: iterate over all user directories and delete the cookie file from each one + while(gDirUtilp->getNextFileInDir(base_dir, "*_*", filename)) + { + target = base_dir; + target += filename; + target += gDirUtilp->getDirDelimiter(); + target += "browser_profile"; + target += gDirUtilp->getDirDelimiter(); + target += "cookies"; + lldebugs << "target = " << target << llendl; + if(LLFile::isfile(target)) + { + LLFile::remove(target); + } + + // Other accounts may have new-style cookie files too -- delete them as well + target = base_dir; + target += filename; + target += gDirUtilp->getDirDelimiter(); + target += PLUGIN_COOKIE_FILE_NAME; + lldebugs << "target = " << target << llendl; + if(LLFile::isfile(target)) + { + LLFile::remove(target); + } + } + + // If we have an OpenID cookie, re-add it to the cookie store. + setOpenIDCookie(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::clearAllCaches() +{ + // Clear all plugins' caches + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + pimpl->clearCache(); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setCookiesEnabled(bool enabled) +{ + // Set the "cookies enabled" flag for all loaded plugins + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->mMediaSource) + { + pimpl->mMediaSource->enable_cookies(enabled); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setProxyConfig(bool enable, const std::string &host, int port) +{ + // Set the proxy config for all loaded plugins + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->mMediaSource) + { + pimpl->mMediaSource->proxy_setup(enable, host, port); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +///////////////////////////////////////////////////////////////////////////////////////// +// static +LLPluginCookieStore *LLViewerMedia::getCookieStore() +{ + if(sCookieStore == NULL) + { + sCookieStore = new LLPluginCookieStore; + } + + return sCookieStore; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::loadCookieFile() +{ + // build filename for each user + std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME); + + if (resolved_filename.empty()) + { + llinfos << "can't get path to plugin cookie file - probably not logged in yet." << llendl; + return; + } + + // open the file for reading + llifstream file(resolved_filename); + if (!file.is_open()) + { + llwarns << "can't load plugin cookies from file \"" << PLUGIN_COOKIE_FILE_NAME << "\"" << llendl; + return; + } + + getCookieStore()->readAllCookies(file, true); + + file.close(); + + // send the clear_cookies message to all loaded plugins + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->mMediaSource) + { + pimpl->mMediaSource->clear_cookies(); + } + } + + // If we have an OpenID cookie, re-add it to the cookie store. + setOpenIDCookie(); +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::saveCookieFile() +{ + // build filename for each user + std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME); + + if (resolved_filename.empty()) + { + llinfos << "can't get path to plugin cookie file - probably not logged in yet." << llendl; + return; + } + + // open a file for writing + llofstream file (resolved_filename); + if (!file.is_open()) + { + llwarns << "can't open plugin cookie file \"" << PLUGIN_COOKIE_FILE_NAME << "\" for writing" << llendl; + return; + } + + getCookieStore()->writePersistentCookies(file); + + file.close(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::addCookie(const std::string &name, const std::string &value, const std::string &domain, const LLDate &expires, const std::string &path, bool secure) +{ + std::stringstream cookie; + + cookie << name << "=" << LLPluginCookieStore::quoteString(value); + + if(expires.notNull()) + { + cookie << "; expires=" << expires.asRFC1123(); + } + + cookie << "; domain=" << domain; + + cookie << "; path=" << path; + + if(secure) + { + cookie << "; secure"; + } + + getCookieStore()->setCookies(cookie.str()); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::addSessionCookie(const std::string &name, const std::string &value, const std::string &domain, const std::string &path, bool secure) +{ + // A session cookie just has a NULL date. + addCookie(name, value, domain, LLDate(), path, secure); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::removeCookie(const std::string &name, const std::string &domain, const std::string &path ) +{ + // To remove a cookie, add one with the same name, domain, and path that expires in the past. + + addCookie(name, "", domain, LLDate(LLDate::now().secondsSinceEpoch() - 1.0), path); +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setOpenIDCookie() +{ + if(!sOpenIDCookie.empty()) + { + // The LLURL can give me the 'authority', which is of the form: [username[:password]@]hostname[:port] + // We want just the hostname for the cookie code, but LLURL doesn't seem to have a way to extract that. + // We therefore do it here. + std::string authority = sOpenIDURL.mAuthority; + std::string::size_type host_start = authority.find('@'); + if(host_start == std::string::npos) + { + // no username/password + host_start = 0; + } + else + { + // Hostname starts after the @. + // (If the hostname part is empty, this may put host_start at the end of the string. In that case, it will end up passing through an empty hostname, which is correct.) + ++host_start; + } + std::string::size_type host_end = authority.rfind(':'); + if((host_end == std::string::npos) || (host_end < host_start)) + { + // no port + host_end = authority.size(); + } + + getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(host_start, host_end - host_start)); + + // *HACK: Doing this here is nasty, find a better way. + LLWebSharing::instance().setOpenIDCookie(sOpenIDCookie); + + // Do a web profile get so we can store the cookie + LLSD headers = LLSD::emptyMap(); + headers["Accept"] = "*/*"; + headers["Cookie"] = sOpenIDCookie; + headers["User-Agent"] = getCurrentUserAgent(); + + std::string profile_url = getProfileURL(""); + LLURL raw_profile_url( profile_url.c_str() ); + + LLHTTPClient::get(profile_url, + new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()), + headers); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string &openid_token) +{ + LL_DEBUGS("MediaAuth") << "url = \"" << openid_url << "\", token = \"" << openid_token << "\"" << LL_ENDL; + + // post the token to the url + // the responder will need to extract the cookie(s). + + // Save the OpenID URL for later -- we may need the host when adding the cookie. + sOpenIDURL.init(openid_url.c_str()); + + // We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies. + sOpenIDCookie.clear(); + + LLSD headers = LLSD::emptyMap(); + // Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header + headers["Accept"] = "*/*"; + // and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream" + headers["Content-Type"] = "application/x-www-form-urlencoded"; + + // postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here. + size_t size = openid_token.size(); + U8 *data = new U8[size]; + memcpy(data, openid_token.data(), size); + + LLHTTPClient::postRaw( + openid_url, + data, + size, + new LLViewerMediaOpenIDResponder(), + headers); + +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::openIDCookieResponse(const std::string &cookie) +{ + LL_DEBUGS("MediaAuth") << "Cookie received: \"" << cookie << "\"" << LL_ENDL; + + sOpenIDCookie += cookie; + + setOpenIDCookie(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::proxyWindowOpened(const std::string &target, const std::string &uuid) +{ + if(uuid.empty()) + return; + + for (impl_list::iterator iter = sViewerMediaImplList.begin(); iter != sViewerMediaImplList.end(); iter++) + { + if((*iter)->mMediaSource && (*iter)->mMediaSource->pluginSupportsMediaBrowser()) + { + (*iter)->mMediaSource->proxyWindowOpened(target, uuid); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::proxyWindowClosed(const std::string &uuid) +{ + if(uuid.empty()) + return; + + for (impl_list::iterator iter = sViewerMediaImplList.begin(); iter != sViewerMediaImplList.end(); iter++) + { + if((*iter)->mMediaSource && (*iter)->mMediaSource->pluginSupportsMediaBrowser()) + { + (*iter)->mMediaSource->proxyWindowClosed(uuid); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::createSpareBrowserMediaSource() +{ + // If we don't have a spare browser media source, create one. + // However, if PluginAttachDebuggerToPlugins is set then don't spawn a spare + // SLPlugin process in order to not be confused by an unrelated gdb terminal + // popping up at the moment we start a media plugin. + if (!sSpareBrowserMediaSource && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")) + { + // The null owner will keep the browser plugin from fully initializing + // (specifically, it keeps LLPluginClassMedia from negotiating a size change, + // which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color) + sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource() +{ + LLPluginClassMedia* result = sSpareBrowserMediaSource; + sSpareBrowserMediaSource = NULL; + return result; +}; + +bool LLViewerMedia::hasInWorldMedia() +{ + if (sInWorldMediaDisabled) return false; + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + // This should be quick, because there should be very few non-in-world-media impls + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if (!pimpl->getUsedInUI() && !pimpl->isParcelMedia()) + { + // Found an in-world media impl + return true; + } + } + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::hasParcelMedia() +{ + return !LLViewerParcelMedia::getURL().empty(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::hasParcelAudio() +{ + return !LLViewerMedia::getParcelAudioURL().empty(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +std::string LLViewerMedia::getParcelAudioURL() +{ + return LLViewerParcelMgr::getInstance()->getAgentParcel()->getMusicURL(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::initClass() +{ + gIdleCallbacks.addFunction(LLViewerMedia::updateMedia, NULL); + sTeleportFinishConnection = LLViewerParcelMgr::getInstance()-> + setTeleportFinishedCallback(boost::bind(&LLViewerMedia::onTeleportFinished)); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::cleanupClass() +{ + gIdleCallbacks.deleteFunction(LLViewerMedia::updateMedia, NULL); + sTeleportFinishConnection.disconnect(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::onTeleportFinished() +{ + // On teleport, clear this setting (i.e. set it to true) + gSavedSettings.setBOOL("MediaTentativeAutoPlay", true); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// LLViewerMediaImpl +////////////////////////////////////////////////////////////////////////////////////////// +LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id, + S32 media_width, + S32 media_height, + U8 media_auto_scale, + U8 media_loop) +: + mMediaSource( NULL ), + mMovieImageHasMips(false), + mMediaWidth(media_width), + mMediaHeight(media_height), + mMediaAutoScale(media_auto_scale), + mMediaLoop(media_loop), + mNeedsNewTexture(true), + mTextureUsedWidth(0), + mTextureUsedHeight(0), + mSuspendUpdates(false), + mVisible(true), + mLastSetCursor( UI_CURSOR_ARROW ), + mMediaNavState( MEDIANAVSTATE_NONE ), + mInterest(0.0f), + mUsedInUI(false), + mHasFocus(false), + mPriority(LLPluginClassMedia::PRIORITY_UNLOADED), + mNavigateRediscoverType(false), + mNavigateServerRequest(false), + mMediaSourceFailed(false), + mRequestedVolume(1.0f), + mIsMuted(false), + mNeedsMuteCheck(false), + mPreviousMediaState(MEDIA_NONE), + mPreviousMediaTime(0.0f), + mIsDisabled(false), + mIsParcelMedia(false), + mProximity(-1), + mProximityDistance(0.0f), + mMimeTypeProbe(NULL), + mMediaAutoPlay(false), + mInNearbyMediaList(false), + mClearCache(false), + mBackgroundColor(LLColor4::white), + mNavigateSuspended(false), + mNavigateSuspendedDeferred(false), + mIsUpdated(false), + mTrustedBrowser(false) +{ + + // Set up the mute list observer if it hasn't been set up already. + if(!sViewerMediaMuteListObserverInitialized) + { + LLMuteList::getInstance()->addObserver(&sViewerMediaMuteListObserver); + sViewerMediaMuteListObserverInitialized = true; + } + + add_media_impl(this); + + setTextureID(texture_id); + + // connect this media_impl to the media texture, creating it if it doesn't exist.0 + // This is necessary because we need to be able to use getMaxVirtualSize() even if the media plugin is not loaded. + LLViewerMediaTexture* media_tex = LLViewerTextureManager::getMediaTexture(mTextureId); + if(media_tex) + { + media_tex->setMediaImpl(); + } + +} + +////////////////////////////////////////////////////////////////////////////////////////// +LLViewerMediaImpl::~LLViewerMediaImpl() +{ + destroyMediaSource(); + + LLViewerMediaTexture::removeMediaImplFromTexture(mTextureId) ; + + setTextureID(); + remove_media_impl(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::emitEvent(LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event) +{ + // Broadcast to observers using the superclass version + LLViewerMediaEventEmitter::emitEvent(plugin, event); + + // If this media is on one or more LLVOVolume objects, tell them about the event as well. + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + while(iter != mObjectList.end()) + { + LLVOVolume *self = *iter; + ++iter; + self->mediaEvent(this, plugin, event); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type) +{ + bool mimeTypeChanged = (mMimeType != mime_type); + bool pluginChanged = (LLMIMETypes::implType(mCurrentMimeType) != LLMIMETypes::implType(mime_type)); + + if(!mMediaSource || pluginChanged) + { + // We don't have a plugin at all, or the new mime type is handled by a different plugin than the old mime type. + (void)initializePlugin(mime_type); + } + else if(mimeTypeChanged) + { + // The same plugin should be able to handle the new media -- just update the stored mime type. + mMimeType = mime_type; + } + + return (mMediaSource != NULL); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::createMediaSource() +{ + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + // This media shouldn't be created yet. + return; + } + + if(! mMediaURL.empty()) + { + navigateInternal(); + } + else if(! mMimeType.empty()) + { + if (!initializeMedia(mMimeType)) + { + LL_WARNS("Media") << "Failed to initialize media for mime type " << mMimeType << LL_ENDL; + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::destroyMediaSource() +{ + mNeedsNewTexture = true; + + // Tell the viewer media texture it's no longer active + LLViewerMediaTexture* oldImage = LLViewerTextureManager::findMediaTexture( mTextureId ); + if (oldImage) + { + oldImage->setPlaying(FALSE) ; + } + + cancelMimeTypeProbe(); + + if(mMediaSource) + { + mMediaSource->setDeleteOK(true) ; + delete mMediaSource; + mMediaSource = NULL; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::setMediaType(const std::string& media_type) +{ + mMimeType = media_type; +} + +////////////////////////////////////////////////////////////////////////////////////////// +/*static*/ +LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target) +{ + std::string plugin_basename = LLMIMETypes::implType(media_type); + LLPluginClassMedia* media_source = NULL; + + // HACK: we always try to keep a spare running webkit plugin around to improve launch times. + // If a spare was already created before PluginAttachDebuggerToPlugins was set, don't use it. + if(plugin_basename == "media_plugin_webkit" && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")) + { + media_source = LLViewerMedia::getSpareBrowserMediaSource(); + if(media_source) + { + media_source->setOwner(owner); + media_source->setTarget(target); + media_source->setSize(default_width, default_height); + + return media_source; + } + } + + if(plugin_basename.empty()) + { + LL_WARNS("Media") << "Couldn't find plugin for media type " << media_type << LL_ENDL; + } + else + { + std::string launcher_name = gDirUtilp->getLLPluginLauncher(); + std::string plugin_name = gDirUtilp->getLLPluginFilename(plugin_basename); + std::string user_data_path = gDirUtilp->getOSUserAppDir(); + user_data_path += gDirUtilp->getDirDelimiter(); + + // Fix for EXT-5960 - make browser profile specific to user (cache, cookies etc.) + // If the linden username returned is blank, that can only mean we are + // at the login page displaying login Web page or Web browser test via Develop menu. + // In this case we just use whatever gDirUtilp->getOSUserAppDir() gives us (this + // is what we always used before this change) + std::string linden_user_dir = gDirUtilp->getLindenUserDir(); + if ( ! linden_user_dir.empty() ) + { + // gDirUtilp->getLindenUserDir() is whole path, not just Linden name + user_data_path = linden_user_dir; + user_data_path += gDirUtilp->getDirDelimiter(); + }; + + // See if the plugin executable exists + llstat s; + if(LLFile::stat(launcher_name, &s)) + { + LL_WARNS("Media") << "Couldn't find launcher at " << launcher_name << LL_ENDL; + } + else if(LLFile::stat(plugin_name, &s)) + { + LL_WARNS("Media") << "Couldn't find plugin at " << plugin_name << LL_ENDL; + } + else + { + media_source = new LLPluginClassMedia(owner); + media_source->setSize(default_width, default_height); + media_source->setUserDataPath(user_data_path); + media_source->setLanguageCode(LLUI::getLanguage()); + + // collect 'cookies enabled' setting from prefs and send to embedded browser + bool cookies_enabled = gSavedSettings.getBOOL( "CookiesEnabled" ); + media_source->enable_cookies( cookies_enabled ); + + // collect 'plugins enabled' setting from prefs and send to embedded browser + bool plugins_enabled = gSavedSettings.getBOOL( "BrowserPluginsEnabled" ); + media_source->setPluginsEnabled( plugins_enabled ); + + // collect 'javascript enabled' setting from prefs and send to embedded browser + bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" ); + media_source->setJavascriptEnabled( javascript_enabled ); + + media_source->setTarget(target); + + const std::string plugin_dir = gDirUtilp->getLLPluginDir(); + if (media_source->init(launcher_name, plugin_dir, plugin_name, gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))) + { + return media_source; + } + else + { + LL_WARNS("Media") << "Failed to init plugin. Destroying." << LL_ENDL; + delete media_source; + } + } + } + + LL_WARNS("Plugin") << "plugin intialization failed for mime type: " << media_type << LL_ENDL; + LLSD args; + args["MIME_TYPE"] = media_type; + LLNotificationsUtil::add("NoPlugin", args); + + return NULL; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) +{ + if(mMediaSource) + { + // Save the previous media source's last set size before destroying it. + mMediaWidth = mMediaSource->getSetWidth(); + mMediaHeight = mMediaSource->getSetHeight(); + } + + // Always delete the old media impl first. + destroyMediaSource(); + + // and unconditionally set the mime type + mMimeType = media_type; + + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + // This impl should not be loaded at this time. + LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL; + + return false; + } + + // If we got here, we want to ignore previous init failures. + mMediaSourceFailed = false; + + // Save the MIME type that really caused the plugin to load + mCurrentMimeType = mMimeType; + + LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight, mTarget); + + if (media_source) + { + media_source->setDisableTimeout(gSavedSettings.getBOOL("DebugPluginDisableTimeout")); + media_source->setLoop(mMediaLoop); + media_source->setAutoScale(mMediaAutoScale); + media_source->setBrowserUserAgent(LLViewerMedia::getCurrentUserAgent()); + media_source->focus(mHasFocus); + media_source->setBackgroundColor(mBackgroundColor); + + if(gSavedSettings.getBOOL("BrowserIgnoreSSLCertErrors")) + { + media_source->ignore_ssl_cert_errors(true); + } + + // the correct way to deal with certs it to load ours from CA.pem and append them to the ones + // Qt/WebKit loads from your system location. + // Note: This needs the new CA.pem file with the Equifax Secure Certificate Authority + // cert at the bottom: (MIIDIDCCAomgAwIBAgIENd70zzANBg) + std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "CA.pem" ); + media_source->addCertificateFilePath( ca_path ); + + media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort")); + + if(mClearCache) + { + mClearCache = false; + media_source->clear_cache(); + } + + // TODO: Only send cookies to plugins that need them + // Ideally, the plugin should tell us whether it handles cookies or not -- either via the init response or through a separate message. + // Due to the ordering of messages, it's possible we wouldn't get that information back in time to send cookies before sending a navigate message, + // which could cause odd race conditions. + std::string all_cookies = LLViewerMedia::getCookieStore()->getAllCookies(); + lldebugs << "setting cookies: " << all_cookies << llendl; + if(!all_cookies.empty()) + { + media_source->set_cookies(all_cookies); + } + + mMediaSource = media_source; + mMediaSource->setDeleteOK(false) ; + updateVolume(); + + return true; + } + + // Make sure the timer doesn't try re-initing this plugin repeatedly until something else changes. + mMediaSourceFailed = true; + + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::loadURI() +{ + if(mMediaSource) + { + // trim whitespace from front and back of URL - fixes EXT-5363 + LLStringUtil::trim( mMediaURL ); + + // *HACK: we don't know if the URI coming in is properly escaped + // (the contract doesn't specify whether it is escaped or not. + // but LLQtWebKit expects it to be, so we do our best to encode + // special characters) + // The strings below were taken right from http://www.ietf.org/rfc/rfc1738.txt + // Note especially that '%' and '/' are there. + std::string uri = LLURI::escape(mMediaURL, + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789" + "$-_.+" + "!*'()," + "{}|\\^~[]`" + "<>#%" + ";/?:@&=", + false); + llinfos << "Asking media source to load URI: " << uri << llendl; + + mMediaSource->loadURI( uri ); + + // A non-zero mPreviousMediaTime means that either this media was previously unloaded by the priority code while playing/paused, + // or a seek happened before the media loaded. In either case, seek to the saved time. + if(mPreviousMediaTime != 0.0f) + { + seek(mPreviousMediaTime); + } + + if(mPreviousMediaState == MEDIA_PLAYING) + { + // This media was playing before this instance was unloaded. + start(); + } + else if(mPreviousMediaState == MEDIA_PAUSED) + { + // This media was paused before this instance was unloaded. + pause(); + } + else + { + // No relevant previous media play state -- if we're loading the URL, we want to start playing. + start(); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::setSize(int width, int height) +{ + mMediaWidth = width; + mMediaHeight = height; + if(mMediaSource) + { + mMediaSource->setSize(width, height); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::showNotification(LLNotificationPtr notify) +{ + mNotification = notify; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::hideNotification() +{ + mNotification.reset(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::play() +{ + // If the media source isn't there, try to initialize it and load an URL. + if(mMediaSource == NULL) + { + if(!initializeMedia(mMimeType)) + { + // This may be the case where the plugin's priority is PRIORITY_UNLOADED + return; + } + + // Only do this if the media source was just loaded. + loadURI(); + } + + // always start the media + start(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::stop() +{ + if(mMediaSource) + { + mMediaSource->stop(); + // destroyMediaSource(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::pause() +{ + if(mMediaSource) + { + mMediaSource->pause(); + } + else + { + mPreviousMediaState = MEDIA_PAUSED; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::start() +{ + if(mMediaSource) + { + mMediaSource->start(); + } + else + { + mPreviousMediaState = MEDIA_PLAYING; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::seek(F32 time) +{ + if(mMediaSource) + { + mMediaSource->seek(time); + } + else + { + // Save the seek time to be set when the media is loaded. + mPreviousMediaTime = time; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::skipBack(F32 step_scale) +{ + if(mMediaSource) + { + if(mMediaSource->pluginSupportsMediaTime()) + { + F64 back_step = mMediaSource->getCurrentTime() - (mMediaSource->getDuration()*step_scale); + if(back_step < 0.0) + { + back_step = 0.0; + } + mMediaSource->seek(back_step); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::skipForward(F32 step_scale) +{ + if(mMediaSource) + { + if(mMediaSource->pluginSupportsMediaTime()) + { + F64 forward_step = mMediaSource->getCurrentTime() + (mMediaSource->getDuration()*step_scale); + if(forward_step > mMediaSource->getDuration()) + { + forward_step = mMediaSource->getDuration(); + } + mMediaSource->seek(forward_step); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::setVolume(F32 volume) +{ + mRequestedVolume = volume; + updateVolume(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::updateVolume() +{ + if(mMediaSource) + { + // always scale the volume by the global media volume + F32 volume = mRequestedVolume * LLViewerMedia::getVolume(); + + if (mProximityCamera > 0) + { + if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMax")) + { + volume = 0; + } + else if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMin")) + { + // attenuated_volume = 1 / (roll_off_rate * (d - min))^2 + // the +1 is there so that for distance 0 the volume stays the same + F64 adjusted_distance = mProximityCamera - gSavedSettings.getF32("MediaRollOffMin"); + F64 attenuation = 1.0 + (gSavedSettings.getF32("MediaRollOffRate") * adjusted_distance); + attenuation = 1.0 / (attenuation * attenuation); + // the attenuation multiplier should never be more than one since that would increase volume + volume = volume * llmin(1.0, attenuation); + } + } + + mMediaSource->setVolume(volume); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +F32 LLViewerMediaImpl::getVolume() +{ + return mRequestedVolume; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::focus(bool focus) +{ + mHasFocus = focus; + + if (mMediaSource) + { + // call focus just for the hell of it, even though this apopears to be a nop + mMediaSource->focus(focus); + if (focus) + { + // spoof a mouse click to *actually* pass focus + // Don't do this anymore -- it actually clicks through now. +// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, 1, 1, 0); +// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 1, 1, 0); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::hasFocus() const +{ + // FIXME: This might be able to be a bit smarter by hooking into LLViewerMediaFocus, etc. + return mHasFocus; +} + +std::string LLViewerMediaImpl::getCurrentMediaURL() +{ + if(!mCurrentMediaURL.empty()) + { + return mCurrentMediaURL; + } + + return mMediaURL; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::clearCache() +{ + if(mMediaSource) + { + mMediaSource->clear_cache(); + } + else + { + mClearCache = true; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseDown(S32 x, S32 y, MASK mask, S32 button) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; +// llinfos << "mouse down (" << x << ", " << y << ")" << llendl; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, button, x, y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseUp(S32 x, S32 y, MASK mask, S32 button) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; +// llinfos << "mouse up (" << x << ", " << y << ")" << llendl; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, button, x, y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseMove(S32 x, S32 y, MASK mask) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; +// llinfos << "mouse move (" << x << ", " << y << ")" << llendl; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, x, y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +//static +void LLViewerMediaImpl::scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y) +{ + F32 texture_x = texture_coords.mV[VX]; + F32 texture_y = texture_coords.mV[VY]; + + // Deal with repeating textures by wrapping the coordinates into the range [0, 1.0) + texture_x = fmodf(texture_x, 1.0f); + if(texture_x < 0.0f) + texture_x = 1.0 + texture_x; + + texture_y = fmodf(texture_y, 1.0f); + if(texture_y < 0.0f) + texture_y = 1.0 + texture_y; + + // scale x and y to texel units. + *x = llround(texture_x * mMediaSource->getTextureWidth()); + *y = llround((1.0f - texture_y) * mMediaSource->getTextureHeight()); + + // Adjust for the difference between the actual texture height and the amount of the texture in use. + *y -= (mMediaSource->getTextureHeight() - mMediaSource->getHeight()); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseDown(const LLVector2& texture_coords, MASK mask, S32 button) +{ + if(mMediaSource) + { + S32 x, y; + scaleTextureCoords(texture_coords, &x, &y); + + mouseDown(x, y, mask, button); + } +} + +void LLViewerMediaImpl::mouseUp(const LLVector2& texture_coords, MASK mask, S32 button) +{ + if(mMediaSource) + { + S32 x, y; + scaleTextureCoords(texture_coords, &x, &y); + + mouseUp(x, y, mask, button); + } +} + +void LLViewerMediaImpl::mouseMove(const LLVector2& texture_coords, MASK mask) +{ + if(mMediaSource) + { + S32 x, y; + scaleTextureCoords(texture_coords, &x, &y); + + mouseMove(x, y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOUBLE_CLICK, button, x, y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::scrollWheel(S32 x, S32 y, MASK mask) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; + if (mMediaSource) + { + mMediaSource->scrollEvent(x, y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::onMouseCaptureLost() +{ + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 0, mLastMouseX, mLastMouseY, 0); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +BOOL LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask) +{ + // NOTE: this is called when the mouse is released when we have capture. + // Due to the way mouse coordinates are mapped to the object, we can't use the x and y coordinates that come in with the event. + + if(hasMouseCapture()) + { + // Release the mouse -- this will also send a mouseup to the media + gFocusMgr.setMouseCapture( FALSE ); + } + + return TRUE; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::updateJavascriptObject() +{ + if ( mMediaSource ) + { + // flag to expose this information to internal browser or not. + bool expose_javascript_object = gSavedSettings.getBOOL("BrowserEnableJSObject"); + mMediaSource->jsExposeObjectEvent( expose_javascript_object ); + + // indicate if the values we have are valid (currently do this blanket-fashion for + // everything depending on whether you are logged in or not - this may require a + // more granular approach once variables are added that ARE valid before login + bool logged_in = LLLoginInstance::getInstance()->authSuccess(); + mMediaSource->jsValuesValidEvent( logged_in ); + + // current location within a region + LLVector3 agent_pos = gAgent.getPositionAgent(); + double x = agent_pos.mV[ VX ]; + double y = agent_pos.mV[ VY ]; + double z = agent_pos.mV[ VZ ]; + mMediaSource->jsAgentLocationEvent( x, y, z ); + + // current region agent is in + std::string region_name(""); + LLViewerRegion* region = gAgent.getRegion(); + if ( region ) + { + region_name = region->getName(); + }; + mMediaSource->jsAgentRegionEvent( region_name ); + + // language code the viewer is set to + mMediaSource->jsAgentLanguageEvent( LLUI::getLanguage() ); + + // maturity setting the agent has selected + if ( gAgent.prefersAdult() ) + mMediaSource->jsAgentMaturityEvent( "GMA" ); // Adult means see adult, mature and general content + else + if ( gAgent.prefersMature() ) + mMediaSource->jsAgentMaturityEvent( "GM" ); // Mature means see mature and general content + else + if ( gAgent.prefersPG() ) + mMediaSource->jsAgentMaturityEvent( "G" ); // PG means only see General content + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +std::string LLViewerMediaImpl::getName() const +{ + if (mMediaSource) + { + return mMediaSource->getMediaName(); + } + + return LLStringUtil::null; +}; + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateBack() +{ + if (mMediaSource) + { + mMediaSource->browse_back(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateForward() +{ + if (mMediaSource) + { + mMediaSource->browse_forward(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateReload() +{ + navigateTo(getCurrentMediaURL(), "", true, false); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateHome() +{ + bool rediscover_mimetype = mHomeMimeType.empty(); + navigateTo(mHomeURL, mHomeMimeType, rediscover_mimetype, false); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::unload() +{ + // Unload the media impl and clear its state. + destroyMediaSource(); + resetPreviousMediaState(); + mMediaURL.clear(); + mMimeType.clear(); + mCurrentMediaURL.clear(); + mCurrentMimeType.clear(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type, bool server_request) +{ + cancelMimeTypeProbe(); + + if(mMediaURL != url) + { + // Don't carry media play state across distinct URLs. + resetPreviousMediaState(); + } + + // Always set the current URL and MIME type. + mMediaURL = url; + mMimeType = mime_type; + + // Clear the current media URL, since it will no longer be correct. + mCurrentMediaURL.clear(); + + // if mime type discovery was requested, we'll need to do it when the media loads + mNavigateRediscoverType = rediscover_type; + + // and if this was a server request, the navigate on load will also need to be one. + mNavigateServerRequest = server_request; + + // An explicit navigate resets the "failed" flag. + mMediaSourceFailed = false; + + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + // Helpful to have media urls in log file. Shouldn't be spammy. + llinfos << "NOT LOADING media id= " << mTextureId << " url=" << url << " mime_type=" << mime_type << llendl; + + // This impl should not be loaded at this time. + LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL; + + return; + } + + navigateInternal(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateInternal() +{ + // Helpful to have media urls in log file. Shouldn't be spammy. + llinfos << "media id= " << mTextureId << " url=" << mMediaURL << " mime_type=" << mMimeType << llendl; + + if(mNavigateSuspended) + { + llwarns << "Deferring navigate." << llendl; + mNavigateSuspendedDeferred = true; + return; + } + + if(mMimeTypeProbe != NULL) + { + llwarns << "MIME type probe already in progress -- bailing out." << llendl; + return; + } + + if(mNavigateServerRequest) + { + setNavState(MEDIANAVSTATE_SERVER_SENT); + } + else + { + setNavState(MEDIANAVSTATE_NONE); + } + + // If the caller has specified a non-empty MIME type, look that up in our MIME types list. + // If we have a plugin for that MIME type, use that instead of attempting auto-discovery. + // This helps in supporting legacy media content where the server the media resides on returns a bogus MIME type + // but the parcel owner has correctly set the MIME type in the parcel media settings. + + if(!mMimeType.empty() && (mMimeType != LLMIMETypes::getDefaultMimeType())) + { + std::string plugin_basename = LLMIMETypes::implType(mMimeType); + if(!plugin_basename.empty()) + { + // We have a plugin for this mime type + mNavigateRediscoverType = false; + } + } + + if(mNavigateRediscoverType) + { + + LLURI uri(mMediaURL); + std::string scheme = uri.scheme(); + + if(scheme.empty() || "http" == scheme || "https" == scheme) + { + // If we don't set an Accept header, LLHTTPClient will add one like this: + // Accept: application/llsd+xml + // which is really not what we want. + LLSD headers = LLSD::emptyMap(); + headers["Accept"] = "*/*"; + // Allow cookies in the response, to prevent a redirect loop when accessing join.secondlife.com + headers["Cookie"] = ""; + LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this), headers, 10.0f); + } + else if("data" == scheme || "file" == scheme || "about" == scheme) + { + // FIXME: figure out how to really discover the type for these schemes + // We use "data" internally for a text/html url for loading the login screen + if(initializeMedia("text/html")) + { + loadURI(); + } + } + else + { + // This catches 'rtsp://' urls + if(initializeMedia(scheme)) + { + loadURI(); + } + } + } + else if(initializeMedia(mMimeType)) + { + loadURI(); + } + else + { + LL_WARNS("Media") << "Couldn't navigate to: " << mMediaURL << " as there is no media type for: " << mMimeType << LL_ENDL; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateStop() +{ + if(mMediaSource) + { + mMediaSource->browse_stop(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask) +{ + bool result = false; + + if (mMediaSource) + { + // FIXME: THIS IS SO WRONG. + // Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it... + if( MASK_CONTROL & mask ) + { + result = true; + } + + if(!result) + { + + LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData(); + + result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask, native_key_data); + // Since the viewer internal event dispatching doesn't give us key-up events, simulate one here. + (void)mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP ,key, mask, native_key_data); + } + } + + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char) +{ + bool result = false; + + if (mMediaSource) + { + // only accept 'printable' characters, sigh... + if (uni_char >= 32 // discard 'control' characters + && uni_char != 127) // SDL thinks this is 'delete' - yuck. + { + LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData(); + + mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE), native_key_data); + } + } + + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::canNavigateForward() +{ + BOOL result = FALSE; + if (mMediaSource) + { + result = mMediaSource->getHistoryForwardAvailable(); + } + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::canNavigateBack() +{ + BOOL result = FALSE; + if (mMediaSource) + { + result = mMediaSource->getHistoryBackAvailable(); + } + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::update() +{ + if(mMediaSource == NULL) + { + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + // This media source should not be loaded. + } + else if(mPriority <= LLPluginClassMedia::PRIORITY_SLIDESHOW) + { + // Don't load new instances that are at PRIORITY_SLIDESHOW or below. They're just kept around to preserve state. + } + else if(mMimeTypeProbe != NULL) + { + // this media source is doing a MIME type probe -- don't try loading it again. + } + else + { + // This media may need to be loaded. + if(sMediaCreateTimer.hasExpired()) + { + LL_DEBUGS("PluginPriority") << this << ": creating media based on timer expiration" << LL_ENDL; + createMediaSource(); + sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY); + } + else + { + LL_DEBUGS("PluginPriority") << this << ": NOT creating media (waiting on timer)" << LL_ENDL; + } + } + } + else + { + updateVolume(); + + // TODO: this is updated every frame - is this bad? + updateJavascriptObject(); + + // If we didn't just create the impl, it may need to get cookie updates. + if(!sUpdatedCookies.empty()) + { + // TODO: Only send cookies to plugins that need them + mMediaSource->set_cookies(sUpdatedCookies); + } + } + + + if(mMediaSource == NULL) + { + return; + } + + // Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash. + setNavigateSuspended(true); + + mMediaSource->idle(); + + setNavigateSuspended(false); + + if(mMediaSource == NULL) + { + return; + } + + if(mMediaSource->isPluginExited()) + { + resetPreviousMediaState(); + destroyMediaSource(); + return; + } + + if(!mMediaSource->textureValid()) + { + return; + } + + if(mSuspendUpdates || !mVisible) + { + return; + } + + LLViewerMediaTexture* placeholder_image = updatePlaceholderImage(); + + if(placeholder_image) + { + LLRect dirty_rect; + + // Since we're updating this texture, we know it's playing. Tell the texture to do its replacement magic so it gets rendered. + placeholder_image->setPlaying(TRUE); + + if(mMediaSource->getDirty(&dirty_rect)) + { + // Constrain the dirty rect to be inside the texture + S32 x_pos = llmax(dirty_rect.mLeft, 0); + S32 y_pos = llmax(dirty_rect.mBottom, 0); + S32 width = llmin(dirty_rect.mRight, placeholder_image->getWidth()) - x_pos; + S32 height = llmin(dirty_rect.mTop, placeholder_image->getHeight()) - y_pos; + + if(width > 0 && height > 0) + { + + U8* data = mMediaSource->getBitsData(); + + // Offset the pixels pointer to match x_pos and y_pos + data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() ); + data += ( y_pos * mMediaSource->getTextureDepth() ); + + placeholder_image->setSubImage( + data, + mMediaSource->getBitsWidth(), + mMediaSource->getBitsHeight(), + x_pos, + y_pos, + width, + height); + + } + + mMediaSource->resetDirty(); + } + } +} + + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::updateImagesMediaStreams() +{ +} + + +////////////////////////////////////////////////////////////////////////////////////////// +LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() +{ + if(mTextureId.isNull()) + { + // The code that created this instance will read from the plugin's bits. + return NULL; + } + + LLViewerMediaTexture* placeholder_image = LLViewerTextureManager::getMediaTexture( mTextureId ); + + if (mNeedsNewTexture + || placeholder_image->getUseMipMaps() + || (placeholder_image->getWidth() != mMediaSource->getTextureWidth()) + || (placeholder_image->getHeight() != mMediaSource->getTextureHeight()) + || (mTextureUsedWidth != mMediaSource->getWidth()) + || (mTextureUsedHeight != mMediaSource->getHeight()) + ) + { + LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL; + LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL; + + int texture_width = mMediaSource->getTextureWidth(); + int texture_height = mMediaSource->getTextureHeight(); + int texture_depth = mMediaSource->getTextureDepth(); + + // MEDIAOPT: check to see if size actually changed before doing work + placeholder_image->destroyGLTexture(); + // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work? + placeholder_image->reinit(FALSE); // probably not needed + + // MEDIAOPT: seems insane that we actually have to make an imageraw then + // immediately discard it + LLPointer raw = new LLImageRaw(texture_width, texture_height, texture_depth); + // Clear the texture to the background color, ignoring alpha. + // convert background color channels from [0.0, 1.0] to [0, 255]; + raw->clear(int(mBackgroundColor.mV[VX] * 255.0f), int(mBackgroundColor.mV[VY] * 255.0f), int(mBackgroundColor.mV[VZ] * 255.0f), 0xff); + int discard_level = 0; + + // ask media source for correct GL image format constants + placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(), + mMediaSource->getTextureFormatPrimary(), + mMediaSource->getTextureFormatType(), + mMediaSource->getTextureFormatSwapBytes()); + + placeholder_image->createGLTexture(discard_level, raw); + + // MEDIAOPT: set this dynamically on play/stop + // FIXME +// placeholder_image->mIsMediaTexture = true; + mNeedsNewTexture = false; + + // If the amount of the texture being drawn by the media goes down in either width or height, + // recreate the texture to avoid leaving parts of the old image behind. + mTextureUsedWidth = mMediaSource->getWidth(); + mTextureUsedHeight = mMediaSource->getHeight(); + } + + return placeholder_image; +} + + +////////////////////////////////////////////////////////////////////////////////////////// +LLUUID LLViewerMediaImpl::getMediaTextureID() const +{ + return mTextureId; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::setVisible(bool visible) +{ + mVisible = visible; + + if(mVisible) + { + if(mMediaSource && mMediaSource->isPluginExited()) + { + destroyMediaSource(); + } + + if(!mMediaSource) + { + createMediaSource(); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseCapture() +{ + gFocusMgr.setMouseCapture(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::scaleMouse(S32 *mouse_x, S32 *mouse_y) +{ +#if 0 + S32 media_width, media_height; + S32 texture_width, texture_height; + getMediaSize( &media_width, &media_height ); + getTextureSize( &texture_width, &texture_height ); + S32 y_delta = texture_height - media_height; + + *mouse_y -= y_delta; +#endif +} + + + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::isMediaTimeBased() +{ + bool result = false; + + if(mMediaSource) + { + result = mMediaSource->pluginSupportsMediaTime(); + } + + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::isMediaPlaying() +{ + bool result = false; + + if(mMediaSource) + { + EMediaStatus status = mMediaSource->getStatus(); + if(status == MEDIA_PLAYING || status == MEDIA_LOADING) + result = true; + } + + return result; +} +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::isMediaPaused() +{ + bool result = false; + + if(mMediaSource) + { + if(mMediaSource->getStatus() == MEDIA_PAUSED) + result = true; + } + + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::hasMedia() const +{ + return mMediaSource != NULL; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +void LLViewerMediaImpl::resetPreviousMediaState() +{ + mPreviousMediaState = MEDIA_NONE; + mPreviousMediaTime = 0.0f; +} + + +////////////////////////////////////////////////////////////////////////////////////////// +// +void LLViewerMediaImpl::setDisabled(bool disabled, bool forcePlayOnEnable) +{ + if(mIsDisabled != disabled) + { + // Only do this on actual state transitions. + mIsDisabled = disabled; + + if(mIsDisabled) + { + // We just disabled this media. Clear all state. + unload(); + } + else + { + // We just (re)enabled this media. Do a navigate if auto-play is in order. + if(isAutoPlayable() || forcePlayOnEnable) + { + navigateTo(mMediaEntryURL, "", true, true); + } + } + + } +}; + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::isForcedUnloaded() const +{ + if(mIsMuted || mMediaSourceFailed || mIsDisabled) + { + return true; + } + + if(sInWorldMediaDisabled) + { + // When inworld media is disabled, all instances that aren't marked as "used in UI" will not be loaded. + if(!mUsedInUI) + { + return true; + } + } + + // If this media's class is not supposed to be shown, unload + if (!shouldShowBasedOnClass()) + { + return true; + } + + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::isPlayable() const +{ + if(isForcedUnloaded()) + { + // All of the forced-unloaded criteria also imply not playable. + return false; + } + + if(hasMedia()) + { + // Anything that's already playing is, by definition, playable. + return true; + } + + if(!mMediaURL.empty()) + { + // If something has navigated the instance, it's ready to be played. + return true; + } + + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginClassMediaOwner::EMediaEvent event) +{ + bool pass_through = true; + switch(event) + { + case MEDIA_EVENT_CLICK_LINK_NOFOLLOW: + { + LL_DEBUGS("Media") << "MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is: " << plugin->getClickURL() << LL_ENDL; + std::string url = plugin->getClickURL(); + std::string nav_type = plugin->getClickNavType(); + LLURLDispatcher::dispatch(url, nav_type, NULL, mTrustedBrowser); + } + break; + case MEDIA_EVENT_CLICK_LINK_HREF: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << plugin->getClickTarget() << "\", uri is " << plugin->getClickURL() << LL_ENDL; + }; + break; + case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH: + { + // The plugin failed to load properly. Make sure the timer doesn't retry. + // TODO: maybe mark this plugin as not loadable somehow? + mMediaSourceFailed = true; + + // Reset the last known state of the media to defaults. + resetPreviousMediaState(); + + // TODO: may want a different message for this case? + LLSD args; + args["PLUGIN"] = LLMIMETypes::implType(mCurrentMimeType); + LLNotificationsUtil::add("MediaPluginFailed", args); + } + break; + + case MEDIA_EVENT_PLUGIN_FAILED: + { + // The plugin crashed. + mMediaSourceFailed = true; + + // Reset the last known state of the media to defaults. + resetPreviousMediaState(); + + LLSD args; + args["PLUGIN"] = LLMIMETypes::implType(mCurrentMimeType); + // SJB: This is getting called every frame if the plugin fails to load, continuously respawining the alert! + //LLNotificationsUtil::add("MediaPluginFailed", args); + } + break; + + case MEDIA_EVENT_CURSOR_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << plugin->getCursorName() << LL_ENDL; + + std::string cursor = plugin->getCursorName(); + + if(cursor == "arrow") + mLastSetCursor = UI_CURSOR_ARROW; + else if(cursor == "ibeam") + mLastSetCursor = UI_CURSOR_IBEAM; + else if(cursor == "splith") + mLastSetCursor = UI_CURSOR_SIZEWE; + else if(cursor == "splitv") + mLastSetCursor = UI_CURSOR_SIZENS; + else if(cursor == "hand") + mLastSetCursor = UI_CURSOR_HAND; + else // for anything else, default to the arrow + mLastSetCursor = UI_CURSOR_ARROW; + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_BEGIN: + { + LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_BEGIN, uri is: " << plugin->getNavigateURI() << LL_ENDL; + hideNotification(); + + if(getNavState() == MEDIANAVSTATE_SERVER_SENT) + { + setNavState(MEDIANAVSTATE_SERVER_BEGUN); + } + else + { + setNavState(MEDIANAVSTATE_BEGUN); + } + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE: + { + LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_COMPLETE, uri is: " << plugin->getNavigateURI() << LL_ENDL; + + std::string url = plugin->getNavigateURI(); + if(getNavState() == MEDIANAVSTATE_BEGUN) + { + if(mCurrentMediaURL == url) + { + // This is a navigate that takes us to the same url as the previous navigate. + setNavState(MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS); + } + else + { + mCurrentMediaURL = url; + setNavState(MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED); + } + } + else if(getNavState() == MEDIANAVSTATE_SERVER_BEGUN) + { + mCurrentMediaURL = url; + setNavState(MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED); + } + else + { + // all other cases need to leave the state alone. + } + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_LOCATION_CHANGED: + { + LL_DEBUGS("Media") << "MEDIA_EVENT_LOCATION_CHANGED, uri is: " << plugin->getLocation() << LL_ENDL; + + std::string url = plugin->getLocation(); + + if(getNavState() == MEDIANAVSTATE_BEGUN) + { + if(mCurrentMediaURL == url) + { + // This is a navigate that takes us to the same url as the previous navigate. + setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS); + } + else + { + mCurrentMediaURL = url; + setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED); + } + } + else if(getNavState() == MEDIANAVSTATE_SERVER_BEGUN) + { + mCurrentMediaURL = url; + setNavState(MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED); + } + else + { + // Don't track redirects. + setNavState(MEDIANAVSTATE_NONE); + } + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_PICK_FILE_REQUEST: + { + // Display a file picker + std::string response; + + LLFilePicker& picker = LLFilePicker::instance(); + if (!picker.getOpenFile(LLFilePicker::FFLOAD_ALL)) + { + // The user didn't pick a file -- the empty response string will indicate this. + } + + response = picker.getFirstFile(); + + plugin->sendPickFileResponse(response); + } + break; + + + case LLViewerMediaObserver::MEDIA_EVENT_AUTH_REQUEST: + { + LLNotification::Params auth_request_params; + auth_request_params.name = "AuthRequest"; + + // pass in host name and realm for site (may be zero length but will always exist) + LLSD args; + LLURL raw_url( plugin->getAuthURL().c_str() ); + args["HOST_NAME"] = raw_url.getAuthority(); + args["REALM"] = plugin->getAuthRealm(); + auth_request_params.substitutions = args; + + auth_request_params.payload = LLSD().with("media_id", mTextureId); + auth_request_params.functor.function = boost::bind(&LLViewerMedia::onAuthSubmit, _1, _2); + LLNotifications::instance().add(auth_request_params); + }; + break; + + case LLViewerMediaObserver::MEDIA_EVENT_CLOSE_REQUEST: + { + std::string uuid = plugin->getClickUUID(); + + llinfos << "MEDIA_EVENT_CLOSE_REQUEST for uuid " << uuid << llendl; + + if(uuid.empty()) + { + // This close request is directed at this instance, let it fall through. + } + else + { + // This close request is directed at another instance + pass_through = false; + LLFloaterMediaBrowser::closeRequest(uuid); + LLFloaterWebContent::closeRequest(uuid); + } + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_GEOMETRY_CHANGE: + { + std::string uuid = plugin->getClickUUID(); + + llinfos << "MEDIA_EVENT_GEOMETRY_CHANGE for uuid " << uuid << llendl; + + if(uuid.empty()) + { + // This geometry change request is directed at this instance, let it fall through. + } + else + { + // This request is directed at another instance + pass_through = false; + LLFloaterMediaBrowser::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight()); + LLFloaterWebContent::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight()); + } + } + break; + + default: + break; + } + + if(pass_through) + { + // Just chain the event to observers. + emitEvent(plugin, event); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void LLViewerMediaImpl::handleCookieSet(LLPluginClassMedia* self, const std::string &cookie) +{ + LLViewerMedia::getCookieStore()->setCookies(cookie); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::cut() +{ + if (mMediaSource) + mMediaSource->cut(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canCut() const +{ + if (mMediaSource) + return mMediaSource->canCut(); + else + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::copy() +{ + if (mMediaSource) + mMediaSource->copy(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canCopy() const +{ + if (mMediaSource) + return mMediaSource->canCopy(); + else + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::paste() +{ + if (mMediaSource) + mMediaSource->paste(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canPaste() const +{ + if (mMediaSource) + return mMediaSource->canPaste(); + else + return FALSE; +} + +void LLViewerMediaImpl::setUpdated(BOOL updated) +{ + mIsUpdated = updated ; +} + +BOOL LLViewerMediaImpl::isUpdated() +{ + return mIsUpdated ; +} + +void LLViewerMediaImpl::calculateInterest() +{ + LLViewerMediaTexture* texture = LLViewerTextureManager::findMediaTexture( mTextureId ); + + if(texture != NULL) + { + mInterest = texture->getMaxVirtualSize(); + } + else + { + // This will be a relatively common case now, since it will always be true for unloaded media. + mInterest = 0.0f; + } + + // Calculate distance from the avatar, for use in the proximity calculation. + mProximityDistance = 0.0f; + mProximityCamera = 0.0f; + if(!mObjectList.empty()) + { + // Just use the first object in the list. We could go through the list and find the closest object, but this should work well enough. + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + LLVOVolume* objp = *iter ; + llassert_always(objp != NULL) ; + + // The distance calculation is invalid for HUD attachments -- leave both mProximityDistance and mProximityCamera at 0 for them. + if(!objp->isHUDAttachment()) + { + LLVector3d obj_global = objp->getPositionGlobal() ; + LLVector3d agent_global = gAgent.getPositionGlobal() ; + LLVector3d global_delta = agent_global - obj_global ; + mProximityDistance = global_delta.magVecSquared(); // use distance-squared because it's cheaper and sorts the same. + + LLVector3d camera_delta = gAgentCamera.getCameraPositionGlobal() - obj_global; + mProximityCamera = camera_delta.magVec(); + } + } + + if(mNeedsMuteCheck) + { + // Check all objects this instance is associated with, and those objects' owners, against the mute list + mIsMuted = false; + + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + for(; iter != mObjectList.end() ; ++iter) + { + LLVOVolume *obj = *iter; + llassert(obj); + if (!obj) continue; + if(LLMuteList::getInstance() && + LLMuteList::getInstance()->isMuted(obj->getID())) + { + mIsMuted = true; + } + else + { + // We won't have full permissions data for all objects. Attempt to mute objects when we can tell their owners are muted. + if (LLSelectMgr::getInstance()) + { + LLPermissions* obj_perm = LLSelectMgr::getInstance()->findObjectPermissions(obj); + if(obj_perm) + { + if(LLMuteList::getInstance() && + LLMuteList::getInstance()->isMuted(obj_perm->getOwner())) + mIsMuted = true; + } + } + } + } + + mNeedsMuteCheck = false; + } +} + +F64 LLViewerMediaImpl::getApproximateTextureInterest() +{ + F64 result = 0.0f; + + if(mMediaSource) + { + result = mMediaSource->getFullWidth(); + result *= mMediaSource->getFullHeight(); + } + else + { + // No media source is loaded -- all we have to go on is the texture size that has been set on the impl, if any. + result = mMediaWidth; + result *= mMediaHeight; + } + + return result; +} + +void LLViewerMediaImpl::setUsedInUI(bool used_in_ui) +{ + mUsedInUI = used_in_ui; + + // HACK: Force elements used in UI to load right away. + // This fixes some issues where UI code that uses the browser instance doesn't expect it to be unloaded. + if(mUsedInUI && (mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)) + { + if(getVisible()) + { + setPriority(LLPluginClassMedia::PRIORITY_NORMAL); + } + else + { + setPriority(LLPluginClassMedia::PRIORITY_HIDDEN); + } + + createMediaSource(); + } +}; + +void LLViewerMediaImpl::setBackgroundColor(LLColor4 color) +{ + mBackgroundColor = color; + + if(mMediaSource) + { + mMediaSource->setBackgroundColor(mBackgroundColor); + } +}; + +F64 LLViewerMediaImpl::getCPUUsage() const +{ + F64 result = 0.0f; + + if(mMediaSource) + { + result = mMediaSource->getCPUUsage(); + } + + return result; +} + +void LLViewerMediaImpl::setPriority(LLPluginClassMedia::EPriority priority) +{ + if(mPriority != priority) + { + LL_DEBUGS("PluginPriority") + << "changing priority of media id " << mTextureId + << " from " << LLPluginClassMedia::priorityToString(mPriority) + << " to " << LLPluginClassMedia::priorityToString(priority) + << LL_ENDL; + } + + mPriority = priority; + + if(priority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + if(mMediaSource) + { + // Need to unload the media source + + // First, save off previous media state + mPreviousMediaState = mMediaSource->getStatus(); + mPreviousMediaTime = mMediaSource->getCurrentTime(); + + destroyMediaSource(); + } + } + + if(mMediaSource) + { + mMediaSource->setPriority(mPriority); + } + + // NOTE: loading (or reloading) media sources whose priority has risen above PRIORITY_UNLOADED is done in update(). +} + +void LLViewerMediaImpl::setLowPrioritySizeLimit(int size) +{ + if(mMediaSource) + { + mMediaSource->setLowPrioritySizeLimit(size); + } +} + +void LLViewerMediaImpl::setNavState(EMediaNavState state) +{ + mMediaNavState = state; + + switch (state) + { + case MEDIANAVSTATE_NONE: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_NONE" << llendl; break; + case MEDIANAVSTATE_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_BEGUN" << llendl; break; + case MEDIANAVSTATE_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED" << llendl; break; + case MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS" << llendl; break; + case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED" << llendl; break; + case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS" << llendl; break; + case MEDIANAVSTATE_SERVER_SENT: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_SENT" << llendl; break; + case MEDIANAVSTATE_SERVER_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_BEGUN" << llendl; break; + case MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED" << llendl; break; + case MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED" << llendl; break; + } +} + +void LLViewerMediaImpl::setNavigateSuspended(bool suspend) +{ + if(mNavigateSuspended != suspend) + { + mNavigateSuspended = suspend; + if(!suspend) + { + // We're coming out of suspend. If someone tried to do a navigate while suspended, do one now instead. + if(mNavigateSuspendedDeferred) + { + mNavigateSuspendedDeferred = false; + navigateInternal(); + } + } + } +} + +void LLViewerMediaImpl::cancelMimeTypeProbe() +{ + if(mMimeTypeProbe != NULL) + { + // There doesn't seem to be a way to actually cancel an outstanding request. + // Simulate it by telling the LLMimeDiscoveryResponder not to write back any results. + mMimeTypeProbe->cancelRequest(); + + // The above should already have set mMimeTypeProbe to NULL. + if(mMimeTypeProbe != NULL) + { + llerrs << "internal error: mMimeTypeProbe is not NULL after cancelling request." << llendl; + } + } +} + +void LLViewerMediaImpl::addObject(LLVOVolume* obj) +{ + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + for(; iter != mObjectList.end() ; ++iter) + { + if(*iter == obj) + { + return ; //already in the list. + } + } + + mObjectList.push_back(obj) ; + mNeedsMuteCheck = true; +} + +void LLViewerMediaImpl::removeObject(LLVOVolume* obj) +{ + mObjectList.remove(obj) ; + mNeedsMuteCheck = true; +} + +const std::list< LLVOVolume* >* LLViewerMediaImpl::getObjectList() const +{ + return &mObjectList ; +} + +LLVOVolume *LLViewerMediaImpl::getSomeObject() +{ + LLVOVolume *result = NULL; + + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + if(iter != mObjectList.end()) + { + result = *iter; + } + + return result; +} + +void LLViewerMediaImpl::setTextureID(LLUUID id) +{ + if(id != mTextureId) + { + if(mTextureId.notNull()) + { + // Remove this item's entry from the map + sViewerMediaTextureIDMap.erase(mTextureId); + } + + if(id.notNull()) + { + sViewerMediaTextureIDMap.insert(LLViewerMedia::impl_id_map::value_type(id, this)); + } + + mTextureId = id; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::isAutoPlayable() const +{ + return (mMediaAutoPlay && + gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && + gSavedSettings.getBOOL("MediaTentativeAutoPlay")); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::shouldShowBasedOnClass() const +{ + // If this is parcel media or in the UI, return true always + if (getUsedInUI() || isParcelMedia()) return true; + + bool attached_to_another_avatar = isAttachedToAnotherAvatar(); + bool inside_parcel = isInAgentParcel(); + + // llinfos << " hasFocus = " << hasFocus() << + // " others = " << (attached_to_another_avatar && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING)) << + // " within = " << (inside_parcel && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING)) << + // " outside = " << (!inside_parcel && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING)) << llendl; + + // If it has focus, we should show it + // This is incorrect, and causes EXT-6750 (disabled attachment media still plays) +// if (hasFocus()) +// return true; + + // If it is attached to an avatar and the pref is off, we shouldn't show it + if (attached_to_another_avatar) + return gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING); + + if (inside_parcel) + return gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING); + else + return gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::isAttachedToAnotherAvatar() const +{ + bool result = false; + + std::list< LLVOVolume* >::const_iterator iter = mObjectList.begin(); + std::list< LLVOVolume* >::const_iterator end = mObjectList.end(); + for ( ; iter != end; iter++) + { + if (isObjectAttachedToAnotherAvatar(*iter)) + { + result = true; + break; + } + } + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +//static +bool LLViewerMediaImpl::isObjectAttachedToAnotherAvatar(LLVOVolume *obj) +{ + bool result = false; + LLXform *xform = obj; + // Walk up parent chain + while (NULL != xform) + { + LLViewerObject *object = dynamic_cast (xform); + if (NULL != object) + { + LLVOAvatar *avatar = object->asAvatar(); + if ((NULL != avatar) && (avatar != gAgentAvatarp)) + { + result = true; + break; + } + } + xform = xform->getParent(); + } + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::isInAgentParcel() const +{ + bool result = false; + + std::list< LLVOVolume* >::const_iterator iter = mObjectList.begin(); + std::list< LLVOVolume* >::const_iterator end = mObjectList.end(); + for ( ; iter != end; iter++) + { + LLVOVolume *object = *iter; + if (LLViewerMediaImpl::isObjectInAgentParcel(object)) + { + result = true; + break; + } + } + return result; +} + +LLNotificationPtr LLViewerMediaImpl::getCurrentNotification() const +{ + return mNotification; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +// static +bool LLViewerMediaImpl::isObjectInAgentParcel(LLVOVolume *obj) +{ + return (LLViewerParcelMgr::getInstance()->inAgentParcel(obj->getPositionGlobal())); +} diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index e2e342cc45..a70c6f4887 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -339,7 +339,10 @@ public: LLVOVolume *getSomeObject(); void setUpdated(BOOL updated) ; BOOL isUpdated() ; - + + // updates the javascript object in the embedded browser with viewer values + void updateJavascriptObject(); + // Updates the "interest" value in this object void calculateInterest(); F64 getInterest() const { return mInterest; }; diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml index 0d4a095e14..32c1d7083a 100644 --- a/indra/newview/skins/default/xui/en/menu_login.xml +++ b/indra/newview/skins/default/xui/en/menu_login.xml @@ -183,11 +183,11 @@ parameter="http://join.secondlife.com/"/> + label="Web Content Floater Debug Test" + name="Web Content Floater Debug Test"> + parameter="http://callum-linden.s3.amazonaws.com/browsertest.html"/> - - - installables - - GL - - copyright - Copyright (c) 1991-2000 Silicon Graphics, Inc. - description - A standard for 3D Graphics rendering engine. - license - GL - packages - - darwin - - md5sum - 0bd2795a2afe09f6c563f2f888f24cc9 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/GL-darwin-20080613.tar.bz2 - - linux - - md5sum - 2ab29212a7f3acdaebf10059af816be0 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/GL-linux-20080812.tar.bz2 - - linux64 - - md5sum - 9c3dff3817f1105f9054401fdef1fe50 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/GL-linux64-20080909.tar.bz2 - - windows - - md5sum - 91155239b02f576384603795d41eb971 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/GL-windows-20090505.tar.bz2 - - - - SDL - - copyright - Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga - description - The Simple DirectMedia Layer libraries are used for handling input and basic window/GL setup on the Linux client. Packages also include cursors. - license - lgpl - packages - - linux - - md5sum - fce0ff7d2cdf0f36c1647e6a3916e29e - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/SDL-1.2.12-linux-20090218.tar.bz2 - - - - apr_suite - - license - apache 2.0 - packages - - darwin - - md5sum - 115d8ac44a91efdb173e9b3e478c46b6 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.3.7-darwin-20090805.tar.bz2 - - linux - - md5sum - 7b84cd6a3c601a104d9c09e58ef2f50c - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.2.8-linux-20080812.tar.bz2 - - linux64 - - md5sum - 1a7e1186855d48d8316ce86803095f70 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.2.8-linux64-20080909a.tar.bz2 - - windows - - md5sum - a02619c1e30a3db02d3883bf1ad7a1e6 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/apr_suite-1.3.8-windows-20090911.tar.bz2 - - - - ares - - copyright - Copyright 1998 by the Massachusetts Institute of Technology. - description - Performs DNS requests and name resolves asynchronously. Used with libcurl to keep all HTTP operations async. - license - c-ares - packages - - darwin - - md5sum - cdb2f5c4a5a1f9ecd75bc1dbdd4db8e9 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ares-1.7.1-darwin-20100606.tar.bz2 - - linux - - md5sum - 91694429e391efeea1de974df26032a2 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ares-1.7.1-linux-20100527.tar.bz2 - - linux64 - - md5sum - c4242416e0b2e642c0bf062a19a250e4 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ares-1.3.0-linux64-20080909.tar.bz2 - - windows - - md5sum - 4b84738eec2e21b0c096d53b79ee2681 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ares-1.7.1-windows-20100611a.tar.bz2 - - - - artwork-common - - copyright - (C) 2008 Linden Research, Inc. - description - Second Life(TM) Viewer Artwork - license - artwork - packages - - darwin - - md5sum - 5e047437d73d1017bf270a6c6e936f23 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/artwork-common-20090415.tar.bz2 - - linux - - md5sum - 5e047437d73d1017bf270a6c6e936f23 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/artwork-common-20090415.tar.bz2 - - windows - - md5sum - 5e047437d73d1017bf270a6c6e936f23 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/artwork-common-20090415.tar.bz2 - - - - berkeley - - copyright - Copyright (c) 1990-1999 Sleepycat Software. All rights reserved. - description - a high-performance, embedded database library - license - sleepycat - - boost - - copyright - various - description - A set of portable C++ libraries which provide a wide set of functionality. - license - boost - packages - - darwin - - md5sum - 71defd179827bf172b76d6020023e0e8 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.39.0-darwin-20100222a.tar.bz2 - - linux - - md5sum - 4db3d74e40d149eeec06f4d97a609bb1 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.39.0-linux-20100624.tar.bz2 - - linux64 - - md5sum - af4badd6b2c10bc4db82ff1256695892 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.39.0-linux64-20100119.tar.bz2 - - windows - - md5sum - 72e6e2eff5d146a107f3059b6c31fb95 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/boost-1.39.0-windows-20100630.tar.bz2 - - - - curl - - copyright - Copyright (c) 1996 - 2008, Daniel Stenberg, <daniel@haxx.se>. - description - Client-side URL transfer library. Handles moving data across the net in many different protocols. Used to GET/POST/PUT/DELETE web resources. - license - curl - packages - - darwin - - md5sum - ca8f0134fa5ab6f34a6eeb8d0896c9b0 - url - https://s3.amazonaws.com/automated-builds-secondlife-com/hg/repo/brad_curl-autobuild/rev/216961/arch/Darwin/installer/curl-7.21.1-darwin-20101214.tar.bz2 - - linux - - md5sum - 9c9b629b62bf874d550c430ad678dc04 - url - https://s3.amazonaws.com/automated-builds-secondlife-com/hg/repo/brad_curl-autobuild/rev/216961/arch/Linux/installer/curl-7.21.1-linux-20101215.tar.bz2 - - linux64 - - md5sum - 6994192cea7ab2d885a158a3de474273 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/curl-7.16.4a-linux64-20090303.tar.bz2 - - windows - - md5sum - 48691883065a82d53691d73aae81d4c1 - url - https://s3.amazonaws.com/automated-builds-secondlife-com/hg/repo/brad_curl-autobuild/rev/216961/arch/CYGWIN/installer/curl-7.21.1-windows-20101214.tar.bz2 - - - - dbghelp - - copyright - Copyright Microsoft Corporation - description - dbghelp: Debug helper from Microsoft Debugging Tools For Windows - license - MSDTW - packages - - windows - - md5sum - b7563064037e032143ca2d610aae5153 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/dbghelp-6.11.1.404-windows-20090520.tar.bz2 - - - - dbusglib - - copyright - Copyright (C) 2002, 2003 CodeFactory AB / Copyright (C) 2003, 2004 Red Hat, Inc. - description - dbus/dbus-glib: headers only - license - AFL2.1 - packages - - linux - - md5sum - eb25444142d4102b0ce1b7ffaadb071e - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/dbusglib-linux-20080707.tar.bz2 - - - - elfio - - license - lgpl - packages - - linux - - md5sum - 82ea408af2f968cfe5f013ab241323ef - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/elfio-1.0.3-linux-20080812.tar.bz2 - - - - expat - - copyright - Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd - description - An XML parser library written in C. It is a stream-oriented parser in which an application registers handlers for things the parser might find in the XML document (like start tags). - license - mit - packages - - darwin - - md5sum - c457a0a041ac4946265889a503d26c3d - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/expat-1.95.8-darwin-20090805.tar.bz2 - - linux - - md5sum - 67b470fd446b08c9831d1039674eae4e - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/expat-1.95.8-linux-20080812.tar.bz2 - - linux64 - - md5sum - 278c61871419b9a4d50a4f88b7922403 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/expat-1.95.8-linux64-20080909.tar.bz2 - - windows - - md5sum - 5dbbdb4a9b5bec86d180ef20a5f8ccfb - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/expat-1.95.8-windows-20090917.tar.bz2 - - - - fmod - - copyright - FMOD Sound System, copyright (C) Firelight Technologies Pty, Ltd., 1994-2006. - description - Audio engine and mp3 stream decoder . - license - fmod - packages - - darwin - - md5sum - 261bcd3387066cf0a1d46549400052b5 - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/fmod-3.75-darwin-20101007.tar.bz2 - - linux - - md5sum - 8490d97430c12c2e1ac19ff80a8d4db4 - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/fmod-3.75-linux-20101007.tar.bz2 - - windows - - md5sum - bab1babcb01ff9849b7f072d352e1ecd - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/fmod-3.75-windows-20101007.tar.bz2 - - - - fontconfig - - license - mit - packages - - linux - - md5sum - 9af6a1ed39fa540bfcaa402b0ea22f78 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/fontconfig-2.2.3-linux-20080613.tar.bz2 - - - - freeglut - - license - mit - packages - - windows - - md5sum - fcbb695ff203775fad96d184bf5f34fc - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/freeglut-2.4.0-windows-20090608.tar.bz2 - - - - freetype - - copyright - Copyright - description - Font - license - freetype - packages - - darwin - - md5sum - f00144dfb597140f328774c3244f0c3e - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/freetype-2.3.9-darwin-20090922.tar.bz2 - - linux - - md5sum - 9de3f44be65645c7f6af236139596942 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/freetype-2.3.9-linux-2010-02-19a-nommap.tar.bz2 - - linux64 - - md5sum - 35f6fa557ba90f9cda0a18d1af2055a4 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/freetype-2.1.5-linux64-20080909.tar.bz2 - - windows - - md5sum - 88980fd6d91ac541b62dea877ebe6ba6 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/freetype-2.3.9-windows-20090917.tar.bz2 - - - - glh_linear - - copyright - Copyright (c) 2000 Cass Everitt; Copyright (c) 2000 NVIDIA Corporation; All rights reserved. - description - nVidia NVParse SDK: platform-indepenedent C++ Apple OpenGL helper library - license - glh_linear - packages - - darwin - - md5sum - 23bd9a75e5a2365a827461e6c324f52b - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glh_linear-darwin-20080613.tar.bz2 - - linux - - md5sum - 23bd9a75e5a2365a827461e6c324f52b - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glh_linear-linux-20080812.tar.bz2 - - linux64 - - md5sum - 2965646aea1d2a6aec1fbc431c02733f - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glh_linear-linux-20080613.tar.bz2 - - windows - - md5sum - 38b9ddfe8dceff55ee4351016a937d1b - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glh_linear-windows-20080613.tar.bz2 - - - - glib - - description - GLib is a library containing many useful C routines for things such as trees, hashes, and lists. - license - gpl - packages - - darwin - - md5sum - 6cc5ce1fafd10299fdb890b3d4c3cf53 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glib-2.0-darwin-20080817.tar.bz2 - - linux - - md5sum - 2f1a9e14f9213c2c9564c1c1cfdd6d47 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glib-2.0-linux-20080817.tar.bz2 - - windows - - md5sum - 3d5e29d444dde4815b36082eedfc775a - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glib-2.0-windows-20080817.tar.bz2 - - - - glui - - license - lgpl - packages - - darwin - - md5sum - 84f792a860691d0fad6d1de6eeb31baa - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glui-2.36-darwin-20090623a.tar.bz2 - - windows - - md5sum - 5b8631fe510d4ebaeb965c673937e1e7 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/glui-2.3.6-windows-freeglut-20090608.tar.bz2 - - - - google - - license - mit - packages - - linux - - md5sum - 40db900872612615e849f17cbdfd2c27 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/google-linux-20080812.tar.bz2 - - - - google-perftools - - copyright - Copyright (c) 2005, Google Inc. - description - Heap performance and validity checking tools from google. Includes TCMalloc, heap-checker, heap-profiler and cpu-profiler. - license - bsd - packages - - windows - - md5sum - 32dba32ddd460a08e082898ebba6315c - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/google-perftools-1.0-windows-20090406.tar.bz2 - - - - google_breakpad - - copyright - Copyright (c) 2006, Google Inc. - description - An open-source multi-platform crash reporting system - license - bsd - packages - - darwin - - md5sum - ced4010b59f1a579caa7fe3c18512499 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/google_breakpad-0.0.0-rev599-darwin-20100528a.tar.bz2 - - linux - - md5sum - 29c3e7dad60bbf02c811786436d99523 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/google_breakpad-0.0.0-rev599-linux-20100521b.tar.bz2 - - windows - - md5sum - 0859d47242990125f17eaab30bece2ff - url - http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/google_breakpad-0.0.0-rev599-windows-20100524.tar.bz2 - - - - googlemock - - copyright - Copyright 2008, Google Inc. - description - Google C++ Mocking Framework (or Google Mock for short) is a library for writing and using C++ mock classes. - license - bsd - packages - - darwin - - md5sum - 4863e9fea433d0a4be761ea5d3e8346a - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/googlemock-1.1.0-darwin-20090626.tar.bz2 - - linux - - md5sum - 877dabecf84339690191c6115c76366e - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/googlemock-1.1.0-linux32-20090527.tar.bz2 - - windows - - md5sum - f601a82ea91030974072da8924cae41e - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/googlemock-1.1.0-windows-20090921.tar.bz2 - - - - gstreamer - - license - lgpl - packages - - linux - - md5sum - c829b638b6eef71ca63418cb9aea46a2 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/gstreamer-linux-20080613.tar.bz2 - - linux64 - - md5sum - befc7520fe01250f39458f65c29bc584 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/gstreamer-linux64-20080909.tar.bz2 - - - - gtk-atk-pango-glib - - copyright - Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - description - Libraries associated with GTK for gui features. atk: interfaces for accessibility; glib: low-level core functionality for using GTK+ and GNOME; pango: layout/rendering of text w/ emphasis on internationalization. - license - lgpl - packages - - linux - - md5sum - 21c16a74f8fc9a62e3ab944a6eb7403d - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/gtk-atk-pango-glib-linux-20080616.tar.bz - - windows - - md5sum - d963750bcd333a108b3697d220c87d09 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/gtk-atk-pango-glib-windows-20080613.tar.bz2 - - - - havok - - copyright - on file - description - Physics engine for the simulator - license - havok - packages - - darwin - - md5sum - f64c08771a4fc456db2a55b47302078b - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/havok-4.6-darwin-20080812.tar.bz2 - - linux - - md5sum - af7b1fc9072443009f19e43fb3c8342f - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/havok-4.6.1-linux-20081029.tar.bz2 - - linux64 - - md5sum - cd4076d6caf5fabff36bf48bd01e4ba8 - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/havok-4.6.1-linux64-20081030.tar.bz2 - - windows - - md5sum - f25fbb29c2275267233c79f0c68ca37f - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/havok-4.6.1-windows-20081030.tar.bz2 - - - - jpeglib - - copyright - Copyright (c) 2003, Yves Piguet. - description - An open-source JPEG (JFIF) library - license - jpeglib - packages - - darwin - - md5sum - 8d38d74c481e9aab4518c8f2a7d52800 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jpeglib-6b-darwin-20080812.tar.bz2 - - linux - - md5sum - 8aa8e01e0c21f60f0ede0ffb04e9214f - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jpeglib-6b-linux-20081218.tar.bz2 - - linux64 - - md5sum - 0e7facf7d48531d20c0cd6a3c3f04021 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jpeglib-6b-linux64-20080909.tar.bz2 - - windows - - md5sum - 6a6bb0143a2561e3276dab4bcfa425ef - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jpeglib-6b-windows-20090917a.tar.bz2 - - - - jsoncpp - - copyright - json-cpp library released to Public Domain by Baptiste Lepilleur <blep@users.sourceforge.net> - description - jsoncpp is an implementation of a JSON (http://json.org) reader and writer in C++. - license - jsoncpp - packages - - darwin - - md5sum - 4c6b949778099a63550898f00f3e6a5e - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jsoncpp-svn-r69-darwin-20090923.tar.bz2 - - linux - - md5sum - a2a94b8ca1d32f23e3e668d64023514e - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jsoncpp-svn-r69-linux-20090922.tar.bz2 - - linux64 - - md5sum - a06ab38628ab7b53b8f3326cd942a6a8 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jsoncpp-svn-r69-linux64-20090922.tar.bz2 - - windows - - md5sum - caf152cfc730737c124f7612cf68fbd3 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/jsoncpp-svn-r69-windows-20090922.tar.bz2 - - - - kdu - - copyright - on file - description - Kakadu (KDU) JPEG-2000 decoder library. - license - kdu - packages - - darwin - - md5sum - 8261994de5af6581e08c26fefe1b2810 - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/kdu-6.4.1-darwin-20101123.tar.bz2 - - linux - - md5sum - ed3e58899a424684dad49c94ba3813e7 - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/kdu-6.4.1-linux-20101124.tar.bz2 - - windows - - md5sum - 066e089a5d9faeaf131e1f4e4860a163 - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/kdu-6.4.1-windows-20101123.tar.bz2 - - - - libmono - - copyright - (C) 2005 Novell, Inc. http://www.novell.com - description - An open source implementation of the ECMA/ISO ECMA-334 Common L\ -anguage Infrstructure (CLI) international standard - license - lgpl - packages - - darwin - - md5sum - 39a803fcbe6f11b72358fc78b7777b6c - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libmono-darwin-20080724.tar.bz2 - - linux - - md5sum - 9bc0f8b7d5e0ff194b6d5635daf9ae3a - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libmono-1.2.6-linux-20080816a.tar.bz2 - - linux64 - - md5sum - 451521b4cb57c35caf3efb8dcf99b99e - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libmono-1.2.6-linux64-20080926.tar.bz2 - - windows - - md5sum - 6712a09311a914752f47d5d62562a239 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libmono-1.2.6-windows-20080903.tar.bz2 - - - - libpng - - copyright - Copyright (c) 2004, 2006-2008 Glenn Randers-Pehrson - description - An open, extensible image format with lossless compression. PNG Reference Library - license - libpng - packages - - darwin - - md5sum - 82659b48831cbf58bf04b86602939e0b - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libpng-1.2.35-darwin-20090304.tar.bz2 - - linux - - md5sum - f5e84c991f6e3caacb26db259593cbea - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libpng-1.2.35-linux-20090304.tar.bz2 - - linux64 - - md5sum - 5ee1e62bde38520c7f134c4afb9ac9b1 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libpng-1.2.35-linux64-20090304.tar.bz2 - - windows - - md5sum - c781cd9846cf20afb90ac40ad1a0ce9d - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libpng-1.2.35-windows-20090917.tar.bz2 - - - - libuuid - - copyright - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> - description - Generates UUIDs under Linux. Originally a part of the ext2fs filesystem. Also see lluuid.cpp for all platforms. Part of the e2fsprogs package. - license - lgpl - packages - - linux - - md5sum - 91b194aed4b38bc23493b198009a8c6a - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libuuid-linux-20090417.tar.bz2 - - - - libxml - - license - mit - packages - - linux - - md5sum - 4b5d2dcfe8a49b73fb69f10aab441092 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libxml-2.6.24-linux-20080613.tar.bz2 - - linux64 - - md5sum - 921d7f980519101afb74623e29e9d175 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/libxml-2.6.24-linux64-20080909.tar.bz2 - - - - llqtwebkit - - license - lgpl - packages - - darwin - - md5sum - f07b063cdc207479b111576dc74127f0 - url - http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/llqtwebkit-darwin-qt4.7.1-20110322.tar.bz2 - - linux - - md5sum - 5d743c93b970abe685b185de83001a6e - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-linux-qt4.6-20100923.tar.bz2 - - windows - - md5sum - 1e66b1ecab911a60ba50b59361ef62e1 - url - http://viewer-source-downloads.s3.amazonaws.com/install_pkgs/llqtwebkit-windows-qt4.7.1-20110317.tar.bz2 - - - - mesa - - copyright - Copyright (C) 1999-2007 Brian Paul All Rights Reserved. - description - Mesa 3-D graphics library. Provides the required Apple OpenGL headers under Linux. - license - mesa - packages - - linux - - md5sum - 70d0bbe1145fff29a0131349c898260e - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/mesa-7.0-linux-20080812.tar.bz2 - - linux64 - - md5sum - 56630977f9261bd82039b0da08a0685c - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/mesa-6.2.1-linux64-20081016.tar.bz2 - - windows - - md5sum - 82cdcdcb2d0615389a7480485ea35f4c - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/mesa-7.0-windows-20080613.tar.bz2 - - - - mysql - - license - gpl - packages - - darwin - - md5sum - df27f2db244ea2762759a06cd75ada4e - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/mysql-darwin-20080812.tar.bz2 - - linux - - md5sum - cc86b4cc858655e23704d1168325d7b9 - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/mysqlclient-linux-20090320.tar.bz2 - - windows - - md5sum - 98bac06680dca907e783d8dd4aa9edde - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/mysql-windows-20080804.tar.bz2 - - - - ndofdev - - copyright - Copyright (c) 2007, 3Dconnexion, Inc. - All rights reserved. - description - in use on windows and darwin for joystick support. - license - linden - packages - - darwin - - md5sum - 17999c47e17f2dd9e12a22372ce8ff14 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ndofdev-darwin-20080812.tar.bz2 - - linux - - md5sum - 9469c3732a33a154fa0a2807b9f36ccc - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ndofdev-linux-0.2-20080828.tar.bz2 - - windows - - md5sum - f0df8a1e60991095e3adca1450b8c9c0 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ndofdev-windows-20090917.tar.bz2 - - - - ogg-vorbis - - copyright - Copyright (C) 2008 Xiph.org Foundation - description - Ogg: container format Vorbis: audio compression scheme - license - ogg-vorbis - packages - - darwin - - md5sum - a6843398b780645c4897c9776c688926 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ogg-vorbis-1.03-1.1.2-darwin-20080812.tar.bz2 - - linux - - md5sum - 6dc0536329a0aadf76e3054ffd4da61c - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ogg-vorbis-1.2.0-linux-20081201.tar.bz2 - - linux64 - - md5sum - 964c71e6ee22be1bcaf6d480e74cdd14 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ogg-vorbis-1.2.0-linux64-20080909.tar.bz2 - - windows - - md5sum - 9bf1fea65e66b2cd3075e6ffd7eb57ad - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ogg-vorbis-1.1.3-1.2.0-windows-20080723.tar.bz2 - - - - openSSL - - license - openSSL - packages - - darwin - - md5sum - 11d2be4f2b172430747b7d4a6739e3d8 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openSSL-0.9.8l-darwin-20100428.tar.bz2 - - linux - - md5sum - f219ef07b02e2abb9282345c3a8f2b39 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openSSL-0.9.7c-linux-20080812.tar.bz2 - - linux64 - - md5sum - 00b23f28a2457d9dabbaff0b29ee7323 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openSSL-0.9.8g-linux64-20080909.tar.bz2 - - windows - - md5sum - dd85209081b832e836de6e1538541d89 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openSSL-0.9.8j-windows-20090129.tar.bz2 - - - - openal-soft - - copyright - Copyright (C) 2008 by authors. - description - 3D Audio library - license - lgpl - packages - - darwin - - md5sum - a0757244e3e6688fde2ffeea35cc1f96 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openal-darwin-20080924.tar.bz2 - - linux - - md5sum - 75a7004ab14bea46594b1c652f1a6040 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openal-linux-20100120-3ad86a1c.tar.bz2 - - linux64 - - md5sum - 5ad0a3ab623356c1ad61394ba238f99f - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openal-soft-1.6.372-linux64-20081219.tar.bz2 - - windows - - md5sum - a0757244e3e6688fde2ffeea35cc1f96 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openal-windows-20080924.tar.bz2 - - - - openjpeg - - copyright - Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium - description - An open-source JPEG-2000 library; a slower alternative to Kadaku. Used in the open source release - license - openjpeg - packages - - darwin - - md5sum - 23313fda213a2496945435db2a0ee78b - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openjpeg-1.3.0-darwin-20090501.tar.bz2 - - linux - - md5sum - 02af0dad64803e0d821bc09e6038682c - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openjpeg-1.3-linux-20081124b.tar.bz2 - - linux64 - - md5sum - 44f1bc9d47e4a54fc274c213f2cb565f - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openjpeg-1.2.0-linux64-20080909.tar.bz2 - - windows - - md5sum - 41541a98106894e28a6bf585010fea65 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openjpeg-1.3-windows-20090407.tar.bz2 - - - - pulseaudio - - copyright - Copyright 2004-2006 Lennart Poettering, Copyright 2006 Pierre Ossman (ossman@cendio.se) for Cendio AB - description - pulseaudio: headers only - license - lgpl - packages - - linux - - md5sum - 30cb00069fe2a545fbf7be1070386236 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/linux-pulse-headers-0.9.14.tar.bz2 - - - - quicktime - - copyright - Copyright (C) 1990-2007 by Apple Computer, Inc., all rights reserved. - description - Separate download. Used to play in-world video clips on a prim. - license - quicktime - packages - - windows - - md5sum - be45825cc14ede53790ac93c58307dcb - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/quicktime-sdk-windows-7.3-20091110.tar.bz2 - - - - smartheap - - copyright - Copyright (C) 1991-2000 Compuware Corporation. All Rights Reserved. - description - Memory Management Library - license - smartheap - packages - - darwin - - md5sum - f54131b5f228e805c64c2e4e6c96579a - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/smartheap-6.0.2-darwin-20080610.tar.bz2 - - linux - - md5sum - 499208522bf7d7843e1d014d64214e06 - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/smartheap-6.0.2-linux-20080610.tar.bz2 - - windows - - md5sum - 78fd47017f21d11eae43bca3e38a3e1e - url - scp:install-packages.lindenlab.com:/local/www/install-packages/doc/smartheap-6.0.2-windows-20080611.tar.bz2 - - - - tut - - copyright - Copyright 2002-2006 Vladimir Dyuzhev, Copyright 2007 Denis Kononenko, Copyright 2008 Michal Rzechonek - description - C++ Template Unit Test - license - bsd - packages - - common - - md5sum - a1b8a118ba9df1f2a73f6aafa7980e83 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/tut-2008-11-30-common-20081208.tar.bz2 - - - - unistd - - copyright - (c) 2008 Linden Lab. - description - Placeholder file to make flex happy on windows. - license - linden - packages - - windows - - md5sum - 6353aff33d7d03b22055aec76f53a866 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/unistd-windows-20080611.tar.bz2 - - - - slvoice - - copyright - - license - vivox - packages - - darwin - - md5sum - 2f9b3528d4b5f858fb8dcee4b6dd5188 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/slvoice-3.2.0002.9361-darwin-20101117a.tar.bz2 - - linux - - md5sum - cde4728b8a75a76c72a8785815cb769f - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/slvoice-3.2.0002.9361-linux-20101117a.tar.bz2 - - windows - - md5sum - 940ac55a6d0141c958bf2b14939d8474 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/slvoice-3.2.0002.9361-windows-20101117a.tar.bz2 - - - - xmlrpc-epi - - copyright - Copyright 2000 Epinions, Inc. - description - Implementation of the xmlrpc protocol in C that provides an API for developers to serialize RPC requests to and from XML. - license - xmlrpc-epi - packages - - darwin - - md5sum - 2d3a918c88d756422c1a8139ebe15f56 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/xmlrpc-epi-0.51-darwin-20080812.tar.bz2 - - linux - - md5sum - 84a219199240ea70f54439c02acef0cd - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/xmlrpc-epi-0.51-linux-20080812.tar.bz2 - - linux64 - - md5sum - dc67b896c56116df8e18f2d1bbd07031 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/xmlrpc-epi-0.51-linux64-20080909.tar.bz2 - - windows - - md5sum - 262629bcaa39dcf7266caa50da01a599 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/xmlrpc-epi-0.51-windows-20091016.tar.bz2 - - - - zlib - - copyright - Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler - description - A Massively Spiffy Yet Delicately Unobtrusive Compression Library (Also Free, Not to Mention Unencumbered by Patents) - license - zlib - packages - - darwin - - md5sum - c844e1b05723ce078dbbd5aea9cdd3ad - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/zlib-1.1.4-darwin-20080818.tar.bz2 - - linux - - md5sum - 26fe88213c213dc6153690ab142c25ca - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/zlib-1.2.3dfsg-linux-20091208.tar.bz2 - - linux64 - - md5sum - 4bddfb2c6dd7b1470a3ed675ac14bd9a - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/zlib-1.2.3-linux64-20080909.tar.bz2 - - windows - - md5sum - 73baf52a740d151fddbc2a008369c462 - url - http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/zlib-1.2.3-windows-20090921.tar.bz2 - - - - - licenses - - AFL2.1 - - url - http://opensource-definition.org/licenses/afl-2.1.html - - GL - - url - http://www.xfree86.org/4.4.0/LICENSE9.html#sgi - - MSDTW - - text - MICROSOFT SOFTWARE LICENSE TERMS -MICROSOFT DEBUGGING TOOLS FOR WINDOWS -These license terms are an agreement between Microsoft Corporation (or based on where you live, one of -its affiliates) and you. Please read them. They apply to the software named above, which includes the -media on which you received it, if any. The terms also apply to any Microsoft -* updates, -* supplements, -* Internet-based services -* support services, and -* Debugging symbol files that you may access over the internet -for this software, unless other terms accompany those items. If so, those terms apply. -By using the software, you accept these terms. If you do not accept them, do not use the -software. -If you comply with these license terms, you have the rights below. -1. INSTALLATION AND USE RIGHTS. One user may install and use any number of copies of the -software on your devices to design, develop, debug and test your programs. -2. ADDITIONAL LICENSING REQUIREMENTS AND/OR USE RIGHTS. -a. Distributable Code. The software contains code that you are permitted to distribute in programs -you develop if you comply with the terms below. -i. Right to Use and Distribute. The code and text files listed below are “Distributable Code.” -* REDIST.TXT Files. You may copy and distribute the object code form of code listed in -REDIST.TXT files. -* Sample Code. You may modify, copy, and distribute the source and object code form of -code marked as “sample.” -* Third Party Distribution. You may permit distributors of your programs to copy and -distribute the Distributable Code as part of those programs. -ii. Distribution Requirements. For any Distributable Code you distribute, you must -* add significant primary functionality to it in your programs; -* require distributors and external end users to agree to terms that protect it at least as much -as this agreement; -* display your valid copyright notice on your programs; and -* indemnify, defend, and hold harmless Microsoft from any claims, including attorneys’ fees, -related to the distribution or use of your programs. -iii. Distribution Restrictions. You may not -* alter any copyright, trademark or patent notice in the Distributable Code; -* distribute any symbol files which you may access or use under these license terms for the -software; -* use Microsoft’s trademarks in your programs’ names or in a way that suggests your -programs come from or are endorsed by Microsoft; -* distribute Distributable Code to run on a platform other than the Windows platform; -* include Distributable Code in malicious, deceptive or unlawful programs; or -* modify or distribute the source code of any Distributable Code so that any part of it -becomes subject to an Excluded License. An Excluded License is one that requires, as a -condition of use, modification or distribution, that -* the code be disclosed or distributed in source code form; or -* others have the right to modify it. -3. SCOPE OF LICENSE. The software is licensed, not sold. This agreement only gives you some rights -to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights -despite this limitation, you may use the software only as expressly permitted in this agreement. In -doing so, you must comply with any technical limitations in the software that only allow you to use it in -certain ways. You may not -* work around any technical limitations in the software; -* reverse engineer, decompile or disassemble the software, except and only to the extent that -applicable law expressly permits, despite this limitation; -* make more copies of the software than specified in this agreement or allowed by applicable law, -despite this limitation; -* publish the software for others to copy; -* rent, lease or lend the software; -* transfer the software or this agreement to any third party; or -* use the software for commercial software hosting services. -4. INTERNET-BASED SERVICES. Microsoft provides Internet-based services with the software. It may -change or cancel them at any time. -a. Consent for Internet-Based Services. The software contains features which may connect to -Microsoft or service provider computer systems over the Internet. In some cases, you will not -receive a separate notice when they connect. You may switch these features on or you may -choose not to use them. For more information about these features, see -http://www.microsoft.com/info/privacy/default.mspx. By using these features, you consent to the transmission of -this information. Microsoft does not use the information to identify or contact you. -b. Misuse of Internet-based Services. You may not use these services in any way that could -harm them or impair anyone else’s use of them. You may not use the services to try to gain -unauthorized access to any service, data, account or network by any means. - -5. BACKUP COPY. You may make one backup copy of the software. You may use it only to reinstall the -software. -6. DOCUMENTATION. Any person that has valid access to your computer or internal network may copy -and use the documentation for your internal, reference purposes. -7. EXPORT RESTRICTIONS. The software is subject to United States export laws and regulations. You -must comply with all domestic and international export laws and regulations that apply to the software. -These laws include restrictions on destinations, end users and end use. For additional information, see -www.microsoft.com/exporting. -8. SUPPORT SERVICES. Because this software is “as is,” we may not provide support services for it. -9. ENTIRE AGREEMENT. This agreement, and the terms for supplements, updates, Internet-based -services and support services that you use, are the entire agreement for the software and support -services. -10. APPLICABLE LAW. -a. United States. If you acquired the software in the United States, Washington state law governs -the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of -laws principles. The laws of the state where you live govern all other claims, including claims under -state consumer protection laws, unfair competition laws, and in tort. -b. Outside the United States. If you acquired the software in any other country, the laws of that -country apply. -11. LEGAL EFFECT. This agreement describes certain legal rights. You may have other rights under the -laws of your country. You may also have rights with respect to the party from whom you acquired the -software. This agreement does not change your rights under the laws of your country if the laws of -your country do not permit it to do so. -12. DISCLAIMER OF WARRANTY. The software is licensed “as-is.” You bear the risk of using -it. Microsoft gives no express warranties, guarantees or conditions. You may have -additional consumer rights under your local laws which this agreement cannot change. To -the extent permitted under your local laws, Microsoft excludes the implied warranties of -merchantability, fitness for a particular purpose and non-infringement. -13. LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. You can recover from -Microsoft and its suppliers only direct damages up to U.S. $5.00. You cannot recover any -other damages, including consequential, lost profits, special, indirect or incidental -damages. -This limitation applies to -* anything related to the software, services, content (including code) on third party Internet sites, or -third party programs; and -* claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, -or other tort to the extent permitted by applicable law. -It also applies even if Microsoft knew or should have known about the possibility of the damages. The -above limitation or exclusion may not apply to you because your country may not allow the exclusion or -limitation of incidental, consequential or other damages. - - - apache 2.0 - - url - http://www.apache.org/licenses/LICENSE-2.0 - - artwork - - text - COPYRIGHT AND PERMISSION NOTICE - -Second Life(TM) Viewer Artwork. Copyright (C) 2008 Linden Research, Inc. - -Linden Research, Inc. ("Linden Lab") licenses the Second Life viewer -artwork and other works in the files distributed with this Notice under -the Creative Commons Attribution-Share Alike 3.0 License, available at -http://creativecommons.org/licenses/by-sa/3.0/legalcode. For the license -summary, see http://creativecommons.org/licenses/by-sa/3.0/. - -Notwithstanding the foregoing, all of Linden Lab's trademarks, including -but not limited to the Second Life brand name and Second Life Eye-in-Hand -logo, are subject to our trademark policy at -http://secondlife.com/corporate/trademark/. - -If you distribute any copies or adaptations of the Second Life viewer -artwork or any other works in these files, you must include this Notice -and clearly identify any changes made to the original works. Include -this Notice and information where copyright notices are usually included, -for example, after your own copyright notice acknowledging your use of -the Second Life viewer artwork, in a text file distributed with your -program, in your application's About window, or on a credits page for -your work. - - url - http://svn.secondlife.com/svn/linden/trunk/doc/LICENSE-logos.txt - - boost - - url - http://www.boost.org/LICENSE_1_0.txt - - bsd - - url - http://www.opensource.org/licenses/bsd-license.php - - c-ares - - text - http://daniel.haxx.se/projects/c-ares/license.html - - curl - - url - http://curl.haxx.se/docs/copyright.html - - fmod - - url - http://www.fmod.org/ifmodlicense.html - - freetype - - url - http://freetype.sourceforge.net/FTL.TXT - - glh_linear - - text - glh - is a platform-indepenedent C++ OpenGL helper library - -Copyright (c) 2000 Cass Everitt -Copyright (c) 2000 NVIDIA Corporation -All rights reserved. - -Redistribution and use in source and binary forms, with or -without modification, are permitted provided that the following -conditions are met: - -Redistributions of source code must retain the above -copyright notice, this list of conditions and the following -disclaimer. -Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following -disclaimer in the documentation and/or other materials -provided with the distribution. -The names of contributors to this software may not be used -to endorse or promote products derived from this software -without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -Cass Everitt - cass@r3.nu - - - - glut - - url - http://www.xmission.com/~nate/glut/README-win32.txt - - gpl - - url - http://www.gnu.org/licenses/gpl.html - - havok - - text - on file - - intel - - text - Haven't yet found. - - - jpeglib - - text - http://nyctergatis.com/jpeglib/ - - jsoncpp - - text - The json-cpp library and this documentation are in Public Domain. Retrieved from http://jsoncpp.sourceforge.net/ on 2009-09-04. - url - http://jsoncpp.sourceforge.net - - kdu - - text - jpeg2000 license #00024 (on file) - - lgpl - - url - http://www.gnu.org/copyleft/lgpl.html - - libpng - - text - http://www.libpng.org/pub/png/src/libpng-LICENSE.txt - - linden - - text - Using this license for Linden Lab owned library files - - mesa - - url - http://www.mesa3d.org/license.html - - mit - - text - http://www.jclark.com/xml/copying.txt - - ogg-vorbis - - url - http://www.xiph.org/licenses/bsd/ - - openSSL - - url - http://www.openssl.org/source/license.html - - openjpeg - - url - http://www.openjpeg.org/BSDlicense.txt - - quicktime - - text - ENGLISH - -Apple Computer, Inc. -QuickTime 7 Software Developer Kit (SDK) -Software License Agreement - -PLEASE READ THIS SOFTWARE LICENSE AGREEMENT ("LICENSE") BEFORE USING THE SOFTWARE. BY USING THE SOFTWARE, YOU ARE AGREEING TO BE BOUND BY THE TERMS OF THIS LICENSE. IF YOU ARE ACCESSING THE SOFTWARE ELECTRONICALLY, SIGNIFY YOUR AGREEMENT TO BE BOUND BY THE TERMS OF THIS LICENSE BY CLICKING THE "AGREE/ACCEPT" BUTTON. IF YOU DO NOT AGREE TO THE TERMS OF THIS LICENSE, RETURN THE APPLE SOFTWARE TO THE PLACE WHERE YOU OBTAINED IT FOR A REFUND OR, IF THE SOFTWARE WAS ACCESSED ELECTRONICALLY, CLICK "DISAGREE/DECLINE". - -IMPORTANT NOTE: To the extent this software may be used to reproduce materials, it is licensed to you only for reproduction of materials you are authorized or legally permitted to reproduce. - -1. License. Any software, tools, utilities, sample code, documentation, fonts, API?s, header files and other materials accompanying this License, whether on disk, print or electronic documentation, in read only memory, or any other media, (collectively, the "Apple Software") are licensed, not sold, to you by Apple Computer, Inc. ("Apple") for use only under the terms of this License, and Apple reserves all rights not expressly granted to you. The rights granted herein are limited to Apple's and its licensors' intellectual property rights in the Apple Software and do not include any other patents or intellectual property rights. You own the media on which the Apple Software is recorded but Apple and/or Apple's licensor(s) retain ownership of the Apple Software itself. The Apple Software in this package and any copies, modifications and derivative works that this License authorizes you to make are subject to this License. - -2. Permitted Uses and Restrictions. You may use the Apple Software to develop application software that is compatible with, and runs only on Mac OS X and/or Windows platforms with QuickTime installed. Except for compiling header files and linking libraries as necessary to build your application software, you have no right to modify, incorporate into or include in combination with your own programs, license or otherwise redistribute any portion of the Apple Software. Your software application may not interfere with the functionality of QuickTime Player or the QuickTime Plug-in, including but not limited to file type or MIME type associations that are registered to QuickTime. You may make only as many internal use copies of the Apple Software as reasonably necessary to use the Apple Software as permitted in this paragraph and distribute such copies only to your employees whose job duties require them to so use the Apple Software. You must reproduce on each copy of the Apple Software or portion thereof, the Apple copyright notice and any other proprietary legends that were on the original copy of the Apple Software. Except as expressly permitted in this License, you may not decompile, reverse engineer, disassemble, modify, rent, lease, loan, sublicense, distribute or create derivative works based upon the Apple Software in whole or part. Your rights under this License will terminate automatically without notice from Apple if you fail to comply with any term(s) of this License. In addition, Apple reserves the right to terminate this License if a new version of Apple's operating system software or the Apple Software is released which is incompatible with the Apple Software. - -3. Disclaimer Of Warranty. The Apple Software may be "alpha", "beta", "development", pre-release, untested, and/or not fully tested and may contain errors that could cause failures or loss of data, be incomplete or contain inaccuracies. YOU EXPRESSLY ACKNOWLEDGE AND AGREE THAT USE OF THE APPLE SOFTWARE IS AT YOUR SOLE RISK AND THAT THE ENTIRE RISK AS TO SATISFACTORY QUALITY, PERFORMANCE, ACCURACY AND EFFORT IS WITH YOU. EXCEPT FOR THE LIMITED WARRANTY ON MEDIA SET FORTH ABOVE AND TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE APPLE SOFTWARE IS PROVIDED "AS IS", WITH ALL FAULTS AND WITHOUT WARRANTY OF ANY KIND, AND APPLE AND APPLE'S LICENSORS (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE PURPOSES OF SECTIONS 4 AND 5) HEREBY DISCLAIM ALL WARRANTIES AND CONDITIONS WITH RESPECT TO THE APPLE SOFTWARE, EITHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NON-INFRINGEMENT OF THIRD PARTY RIGHTS. APPLE DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE APPLE SOFTWARE, THAT THE FUNCTIONS CONTAINED IN THE APPLE SOFTWARE WILL MEET YOUR REQUIREMENTS, THAT THE OPERATION OF THE APPLE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT DEFECTS IN THE APPLE SOFTWARE WILL BE CORRECTED. NO ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SHOULD THE APPLE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE ENTIRE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES OR LIMITATIONS ON APPLICABLE STATUTORY RIGHTS OF A CONSUMER, SO THE ABOVE EXCLUSION AND LIMITATIONS MAY NOT APPLY TO YOU. - -4. Limitation Of Liability. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT SHALL APPLE BE LIABLE FOR PERSONAL INJURY, OR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES WHATSOEVER, INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, LOSS OF DATA, BUSINESS INTERRUPTION OR ANY OTHER COMMERCIAL DAMAGES OR LOSSES, ARISING OUT OF OR RELATED TO YOUR USE OR INABILITY TO USE THE APPLE SOFTWARE, HOWEVER CAUSED, REGARDLESS OF THE THEORY OF LIABILITY (CONTRACT, TORT OR OTHERWISE) AND EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY FOR PERSONAL INJURY, OR OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY TO YOU. In no event shall Apple's total liability to you for all damages (other than as may be required by applicable law in cases involving personal injury) exceed the amount of fifty dollars ($50.00). The foregoing limitations will apply even if the above stated remedy fails of its essential purpose. - -5. Export Control. You may not use or otherwise export or reexport the Apple Product except as authorized by United States law and the laws of the jurisdiction in which the Apple Product was obtained. In particular, but without limitation, the Apple Product may not be exported or re-exported (a) into any U.S. embargoed countries or (b) to anyone on the U.S. Treasury Department's list of Specially Designated Nationals or the U.S. Department of Commerce Denied Person?s List or Entity List. By using the Apple Product, you represent and warrant that you are not located in any such country or on any such list. - -6. Government End Users. The Apple Software and related documentation are "Commercial Items", as that term is defined at 48 C.F.R. ?2.101, consisting of "Commercial Computer Software" and "Commercial Computer Software Documentation", as such terms are used in 48 C.F.R. ?12.212 or 48 C.F.R. ?227.7202, as applicable. Consistent with 48 C.F.R. ?12.212 or 48 C.F.R. ?227.7202-1through 227.7202-4, as applicable, the Commercial Computer Software and Commercial Computer Software Documentation are being licensed to U.S. Government end users (a) only as Commercial Items and (b) with only those rights as are granted to all other end users pursuant to the terms and conditions herein. Unpublished-rights reserved under the copyright laws of the United States. - -7. Controlling Law and Severability. This License will be governed by and construed in accordance with the laws of the State of California, as applied to agreements entered into and to be performed entirely within California between California residents. This License shall not be governed by the United Nations Convention on Contracts for the International Sale of Goods, the application of which is expressly excluded. If for any reason a court of competent jurisdiction finds any provision, or portion thereof, to be unenforceable, the remainder of this License shall continue in full force and effect. - -8. Complete Agreement. This License constitutes the entire agreement between the parties with respect to the use of the Apple Software licensed hereunder and supersedes all prior or contemporaneous understandings regarding such subject matter. No amendment to or modification of this License will be binding unless in writing and signed by Apple. Any translation of this License is done for local requirements and in the event of a dispute between the English and any non-English versions, the English version of this License shall govern. - -EA0300 - - - sleepycat - - url - http://opensource.org/licenses/sleepycat.php - - smartheap - - text - on file - - - things - - - vivox - - text - on file - - xmlrpc-epi - - url - http://xmlrpc-epi.sourceforge.net/main.php?t=license - - zlib - - url - http://www.gzip.org/zlib/zlib_license.html - - - - -- cgit v1.2.3 From 90d41bd746eda43f7bb7acdf3a2066e3ab948a3e Mon Sep 17 00:00:00 2001 From: Leyla Farazha Date: Mon, 16 May 2011 15:17:27 -0700 Subject: EXP-819 Turning off Voice Chat setting in Basic mode reverts changes made in Sound Device selection and turning setting back on results in drop downs not being populated --- indra/newview/llfloatersounddevices.cpp | 3 +++ indra/newview/llpanelvoicedevicesettings.cpp | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/indra/newview/llfloatersounddevices.cpp b/indra/newview/llfloatersounddevices.cpp index 9fe7c7f9dd..e692f1735a 100644 --- a/indra/newview/llfloatersounddevices.cpp +++ b/indra/newview/llfloatersounddevices.cpp @@ -68,6 +68,9 @@ BOOL LLFloaterSoundDevices::postBuild() if (panel) { panel->setUseTuningMode(false); + getChild("voice_input_device")->setCommitCallback(boost::bind(&LLPanelVoiceDeviceSettings::apply, panel)); + getChild("voice_output_device")->setCommitCallback(boost::bind(&LLPanelVoiceDeviceSettings::apply, panel)); + getChild("mic_volume_slider")->setCommitCallback(boost::bind(&LLPanelVoiceDeviceSettings::apply, panel)); } return TRUE; } diff --git a/indra/newview/llpanelvoicedevicesettings.cpp b/indra/newview/llpanelvoicedevicesettings.cpp index dc87bd0077..4a80bbbe5e 100644 --- a/indra/newview/llpanelvoicedevicesettings.cpp +++ b/indra/newview/llpanelvoicedevicesettings.cpp @@ -191,7 +191,21 @@ void LLPanelVoiceDeviceSettings::refresh() mCtrlInputDevices = getChild("voice_input_device"); mCtrlOutputDevices = getChild("voice_output_device"); - if(!LLVoiceClient::getInstance()->deviceSettingsAvailable()) + bool device_settings_available = LLVoiceClient::getInstance()->deviceSettingsAvailable(); + + if (mCtrlInputDevices) + { + mCtrlInputDevices->setEnabled(device_settings_available); + } + + if (mCtrlOutputDevices) + { + mCtrlOutputDevices->setEnabled(device_settings_available); + } + + getChild("mic_volume_slider")->setEnabled(device_settings_available); + + if(!device_settings_available) { // The combo boxes are disabled, since we can't get the device settings from the daemon just now. // Put the currently set default (ONLY) in the box, and select it. @@ -207,6 +221,7 @@ void LLPanelVoiceDeviceSettings::refresh() mCtrlOutputDevices->add( mOutputDevice, ADD_BOTTOM ); mCtrlOutputDevices->setSimple(mOutputDevice); } + mDevicesUpdated = FALSE; } else if (!mDevicesUpdated) { -- cgit v1.2.3 From d2c697832f707ebcc102b489b83bdf6ed1760d93 Mon Sep 17 00:00:00 2001 From: callum Date: Tue, 17 May 2011 09:31:43 -0700 Subject: Point to updated (working) builds of LLQtWebKit. Windows one was missing debug libs/dlls Mac one was missing updated exports. Linux one included for completeness. --- autobuild.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index ba0eb75f16..7044cc27c8 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1062,9 +1062,9 @@ archive hash - 1aec55e90d510ffa3beb83c427af8312 + f13dd42b97d11b138625d5d08c141f63 url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/229944/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20110513.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/230056/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20110516.tar.bz name darwin @@ -1074,9 +1074,9 @@ archive hash - 834215a2a004efb983e318d9c458d112 + 9f4d1203d2138398d3b17b78021ed536 url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/229944/arch/Linux/installer/llqtwebkit-4.7.1-linux-20110513.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/230056/arch/Linux/installer/llqtwebkit-4.7.1-linux-20110517.tar.bz2 name linux @@ -1086,9 +1086,9 @@ archive hash - 4442288be66754063f7dbc53b9b4a9a9 + 2cacfcffe0e019fd22d6efe57840775f url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/229944/arch/CYGWIN/installer/llqtwebkit-4.7.1-windows-20110513.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/230056/arch/CYGWIN/installer/llqtwebkit-4.7.1-windows-20110516.tar.bz2 name windows -- cgit v1.2.3 From 465072626e7ad2aa33b3cc48f1a161a0023c5483 Mon Sep 17 00:00:00 2001 From: callum Date: Tue, 17 May 2011 10:05:49 -0700 Subject: Typo in Mac/Darwin LLQtWebkit archive name --- autobuild.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autobuild.xml b/autobuild.xml index 7044cc27c8..e13b00b086 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1064,7 +1064,7 @@ hash f13dd42b97d11b138625d5d08c141f63 url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/230056/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20110516.tar.bz + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/230056/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20110516.tar.bz2 name darwin -- cgit v1.2.3 From 42654e759e4c1971bd2f5ea9968190a19c3956f0 Mon Sep 17 00:00:00 2001 From: callum Date: Tue, 17 May 2011 17:47:06 -0700 Subject: Replace older (but working) reference to version of LLQtWebKit for Linux --- autobuild.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index e13b00b086..b84a2c848b 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1074,9 +1074,9 @@ archive hash - 9f4d1203d2138398d3b17b78021ed536 + c05a33ee8b6f253b5a744596dfc3707d url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/230056/arch/Linux/installer/llqtwebkit-4.7.1-linux-20110517.tar.bz2 + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/llqtwebkit-linux-qt4.6-20101013.tar.bz2 name linux -- cgit v1.2.3 From e5e98a597d6bad6d2ccbe5a5a0bee45f8e66eb0b Mon Sep 17 00:00:00 2001 From: callum Date: Wed, 18 May 2011 09:56:02 -0700 Subject: Reverted Linux LLQtWebKit to older version which triggered warnings here that are treated as errors. --- indra/media_plugins/webkit/media_plugin_webkit.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index b22dbc6604..bdfbde8494 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -1170,50 +1170,50 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) else if(message_name == "js_expose_object") { - bool expose_object = message_in.getValueBoolean( "expose" ); #if LLQTWEBKIT_API_VERSION >= 9 + bool expose_object = message_in.getValueBoolean( "expose" ); LLQtWebKit::getInstance()->setExposeObject( expose_object ); #endif } else if(message_name == "js_values_valid") { - bool valid = message_in.getValueBoolean( "valid" ); #if LLQTWEBKIT_API_VERSION >= 9 + bool valid = message_in.getValueBoolean( "valid" ); LLQtWebKit::getInstance()->setValuesValid( valid ); #endif } else if(message_name == "js_agent_location") { +#if LLQTWEBKIT_API_VERSION >= 9 F32 x = message_in.getValueReal("x"); F32 y = message_in.getValueReal("y"); F32 z = message_in.getValueReal("z"); -#if LLQTWEBKIT_API_VERSION >= 9 LLQtWebKit::getInstance()->setAgentLocation( x, y, z ); #endif } else if(message_name == "js_agent_language") { - const std::string& language = message_in.getValue("language"); #if LLQTWEBKIT_API_VERSION >= 9 + const std::string& language = message_in.getValue("language"); LLQtWebKit::getInstance()->setAgentLanguage( language ); #endif } else if(message_name == "js_agent_region") { - const std::string& region = message_in.getValue("region"); #if LLQTWEBKIT_API_VERSION >= 9 + const std::string& region = message_in.getValue("region"); LLQtWebKit::getInstance()->setAgentRegion( region ); #endif } else if(message_name == "js_agent_maturity") { - const std::string& maturity = message_in.getValue("maturity"); #if LLQTWEBKIT_API_VERSION >= 9 + const std::string& maturity = message_in.getValue("maturity"); LLQtWebKit::getInstance()->setAgentMaturity( maturity ); #endif } -- cgit v1.2.3 From 1afbbba03d0c93ad7897f336bb070bdf0bf1ecda Mon Sep 17 00:00:00 2001 From: callum Date: Mon, 23 May 2011 17:12:08 -0700 Subject: EXP-826 FIX Help -> About Secondlife Info is corrupted. --- indra/llkdu/llimagej2ckdu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index 39ae09650e..c156ed0cef 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -73,7 +73,7 @@ void set_default_colour_weights(kdu_params *siz); const char* engineInfoLLImageJ2CKDU() { - std::string version = llformat("KDU %s", KDU_CORE_VERSION); + static std::string version = llformat("KDU %s", KDU_CORE_VERSION); return version.c_str(); } -- cgit v1.2.3 From e9f8a5441b0d737133a833cd240709962add56a5 Mon Sep 17 00:00:00 2001 From: callum Date: Wed, 25 May 2011 08:10:04 -0700 Subject: Added support for pushing agent global location on grid and agent orientation out to LLQtWebKit --- indra/llplugin/llpluginclassmedia.cpp | 27 ++++++++++++++++++++++ indra/llplugin/llpluginclassmedia.h | 2 ++ indra/media_plugins/webkit/media_plugin_webkit.cpp | 16 ++++++++++--- indra/newview/llviewermedia.cpp | 13 +++++++++++ 4 files changed, 55 insertions(+), 3 deletions(-) diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index cc8fe53c3b..8f161201f4 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -474,6 +474,33 @@ void LLPluginClassMedia::jsAgentLocationEvent( double x, double y, double z ) sendMessage( message ); } +void LLPluginClassMedia::jsAgentGlobalLocationEvent( double x, double y, double z ) +{ + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_global_location"); + message.setValueReal( "x", x ); + message.setValueReal( "y", y ); + message.setValueReal( "z", z ); + sendMessage( message ); +} + +void LLPluginClassMedia::jsAgentOrientationEvent( double angle ) +{ + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_orientation"); + message.setValueReal( "angle", angle ); + + sendMessage( message ); +} + void LLPluginClassMedia::jsAgentLanguageEvent( const std::string& language ) { if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 015fb31252..c061390699 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -122,6 +122,8 @@ public: void jsExposeObjectEvent( bool expose ); void jsValuesValidEvent( bool valid ); void jsAgentLocationEvent( double x, double y, double z ); + void jsAgentGlobalLocationEvent( double x, double y, double z ); + void jsAgentOrientationEvent( double angle ); void jsAgentLanguageEvent( const std::string& language ); void jsAgentRegionEvent( const std::string& region_name ); void jsAgentMaturityEvent( const std::string& maturity ); diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index bdfbde8494..27f3c7260e 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -1194,11 +1194,21 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) #endif } else - if(message_name == "js_agent_language") + if(message_name == "js_agent_global_location") { #if LLQTWEBKIT_API_VERSION >= 9 - const std::string& language = message_in.getValue("language"); - LLQtWebKit::getInstance()->setAgentLanguage( language ); + F32 x = message_in.getValueReal("x"); + F32 y = message_in.getValueReal("y"); + F32 z = message_in.getValueReal("z"); + LLQtWebKit::getInstance()->setAgentGlobalLocation( x, y, z ); +#endif + } + else + if(message_name == "js_agent_orientation") + { +#if LLQTWEBKIT_API_VERSION >= 9 + F32 angle = message_in.getValueReal("angle"); + LLQtWebKit::getInstance()->setAgentOrientation( angle ); #endif } else diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 2b9f32f6f5..c88c07942e 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -2365,6 +2365,19 @@ void LLViewerMediaImpl::updateJavascriptObject() double z = agent_pos.mV[ VZ ]; mMediaSource->jsAgentLocationEvent( x, y, z ); + // current location within the grid + LLVector3d agent_pos_global = gAgent.getLastPositionGlobal(); + double global_x = agent_pos_global.mdV[ VX ]; + double global_y = agent_pos_global.mdV[ VY ]; + double global_z = agent_pos_global.mdV[ VZ ]; + mMediaSource->jsAgentGlobalLocationEvent( global_x, global_y, global_z ); + + // current agent orientation + double rotation = atan2( gAgent.getAtAxis().mV[VX], gAgent.getAtAxis().mV[VY] ); + double angle = rotation * RAD_TO_DEG; + if ( angle < 0.0f ) angle = 360.0f + angle; // TODO: has to be a better way to get orientation! + mMediaSource->jsAgentOrientationEvent( angle ); + // current region agent is in std::string region_name(""); LLViewerRegion* region = gAgent.getRegion(); -- cgit v1.2.3 From ae6ceb6193aa2070fbcafa79a8531af80cce1507 Mon Sep 17 00:00:00 2001 From: callum Date: Wed, 25 May 2011 10:19:00 -0700 Subject: Point to updated version of LLQtWebKit that supports local changes., --- autobuild.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index b84a2c848b..151f680e3e 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1062,9 +1062,9 @@ archive hash - f13dd42b97d11b138625d5d08c141f63 + c62b44436e1c4319e75e646512b1632c url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/230056/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20110516.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/230953/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20110525.tar.bz2 name darwin @@ -1086,9 +1086,9 @@ archive hash - 2cacfcffe0e019fd22d6efe57840775f + 3cc6ab358f7f19cbdee7774d222380f3 url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/230056/arch/CYGWIN/installer/llqtwebkit-4.7.1-windows-20110516.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/230953/arch/CYGWIN/installer/llqtwebkit-4.7.1-windows-20110525.tar.bz2 name windows -- cgit v1.2.3 From e6ecf1ee7ea73139fa134fb6bc6e0088009c9f7e Mon Sep 17 00:00:00 2001 From: callum Date: Wed, 25 May 2011 18:00:46 -0700 Subject: Replaced my test page with more generic URL for Web floater test at login page --- indra/newview/skins/default/xui/en/menu_login.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml index 32c1d7083a..4c4ff3e5c4 100644 --- a/indra/newview/skins/default/xui/en/menu_login.xml +++ b/indra/newview/skins/default/xui/en/menu_login.xml @@ -187,7 +187,7 @@ name="Web Content Floater Debug Test"> + parameter="http://google.com"/> Date: Wed, 25 May 2011 18:10:58 -0700 Subject: EXP-829 FIX Text Box Alignment bug EXP-755 FIX [PUBLIC] 'Search' and 'World Map' links in Sidebar are unclickable fixed issues with UI scaling and text layout as well as incorrect text editor rect transforms reviewed by Callum --- indra/llrender/llfontgl.cpp | 2 +- indra/llui/lltextbase.cpp | 119 ++++++++++++++++++++++---------------------- 2 files changed, 61 insertions(+), 60 deletions(-) diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 13008292f6..62aa49d235 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -555,7 +555,7 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch BOOL in_word = FALSE; // avoid S32 overflow when max_pixels == S32_MAX by staying in floating point - F32 scaled_max_pixels = ceil(max_pixels * sScaleX); + F32 scaled_max_pixels = max_pixels * sScaleX; F32 width_padding = 0.f; LLFontGlyphInfo* next_glyph = NULL; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index fd7bb699f8..c4430593ad 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -280,7 +280,7 @@ bool LLTextBase::truncate() if (getLength() >= S32(mMaxTextByteLength / 4)) { // Have to check actual byte size - LLWString text(getWText()); + LLWString text(getWText()); S32 utf8_byte_size = wstring_utf8_length(text); if ( utf8_byte_size > mMaxTextByteLength ) { @@ -547,8 +547,7 @@ void LLTextBase::drawText() } LLRect text_rect(line.mRect); - text_rect.mRight = llmin(mDocumentView->getRect().getWidth(), text_rect.mRight); // clamp right edge to document extents - text_rect.translate(mVisibleTextRect.mLeft, mVisibleTextRect.mBottom); // translate into display region of text widget + text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position // draw a single line of text @@ -655,7 +654,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s } text.insert(pos, wstr); - getViewModel()->setDisplay(text); + getViewModel()->setDisplay(text); if ( truncate() ) { @@ -670,7 +669,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length) { - LLWString text(getWText()); + LLWString text(getWText()); segment_set_t::iterator seg_iter = getSegIterContaining(pos); while(seg_iter != mSegments.end()) { @@ -717,7 +716,7 @@ S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length) } text.erase(pos, length); - getViewModel()->setDisplay(text); + getViewModel()->setDisplay(text); // recreate default segment in case we erased everything createDefaultSegment(); @@ -734,9 +733,9 @@ S32 LLTextBase::overwriteCharNoUndo(S32 pos, llwchar wc) { return 0; } - LLWString text(getWText()); + LLWString text(getWText()); text[pos] = wc; - getViewModel()->setDisplay(text); + getViewModel()->setDisplay(text); onValueChange(pos, pos + 1); needsReflow(pos); @@ -857,7 +856,7 @@ BOOL LLTextBase::handleMouseUp(S32 x, S32 y, MASK mask) // Did we just click on a link? if (mURLClickSignal && cur_segment->getStyle() - && cur_segment->getStyle()->isLink()) + && cur_segment->getStyle()->isLink()) { // *TODO: send URL here? (*mURLClickSignal)(this, LLSD() ); @@ -1035,27 +1034,27 @@ void LLTextBase::draw() gl_rect_2d(text_rect, bg_color % alpha, TRUE); } - bool should_clip = mClip || mScroller != NULL; - { LLLocalClipRect clip(text_rect, should_clip); + bool should_clip = mClip || mScroller != NULL; + { LLLocalClipRect clip(text_rect, should_clip); - // draw document view - if (mScroller) + // draw document view + if (mScroller) + { + drawChild(mScroller); + } + else { - drawChild(mScroller); - } - else - { - drawChild(mDocumentView); - } + drawChild(mDocumentView); + } drawSelectionBackground(); drawText(); drawCursor(); } - mDocumentView->setVisible(FALSE); - LLUICtrl::draw(); - mDocumentView->setVisible(TRUE); + mDocumentView->setVisible(FALSE); + LLUICtrl::draw(); + mDocumentView->setVisible(TRUE); } @@ -1119,8 +1118,7 @@ void LLTextBase::updateScrollFromCursor() // scroll so that the cursor is at the top of the page LLRect scroller_doc_window = getVisibleDocumentRect(); - LLRect cursor_rect_doc = getLocalRectFromDocIndex(mCursorPos); - cursor_rect_doc.translate(scroller_doc_window.mLeft, scroller_doc_window.mBottom); + LLRect cursor_rect_doc = getDocRectFromDocIndex(mCursorPos); mScroller->scrollToShowRect(cursor_rect_doc, LLRect(0, scroller_doc_window.getHeight() - 5, scroller_doc_window.getWidth(), 5)); } @@ -1366,9 +1364,9 @@ S32 LLTextBase::getLineStart( S32 line ) const { S32 num_lines = getLineCount(); if (num_lines == 0) - { + { return 0; - } + } line = llclamp(line, 0, num_lines-1); return mLineInfoList[line].mDocIndexStart; @@ -1378,9 +1376,9 @@ S32 LLTextBase::getLineEnd( S32 line ) const { S32 num_lines = getLineCount(); if (num_lines == 0) - { + { return 0; - } + } line = llclamp(line, 0, num_lines-1); return mLineInfoList[line].mDocIndexEnd; @@ -1656,7 +1654,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para LLUrlMatch match; std::string text = new_text; while ( LLUrlRegistry::instance().findUrl(text, match, - boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3)) ) + boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3)) ) { start = match.getStart(); end = match.getEnd()+1; @@ -1950,7 +1948,7 @@ void LLTextBase::setWText(const LLWString& text) const LLWString& LLTextBase::getWText() const { - return getViewModel()->getDisplay(); + return getViewModel()->getDisplay(); } // If round is true, if the position is on the right half of a character, the cursor @@ -1961,9 +1959,12 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round, { // Figure out which line we're nearest to. LLRect visible_region = getVisibleDocumentRect(); + LLRect doc_rect = mDocumentView->getRect(); + + S32 doc_y = local_y - doc_rect.mBottom; // binary search for line that starts before local_y - line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), local_y - mVisibleTextRect.mBottom + visible_region.mBottom, compare_bottom()); + line_list_t::const_iterator line_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), doc_y, compare_bottom()); if (line_iter == mLineInfoList.end()) { @@ -1971,7 +1972,7 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round, } S32 pos = getLength(); - S32 start_x = mVisibleTextRect.mLeft + line_iter->mRect.mLeft - visible_region.mLeft; + S32 start_x = line_iter->mRect.mLeft + doc_rect.mLeft; segment_set_t::iterator line_seg_iter; S32 line_seg_offset; @@ -1993,7 +1994,7 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round, } // if we've reached a line of text *below* the mouse cursor, doc index is first character on that line - if (hit_past_end_of_line && local_y - mVisibleTextRect.mBottom + visible_region.mBottom > line_iter->mRect.mTop) + if (hit_past_end_of_line && doc_y > line_iter->mRect.mTop) { pos = segment_line_start; break; @@ -2462,7 +2463,7 @@ LLRect LLTextBase::getVisibleDocumentRect() const LLRect doc_rect = mDocumentView->getLocalRect(); doc_rect.mLeft -= mDocumentView->getRect().mLeft; // adjust for height of text above widget baseline - doc_rect.mBottom = llmin(0, doc_rect.getHeight() - mVisibleTextRect.getHeight()); + doc_rect.mBottom = doc_rect.getHeight() - mVisibleTextRect.getHeight(); return doc_rect; } } @@ -2576,21 +2577,21 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele LLColor4 color = (mEditor.getReadOnly() ? mStyle->getReadOnlyColor() : mStyle->getColor()) % alpha; - if( selection_start > seg_start ) + if( selection_start > seg_start ) { // Draw normally S32 start = seg_start; S32 end = llmin( selection_start, seg_end ); S32 length = end - start; font->render(text, start, - rect, - color, - LLFontGL::LEFT, mEditor.mVAlign, - LLFontGL::NORMAL, - mStyle->getShadowType(), - length, - &right_x, - mEditor.getUseEllipses()); + rect, + color, + LLFontGL::LEFT, mEditor.mVAlign, + LLFontGL::NORMAL, + mStyle->getShadowType(), + length, + &right_x, + mEditor.getUseEllipses()); } rect.mLeft = (S32)ceil(right_x); @@ -2602,14 +2603,14 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele S32 length = end - start; font->render(text, start, - rect, - mStyle->getSelectedColor().get(), - LLFontGL::LEFT, mEditor.mVAlign, - LLFontGL::NORMAL, - LLFontGL::NO_SHADOW, - length, - &right_x, - mEditor.getUseEllipses()); + rect, + mStyle->getSelectedColor().get(), + LLFontGL::LEFT, mEditor.mVAlign, + LLFontGL::NORMAL, + LLFontGL::NO_SHADOW, + length, + &right_x, + mEditor.getUseEllipses()); } rect.mLeft = (S32)ceil(right_x); if( selection_end < seg_end ) @@ -2619,14 +2620,14 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele S32 end = seg_end; S32 length = end - start; font->render(text, start, - rect, - color, - LLFontGL::LEFT, mEditor.mVAlign, - LLFontGL::NORMAL, - mStyle->getShadowType(), - length, - &right_x, - mEditor.getUseEllipses()); + rect, + color, + LLFontGL::LEFT, mEditor.mVAlign, + LLFontGL::NORMAL, + mStyle->getShadowType(), + length, + &right_x, + mEditor.getUseEllipses()); } return right_x; } -- cgit v1.2.3 From 4cd295badd5fa51c6b9d5cb52726e48a57ba3bec Mon Sep 17 00:00:00 2001 From: callum Date: Thu, 26 May 2011 12:42:19 -0700 Subject: Updated links to new version of LLQtWebKit package for Mac with valid exports file. Addition of Windows version for completenes. No changes. --- autobuild.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 09ebee3720..8851e003ea 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1206,9 +1206,9 @@ archive hash - c62b44436e1c4319e75e646512b1632c + 82798d0da3ac3d97c91517a575d9ea1c url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/230953/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20110525.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/231093/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20110526.tar.bz2 name darwin @@ -1230,9 +1230,9 @@ archive hash - 3cc6ab358f7f19cbdee7774d222380f3 + f0708d18943a05013493f69ab7dc6429 url - http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/230953/arch/CYGWIN/installer/llqtwebkit-4.7.1-windows-20110525.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/231093/arch/CYGWIN/installer/llqtwebkit-4.7.1-windows-20110526.tar.bz2 name windows -- cgit v1.2.3 From ecd0cc3a5a411ea050e54044bcea0dfb695b000b Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 26 May 2011 17:25:26 -0400 Subject: EXP-772: If URIs returned by SRV fail, fall back on original URI. --- indra/viewer_components/login/lllogin.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp index 651d803e0d..d480b63094 100644 --- a/indra/viewer_components/login/lllogin.cpp +++ b/indra/viewer_components/login/lllogin.cpp @@ -178,6 +178,8 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_para request["uri"] = uri; request["reply"] = replyPump.getName(); rewrittenURIs = postAndWait(self, request, srv_pump_name, filter); + // EXP-772: If rewrittenURIs fail, try original URI as a fallback. + rewrittenURIs.append(uri); } // we no longer need the filter LLEventPump& xmlrpcPump(LLEventPumps::instance().obtain("LLXMLRPCTransaction")); -- cgit v1.2.3 From b530648dd4c5fbf9e566401b4262865047de2e4a Mon Sep 17 00:00:00 2001 From: Leslie Linden Date: Wed, 1 Jun 2011 11:46:53 -0700 Subject: EXP-869 FIX -- Mac viewer should build without requiring settings modifications Modified cmake GCC_VERSION from 4.2 to 4.0, our officially supported GCC version Reviewed by Richard --- indra/cmake/Variables.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index cfccd29def..4cbf7aa043 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -102,7 +102,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") # To support a different SDK update these Xcode settings: set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5) set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk) - set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "4.2") + set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "4.0") set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT dwarf-with-dsym) # NOTE: To attempt an i386/PPC Universal build, add this on the configure line: -- cgit v1.2.3