From 268ea7bd452e6fafc4b9a27372b4e053a827d614 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Sat, 4 Jun 2011 08:00:15 -0400 Subject: fix DOS line endings --- indra/llplugin/llpluginclassmedia.cpp | 2872 ++++----- indra/llplugin/llpluginclassmedia.h | 852 +-- indra/newview/llgesturelistener.cpp | 318 +- indra/newview/llgesturelistener.h | 104 +- indra/newview/llnearbychatbarlistener.cpp | 200 +- indra/newview/llnearbychatbarlistener.h | 100 +- .../skins/default/xui/de/floater_postcard.xml | 72 +- .../skins/default/xui/en/floater_model_preview.xml | 1094 ++-- .../skins/default/xui/en/floater_model_wizard.xml | 2078 +++---- .../newview/skins/default/xui/en/floater_tools.xml | 6388 ++++++++++---------- .../skins/default/xui/fr/floater_postcard.xml | 72 +- .../default/xui/pt/floater_preview_gesture.xml | 148 +- 12 files changed, 7149 insertions(+), 7149 deletions(-) diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 8f161201f4..9f666369d4 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -1,1436 +1,1436 @@ -/** - * @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::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() ) - { - 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; -} - +/** + * @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::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() ) + { + 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 c061390699..fea836aa68 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -1,426 +1,426 @@ -/** - * @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 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 ); - - // 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 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 ); + + // 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/newview/llgesturelistener.cpp b/indra/newview/llgesturelistener.cpp index 22b7d233c5..2fff506681 100644 --- a/indra/newview/llgesturelistener.cpp +++ b/indra/newview/llgesturelistener.cpp @@ -1,159 +1,159 @@ -/** - * @file llgesturelistener.cpp - * @author Dave Simmons - * @date 2011-03-28 - * @brief Implementation for LLGestureListener. - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, 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 "llgesturelistener.h" -#include "llgesturemgr.h" -#include "llmultigesture.h" - - -LLGestureListener::LLGestureListener() - : LLEventAPI("LLGesture", - "LLGesture listener interface to control gestures") -{ - add("getActiveGestures", - "Return information about the agent's available gestures [\"reply\"]:\n" - "[\"gestures\"]: a dictionary with UUID strings as keys\n" - " and the following dict values for each entry:\n" - " [\"name\"]: name of the gesture, may be empty\n" - " [\"trigger\"]: trigger string used to invoke via user chat, may be empty\n" - " [\"playing\"]: true or false indicating the playing state", - &LLGestureListener::getActiveGestures, - LLSDMap("reply", LLSD())); - add("isGesturePlaying", - "[\"id\"]: UUID of the gesture to query. Returns True or False in [\"playing\"] value of the result", - &LLGestureListener::isGesturePlaying); - add("startGesture", - "[\"id\"]: UUID of the gesture to start playing", - &LLGestureListener::startGesture); - add("stopGesture", - "[\"id\"]: UUID of the gesture to stop", - &LLGestureListener::stopGesture); -} - - -// "getActiveGestures" command -void LLGestureListener::getActiveGestures(const LLSD& event_data) const -{ - LLSD reply = LLSD::emptyMap(); - LLSD gesture_map = LLSD::emptyMap(); - - const LLGestureMgr::item_map_t& active_gestures = LLGestureMgr::instance().getActiveGestures(); - - // Scan active gesture map and get all the names - LLGestureMgr::item_map_t::const_iterator it; - for (it = active_gestures.begin(); it != active_gestures.end(); ++it) - { - LLMultiGesture* gesture = (*it).second; - if (gesture) - { // Add an entry to the result map with the LLUUID as key with a map containing data - LLSD info = LLSD::emptyMap(); - info["name"] = (LLSD::String) gesture->mName; - info["trigger"] = (LLSD::String) gesture->mTrigger; - info["playing"] = (LLSD::Boolean) gesture->mPlaying; - - gesture_map[(*it).first.asString()] = info; - } - } - - reply["gestures"] = gesture_map; - sendReply(reply, event_data); -} - - - -// "isGesturePlaying" command -void LLGestureListener::isGesturePlaying(const LLSD& event_data) const -{ - bool is_playing = false; - if (event_data.has("id")) - { - LLUUID gesture_id = event_data["id"].asUUID(); - if (gesture_id.notNull()) - { - is_playing = LLGestureMgr::instance().isGesturePlaying(gesture_id); - } - else - { - llwarns << "isGesturePlaying did not find a gesture object for " << gesture_id << llendl; - } - } - else - { - llwarns << "isGesturePlaying didn't have 'id' value passed in" << llendl; - } - - LLSD reply = LLSD::emptyMap(); - reply["playing"] = (LLSD::Boolean) is_playing; - sendReply(reply, event_data); -} - - -// "startGesture" command -void LLGestureListener::startGesture(LLSD const & event_data) const -{ - startOrStopGesture(event_data, true); -} - - -// "stopGesture" command -void LLGestureListener::stopGesture(LLSD const & event_data) const -{ - startOrStopGesture(event_data, false); -} - - -// Real code for "startGesture" or "stopGesture" -void LLGestureListener::startOrStopGesture(LLSD const & event_data, bool start) const -{ - if (event_data.has("id")) - { - LLUUID gesture_id = event_data["id"].asUUID(); - if (gesture_id.notNull()) - { - if (start) - { - LLGestureMgr::instance().playGesture(gesture_id); - } - else - { - LLGestureMgr::instance().stopGesture(gesture_id); - } - } - else - { - llwarns << "startOrStopGesture did not find a gesture object for " << gesture_id << llendl; - } - } - else - { - llwarns << "startOrStopGesture didn't have 'id' value passed in" << llendl; - } -} - +/** + * @file llgesturelistener.cpp + * @author Dave Simmons + * @date 2011-03-28 + * @brief Implementation for LLGestureListener. + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, 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 "llgesturelistener.h" +#include "llgesturemgr.h" +#include "llmultigesture.h" + + +LLGestureListener::LLGestureListener() + : LLEventAPI("LLGesture", + "LLGesture listener interface to control gestures") +{ + add("getActiveGestures", + "Return information about the agent's available gestures [\"reply\"]:\n" + "[\"gestures\"]: a dictionary with UUID strings as keys\n" + " and the following dict values for each entry:\n" + " [\"name\"]: name of the gesture, may be empty\n" + " [\"trigger\"]: trigger string used to invoke via user chat, may be empty\n" + " [\"playing\"]: true or false indicating the playing state", + &LLGestureListener::getActiveGestures, + LLSDMap("reply", LLSD())); + add("isGesturePlaying", + "[\"id\"]: UUID of the gesture to query. Returns True or False in [\"playing\"] value of the result", + &LLGestureListener::isGesturePlaying); + add("startGesture", + "[\"id\"]: UUID of the gesture to start playing", + &LLGestureListener::startGesture); + add("stopGesture", + "[\"id\"]: UUID of the gesture to stop", + &LLGestureListener::stopGesture); +} + + +// "getActiveGestures" command +void LLGestureListener::getActiveGestures(const LLSD& event_data) const +{ + LLSD reply = LLSD::emptyMap(); + LLSD gesture_map = LLSD::emptyMap(); + + const LLGestureMgr::item_map_t& active_gestures = LLGestureMgr::instance().getActiveGestures(); + + // Scan active gesture map and get all the names + LLGestureMgr::item_map_t::const_iterator it; + for (it = active_gestures.begin(); it != active_gestures.end(); ++it) + { + LLMultiGesture* gesture = (*it).second; + if (gesture) + { // Add an entry to the result map with the LLUUID as key with a map containing data + LLSD info = LLSD::emptyMap(); + info["name"] = (LLSD::String) gesture->mName; + info["trigger"] = (LLSD::String) gesture->mTrigger; + info["playing"] = (LLSD::Boolean) gesture->mPlaying; + + gesture_map[(*it).first.asString()] = info; + } + } + + reply["gestures"] = gesture_map; + sendReply(reply, event_data); +} + + + +// "isGesturePlaying" command +void LLGestureListener::isGesturePlaying(const LLSD& event_data) const +{ + bool is_playing = false; + if (event_data.has("id")) + { + LLUUID gesture_id = event_data["id"].asUUID(); + if (gesture_id.notNull()) + { + is_playing = LLGestureMgr::instance().isGesturePlaying(gesture_id); + } + else + { + llwarns << "isGesturePlaying did not find a gesture object for " << gesture_id << llendl; + } + } + else + { + llwarns << "isGesturePlaying didn't have 'id' value passed in" << llendl; + } + + LLSD reply = LLSD::emptyMap(); + reply["playing"] = (LLSD::Boolean) is_playing; + sendReply(reply, event_data); +} + + +// "startGesture" command +void LLGestureListener::startGesture(LLSD const & event_data) const +{ + startOrStopGesture(event_data, true); +} + + +// "stopGesture" command +void LLGestureListener::stopGesture(LLSD const & event_data) const +{ + startOrStopGesture(event_data, false); +} + + +// Real code for "startGesture" or "stopGesture" +void LLGestureListener::startOrStopGesture(LLSD const & event_data, bool start) const +{ + if (event_data.has("id")) + { + LLUUID gesture_id = event_data["id"].asUUID(); + if (gesture_id.notNull()) + { + if (start) + { + LLGestureMgr::instance().playGesture(gesture_id); + } + else + { + LLGestureMgr::instance().stopGesture(gesture_id); + } + } + else + { + llwarns << "startOrStopGesture did not find a gesture object for " << gesture_id << llendl; + } + } + else + { + llwarns << "startOrStopGesture didn't have 'id' value passed in" << llendl; + } +} + diff --git a/indra/newview/llgesturelistener.h b/indra/newview/llgesturelistener.h index 326881ac2b..6f59698ed1 100644 --- a/indra/newview/llgesturelistener.h +++ b/indra/newview/llgesturelistener.h @@ -1,52 +1,52 @@ -/** - * @file llgesturelistener.h - * @author Dave Simmons - * @date 2011-03-15 - * @brief Class definition for LLGestureListener. - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, 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$ - */ - - -#ifndef LL_LLGESTURELISTENER_H -#define LL_LLGESTURELISTENER_H - -#include "lleventapi.h" - -class LLSD; - -class LLGestureListener : public LLEventAPI -{ -public: - LLGestureListener(); - -private: - void getActiveGestures(LLSD const & gesture_data) const; - void isGesturePlaying(LLSD const & gesture_data) const; - void startGesture(LLSD const & gesture_data) const; - void stopGesture(LLSD const & gesture_data) const; - - void startOrStopGesture(LLSD const & event_data, bool start) const; -}; - -#endif // LL_LLGESTURELISTENER_H - +/** + * @file llgesturelistener.h + * @author Dave Simmons + * @date 2011-03-15 + * @brief Class definition for LLGestureListener. + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, 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$ + */ + + +#ifndef LL_LLGESTURELISTENER_H +#define LL_LLGESTURELISTENER_H + +#include "lleventapi.h" + +class LLSD; + +class LLGestureListener : public LLEventAPI +{ +public: + LLGestureListener(); + +private: + void getActiveGestures(LLSD const & gesture_data) const; + void isGesturePlaying(LLSD const & gesture_data) const; + void startGesture(LLSD const & gesture_data) const; + void stopGesture(LLSD const & gesture_data) const; + + void startOrStopGesture(LLSD const & event_data, bool start) const; +}; + +#endif // LL_LLGESTURELISTENER_H + diff --git a/indra/newview/llnearbychatbarlistener.cpp b/indra/newview/llnearbychatbarlistener.cpp index 0d64eaed47..a63e1fb76e 100644 --- a/indra/newview/llnearbychatbarlistener.cpp +++ b/indra/newview/llnearbychatbarlistener.cpp @@ -1,100 +1,100 @@ -/** - * @file llnearbychatbarlistener.cpp - * @author Dave Simmons - * @date 2011-03-15 - * @brief Implementation for LLNearbyChatBarListener. - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, 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 "llnearbychatbarlistener.h" -#include "llnearbychatbar.h" - -#include "llagent.h" -#include "llchat.h" - - - -LLNearbyChatBarListener::LLNearbyChatBarListener(LLNearbyChatBar & chatbar) - : LLEventAPI("LLChatBar", - "LLChatBar listener to (e.g.) sendChat, etc."), - mChatbar(chatbar) -{ - add("sendChat", - "Send chat to the simulator:\n" - "[\"message\"] chat message text [required]\n" - "[\"channel\"] chat channel number [default = 0]\n" - "[\"type\"] chat type \"whisper\", \"normal\", \"shout\" [default = \"normal\"]", - &LLNearbyChatBarListener::sendChat); -} - - -// "sendChat" command -void LLNearbyChatBarListener::sendChat(LLSD const & chat_data) const -{ - // Extract the data - std::string chat_text = chat_data["message"].asString(); - - S32 channel = 0; - if (chat_data.has("channel")) - { - channel = chat_data["channel"].asInteger(); - if (channel < 0 || channel >= CHAT_CHANNEL_DEBUG) - { // Use 0 up to (but not including) CHAT_CHANNEL_DEBUG - channel = 0; - } - } - - EChatType type_o_chat = CHAT_TYPE_NORMAL; - if (chat_data.has("type")) - { - std::string type_string = chat_data["type"].asString(); - if (type_string == "whisper") - { - type_o_chat = CHAT_TYPE_WHISPER; - } - else if (type_string == "shout") - { - type_o_chat = CHAT_TYPE_SHOUT; - } - } - - // Have to prepend /42 style channel numbers - std::string chat_to_send; - if (channel == 0) - { - chat_to_send = chat_text; - } - else - { - chat_to_send += "/"; - chat_to_send += chat_data["channel"].asString(); - chat_to_send += " "; - chat_to_send += chat_text; - } - - // Send it as if it was typed in - mChatbar.sendChatFromViewer(chat_to_send, type_o_chat, (BOOL)(channel == 0)); -} - +/** + * @file llnearbychatbarlistener.cpp + * @author Dave Simmons + * @date 2011-03-15 + * @brief Implementation for LLNearbyChatBarListener. + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, 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 "llnearbychatbarlistener.h" +#include "llnearbychatbar.h" + +#include "llagent.h" +#include "llchat.h" + + + +LLNearbyChatBarListener::LLNearbyChatBarListener(LLNearbyChatBar & chatbar) + : LLEventAPI("LLChatBar", + "LLChatBar listener to (e.g.) sendChat, etc."), + mChatbar(chatbar) +{ + add("sendChat", + "Send chat to the simulator:\n" + "[\"message\"] chat message text [required]\n" + "[\"channel\"] chat channel number [default = 0]\n" + "[\"type\"] chat type \"whisper\", \"normal\", \"shout\" [default = \"normal\"]", + &LLNearbyChatBarListener::sendChat); +} + + +// "sendChat" command +void LLNearbyChatBarListener::sendChat(LLSD const & chat_data) const +{ + // Extract the data + std::string chat_text = chat_data["message"].asString(); + + S32 channel = 0; + if (chat_data.has("channel")) + { + channel = chat_data["channel"].asInteger(); + if (channel < 0 || channel >= CHAT_CHANNEL_DEBUG) + { // Use 0 up to (but not including) CHAT_CHANNEL_DEBUG + channel = 0; + } + } + + EChatType type_o_chat = CHAT_TYPE_NORMAL; + if (chat_data.has("type")) + { + std::string type_string = chat_data["type"].asString(); + if (type_string == "whisper") + { + type_o_chat = CHAT_TYPE_WHISPER; + } + else if (type_string == "shout") + { + type_o_chat = CHAT_TYPE_SHOUT; + } + } + + // Have to prepend /42 style channel numbers + std::string chat_to_send; + if (channel == 0) + { + chat_to_send = chat_text; + } + else + { + chat_to_send += "/"; + chat_to_send += chat_data["channel"].asString(); + chat_to_send += " "; + chat_to_send += chat_text; + } + + // Send it as if it was typed in + mChatbar.sendChatFromViewer(chat_to_send, type_o_chat, (BOOL)(channel == 0)); +} + diff --git a/indra/newview/llnearbychatbarlistener.h b/indra/newview/llnearbychatbarlistener.h index 13e4e5990c..9af9bc1f7b 100644 --- a/indra/newview/llnearbychatbarlistener.h +++ b/indra/newview/llnearbychatbarlistener.h @@ -1,50 +1,50 @@ -/** - * @file llnearbychatbarlistener.h - * @author Dave Simmons - * @date 2011-03-15 - * @brief Class definition for LLNearbyChatBarListener. - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, 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$ - */ - - -#ifndef LL_LLNEARBYCHATBARLISTENER_H -#define LL_LLNEARBYCHATBARLISTENER_H - -#include "lleventapi.h" - -class LLSD; -class LLNearbyChatBar; - -class LLNearbyChatBarListener : public LLEventAPI -{ -public: - LLNearbyChatBarListener(LLNearbyChatBar & chatbar); - -private: - void sendChat(LLSD const & chat_data) const; - - LLNearbyChatBar & mChatbar; -}; - -#endif // LL_LLNEARBYCHATBARLISTENER_H - +/** + * @file llnearbychatbarlistener.h + * @author Dave Simmons + * @date 2011-03-15 + * @brief Class definition for LLNearbyChatBarListener. + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, 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$ + */ + + +#ifndef LL_LLNEARBYCHATBARLISTENER_H +#define LL_LLNEARBYCHATBARLISTENER_H + +#include "lleventapi.h" + +class LLSD; +class LLNearbyChatBar; + +class LLNearbyChatBarListener : public LLEventAPI +{ +public: + LLNearbyChatBarListener(LLNearbyChatBar & chatbar); + +private: + void sendChat(LLSD const & chat_data) const; + + LLNearbyChatBar & mChatbar; +}; + +#endif // LL_LLNEARBYCHATBARLISTENER_H + diff --git a/indra/newview/skins/default/xui/de/floater_postcard.xml b/indra/newview/skins/default/xui/de/floater_postcard.xml index 49dcd4af51..28af0183cb 100644 --- a/indra/newview/skins/default/xui/de/floater_postcard.xml +++ b/indra/newview/skins/default/xui/de/floater_postcard.xml @@ -1,36 +1,36 @@ - - - - E-Mail des Empfängers: - - - Ihre E-Mail: - - - Ihr Name: - - - Betreff: - - - - Nachricht: - - - Nachricht hier eingeben. - - - Wenn sich der Empfänger bei SL anmeldet, erhalten Sie einen Empfehlungsbonus. - - - - - - - - - - - Upload Model - - - - This wizard will help you import mesh models to Second Life. First specify a file containing the model you wish to import. Second Life supports COLLADA (.dae) files. - - - - Filename: - - - - - Model Preview: - - - - - - Dimensions (meters): - - - X: Y: Z: - - - | | - - - - - - Note: - - -Advanced users familiar with 3d content creation tools may prefer to use the [secondlife:///app/floater/upload_model Advanced Mesh Import Window] . - - - - - - - - - Optimize - - - - This wizard has optimized your model to improve performance. You may adjust the results of the optimization process bellow or click Next to continue. - - - Generating Level of Detail - - - Generate Level of Detail: High - - Generate Level of Detail: Medium - - Generate Level of Detail: Low - - Generate Level of Detail: Lowest - - - - Model Preview: - - - - High - - - Medium - - - Low - - - Lowest - - - - - Higher Performance - Faster rendering but less detailed; lowers Resource (prim) cost. - Higher Accuracy - More detailed model but slower; increases Resource (prim) cost. - - - ' - - - - - - Resource Cost: [COST] - - Dimensions (meters): - - - X: Y: Z: - - - | | - - - - - - - - - - - Physics - - - - The wizard will create a physical shape, which determines how the object interacts with other objects and avatars. Set the slider to the detail level most appropriate for how your object will be used: - - - Higher Performance - Faster rendering but less detailed; lowers Resource (prim) cost. - Higher Accuracy - More detailed model but slower; increases Resource (prim) cost. - - - ' ' ' ' ' ' ' ' ' ' ' - Recommended for solid objects - Recommended for buildings - Recommended for vehicles - - - - - Resource Cost: [COST] - - - - - - - - Physics - - - - Preview the physics shape below then click Next to continue. To modify the physics shape, click the Back button. - - - - Model Preview: - - - - High - - - Medium - - - Low - - - Lowest - - - - - - Dimensions (meters): - - - X: Y: Z: - - - | | - - - - - Resource Cost: [COST] - - - - - - - Review - - - - Review the details below then click. Upload to upload your model. Your L$ balance will be charged when you click Upload. - - - - - Model Preview: - - - - High - - - Medium - - - Low - - - Lowest - - - - - - Dimensions (meters): - - - X: Y: Z: - - - | | - - - - - - Resource Cost: [COST] - This is the cost to your Region's prim/object limit, at default scale - Physics Cost: [COST] - This is the cost to your Region's prim/object limit, at default scale - Upload Fee: - This is the amount the upload will cost. - - I confirm that I have the appropriate rights to the material contained in this model. [secondlife:///app/floater/learn_more Learn more] - - - - - - - - - Upload Complete! - - - - Congratulations! Your model has been sucessfully uploaded. You will find the model in the Objects folder in your inventory. - - - - - - - + + + + + + + + + Upload Model + + + + This wizard will help you import mesh models to Second Life. First specify a file containing the model you wish to import. Second Life supports COLLADA (.dae) files. + + + + Filename: + + + + + Model Preview: + + + + + + Dimensions (meters): + + + X: Y: Z: + + + | | + + + + + + Note: + + +Advanced users familiar with 3d content creation tools may prefer to use the [secondlife:///app/floater/upload_model Advanced Mesh Import Window] . + + + + + + + + + Optimize + + + + This wizard has optimized your model to improve performance. You may adjust the results of the optimization process bellow or click Next to continue. + + + Generating Level of Detail + + + Generate Level of Detail: High + + Generate Level of Detail: Medium + + Generate Level of Detail: Low + + Generate Level of Detail: Lowest + + + + Model Preview: + + + + High + + + Medium + + + Low + + + Lowest + + + + + Higher Performance + Faster rendering but less detailed; lowers Resource (prim) cost. + Higher Accuracy + More detailed model but slower; increases Resource (prim) cost. + + + ' + + + + + + Resource Cost: [COST] + + Dimensions (meters): + + + X: Y: Z: + + + | | + + + + + + + + + + + Physics + + + + The wizard will create a physical shape, which determines how the object interacts with other objects and avatars. Set the slider to the detail level most appropriate for how your object will be used: + + + Higher Performance + Faster rendering but less detailed; lowers Resource (prim) cost. + Higher Accuracy + More detailed model but slower; increases Resource (prim) cost. + + + ' ' ' ' ' ' ' ' ' ' ' + Recommended for solid objects + Recommended for buildings + Recommended for vehicles + + + + + Resource Cost: [COST] + + + + + + + + Physics + + + + Preview the physics shape below then click Next to continue. To modify the physics shape, click the Back button. + + + + Model Preview: + + + + High + + + Medium + + + Low + + + Lowest + + + + + + Dimensions (meters): + + + X: Y: Z: + + + | | + + + + + Resource Cost: [COST] + + + + + + + Review + + + + Review the details below then click. Upload to upload your model. Your L$ balance will be charged when you click Upload. + + + + + Model Preview: + + + + High + + + Medium + + + Low + + + Lowest + + + + + + Dimensions (meters): + + + X: Y: Z: + + + | | + + + + + + Resource Cost: [COST] + This is the cost to your Region's prim/object limit, at default scale + Physics Cost: [COST] + This is the cost to your Region's prim/object limit, at default scale + Upload Fee: + This is the amount the upload will cost. + + I confirm that I have the appropriate rights to the material contained in this model. [secondlife:///app/floater/learn_more Learn more] + + + + + + + + + Upload Complete! + + + + Congratulations! Your model has been sucessfully uploaded. You will find the model in the Objects folder in your inventory. + + + + + + + - - - - - - Drag to move, shift-drag to copy - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - þ: [COUNT] - - - - Stretch Both Sides - - - - - - - - - - - - - Objects: [COUNT] - - - Prims: [COUNT] - - - Linked Sets: [COUNT] - - - Cost: [COST] / [PHYSICS] - - - Objects: [COUNT] - - - Cost: [COST] / [PHYSICS] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Deed - - - Deed - - - You can modify this object - - - You can modify these objects - - - You can't modify this object - - - You can't modify these objects - - - You must select entire object to set permissions - - - Price: L$ - - - Total Price: L$ - - - Price Per: L$ - - - Mixed Price - - - Mixed Sale - - - Name: - - - - Description: - - - - Creator: - - - - TestString PleaseIgnore (please.ignore) - - - Owner: - - - - TestString PleaseIgnore (please.ignore) - - - Group: - - - - - - - - + + + + + + Drag to move, shift-drag to copy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + þ: [COUNT] + + + + Stretch Both Sides + + + + + + + + + + + + + Objects: [COUNT] + + + Prims: [COUNT] + + + Linked Sets: [COUNT] + + + Cost: [COST] / [PHYSICS] + + + Objects: [COUNT] + + + Cost: [COST] / [PHYSICS] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Deed + + + Deed + + + You can modify this object + + + You can modify these objects + + + You can't modify this object + + + You can't modify these objects + + + You must select entire object to set permissions + + + Price: L$ + + + Total Price: L$ + + + Price Per: L$ + + + Mixed Price + + + Mixed Sale + + + Name: + + + + Description: + + + + Creator: + + + + TestString PleaseIgnore (please.ignore) + + + Owner: + + + + TestString PleaseIgnore (please.ignore) + + + Group: + + + + + + + +