diff options
Diffstat (limited to 'indra')
-rw-r--r-- | indra/llplugin/llpluginclassmedia.cpp | 2890 | ||||
-rw-r--r-- | indra/media_plugins/webkit/media_plugin_webkit.cpp | 2894 | ||||
-rw-r--r-- | indra/newview/llappearancemgr.cpp | 4 | ||||
-rw-r--r-- | indra/newview/llpanelmarketplaceinbox.cpp | 476 | ||||
-rw-r--r-- | indra/newview/llstatusbar.h | 4 | ||||
-rw-r--r-- | indra/newview/lltooldraganddrop.cpp | 8 |
6 files changed, 3138 insertions, 3138 deletions
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 9cd3216ab2..c53857fcee 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -1,1445 +1,1445 @@ -/**
- * @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::jsEnableObject( bool enable )
-{
- if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
- {
- return;
- }
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_enable_object");
- message.setValueBoolean( "enable", enable );
- 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::enableMediaPluginDebugging( bool enable )
-{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "enable_media_plugin_debugging");
- message.setValueBoolean( "enable", enable );
- 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 if(message_name == "debug_message")
- {
- mDebugMessageText = message.getValue("message_text");
- mDebugMessageLevel = message.getValue("message_level");
- mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_DEBUG_MESSAGE);
- }
- 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::showWebInspector( bool show )
-{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "show_web_inspector");
- message.setValueBoolean("show", true); // only open for now - closed manually by user
- 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::jsEnableObject( bool enable ) +{ + if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) + { + return; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_enable_object"); + message.setValueBoolean( "enable", enable ); + 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::enableMediaPluginDebugging( bool enable ) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "enable_media_plugin_debugging"); + message.setValueBoolean( "enable", enable ); + 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 if(message_name == "debug_message") + { + mDebugMessageText = message.getValue("message_text"); + mDebugMessageLevel = message.getValue("message_level"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_DEBUG_MESSAGE); + } + 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::showWebInspector( bool show ) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "show_web_inspector"); + message.setValueBoolean("show", true); // only open for now - closed manually by user + 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/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index 430ae9d4dc..0f74772e42 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -1,1447 +1,1447 @@ -/**
- * @file media_plugin_webkit.cpp
- * @brief Webkit plugin for LLMedia API plugin system
- *
- * @cond
- * $LicenseInfo:firstyear=2008&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- * @endcond
- */
-
-#include "llqtwebkit.h"
-
-#include "linden_common.h"
-#include "indra_constants.h" // for indra keyboard codes
-
-#include "llgl.h"
-
-#include "llplugininstance.h"
-#include "llpluginmessage.h"
-#include "llpluginmessageclasses.h"
-#include "media_plugin_base.h"
-
-// set to 1 if you're using the version of llqtwebkit that's QPixmap-ified
-#if LL_LINUX
-# define LL_QTWEBKIT_USES_PIXMAPS 0
-extern "C" {
-# include <glib.h>
-# include <glib-object.h>
-}
-#else
-# define LL_QTWEBKIT_USES_PIXMAPS 0
-#endif // LL_LINUX
-
-# include "volume_catcher.h"
-
-#if LL_WINDOWS
-# include <direct.h>
-#else
-# include <unistd.h>
-# include <stdlib.h>
-#endif
-
-#if LL_WINDOWS
- // *NOTE:Mani - This captures the module handle for the dll. This is used below
- // to get the path to this dll for webkit initialization.
- // I don't know how/if this can be done with apr...
- namespace { HMODULE gModuleHandle;};
- BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
- {
- gModuleHandle = (HMODULE) hinstDLL;
- return TRUE;
- }
-#endif
-
-////////////////////////////////////////////////////////////////////////////////
-//
-class MediaPluginWebKit :
- public MediaPluginBase,
- public LLEmbeddedBrowserWindowObserver
-{
-public:
- MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
- ~MediaPluginWebKit();
-
- /*virtual*/ void receiveMessage(const char *message_string);
-
-private:
-
- std::string mProfileDir;
- std::string mHostLanguage;
- std::string mUserAgent;
- bool mCookiesEnabled;
- bool mJavascriptEnabled;
- bool mPluginsEnabled;
- bool mEnableMediaPluginDebugging;
-
- enum
- {
- INIT_STATE_UNINITIALIZED, // LLQtWebkit hasn't been set up yet
- INIT_STATE_INITIALIZED, // LLQtWebkit has been set up, but no browser window has been created yet.
- INIT_STATE_NAVIGATING, // Browser instance has been set up and initial navigate to about:blank has been issued
- INIT_STATE_NAVIGATE_COMPLETE, // initial navigate to about:blank has completed
- INIT_STATE_WAIT_REDRAW, // First real navigate begin has been received, waiting for page changed event to start handling redraws
- INIT_STATE_WAIT_COMPLETE, // Waiting for first real navigate complete event
- INIT_STATE_RUNNING // All initialization gymnastics are complete.
- };
- int mBrowserWindowId;
- int mInitState;
- std::string mInitialNavigateURL;
- bool mNeedsUpdate;
-
- bool mCanCut;
- bool mCanCopy;
- bool mCanPaste;
- int mLastMouseX;
- int mLastMouseY;
- bool mFirstFocus;
- F32 mBackgroundR;
- F32 mBackgroundG;
- F32 mBackgroundB;
- std::string mTarget;
-
- VolumeCatcher mVolumeCatcher;
-
- void postDebugMessage( const std::string& msg )
- {
- if ( mEnableMediaPluginDebugging )
- {
- LLPluginMessage debug_message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "debug_message");
- debug_message.setValue("message_text", "Media> " + msg);
- debug_message.setValue("message_level", "info");
- sendMessage(debug_message);
- }
- }
-
- void setInitState(int state)
- {
-// std::cerr << "changing init state to " << state << std::endl;
- mInitState = state;
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- void update(int milliseconds)
- {
-#if LL_QTLINUX_DOESNT_HAVE_GLIB
- // pump glib generously, as Linux browser plugins are on the
- // glib main loop, even if the browser itself isn't - ugh
- // This is NOT NEEDED if Qt itself was built with glib
- // mainloop integration.
- GMainContext *mainc = g_main_context_default();
- while(g_main_context_iteration(mainc, FALSE));
-#endif // LL_QTLINUX_DOESNT_HAVE_GLIB
-
- // pump qt
- LLQtWebKit::getInstance()->pump( milliseconds );
-
- mVolumeCatcher.pump();
-
- checkEditState();
-
- if(mInitState == INIT_STATE_NAVIGATE_COMPLETE)
- {
- if(!mInitialNavigateURL.empty())
- {
- // We already have the initial navigate URL -- kick off the navigate.
- LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, mInitialNavigateURL );
- mInitialNavigateURL.clear();
- }
- }
-
- if ( (mInitState > INIT_STATE_WAIT_REDRAW) && mNeedsUpdate )
- {
- const unsigned char* browser_pixels = LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId );
-
- unsigned int rowspan = LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId );
- unsigned int height = LLQtWebKit::getInstance()->getBrowserHeight( mBrowserWindowId );
-#if !LL_QTWEBKIT_USES_PIXMAPS
- unsigned int buffer_size = rowspan * height;
-#endif // !LL_QTWEBKIT_USES_PIXMAPS
-
-// std::cerr << "webkit plugin: updating" << std::endl;
-
- // TODO: should get rid of this memcpy if possible
- if ( mPixels && browser_pixels )
- {
-// std::cerr << " memcopy of " << buffer_size << " bytes" << std::endl;
-
-#if LL_QTWEBKIT_USES_PIXMAPS
- // copy the pixel data upside-down because of the co-ord system
- for (int y=0; y<height; ++y)
- {
- memcpy( &mPixels[(height-y-1)*rowspan], &browser_pixels[y*rowspan], rowspan );
- }
-#else
- memcpy( mPixels, browser_pixels, buffer_size );
-#endif // LL_QTWEBKIT_USES_PIXMAPS
- }
-
- if ( mWidth > 0 && mHeight > 0 )
- {
-// std::cerr << "Setting dirty, " << mWidth << " x " << mHeight << std::endl;
- setDirty( 0, 0, mWidth, mHeight );
- }
-
- mNeedsUpdate = false;
- };
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- bool initBrowser()
- {
- // already initialized
- if ( mInitState > INIT_STATE_UNINITIALIZED )
- return true;
-
- // set up directories
- char cwd[ FILENAME_MAX ]; // I *think* this is defined on all platforms we use
- if (NULL == getcwd( cwd, FILENAME_MAX - 1 ))
- {
- llwarns << "Couldn't get cwd - probably too long - failing to init." << llendl;
- return false;
- }
- std::string application_dir = std::string( cwd );
-
-#if LL_LINUX
- // take care to initialize glib properly, because some
- // versions of Qt don't, and we indirectly need it for (some
- // versions of) Flash to not crash the browser.
- if (!g_thread_supported ()) g_thread_init (NULL);
- g_type_init();
-#endif
-
-#if LL_DARWIN
- // When running under the Xcode debugger, there's a setting called "Break on Debugger()/DebugStr()" which defaults to being turned on.
- // This causes the environment variable USERBREAK to be set to 1, which causes these legacy calls to break into the debugger.
- // This wouldn't cause any problems except for the fact that the current release version of the Flash plugin has a call to Debugger() in it
- // which gets hit when the plugin is probed by webkit.
- // Unsetting the environment variable here works around this issue.
- unsetenv("USERBREAK");
-#endif
-
-#if LL_WINDOWS
- //*NOTE:Mani - On windows, at least, the component path is the
- // location of this dll's image file.
- std::string component_dir;
- char dll_path[_MAX_PATH];
- DWORD len = GetModuleFileNameA(gModuleHandle, (LPCH)&dll_path, _MAX_PATH);
- while(len && dll_path[ len ] != ('\\') )
- {
- len--;
- }
- if(len >= 0)
- {
- dll_path[len] = 0;
- component_dir = dll_path;
- }
- else
- {
- // *NOTE:Mani - This case should be an rare exception.
- // GetModuleFileNameA should always give you a full path, no?
- component_dir = application_dir;
- }
-#else
- std::string component_dir = application_dir;
-#endif
-
- // debug spam sent to viewer and displayed in the log as usual
- postDebugMessage( "Component dir set to: " + component_dir );
-
- // window handle - needed on Windows and must be app window.
-#if LL_WINDOWS
- char window_title[ MAX_PATH ];
- GetConsoleTitleA( window_title, MAX_PATH );
- void* native_window_handle = (void*)FindWindowA( NULL, window_title );
-#else
- void* native_window_handle = 0;
-#endif
-
- // main browser initialization
- bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, mProfileDir, native_window_handle );
- if ( result )
- {
- mInitState = INIT_STATE_INITIALIZED;
-
- // debug spam sent to viewer and displayed in the log as usual
- postDebugMessage( "browser initialized okay" );
-
- return true;
- };
-
- // debug spam sent to viewer and displayed in the log as usual
- postDebugMessage( "browser nOT initialized." );
-
- return false;
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- bool initBrowserWindow()
- {
- // already initialized
- if ( mInitState > INIT_STATE_INITIALIZED )
- return true;
-
- // not enough information to initialize the browser yet.
- if ( mWidth < 0 || mHeight < 0 || mDepth < 0 ||
- mTextureWidth < 0 || mTextureHeight < 0 )
- {
- return false;
- };
-
- // Set up host language before creating browser window
- if(!mHostLanguage.empty())
- {
- LLQtWebKit::getInstance()->setHostLanguage(mHostLanguage);
- postDebugMessage( "Setting language to " + mHostLanguage );
- }
-
- // turn on/off cookies based on what host app tells us
- LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled );
-
- // turn on/off plugins based on what host app tells us
- LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled );
-
- // turn on/off Javascript based on what host app tells us
- LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled );
-
- std::stringstream str;
- str << "Cookies enabled = " << mCookiesEnabled << ", plugins enabled = " << mPluginsEnabled << ", Javascript enabled = " << mJavascriptEnabled;
- postDebugMessage( str.str() );
-
- // create single browser window
- mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight, mTarget);
-
- str.str("");
- str.clear();
- str << "Setting browser window size to " << mWidth << " x " << mHeight;
- postDebugMessage( str.str() );
-
- // tell LLQtWebKit about the size of the browser window
- LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight );
-
- // observer events that LLQtWebKit emits
- LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this );
-
- // append details to agent string
- LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent );
- postDebugMessage( "Updating user agent with " + mUserAgent );
-
-#if !LL_QTWEBKIT_USES_PIXMAPS
- // don't flip bitmap
- LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true );
-#endif // !LL_QTWEBKIT_USES_PIXMAPS
-
- // set background color
- // convert background color channels from [0.0, 1.0] to [0, 255];
- LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, int(mBackgroundR * 255.0f), int(mBackgroundG * 255.0f), int(mBackgroundB * 255.0f) );
-
- // Set state _before_ starting the navigate, since onNavigateBegin might get called before this call returns.
- setInitState(INIT_STATE_NAVIGATING);
-
- // Don't do this here -- it causes the dreaded "white flash" when loading a browser instance.
- // FIXME: Re-added this because navigating to a "page" initializes things correctly - especially
- // for the HTTP AUTH dialog issues (DEV-41731). Will fix at a later date.
- // Build a data URL like this: "data:text/html,%3Chtml%3E%3Cbody bgcolor=%22#RRGGBB%22%3E%3C/body%3E%3C/html%3E"
- // where RRGGBB is the background color in HTML style
- std::stringstream url;
-
- url << "data:text/html,%3Chtml%3E%3Cbody%20bgcolor=%22#";
- // convert background color channels from [0.0, 1.0] to [0, 255];
- url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundR * 255.0f);
- url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundG * 255.0f);
- url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundB * 255.0f);
- url << "%22%3E%3C/body%3E%3C/html%3E";
-
- //lldebugs << "data url is: " << url.str() << llendl;
-
- LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, url.str() );
-// LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" );
-
- return true;
- }
-
- void setVolume(F32 vol);
-
- ////////////////////////////////////////////////////////////////////////////////
- // virtual
- void onCursorChanged(const EventType& event)
- {
- LLQtWebKit::ECursor llqt_cursor = (LLQtWebKit::ECursor)event.getIntValue();
- std::string name;
-
- switch(llqt_cursor)
- {
- case LLQtWebKit::C_ARROW:
- name = "arrow";
- break;
- case LLQtWebKit::C_IBEAM:
- name = "ibeam";
- break;
- case LLQtWebKit::C_SPLITV:
- name = "splitv";
- break;
- case LLQtWebKit::C_SPLITH:
- name = "splith";
- break;
- case LLQtWebKit::C_POINTINGHAND:
- name = "hand";
- break;
-
- default:
- llwarns << "Unknown cursor ID: " << (int)llqt_cursor << llendl;
- break;
- }
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed");
- message.setValue("name", name);
- sendMessage(message);
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // virtual
- void onPageChanged( const EventType& event )
- {
- if(mInitState == INIT_STATE_WAIT_REDRAW)
- {
- setInitState(INIT_STATE_WAIT_COMPLETE);
- }
-
- // flag that an update is required
- mNeedsUpdate = true;
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- // virtual
- void onNavigateBegin(const EventType& event)
- {
- if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
- {
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
- message.setValue("uri", event.getEventUri());
- message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK));
- message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD));
- sendMessage(message);
-
- // debug spam sent to viewer and displayed in the log as usual
- postDebugMessage( "Navigate begin event at: " + event.getEventUri() );
-
- setStatus(STATUS_LOADING);
- }
-
- if(mInitState == INIT_STATE_NAVIGATE_COMPLETE)
- {
- // Skip the WAIT_REDRAW state now -- with the right background color set, it should no longer be necessary.
-// setInitState(INIT_STATE_WAIT_REDRAW);
- setInitState(INIT_STATE_WAIT_COMPLETE);
- }
-
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // virtual
- void onNavigateComplete(const EventType& event)
- {
- if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
- {
- if(mInitState < INIT_STATE_RUNNING)
- {
- setInitState(INIT_STATE_RUNNING);
-
- // Clear the history, so the "back" button doesn't take you back to "about:blank".
- LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId);
- }
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete");
- message.setValue("uri", event.getEventUri());
- message.setValueS32("result_code", event.getIntValue());
- message.setValue("result_string", event.getStringValue());
- message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK));
- message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD));
- sendMessage(message);
-
- setStatus(STATUS_LOADED);
- }
- else if(mInitState == INIT_STATE_NAVIGATING)
- {
- setInitState(INIT_STATE_NAVIGATE_COMPLETE);
- }
-
- // debug spam sent to viewer and displayed in the log as usual
- postDebugMessage( "Navigate complete event at: " + event.getEventUri() );
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // virtual
- void onUpdateProgress(const EventType& event)
- {
- if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
- {
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "progress");
- message.setValueS32("percent", event.getIntValue());
- sendMessage(message);
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // virtual
- void onStatusTextChange(const EventType& event)
- {
- if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
- {
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text");
- message.setValue("status", event.getStringValue());
- sendMessage(message);
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // virtual
- void onTitleChange(const EventType& event)
- {
- if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
- {
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
- message.setValue("name", event.getStringValue());
- sendMessage(message);
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // virtual
- void onNavigateErrorPage(const EventType& event)
- {
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_error_page");
- message.setValueS32("status_code", event.getIntValue());
- sendMessage(message);
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // virtual
- void onLocationChange(const EventType& event)
- {
- if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
- {
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed");
- message.setValue("uri", event.getEventUri());
- sendMessage(message);
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // virtual
- void onClickLinkHref(const EventType& event)
- {
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href");
- message.setValue("uri", event.getEventUri());
- message.setValue("target", event.getStringValue());
- message.setValue("uuid", event.getStringValue2());
- sendMessage(message);
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // virtual
- void onClickLinkNoFollow(const EventType& event)
- {
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
- message.setValue("uri", event.getEventUri());
-#if LLQTWEBKIT_API_VERSION >= 7
- message.setValue("nav_type", event.getNavigationType());
-#else
- message.setValue("nav_type", "clicked");
-#endif
- sendMessage(message);
- }
-
-
- ////////////////////////////////////////////////////////////////////////////////
- // virtual
- void onCookieChanged(const EventType& event)
- {
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "cookie_set");
- message.setValue("cookie", event.getStringValue());
- // These could be passed through as well, but aren't really needed.
-// message.setValue("uri", event.getEventUri());
-// message.setValueBoolean("dead", (event.getIntValue() != 0))
- sendMessage(message);
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // virtual
- void onWindowCloseRequested(const EventType& event)
- {
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "close_request");
- message.setValue("uuid", event.getStringValue());
- sendMessage(message);
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // virtual
- void onWindowGeometryChangeRequested(const EventType& event)
- {
- int x, y, width, height;
- event.getRectValue(x, y, width, height);
-
- // This sometimes gets called with a zero-size request. Don't pass these along.
- if(width > 0 && height > 0)
- {
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "geometry_change");
- message.setValue("uuid", event.getStringValue());
- message.setValueS32("x", x);
- message.setValueS32("y", y);
- message.setValueS32("width", width);
- message.setValueS32("height", height);
- sendMessage(message);
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // virtual
- std::string onRequestFilePicker( const EventType& eventIn )
- {
- return blockingPickFile();
- }
-
- std::string mAuthUsername;
- std::string mAuthPassword;
- bool mAuthOK;
-
- ////////////////////////////////////////////////////////////////////////////////
- // virtual
- bool onAuthRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password)
- {
- mAuthOK = false;
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_request");
- message.setValue("url", in_url);
- message.setValue("realm", in_realm);
- message.setValueBoolean("blocking_request", true);
-
- // The "blocking_request" key in the message means this sendMessage call will block until a response is received.
- sendMessage(message);
-
- if(mAuthOK)
- {
- out_username = mAuthUsername;
- out_password = mAuthPassword;
- }
-
- return mAuthOK;
- }
-
- void authResponse(LLPluginMessage &message)
- {
- mAuthOK = message.getValueBoolean("ok");
- if(mAuthOK)
- {
- mAuthUsername = message.getValue("username");
- mAuthPassword = message.getValue("password");
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // virtual
- void onLinkHovered(const EventType& event)
- {
- if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
- {
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "link_hovered");
- message.setValue("link", event.getEventUri());
- message.setValue("title", event.getStringValue());
- message.setValue("text", event.getStringValue2());
- sendMessage(message);
- }
- }
-
- LLQtWebKit::EKeyboardModifier decodeModifiers(std::string &modifiers)
- {
- int result = 0;
-
- if(modifiers.find("shift") != std::string::npos)
- result |= LLQtWebKit::KM_MODIFIER_SHIFT;
-
- if(modifiers.find("alt") != std::string::npos)
- result |= LLQtWebKit::KM_MODIFIER_ALT;
-
- if(modifiers.find("control") != std::string::npos)
- result |= LLQtWebKit::KM_MODIFIER_CONTROL;
-
- if(modifiers.find("meta") != std::string::npos)
- result |= LLQtWebKit::KM_MODIFIER_META;
-
- return (LLQtWebKit::EKeyboardModifier)result;
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- void deserializeKeyboardData( LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers )
- {
- native_scan_code = 0;
- native_virtual_key = 0;
- native_modifiers = 0;
-
- if( native_key_data.isMap() )
- {
-#if LL_DARWIN
- native_scan_code = (uint32_t)(native_key_data["char_code"].asInteger());
- native_virtual_key = (uint32_t)(native_key_data["key_code"].asInteger());
- native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger());
-#elif LL_WINDOWS
- native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger());
- native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());
- // TODO: I don't think we need to do anything with native modifiers here -- please verify
-#elif LL_LINUX
- native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger());
- native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());
- native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger());
-#else
- // Add other platforms here as needed
-#endif
- };
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- void keyEvent(LLQtWebKit::EKeyEvent key_event, int key, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
- {
- // The incoming values for 'key' will be the ones from indra_constants.h
- std::string utf8_text;
-
- if(key < KEY_SPECIAL)
- {
- // Low-ascii characters need to get passed through.
- utf8_text = (char)key;
- }
-
- // Any special-case handling we want to do for particular keys...
- switch((KEY)key)
- {
- // ASCII codes for some standard keys
- case LLQtWebKit::KEY_BACKSPACE: utf8_text = (char)8; break;
- case LLQtWebKit::KEY_TAB: utf8_text = (char)9; break;
- case LLQtWebKit::KEY_RETURN: utf8_text = (char)13; break;
- case LLQtWebKit::KEY_PAD_RETURN: utf8_text = (char)13; break;
- case LLQtWebKit::KEY_ESCAPE: utf8_text = (char)27; break;
-
- default:
- break;
- }
-
-// std::cerr << "key event " << (int)key_event << ", native_key_data = " << native_key_data << std::endl;
-
- uint32_t native_scan_code = 0;
- uint32_t native_virtual_key = 0;
- uint32_t native_modifiers = 0;
- deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers );
-
- LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, key_event, (uint32_t)key, utf8_text.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
-
- checkEditState();
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- void unicodeInput( const std::string &utf8str, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
- {
- uint32_t key = LLQtWebKit::KEY_NONE;
-
-// std::cerr << "unicode input, native_key_data = " << native_key_data << std::endl;
-
- if(utf8str.size() == 1)
- {
- // The only way a utf8 string can be one byte long is if it's actually a single 7-bit ascii character.
- // In this case, use it as the key value.
- key = utf8str[0];
- }
-
- uint32_t native_scan_code = 0;
- uint32_t native_virtual_key = 0;
- uint32_t native_modifiers = 0;
- deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers );
-
- LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_DOWN, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
- LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_UP, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
-
- checkEditState();
- };
-
- void checkEditState(void)
- {
- bool can_cut = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT);
- bool can_copy = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY);
- bool can_paste = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE);
-
- if((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste))
- {
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state");
-
- if(can_cut != mCanCut)
- {
- mCanCut = can_cut;
- message.setValueBoolean("cut", can_cut);
- }
-
- if(can_copy != mCanCopy)
- {
- mCanCopy = can_copy;
- message.setValueBoolean("copy", can_copy);
- }
-
- if(can_paste != mCanPaste)
- {
- mCanPaste = can_paste;
- message.setValueBoolean("paste", can_paste);
- }
-
- sendMessage(message);
-
- }
- }
-
- std::string mPickedFile;
-
- std::string blockingPickFile(void)
- {
- mPickedFile.clear();
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file");
- message.setValueBoolean("blocking_request", true);
-
- // The "blocking_request" key in the message means this sendMessage call will block until a response is received.
- sendMessage(message);
-
- return mPickedFile;
- }
-
- void onPickFileResponse(const std::string &file)
- {
- mPickedFile = file;
- }
-
-};
-
-MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) :
- MediaPluginBase(host_send_func, host_user_data)
-{
-// std::cerr << "MediaPluginWebKit constructor" << std::endl;
-
- mBrowserWindowId = 0;
- mInitState = INIT_STATE_UNINITIALIZED;
- mNeedsUpdate = true;
- mCanCut = false;
- mCanCopy = false;
- mCanPaste = false;
- mLastMouseX = 0;
- mLastMouseY = 0;
- mFirstFocus = true;
- mBackgroundR = 0.0f;
- mBackgroundG = 0.0f;
- mBackgroundB = 0.0f;
-
- mHostLanguage = "en"; // default to english
- mJavascriptEnabled = true; // default to on
- mPluginsEnabled = true; // default to on
- mEnableMediaPluginDebugging = false;
- mUserAgent = "LLPluginMedia Web Browser";
-}
-
-MediaPluginWebKit::~MediaPluginWebKit()
-{
- // unhook observer
- LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this );
-
- // clean up
- LLQtWebKit::getInstance()->reset();
-
-// std::cerr << "MediaPluginWebKit destructor" << std::endl;
-}
-
-void MediaPluginWebKit::receiveMessage(const char *message_string)
-{
-// std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
- LLPluginMessage message_in;
-
- if(message_in.parse(message_string) >= 0)
- {
- std::string message_class = message_in.getClass();
- std::string message_name = message_in.getName();
- if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
- {
- if(message_name == "init")
- {
- LLPluginMessage message("base", "init_response");
- LLSD versions = LLSD::emptyMap();
- versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
- versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
- versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
- message.setValueLLSD("versions", versions);
-
- std::string plugin_version = "Webkit media plugin, Webkit version ";
- plugin_version += LLQtWebKit::getInstance()->getVersion();
- message.setValue("plugin_version", plugin_version);
- sendMessage(message);
- }
- else if(message_name == "idle")
- {
- // no response is necessary here.
- F64 time = message_in.getValueReal("time");
-
- // Convert time to milliseconds for update()
- update((int)(time * 1000.0f));
- }
- else if(message_name == "cleanup")
- {
- // DTOR most likely won't be called but the recent change to the way this process
- // is (not) killed means we see this message and can do what we need to here.
- // Note: this cleanup is ultimately what writes cookies to the disk
- LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this );
- LLQtWebKit::getInstance()->reset();
- }
- else if(message_name == "shm_added")
- {
- SharedSegmentInfo info;
- info.mAddress = message_in.getValuePointer("address");
- info.mSize = (size_t)message_in.getValueS32("size");
- std::string name = message_in.getValue("name");
-
-// std::cerr << "MediaPluginWebKit::receiveMessage: shared memory added, name: " << name
-// << ", size: " << info.mSize
-// << ", address: " << info.mAddress
-// << std::endl;
-
- mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
-
- }
- else if(message_name == "shm_remove")
- {
- std::string name = message_in.getValue("name");
-
-// std::cerr << "MediaPluginWebKit::receiveMessage: shared memory remove, name = " << name << std::endl;
-
- SharedSegmentMap::iterator iter = mSharedSegments.find(name);
- if(iter != mSharedSegments.end())
- {
- if(mPixels == iter->second.mAddress)
- {
- // This is the currently active pixel buffer. Make sure we stop drawing to it.
- mPixels = NULL;
- mTextureSegmentName.clear();
- }
- mSharedSegments.erase(iter);
- }
- else
- {
-// std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl;
- }
-
- // Send the response so it can be cleaned up.
- LLPluginMessage message("base", "shm_remove_response");
- message.setValue("name", name);
- sendMessage(message);
- }
- else
- {
-// std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl;
- }
- }
- else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
- {
- if(message_name == "set_volume")
- {
- F32 volume = message_in.getValueReal("volume");
- setVolume(volume);
- }
- }
- else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
- {
- if(message_name == "init")
- {
- mTarget = message_in.getValue("target");
-
- // This is the media init message -- all necessary data for initialization should have been received.
- if(initBrowser())
- {
-
- // Plugin gets to decide the texture parameters to use.
- mDepth = 4;
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
- message.setValueS32("default_width", 1024);
- message.setValueS32("default_height", 1024);
- message.setValueS32("depth", mDepth);
- message.setValueU32("internalformat", GL_RGBA);
- #if LL_QTWEBKIT_USES_PIXMAPS
- message.setValueU32("format", GL_BGRA_EXT); // I hope this isn't system-dependant... is it? If so, we'll have to check the root window's pixel layout or something... yuck.
- #else
- message.setValueU32("format", GL_RGBA);
- #endif // LL_QTWEBKIT_USES_PIXMAPS
- message.setValueU32("type", GL_UNSIGNED_BYTE);
- message.setValueBoolean("coords_opengl", true);
- sendMessage(message);
- }
- else
- {
- // if initialization failed, we're done.
- mDeleteMe = true;
- }
-
- }
- else if(message_name == "set_user_data_path")
- {
- std::string user_data_path = message_in.getValue("path"); // n.b. always has trailing platform-specific dir-delimiter
- mProfileDir = user_data_path + "browser_profile";
-
- // FIXME: Should we do anything with this if it comes in after the browser has been initialized?
- }
- else if(message_name == "set_language_code")
- {
- mHostLanguage = message_in.getValue("language");
-
- // FIXME: Should we do anything with this if it comes in after the browser has been initialized?
- }
- else if(message_name == "plugins_enabled")
- {
- mPluginsEnabled = message_in.getValueBoolean("enable");
- }
- else if(message_name == "javascript_enabled")
- {
- mJavascriptEnabled = message_in.getValueBoolean("enable");
- }
- else if(message_name == "size_change")
- {
- std::string name = message_in.getValue("name");
- S32 width = message_in.getValueS32("width");
- S32 height = message_in.getValueS32("height");
- S32 texture_width = message_in.getValueS32("texture_width");
- S32 texture_height = message_in.getValueS32("texture_height");
- mBackgroundR = message_in.getValueReal("background_r");
- mBackgroundG = message_in.getValueReal("background_g");
- mBackgroundB = message_in.getValueReal("background_b");
-// mBackgroundA = message_in.setValueReal("background_a"); // Ignore any alpha
-
- if(!name.empty())
- {
- // Find the shared memory region with this name
- SharedSegmentMap::iterator iter = mSharedSegments.find(name);
- if(iter != mSharedSegments.end())
- {
- mPixels = (unsigned char*)iter->second.mAddress;
- mWidth = width;
- mHeight = height;
-
- if(initBrowserWindow())
- {
-
- // size changed so tell the browser
- LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight );
-
- // std::cerr << "webkit plugin: set size to " << mWidth << " x " << mHeight
- // << ", rowspan is " << LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) << std::endl;
-
- S32 real_width = LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) / LLQtWebKit::getInstance()->getBrowserDepth(mBrowserWindowId);
-
- // The actual width the browser will be drawing to is probably smaller... let the host know by modifying texture_width in the response.
- if(real_width <= texture_width)
- {
- texture_width = real_width;
- }
- else
- {
- // This won't work -- it'll be bigger than the allocated memory. This is a fatal error.
- // std::cerr << "Fatal error: browser rowbytes greater than texture width" << std::endl;
- mDeleteMe = true;
- return;
- }
- }
- else
- {
- // Setting up the browser window failed. This is a fatal error.
- mDeleteMe = true;
- }
-
-
- mTextureWidth = texture_width;
- mTextureHeight = texture_height;
-
- };
- };
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
- message.setValue("name", name);
- message.setValueS32("width", width);
- message.setValueS32("height", height);
- message.setValueS32("texture_width", texture_width);
- message.setValueS32("texture_height", texture_height);
- sendMessage(message);
-
- }
- else if(message_name == "load_uri")
- {
- std::string uri = message_in.getValue("uri");
-
-// std::cout << "loading URI: " << uri << std::endl;
-
- if(!uri.empty())
- {
- if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
- {
- LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, uri );
- }
- else
- {
- mInitialNavigateURL = uri;
- }
- }
- }
- else if(message_name == "mouse_event")
- {
- std::string event = message_in.getValue("event");
- S32 button = message_in.getValueS32("button");
- mLastMouseX = message_in.getValueS32("x");
- mLastMouseY = message_in.getValueS32("y");
- std::string modifiers = message_in.getValue("modifiers");
-
- // Treat unknown mouse events as mouse-moves.
- LLQtWebKit::EMouseEvent mouse_event = LLQtWebKit::ME_MOUSE_MOVE;
- if(event == "down")
- {
- mouse_event = LLQtWebKit::ME_MOUSE_DOWN;
- }
- else if(event == "up")
- {
- mouse_event = LLQtWebKit::ME_MOUSE_UP;
- }
- else if(event == "double_click")
- {
- mouse_event = LLQtWebKit::ME_MOUSE_DOUBLE_CLICK;
- }
-
- LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, mouse_event, button, mLastMouseX, mLastMouseY, decodeModifiers(modifiers));
- checkEditState();
- }
- else if(message_name == "scroll_event")
- {
- S32 x = message_in.getValueS32("x");
- S32 y = message_in.getValueS32("y");
- std::string modifiers = message_in.getValue("modifiers");
-
- // Incoming scroll events are adjusted so that 1 detent is approximately 1 unit.
- // Qt expects 1 detent to be 120 units.
- // It also seems that our y scroll direction is inverted vs. what Qt expects.
-
- x *= 120;
- y *= -120;
-
- LLQtWebKit::getInstance()->scrollWheelEvent(mBrowserWindowId, mLastMouseX, mLastMouseY, x, y, decodeModifiers(modifiers));
- }
- else if(message_name == "key_event")
- {
- std::string event = message_in.getValue("event");
- S32 key = message_in.getValueS32("key");
- std::string modifiers = message_in.getValue("modifiers");
- LLSD native_key_data = message_in.getValueLLSD("native_key_data");
-
- // Treat unknown events as key-up for safety.
- LLQtWebKit::EKeyEvent key_event = LLQtWebKit::KE_KEY_UP;
- if(event == "down")
- {
- key_event = LLQtWebKit::KE_KEY_DOWN;
- }
- else if(event == "repeat")
- {
- key_event = LLQtWebKit::KE_KEY_REPEAT;
- }
-
- keyEvent(key_event, key, decodeModifiers(modifiers), native_key_data);
- }
- else if(message_name == "text_event")
- {
- std::string text = message_in.getValue("text");
- std::string modifiers = message_in.getValue("modifiers");
- LLSD native_key_data = message_in.getValueLLSD("native_key_data");
-
- unicodeInput(text, decodeModifiers(modifiers), native_key_data);
- }
- if(message_name == "edit_cut")
- {
- LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT );
- checkEditState();
- }
- if(message_name == "edit_copy")
- {
- LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY );
- checkEditState();
- }
- if(message_name == "edit_paste")
- {
- LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE );
- checkEditState();
- }
- if(message_name == "pick_file_response")
- {
- onPickFileResponse(message_in.getValue("file"));
- }
- if(message_name == "auth_response")
- {
- authResponse(message_in);
- }
- else
- if(message_name == "enable_media_plugin_debugging")
- {
- mEnableMediaPluginDebugging = message_in.getValueBoolean( "enable" );
- }
-
- else
- if(message_name == "js_enable_object")
- {
-#if LLQTWEBKIT_API_VERSION >= 9
- bool enable = message_in.getValueBoolean( "enable" );
- LLQtWebKit::getInstance()->setSLObjectEnabled( enable );
-#endif
- }
- else
- if(message_name == "js_agent_location")
- {
-#if LLQTWEBKIT_API_VERSION >= 9
- F32 x = message_in.getValueReal("x");
- F32 y = message_in.getValueReal("y");
- F32 z = message_in.getValueReal("z");
- LLQtWebKit::getInstance()->setAgentLocation( x, y, z );
- LLQtWebKit::getInstance()->emitLocation();
-#endif
- }
- else
- if(message_name == "js_agent_global_location")
- {
-#if LLQTWEBKIT_API_VERSION >= 9
- F32 x = message_in.getValueReal("x");
- F32 y = message_in.getValueReal("y");
- F32 z = message_in.getValueReal("z");
- LLQtWebKit::getInstance()->setAgentGlobalLocation( x, y, z );
- LLQtWebKit::getInstance()->emitLocation();
-#endif
- }
- else
- if(message_name == "js_agent_orientation")
- {
-#if LLQTWEBKIT_API_VERSION >= 9
- F32 angle = message_in.getValueReal("angle");
- LLQtWebKit::getInstance()->setAgentOrientation( angle );
- LLQtWebKit::getInstance()->emitLocation();
-#endif
- }
- else
- if(message_name == "js_agent_region")
- {
-#if LLQTWEBKIT_API_VERSION >= 9
- const std::string& region = message_in.getValue("region");
- LLQtWebKit::getInstance()->setAgentRegion( region );
- LLQtWebKit::getInstance()->emitLocation();
-#endif
- }
- else
- if(message_name == "js_agent_maturity")
- {
-#if LLQTWEBKIT_API_VERSION >= 9
- const std::string& maturity = message_in.getValue("maturity");
- LLQtWebKit::getInstance()->setAgentMaturity( maturity );
- LLQtWebKit::getInstance()->emitMaturity();
-#endif
- }
- else
- if(message_name == "js_agent_language")
- {
-#if LLQTWEBKIT_API_VERSION >= 9
- const std::string& language = message_in.getValue("language");
- LLQtWebKit::getInstance()->setAgentLanguage( language );
- LLQtWebKit::getInstance()->emitLanguage();
-#endif
- }
- else
- {
-// std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl;
- }
- }
- else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
- {
- if(message_name == "focus")
- {
- bool val = message_in.getValueBoolean("focused");
- LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, val );
-
- if(mFirstFocus && val)
- {
- // On the first focus, post a tab key event. This fixes a problem with initial focus.
- std::string empty;
- keyEvent(LLQtWebKit::KE_KEY_DOWN, KEY_TAB, decodeModifiers(empty));
- keyEvent(LLQtWebKit::KE_KEY_UP, KEY_TAB, decodeModifiers(empty));
- mFirstFocus = false;
- }
- }
- else if(message_name == "clear_cache")
- {
- LLQtWebKit::getInstance()->clearCache();
- }
- else if(message_name == "clear_cookies")
- {
- LLQtWebKit::getInstance()->clearAllCookies();
- }
- else if(message_name == "enable_cookies")
- {
- mCookiesEnabled = message_in.getValueBoolean("enable");
- LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled );
- }
- else if(message_name == "enable_plugins")
- {
- mPluginsEnabled = message_in.getValueBoolean("enable");
- LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled );
- }
- else if(message_name == "enable_javascript")
- {
- mJavascriptEnabled = message_in.getValueBoolean("enable");
- //LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled );
- }
- else if(message_name == "set_cookies")
- {
- LLQtWebKit::getInstance()->setCookies(message_in.getValue("cookies"));
- }
- else if(message_name == "proxy_setup")
- {
- bool val = message_in.getValueBoolean("enable");
- std::string host = message_in.getValue("host");
- int port = message_in.getValueS32("port");
- LLQtWebKit::getInstance()->enableProxy( val, host, port );
- }
- else if(message_name == "browse_stop")
- {
- LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_STOP );
- }
- else if(message_name == "browse_reload")
- {
- // foo = message_in.getValueBoolean("ignore_cache");
- LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD );
- }
- else if(message_name == "browse_forward")
- {
- LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD );
- }
- else if(message_name == "browse_back")
- {
- LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK );
- }
- else if(message_name == "set_status_redirect")
- {
- int code = message_in.getValueS32("code");
- std::string url = message_in.getValue("url");
- if ( 404 == code ) // browser lib only supports 404 right now
- {
-#if LLQTWEBKIT_API_VERSION < 8
- LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url );
-#endif
- };
- }
- else if(message_name == "set_user_agent")
- {
- mUserAgent = message_in.getValue("user_agent");
- LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent );
- }
- else if(message_name == "show_web_inspector")
- {
-#if LLQTWEBKIT_API_VERSION >= 10
- bool val = message_in.getValueBoolean("show");
- LLQtWebKit::getInstance()->showWebInspector( val );
-#else
- llwarns << "Ignoring showWebInspector message (llqtwebkit version is too old)." << llendl;
-#endif
- }
- else if(message_name == "ignore_ssl_cert_errors")
- {
-#if LLQTWEBKIT_API_VERSION >= 3
- LLQtWebKit::getInstance()->setIgnoreSSLCertErrors( message_in.getValueBoolean("ignore") );
-#else
- llwarns << "Ignoring ignore_ssl_cert_errors message (llqtwebkit version is too old)." << llendl;
-#endif
- }
- else if(message_name == "add_certificate_file_path")
- {
-#if LLQTWEBKIT_API_VERSION >= 6
- LLQtWebKit::getInstance()->setCAFile( message_in.getValue("path") );
-#else
- llwarns << "Ignoring add_certificate_file_path message (llqtwebkit version is too old)." << llendl;
-#endif
- }
- else if(message_name == "init_history")
- {
- // Initialize browser history
- LLSD history = message_in.getValueLLSD("history");
- // First, clear the URL history
- LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId);
- // Then, add the history items in order
- LLSD::array_iterator iter_history = history.beginArray();
- LLSD::array_iterator end_history = history.endArray();
- for(; iter_history != end_history; ++iter_history)
- {
- std::string url = (*iter_history).asString();
- if(! url.empty()) {
- LLQtWebKit::getInstance()->prependHistoryUrl(mBrowserWindowId, url);
- }
- }
- }
- else if(message_name == "proxy_window_opened")
- {
- std::string target = message_in.getValue("target");
- std::string uuid = message_in.getValue("uuid");
- LLQtWebKit::getInstance()->proxyWindowOpened(mBrowserWindowId, target, uuid);
- }
- else if(message_name == "proxy_window_closed")
- {
- std::string uuid = message_in.getValue("uuid");
- LLQtWebKit::getInstance()->proxyWindowClosed(mBrowserWindowId, uuid);
- }
- else
- {
-// std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl;
- };
- }
- else
- {
-// std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl;
- };
- }
-}
-
-void MediaPluginWebKit::setVolume(F32 volume)
-{
- mVolumeCatcher.setVolume(volume);
-}
-
-int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
-{
- MediaPluginWebKit *self = new MediaPluginWebKit(host_send_func, host_user_data);
- *plugin_send_func = MediaPluginWebKit::staticReceiveMessage;
- *plugin_user_data = (void*)self;
-
- return 0;
-}
-
-
+/** + * @file media_plugin_webkit.cpp + * @brief Webkit plugin for LLMedia API plugin system + * + * @cond + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + * @endcond + */ + +#include "llqtwebkit.h" + +#include "linden_common.h" +#include "indra_constants.h" // for indra keyboard codes + +#include "llgl.h" + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" +#include "media_plugin_base.h" + +// set to 1 if you're using the version of llqtwebkit that's QPixmap-ified +#if LL_LINUX +# define LL_QTWEBKIT_USES_PIXMAPS 0 +extern "C" { +# include <glib.h> +# include <glib-object.h> +} +#else +# define LL_QTWEBKIT_USES_PIXMAPS 0 +#endif // LL_LINUX + +# include "volume_catcher.h" + +#if LL_WINDOWS +# include <direct.h> +#else +# include <unistd.h> +# include <stdlib.h> +#endif + +#if LL_WINDOWS + // *NOTE:Mani - This captures the module handle for the dll. This is used below + // to get the path to this dll for webkit initialization. + // I don't know how/if this can be done with apr... + namespace { HMODULE gModuleHandle;}; + BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) + { + gModuleHandle = (HMODULE) hinstDLL; + return TRUE; + } +#endif + +//////////////////////////////////////////////////////////////////////////////// +// +class MediaPluginWebKit : + public MediaPluginBase, + public LLEmbeddedBrowserWindowObserver +{ +public: + MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~MediaPluginWebKit(); + + /*virtual*/ void receiveMessage(const char *message_string); + +private: + + std::string mProfileDir; + std::string mHostLanguage; + std::string mUserAgent; + bool mCookiesEnabled; + bool mJavascriptEnabled; + bool mPluginsEnabled; + bool mEnableMediaPluginDebugging; + + enum + { + INIT_STATE_UNINITIALIZED, // LLQtWebkit hasn't been set up yet + INIT_STATE_INITIALIZED, // LLQtWebkit has been set up, but no browser window has been created yet. + INIT_STATE_NAVIGATING, // Browser instance has been set up and initial navigate to about:blank has been issued + INIT_STATE_NAVIGATE_COMPLETE, // initial navigate to about:blank has completed + INIT_STATE_WAIT_REDRAW, // First real navigate begin has been received, waiting for page changed event to start handling redraws + INIT_STATE_WAIT_COMPLETE, // Waiting for first real navigate complete event + INIT_STATE_RUNNING // All initialization gymnastics are complete. + }; + int mBrowserWindowId; + int mInitState; + std::string mInitialNavigateURL; + bool mNeedsUpdate; + + bool mCanCut; + bool mCanCopy; + bool mCanPaste; + int mLastMouseX; + int mLastMouseY; + bool mFirstFocus; + F32 mBackgroundR; + F32 mBackgroundG; + F32 mBackgroundB; + std::string mTarget; + + VolumeCatcher mVolumeCatcher; + + void postDebugMessage( const std::string& msg ) + { + if ( mEnableMediaPluginDebugging ) + { + LLPluginMessage debug_message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "debug_message"); + debug_message.setValue("message_text", "Media> " + msg); + debug_message.setValue("message_level", "info"); + sendMessage(debug_message); + } + } + + void setInitState(int state) + { +// std::cerr << "changing init state to " << state << std::endl; + mInitState = state; + } + + //////////////////////////////////////////////////////////////////////////////// + // + void update(int milliseconds) + { +#if LL_QTLINUX_DOESNT_HAVE_GLIB + // pump glib generously, as Linux browser plugins are on the + // glib main loop, even if the browser itself isn't - ugh + // This is NOT NEEDED if Qt itself was built with glib + // mainloop integration. + GMainContext *mainc = g_main_context_default(); + while(g_main_context_iteration(mainc, FALSE)); +#endif // LL_QTLINUX_DOESNT_HAVE_GLIB + + // pump qt + LLQtWebKit::getInstance()->pump( milliseconds ); + + mVolumeCatcher.pump(); + + checkEditState(); + + if(mInitState == INIT_STATE_NAVIGATE_COMPLETE) + { + if(!mInitialNavigateURL.empty()) + { + // We already have the initial navigate URL -- kick off the navigate. + LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, mInitialNavigateURL ); + mInitialNavigateURL.clear(); + } + } + + if ( (mInitState > INIT_STATE_WAIT_REDRAW) && mNeedsUpdate ) + { + const unsigned char* browser_pixels = LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId ); + + unsigned int rowspan = LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId ); + unsigned int height = LLQtWebKit::getInstance()->getBrowserHeight( mBrowserWindowId ); +#if !LL_QTWEBKIT_USES_PIXMAPS + unsigned int buffer_size = rowspan * height; +#endif // !LL_QTWEBKIT_USES_PIXMAPS + +// std::cerr << "webkit plugin: updating" << std::endl; + + // TODO: should get rid of this memcpy if possible + if ( mPixels && browser_pixels ) + { +// std::cerr << " memcopy of " << buffer_size << " bytes" << std::endl; + +#if LL_QTWEBKIT_USES_PIXMAPS + // copy the pixel data upside-down because of the co-ord system + for (int y=0; y<height; ++y) + { + memcpy( &mPixels[(height-y-1)*rowspan], &browser_pixels[y*rowspan], rowspan ); + } +#else + memcpy( mPixels, browser_pixels, buffer_size ); +#endif // LL_QTWEBKIT_USES_PIXMAPS + } + + if ( mWidth > 0 && mHeight > 0 ) + { +// std::cerr << "Setting dirty, " << mWidth << " x " << mHeight << std::endl; + setDirty( 0, 0, mWidth, mHeight ); + } + + mNeedsUpdate = false; + }; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + bool initBrowser() + { + // already initialized + if ( mInitState > INIT_STATE_UNINITIALIZED ) + return true; + + // set up directories + char cwd[ FILENAME_MAX ]; // I *think* this is defined on all platforms we use + if (NULL == getcwd( cwd, FILENAME_MAX - 1 )) + { + llwarns << "Couldn't get cwd - probably too long - failing to init." << llendl; + return false; + } + std::string application_dir = std::string( cwd ); + +#if LL_LINUX + // take care to initialize glib properly, because some + // versions of Qt don't, and we indirectly need it for (some + // versions of) Flash to not crash the browser. + if (!g_thread_supported ()) g_thread_init (NULL); + g_type_init(); +#endif + +#if LL_DARWIN + // When running under the Xcode debugger, there's a setting called "Break on Debugger()/DebugStr()" which defaults to being turned on. + // This causes the environment variable USERBREAK to be set to 1, which causes these legacy calls to break into the debugger. + // This wouldn't cause any problems except for the fact that the current release version of the Flash plugin has a call to Debugger() in it + // which gets hit when the plugin is probed by webkit. + // Unsetting the environment variable here works around this issue. + unsetenv("USERBREAK"); +#endif + +#if LL_WINDOWS + //*NOTE:Mani - On windows, at least, the component path is the + // location of this dll's image file. + std::string component_dir; + char dll_path[_MAX_PATH]; + DWORD len = GetModuleFileNameA(gModuleHandle, (LPCH)&dll_path, _MAX_PATH); + while(len && dll_path[ len ] != ('\\') ) + { + len--; + } + if(len >= 0) + { + dll_path[len] = 0; + component_dir = dll_path; + } + else + { + // *NOTE:Mani - This case should be an rare exception. + // GetModuleFileNameA should always give you a full path, no? + component_dir = application_dir; + } +#else + std::string component_dir = application_dir; +#endif + + // debug spam sent to viewer and displayed in the log as usual + postDebugMessage( "Component dir set to: " + component_dir ); + + // window handle - needed on Windows and must be app window. +#if LL_WINDOWS + char window_title[ MAX_PATH ]; + GetConsoleTitleA( window_title, MAX_PATH ); + void* native_window_handle = (void*)FindWindowA( NULL, window_title ); +#else + void* native_window_handle = 0; +#endif + + // main browser initialization + bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, mProfileDir, native_window_handle ); + if ( result ) + { + mInitState = INIT_STATE_INITIALIZED; + + // debug spam sent to viewer and displayed in the log as usual + postDebugMessage( "browser initialized okay" ); + + return true; + }; + + // debug spam sent to viewer and displayed in the log as usual + postDebugMessage( "browser nOT initialized." ); + + return false; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + bool initBrowserWindow() + { + // already initialized + if ( mInitState > INIT_STATE_INITIALIZED ) + return true; + + // not enough information to initialize the browser yet. + if ( mWidth < 0 || mHeight < 0 || mDepth < 0 || + mTextureWidth < 0 || mTextureHeight < 0 ) + { + return false; + }; + + // Set up host language before creating browser window + if(!mHostLanguage.empty()) + { + LLQtWebKit::getInstance()->setHostLanguage(mHostLanguage); + postDebugMessage( "Setting language to " + mHostLanguage ); + } + + // turn on/off cookies based on what host app tells us + LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled ); + + // turn on/off plugins based on what host app tells us + LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled ); + + // turn on/off Javascript based on what host app tells us + LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled ); + + std::stringstream str; + str << "Cookies enabled = " << mCookiesEnabled << ", plugins enabled = " << mPluginsEnabled << ", Javascript enabled = " << mJavascriptEnabled; + postDebugMessage( str.str() ); + + // create single browser window + mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight, mTarget); + + str.str(""); + str.clear(); + str << "Setting browser window size to " << mWidth << " x " << mHeight; + postDebugMessage( str.str() ); + + // tell LLQtWebKit about the size of the browser window + LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); + + // observer events that LLQtWebKit emits + LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this ); + + // append details to agent string + LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent ); + postDebugMessage( "Updating user agent with " + mUserAgent ); + +#if !LL_QTWEBKIT_USES_PIXMAPS + // don't flip bitmap + LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true ); +#endif // !LL_QTWEBKIT_USES_PIXMAPS + + // set background color + // convert background color channels from [0.0, 1.0] to [0, 255]; + LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, int(mBackgroundR * 255.0f), int(mBackgroundG * 255.0f), int(mBackgroundB * 255.0f) ); + + // Set state _before_ starting the navigate, since onNavigateBegin might get called before this call returns. + setInitState(INIT_STATE_NAVIGATING); + + // Don't do this here -- it causes the dreaded "white flash" when loading a browser instance. + // FIXME: Re-added this because navigating to a "page" initializes things correctly - especially + // for the HTTP AUTH dialog issues (DEV-41731). Will fix at a later date. + // Build a data URL like this: "data:text/html,%3Chtml%3E%3Cbody bgcolor=%22#RRGGBB%22%3E%3C/body%3E%3C/html%3E" + // where RRGGBB is the background color in HTML style + std::stringstream url; + + url << "data:text/html,%3Chtml%3E%3Cbody%20bgcolor=%22#"; + // convert background color channels from [0.0, 1.0] to [0, 255]; + url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundR * 255.0f); + url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundG * 255.0f); + url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundB * 255.0f); + url << "%22%3E%3C/body%3E%3C/html%3E"; + + //lldebugs << "data url is: " << url.str() << llendl; + + LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, url.str() ); +// LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" ); + + return true; + } + + void setVolume(F32 vol); + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onCursorChanged(const EventType& event) + { + LLQtWebKit::ECursor llqt_cursor = (LLQtWebKit::ECursor)event.getIntValue(); + std::string name; + + switch(llqt_cursor) + { + case LLQtWebKit::C_ARROW: + name = "arrow"; + break; + case LLQtWebKit::C_IBEAM: + name = "ibeam"; + break; + case LLQtWebKit::C_SPLITV: + name = "splitv"; + break; + case LLQtWebKit::C_SPLITH: + name = "splith"; + break; + case LLQtWebKit::C_POINTINGHAND: + name = "hand"; + break; + + default: + llwarns << "Unknown cursor ID: " << (int)llqt_cursor << llendl; + break; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed"); + message.setValue("name", name); + sendMessage(message); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onPageChanged( const EventType& event ) + { + if(mInitState == INIT_STATE_WAIT_REDRAW) + { + setInitState(INIT_STATE_WAIT_COMPLETE); + } + + // flag that an update is required + mNeedsUpdate = true; + }; + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onNavigateBegin(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin"); + message.setValue("uri", event.getEventUri()); + message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK)); + message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD)); + sendMessage(message); + + // debug spam sent to viewer and displayed in the log as usual + postDebugMessage( "Navigate begin event at: " + event.getEventUri() ); + + setStatus(STATUS_LOADING); + } + + if(mInitState == INIT_STATE_NAVIGATE_COMPLETE) + { + // Skip the WAIT_REDRAW state now -- with the right background color set, it should no longer be necessary. +// setInitState(INIT_STATE_WAIT_REDRAW); + setInitState(INIT_STATE_WAIT_COMPLETE); + } + + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onNavigateComplete(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + if(mInitState < INIT_STATE_RUNNING) + { + setInitState(INIT_STATE_RUNNING); + + // Clear the history, so the "back" button doesn't take you back to "about:blank". + LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId); + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete"); + message.setValue("uri", event.getEventUri()); + message.setValueS32("result_code", event.getIntValue()); + message.setValue("result_string", event.getStringValue()); + message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK)); + message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD)); + sendMessage(message); + + setStatus(STATUS_LOADED); + } + else if(mInitState == INIT_STATE_NAVIGATING) + { + setInitState(INIT_STATE_NAVIGATE_COMPLETE); + } + + // debug spam sent to viewer and displayed in the log as usual + postDebugMessage( "Navigate complete event at: " + event.getEventUri() ); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onUpdateProgress(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "progress"); + message.setValueS32("percent", event.getIntValue()); + sendMessage(message); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onStatusTextChange(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text"); + message.setValue("status", event.getStringValue()); + sendMessage(message); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onTitleChange(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); + message.setValue("name", event.getStringValue()); + sendMessage(message); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onNavigateErrorPage(const EventType& event) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_error_page"); + message.setValueS32("status_code", event.getIntValue()); + sendMessage(message); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onLocationChange(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed"); + message.setValue("uri", event.getEventUri()); + sendMessage(message); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onClickLinkHref(const EventType& event) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href"); + message.setValue("uri", event.getEventUri()); + message.setValue("target", event.getStringValue()); + message.setValue("uuid", event.getStringValue2()); + sendMessage(message); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onClickLinkNoFollow(const EventType& event) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow"); + message.setValue("uri", event.getEventUri()); +#if LLQTWEBKIT_API_VERSION >= 7 + message.setValue("nav_type", event.getNavigationType()); +#else + message.setValue("nav_type", "clicked"); +#endif + sendMessage(message); + } + + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onCookieChanged(const EventType& event) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "cookie_set"); + message.setValue("cookie", event.getStringValue()); + // These could be passed through as well, but aren't really needed. +// message.setValue("uri", event.getEventUri()); +// message.setValueBoolean("dead", (event.getIntValue() != 0)) + sendMessage(message); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onWindowCloseRequested(const EventType& event) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "close_request"); + message.setValue("uuid", event.getStringValue()); + sendMessage(message); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onWindowGeometryChangeRequested(const EventType& event) + { + int x, y, width, height; + event.getRectValue(x, y, width, height); + + // This sometimes gets called with a zero-size request. Don't pass these along. + if(width > 0 && height > 0) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "geometry_change"); + message.setValue("uuid", event.getStringValue()); + message.setValueS32("x", x); + message.setValueS32("y", y); + message.setValueS32("width", width); + message.setValueS32("height", height); + sendMessage(message); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + std::string onRequestFilePicker( const EventType& eventIn ) + { + return blockingPickFile(); + } + + std::string mAuthUsername; + std::string mAuthPassword; + bool mAuthOK; + + //////////////////////////////////////////////////////////////////////////////// + // virtual + bool onAuthRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password) + { + mAuthOK = false; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_request"); + message.setValue("url", in_url); + message.setValue("realm", in_realm); + message.setValueBoolean("blocking_request", true); + + // The "blocking_request" key in the message means this sendMessage call will block until a response is received. + sendMessage(message); + + if(mAuthOK) + { + out_username = mAuthUsername; + out_password = mAuthPassword; + } + + return mAuthOK; + } + + void authResponse(LLPluginMessage &message) + { + mAuthOK = message.getValueBoolean("ok"); + if(mAuthOK) + { + mAuthUsername = message.getValue("username"); + mAuthPassword = message.getValue("password"); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onLinkHovered(const EventType& event) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "link_hovered"); + message.setValue("link", event.getEventUri()); + message.setValue("title", event.getStringValue()); + message.setValue("text", event.getStringValue2()); + sendMessage(message); + } + } + + LLQtWebKit::EKeyboardModifier decodeModifiers(std::string &modifiers) + { + int result = 0; + + if(modifiers.find("shift") != std::string::npos) + result |= LLQtWebKit::KM_MODIFIER_SHIFT; + + if(modifiers.find("alt") != std::string::npos) + result |= LLQtWebKit::KM_MODIFIER_ALT; + + if(modifiers.find("control") != std::string::npos) + result |= LLQtWebKit::KM_MODIFIER_CONTROL; + + if(modifiers.find("meta") != std::string::npos) + result |= LLQtWebKit::KM_MODIFIER_META; + + return (LLQtWebKit::EKeyboardModifier)result; + } + + //////////////////////////////////////////////////////////////////////////////// + // + void deserializeKeyboardData( LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers ) + { + native_scan_code = 0; + native_virtual_key = 0; + native_modifiers = 0; + + if( native_key_data.isMap() ) + { +#if LL_DARWIN + native_scan_code = (uint32_t)(native_key_data["char_code"].asInteger()); + native_virtual_key = (uint32_t)(native_key_data["key_code"].asInteger()); + native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger()); +#elif LL_WINDOWS + native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger()); + native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger()); + // TODO: I don't think we need to do anything with native modifiers here -- please verify +#elif LL_LINUX + native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger()); + native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger()); + native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger()); +#else + // Add other platforms here as needed +#endif + }; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void keyEvent(LLQtWebKit::EKeyEvent key_event, int key, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap()) + { + // The incoming values for 'key' will be the ones from indra_constants.h + std::string utf8_text; + + if(key < KEY_SPECIAL) + { + // Low-ascii characters need to get passed through. + utf8_text = (char)key; + } + + // Any special-case handling we want to do for particular keys... + switch((KEY)key) + { + // ASCII codes for some standard keys + case LLQtWebKit::KEY_BACKSPACE: utf8_text = (char)8; break; + case LLQtWebKit::KEY_TAB: utf8_text = (char)9; break; + case LLQtWebKit::KEY_RETURN: utf8_text = (char)13; break; + case LLQtWebKit::KEY_PAD_RETURN: utf8_text = (char)13; break; + case LLQtWebKit::KEY_ESCAPE: utf8_text = (char)27; break; + + default: + break; + } + +// std::cerr << "key event " << (int)key_event << ", native_key_data = " << native_key_data << std::endl; + + uint32_t native_scan_code = 0; + uint32_t native_virtual_key = 0; + uint32_t native_modifiers = 0; + deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers ); + + LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, key_event, (uint32_t)key, utf8_text.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); + + checkEditState(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void unicodeInput( const std::string &utf8str, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap()) + { + uint32_t key = LLQtWebKit::KEY_NONE; + +// std::cerr << "unicode input, native_key_data = " << native_key_data << std::endl; + + if(utf8str.size() == 1) + { + // The only way a utf8 string can be one byte long is if it's actually a single 7-bit ascii character. + // In this case, use it as the key value. + key = utf8str[0]; + } + + uint32_t native_scan_code = 0; + uint32_t native_virtual_key = 0; + uint32_t native_modifiers = 0; + deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers ); + + LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_DOWN, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); + LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_UP, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); + + checkEditState(); + }; + + void checkEditState(void) + { + bool can_cut = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT); + bool can_copy = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY); + bool can_paste = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE); + + if((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste)) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state"); + + if(can_cut != mCanCut) + { + mCanCut = can_cut; + message.setValueBoolean("cut", can_cut); + } + + if(can_copy != mCanCopy) + { + mCanCopy = can_copy; + message.setValueBoolean("copy", can_copy); + } + + if(can_paste != mCanPaste) + { + mCanPaste = can_paste; + message.setValueBoolean("paste", can_paste); + } + + sendMessage(message); + + } + } + + std::string mPickedFile; + + std::string blockingPickFile(void) + { + mPickedFile.clear(); + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file"); + message.setValueBoolean("blocking_request", true); + + // The "blocking_request" key in the message means this sendMessage call will block until a response is received. + sendMessage(message); + + return mPickedFile; + } + + void onPickFileResponse(const std::string &file) + { + mPickedFile = file; + } + +}; + +MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) : + MediaPluginBase(host_send_func, host_user_data) +{ +// std::cerr << "MediaPluginWebKit constructor" << std::endl; + + mBrowserWindowId = 0; + mInitState = INIT_STATE_UNINITIALIZED; + mNeedsUpdate = true; + mCanCut = false; + mCanCopy = false; + mCanPaste = false; + mLastMouseX = 0; + mLastMouseY = 0; + mFirstFocus = true; + mBackgroundR = 0.0f; + mBackgroundG = 0.0f; + mBackgroundB = 0.0f; + + mHostLanguage = "en"; // default to english + mJavascriptEnabled = true; // default to on + mPluginsEnabled = true; // default to on + mEnableMediaPluginDebugging = false; + mUserAgent = "LLPluginMedia Web Browser"; +} + +MediaPluginWebKit::~MediaPluginWebKit() +{ + // unhook observer + LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this ); + + // clean up + LLQtWebKit::getInstance()->reset(); + +// std::cerr << "MediaPluginWebKit destructor" << std::endl; +} + +void MediaPluginWebKit::receiveMessage(const char *message_string) +{ +// std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl; + LLPluginMessage message_in; + + if(message_in.parse(message_string) >= 0) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) + { + if(message_name == "init") + { + LLPluginMessage message("base", "init_response"); + LLSD versions = LLSD::emptyMap(); + versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; + message.setValueLLSD("versions", versions); + + std::string plugin_version = "Webkit media plugin, Webkit version "; + plugin_version += LLQtWebKit::getInstance()->getVersion(); + message.setValue("plugin_version", plugin_version); + sendMessage(message); + } + else if(message_name == "idle") + { + // no response is necessary here. + F64 time = message_in.getValueReal("time"); + + // Convert time to milliseconds for update() + update((int)(time * 1000.0f)); + } + else if(message_name == "cleanup") + { + // DTOR most likely won't be called but the recent change to the way this process + // is (not) killed means we see this message and can do what we need to here. + // Note: this cleanup is ultimately what writes cookies to the disk + LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this ); + LLQtWebKit::getInstance()->reset(); + } + else if(message_name == "shm_added") + { + SharedSegmentInfo info; + info.mAddress = message_in.getValuePointer("address"); + info.mSize = (size_t)message_in.getValueS32("size"); + std::string name = message_in.getValue("name"); + +// std::cerr << "MediaPluginWebKit::receiveMessage: shared memory added, name: " << name +// << ", size: " << info.mSize +// << ", address: " << info.mAddress +// << std::endl; + + mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); + + } + else if(message_name == "shm_remove") + { + std::string name = message_in.getValue("name"); + +// std::cerr << "MediaPluginWebKit::receiveMessage: shared memory remove, name = " << name << std::endl; + + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + if(mPixels == iter->second.mAddress) + { + // This is the currently active pixel buffer. Make sure we stop drawing to it. + mPixels = NULL; + mTextureSegmentName.clear(); + } + mSharedSegments.erase(iter); + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl; + } + + // Send the response so it can be cleaned up. + LLPluginMessage message("base", "shm_remove_response"); + message.setValue("name", name); + sendMessage(message); + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) + { + if(message_name == "set_volume") + { + F32 volume = message_in.getValueReal("volume"); + setVolume(volume); + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + if(message_name == "init") + { + mTarget = message_in.getValue("target"); + + // This is the media init message -- all necessary data for initialization should have been received. + if(initBrowser()) + { + + // Plugin gets to decide the texture parameters to use. + mDepth = 4; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); + message.setValueS32("default_width", 1024); + message.setValueS32("default_height", 1024); + message.setValueS32("depth", mDepth); + message.setValueU32("internalformat", GL_RGBA); + #if LL_QTWEBKIT_USES_PIXMAPS + message.setValueU32("format", GL_BGRA_EXT); // I hope this isn't system-dependant... is it? If so, we'll have to check the root window's pixel layout or something... yuck. + #else + message.setValueU32("format", GL_RGBA); + #endif // LL_QTWEBKIT_USES_PIXMAPS + message.setValueU32("type", GL_UNSIGNED_BYTE); + message.setValueBoolean("coords_opengl", true); + sendMessage(message); + } + else + { + // if initialization failed, we're done. + mDeleteMe = true; + } + + } + else if(message_name == "set_user_data_path") + { + std::string user_data_path = message_in.getValue("path"); // n.b. always has trailing platform-specific dir-delimiter + mProfileDir = user_data_path + "browser_profile"; + + // FIXME: Should we do anything with this if it comes in after the browser has been initialized? + } + else if(message_name == "set_language_code") + { + mHostLanguage = message_in.getValue("language"); + + // FIXME: Should we do anything with this if it comes in after the browser has been initialized? + } + else if(message_name == "plugins_enabled") + { + mPluginsEnabled = message_in.getValueBoolean("enable"); + } + else if(message_name == "javascript_enabled") + { + mJavascriptEnabled = message_in.getValueBoolean("enable"); + } + else if(message_name == "size_change") + { + std::string name = message_in.getValue("name"); + S32 width = message_in.getValueS32("width"); + S32 height = message_in.getValueS32("height"); + S32 texture_width = message_in.getValueS32("texture_width"); + S32 texture_height = message_in.getValueS32("texture_height"); + mBackgroundR = message_in.getValueReal("background_r"); + mBackgroundG = message_in.getValueReal("background_g"); + mBackgroundB = message_in.getValueReal("background_b"); +// mBackgroundA = message_in.setValueReal("background_a"); // Ignore any alpha + + if(!name.empty()) + { + // Find the shared memory region with this name + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + mPixels = (unsigned char*)iter->second.mAddress; + mWidth = width; + mHeight = height; + + if(initBrowserWindow()) + { + + // size changed so tell the browser + LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); + + // std::cerr << "webkit plugin: set size to " << mWidth << " x " << mHeight + // << ", rowspan is " << LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) << std::endl; + + S32 real_width = LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) / LLQtWebKit::getInstance()->getBrowserDepth(mBrowserWindowId); + + // The actual width the browser will be drawing to is probably smaller... let the host know by modifying texture_width in the response. + if(real_width <= texture_width) + { + texture_width = real_width; + } + else + { + // This won't work -- it'll be bigger than the allocated memory. This is a fatal error. + // std::cerr << "Fatal error: browser rowbytes greater than texture width" << std::endl; + mDeleteMe = true; + return; + } + } + else + { + // Setting up the browser window failed. This is a fatal error. + mDeleteMe = true; + } + + + mTextureWidth = texture_width; + mTextureHeight = texture_height; + + }; + }; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); + message.setValue("name", name); + message.setValueS32("width", width); + message.setValueS32("height", height); + message.setValueS32("texture_width", texture_width); + message.setValueS32("texture_height", texture_height); + sendMessage(message); + + } + else if(message_name == "load_uri") + { + std::string uri = message_in.getValue("uri"); + +// std::cout << "loading URI: " << uri << std::endl; + + if(!uri.empty()) + { + if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) + { + LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, uri ); + } + else + { + mInitialNavigateURL = uri; + } + } + } + else if(message_name == "mouse_event") + { + std::string event = message_in.getValue("event"); + S32 button = message_in.getValueS32("button"); + mLastMouseX = message_in.getValueS32("x"); + mLastMouseY = message_in.getValueS32("y"); + std::string modifiers = message_in.getValue("modifiers"); + + // Treat unknown mouse events as mouse-moves. + LLQtWebKit::EMouseEvent mouse_event = LLQtWebKit::ME_MOUSE_MOVE; + if(event == "down") + { + mouse_event = LLQtWebKit::ME_MOUSE_DOWN; + } + else if(event == "up") + { + mouse_event = LLQtWebKit::ME_MOUSE_UP; + } + else if(event == "double_click") + { + mouse_event = LLQtWebKit::ME_MOUSE_DOUBLE_CLICK; + } + + LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, mouse_event, button, mLastMouseX, mLastMouseY, decodeModifiers(modifiers)); + checkEditState(); + } + else if(message_name == "scroll_event") + { + S32 x = message_in.getValueS32("x"); + S32 y = message_in.getValueS32("y"); + std::string modifiers = message_in.getValue("modifiers"); + + // Incoming scroll events are adjusted so that 1 detent is approximately 1 unit. + // Qt expects 1 detent to be 120 units. + // It also seems that our y scroll direction is inverted vs. what Qt expects. + + x *= 120; + y *= -120; + + LLQtWebKit::getInstance()->scrollWheelEvent(mBrowserWindowId, mLastMouseX, mLastMouseY, x, y, decodeModifiers(modifiers)); + } + else if(message_name == "key_event") + { + std::string event = message_in.getValue("event"); + S32 key = message_in.getValueS32("key"); + std::string modifiers = message_in.getValue("modifiers"); + LLSD native_key_data = message_in.getValueLLSD("native_key_data"); + + // Treat unknown events as key-up for safety. + LLQtWebKit::EKeyEvent key_event = LLQtWebKit::KE_KEY_UP; + if(event == "down") + { + key_event = LLQtWebKit::KE_KEY_DOWN; + } + else if(event == "repeat") + { + key_event = LLQtWebKit::KE_KEY_REPEAT; + } + + keyEvent(key_event, key, decodeModifiers(modifiers), native_key_data); + } + else if(message_name == "text_event") + { + std::string text = message_in.getValue("text"); + std::string modifiers = message_in.getValue("modifiers"); + LLSD native_key_data = message_in.getValueLLSD("native_key_data"); + + unicodeInput(text, decodeModifiers(modifiers), native_key_data); + } + if(message_name == "edit_cut") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT ); + checkEditState(); + } + if(message_name == "edit_copy") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY ); + checkEditState(); + } + if(message_name == "edit_paste") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE ); + checkEditState(); + } + if(message_name == "pick_file_response") + { + onPickFileResponse(message_in.getValue("file")); + } + if(message_name == "auth_response") + { + authResponse(message_in); + } + else + if(message_name == "enable_media_plugin_debugging") + { + mEnableMediaPluginDebugging = message_in.getValueBoolean( "enable" ); + } + + else + if(message_name == "js_enable_object") + { +#if LLQTWEBKIT_API_VERSION >= 9 + bool enable = message_in.getValueBoolean( "enable" ); + LLQtWebKit::getInstance()->setSLObjectEnabled( enable ); +#endif + } + else + if(message_name == "js_agent_location") + { +#if LLQTWEBKIT_API_VERSION >= 9 + F32 x = message_in.getValueReal("x"); + F32 y = message_in.getValueReal("y"); + F32 z = message_in.getValueReal("z"); + LLQtWebKit::getInstance()->setAgentLocation( x, y, z ); + LLQtWebKit::getInstance()->emitLocation(); +#endif + } + else + if(message_name == "js_agent_global_location") + { +#if LLQTWEBKIT_API_VERSION >= 9 + F32 x = message_in.getValueReal("x"); + F32 y = message_in.getValueReal("y"); + F32 z = message_in.getValueReal("z"); + LLQtWebKit::getInstance()->setAgentGlobalLocation( x, y, z ); + LLQtWebKit::getInstance()->emitLocation(); +#endif + } + else + if(message_name == "js_agent_orientation") + { +#if LLQTWEBKIT_API_VERSION >= 9 + F32 angle = message_in.getValueReal("angle"); + LLQtWebKit::getInstance()->setAgentOrientation( angle ); + LLQtWebKit::getInstance()->emitLocation(); +#endif + } + else + if(message_name == "js_agent_region") + { +#if LLQTWEBKIT_API_VERSION >= 9 + const std::string& region = message_in.getValue("region"); + LLQtWebKit::getInstance()->setAgentRegion( region ); + LLQtWebKit::getInstance()->emitLocation(); +#endif + } + else + if(message_name == "js_agent_maturity") + { +#if LLQTWEBKIT_API_VERSION >= 9 + const std::string& maturity = message_in.getValue("maturity"); + LLQtWebKit::getInstance()->setAgentMaturity( maturity ); + LLQtWebKit::getInstance()->emitMaturity(); +#endif + } + else + if(message_name == "js_agent_language") + { +#if LLQTWEBKIT_API_VERSION >= 9 + const std::string& language = message_in.getValue("language"); + LLQtWebKit::getInstance()->setAgentLanguage( language ); + LLQtWebKit::getInstance()->emitLanguage(); +#endif + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) + { + if(message_name == "focus") + { + bool val = message_in.getValueBoolean("focused"); + LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, val ); + + if(mFirstFocus && val) + { + // On the first focus, post a tab key event. This fixes a problem with initial focus. + std::string empty; + keyEvent(LLQtWebKit::KE_KEY_DOWN, KEY_TAB, decodeModifiers(empty)); + keyEvent(LLQtWebKit::KE_KEY_UP, KEY_TAB, decodeModifiers(empty)); + mFirstFocus = false; + } + } + else if(message_name == "clear_cache") + { + LLQtWebKit::getInstance()->clearCache(); + } + else if(message_name == "clear_cookies") + { + LLQtWebKit::getInstance()->clearAllCookies(); + } + else if(message_name == "enable_cookies") + { + mCookiesEnabled = message_in.getValueBoolean("enable"); + LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled ); + } + else if(message_name == "enable_plugins") + { + mPluginsEnabled = message_in.getValueBoolean("enable"); + LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled ); + } + else if(message_name == "enable_javascript") + { + mJavascriptEnabled = message_in.getValueBoolean("enable"); + //LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled ); + } + else if(message_name == "set_cookies") + { + LLQtWebKit::getInstance()->setCookies(message_in.getValue("cookies")); + } + else if(message_name == "proxy_setup") + { + bool val = message_in.getValueBoolean("enable"); + std::string host = message_in.getValue("host"); + int port = message_in.getValueS32("port"); + LLQtWebKit::getInstance()->enableProxy( val, host, port ); + } + else if(message_name == "browse_stop") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_STOP ); + } + else if(message_name == "browse_reload") + { + // foo = message_in.getValueBoolean("ignore_cache"); + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD ); + } + else if(message_name == "browse_forward") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD ); + } + else if(message_name == "browse_back") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK ); + } + else if(message_name == "set_status_redirect") + { + int code = message_in.getValueS32("code"); + std::string url = message_in.getValue("url"); + if ( 404 == code ) // browser lib only supports 404 right now + { +#if LLQTWEBKIT_API_VERSION < 8 + LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url ); +#endif + }; + } + else if(message_name == "set_user_agent") + { + mUserAgent = message_in.getValue("user_agent"); + LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent ); + } + else if(message_name == "show_web_inspector") + { +#if LLQTWEBKIT_API_VERSION >= 10 + bool val = message_in.getValueBoolean("show"); + LLQtWebKit::getInstance()->showWebInspector( val ); +#else + llwarns << "Ignoring showWebInspector message (llqtwebkit version is too old)." << llendl; +#endif + } + else if(message_name == "ignore_ssl_cert_errors") + { +#if LLQTWEBKIT_API_VERSION >= 3 + LLQtWebKit::getInstance()->setIgnoreSSLCertErrors( message_in.getValueBoolean("ignore") ); +#else + llwarns << "Ignoring ignore_ssl_cert_errors message (llqtwebkit version is too old)." << llendl; +#endif + } + else if(message_name == "add_certificate_file_path") + { +#if LLQTWEBKIT_API_VERSION >= 6 + LLQtWebKit::getInstance()->setCAFile( message_in.getValue("path") ); +#else + llwarns << "Ignoring add_certificate_file_path message (llqtwebkit version is too old)." << llendl; +#endif + } + else if(message_name == "init_history") + { + // Initialize browser history + LLSD history = message_in.getValueLLSD("history"); + // First, clear the URL history + LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId); + // Then, add the history items in order + LLSD::array_iterator iter_history = history.beginArray(); + LLSD::array_iterator end_history = history.endArray(); + for(; iter_history != end_history; ++iter_history) + { + std::string url = (*iter_history).asString(); + if(! url.empty()) { + LLQtWebKit::getInstance()->prependHistoryUrl(mBrowserWindowId, url); + } + } + } + else if(message_name == "proxy_window_opened") + { + std::string target = message_in.getValue("target"); + std::string uuid = message_in.getValue("uuid"); + LLQtWebKit::getInstance()->proxyWindowOpened(mBrowserWindowId, target, uuid); + } + else if(message_name == "proxy_window_closed") + { + std::string uuid = message_in.getValue("uuid"); + LLQtWebKit::getInstance()->proxyWindowClosed(mBrowserWindowId, uuid); + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl; + }; + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl; + }; + } +} + +void MediaPluginWebKit::setVolume(F32 volume) +{ + mVolumeCatcher.setVolume(volume); +} + +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + MediaPluginWebKit *self = new MediaPluginWebKit(host_send_func, host_user_data); + *plugin_send_func = MediaPluginWebKit::staticReceiveMessage; + *plugin_user_data = (void*)self; + + return 0; +} + + diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index a0af94ba77..3cb9b77010 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -2285,8 +2285,8 @@ void LLAppearanceMgr::autopopulateOutfits() void LLAppearanceMgr::onFirstFullyVisible() { gAgentAvatarp->debugAvatarVisible(); - // The auto-populate is failing at the point of generating outfits
- // folders, so don't do the library copy until that is resolved.
+ // The auto-populate is failing at the point of generating outfits + // folders, so don't do the library copy until that is resolved. // autopopulateOutfits(); } diff --git a/indra/newview/llpanelmarketplaceinbox.cpp b/indra/newview/llpanelmarketplaceinbox.cpp index 8d0712a328..2cb91f771f 100644 --- a/indra/newview/llpanelmarketplaceinbox.cpp +++ b/indra/newview/llpanelmarketplaceinbox.cpp @@ -1,238 +1,238 @@ -/**
- * @file llpanelmarketplaceinbox.cpp
- * @brief Panel for marketplace inbox
- *
-* $LicenseInfo:firstyear=2011&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llpanelmarketplaceinbox.h"
-#include "llpanelmarketplaceinboxinventory.h"
-
-#include "llappviewer.h"
-#include "llbutton.h"
-#include "llinventorypanel.h"
-#include "llfolderview.h"
-#include "llsidepanelinventory.h"
-#include "llviewercontrol.h"
-
-
-static LLRegisterPanelClassWrapper<LLPanelMarketplaceInbox> t_panel_marketplace_inbox("panel_marketplace_inbox");
-
-const LLPanelMarketplaceInbox::Params& LLPanelMarketplaceInbox::getDefaultParams()
-{
- return LLUICtrlFactory::getDefaultParams<LLPanelMarketplaceInbox>();
-}
-
-// protected
-LLPanelMarketplaceInbox::LLPanelMarketplaceInbox(const Params& p)
- : LLPanel(p)
- , mInventoryPanel(NULL)
-{
-}
-
-LLPanelMarketplaceInbox::~LLPanelMarketplaceInbox()
-{
-}
-
-// virtual
-BOOL LLPanelMarketplaceInbox::postBuild()
-{
- LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLPanelMarketplaceInbox::handleLoginComplete, this));
-
- LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLPanelMarketplaceInbox::onFocusReceived, this));
-
- return TRUE;
-}
-
-void LLPanelMarketplaceInbox::onSelectionChange()
-{
- LLSidepanelInventory* sidepanel_inventory = dynamic_cast<LLSidepanelInventory*>(LLSideTray::getInstance()->getPanel("sidepanel_inventory"));
-
- sidepanel_inventory->updateVerbs();
-}
-
-
-void LLPanelMarketplaceInbox::handleLoginComplete()
-{
- // Set us up as the class to drive the badge value for the sidebar_inventory button
- LLSideTray::getInstance()->setTabButtonBadgeDriver("sidebar_inventory", this);
-}
-
-LLInventoryPanel * LLPanelMarketplaceInbox::setupInventoryPanel()
-{
- LLView * inbox_inventory_placeholder = getChild<LLView>("inbox_inventory_placeholder");
- LLView * inbox_inventory_parent = inbox_inventory_placeholder->getParent();
-
- mInventoryPanel =
- LLUICtrlFactory::createFromFile<LLInventoryPanel>("panel_inbox_inventory.xml",
- inbox_inventory_parent,
- LLInventoryPanel::child_registry_t::instance());
-
- llassert(mInventoryPanel);
-
- // Reshape the inventory to the proper size
- LLRect inventory_placeholder_rect = inbox_inventory_placeholder->getRect();
- mInventoryPanel->setShape(inventory_placeholder_rect);
-
- // Set the sort order newest to oldest
- mInventoryPanel->setSortOrder(LLInventoryFilter::SO_DATE);
-
- // Set selection callback for proper update of inventory status buttons
- mInventoryPanel->setSelectCallback(boost::bind(&LLPanelMarketplaceInbox::onSelectionChange, this));
-
- // Set up the note to display when the inbox is empty
- mInventoryPanel->getFilter()->setEmptyLookupMessage("InventoryInboxNoItems");
-
- // Hide the placeholder text
- inbox_inventory_placeholder->setVisible(FALSE);
-
- return mInventoryPanel;
-}
-
-void LLPanelMarketplaceInbox::onFocusReceived()
-{
- LLSidepanelInventory * sidepanel_inventory = LLSideTray::getInstance()->getPanel<LLSidepanelInventory>("sidepanel_inventory");
-
- sidepanel_inventory->clearSelections(true, false, true);
-
- gSavedPerAccountSettings.setString("LastInventoryInboxActivity", LLDate::now().asString());
-}
-
-BOOL LLPanelMarketplaceInbox::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string& tooltip_msg)
-{
- *accept = ACCEPT_NO;
- return TRUE;
-}
-
-U32 LLPanelMarketplaceInbox::getFreshItemCount() const
-{
-#if SUPPORTING_FRESH_ITEM_COUNT
-
- //
- // NOTE: When turning this on, be sure to test the no inbox/outbox case because this code probably
- // will return "2" for the Inventory and LIBRARY top-levels when that happens.
- //
-
- U32 fresh_item_count = 0;
-
- if (mInventoryPanel)
- {
- const LLFolderViewFolder * inbox_folder = mInventoryPanel->getRootFolder();
-
- if (inbox_folder)
- {
- LLFolderViewFolder::folders_t::const_iterator folders_it = inbox_folder->getFoldersBegin();
- LLFolderViewFolder::folders_t::const_iterator folders_end = inbox_folder->getFoldersEnd();
-
- for (; folders_it != folders_end; ++folders_it)
- {
- const LLFolderViewFolder * folder_view = *folders_it;
- const LLInboxFolderViewFolder * inbox_folder_view = dynamic_cast<const LLInboxFolderViewFolder*>(folder_view);
-
- if (inbox_folder_view && inbox_folder_view->isFresh())
- {
- fresh_item_count++;
- }
- }
- }
- }
-
- return fresh_item_count;
-#else
- return getTotalItemCount();
-#endif
-}
-
-U32 LLPanelMarketplaceInbox::getTotalItemCount() const
-{
- U32 item_count = 0;
-
- if (mInventoryPanel)
- {
- const LLFolderViewFolder * inbox_folder = mInventoryPanel->getRootFolder();
-
- if (inbox_folder)
- {
- item_count += inbox_folder->getFoldersCount();
- }
- }
-
- return item_count;
-}
-
-std::string LLPanelMarketplaceInbox::getBadgeString() const
-{
- std::string item_count_str("");
-
- // If the inbox is visible, and the side panel is collapsed or expanded and not the inventory panel
- if (getParent()->getVisible() &&
- (LLSideTray::getInstance()->getCollapsed() || !LLSideTray::getInstance()->isPanelActive("sidepanel_inventory")))
- {
- U32 item_count = getFreshItemCount();
-
- if (item_count)
- {
- item_count_str = llformat("%d", item_count);
- }
- }
-
- return item_count_str;
-}
-
-void LLPanelMarketplaceInbox::draw()
-{
- U32 item_count = getTotalItemCount();
-
- LLView * fresh_new_count_view = getChildView("inbox_fresh_new_count");
-
- if (item_count > 0)
- {
- std::string item_count_str = llformat("%d", item_count);
-
- LLStringUtil::format_map_t args;
- args["[NUM]"] = item_count_str;
- getChild<LLButton>("inbox_btn")->setLabel(getString("InboxLabelWithArg", args));
-
-#if SUPPORTING_FRESH_ITEM_COUNT
- // set green text to fresh item count
- U32 fresh_item_count = getFreshItemCount();
- fresh_new_count_view->setVisible((fresh_item_count > 0));
-
- if (fresh_item_count > 0)
- {
- getChild<LLUICtrl>("inbox_fresh_new_count")->setTextArg("[NUM]", llformat("%d", fresh_item_count));
- }
-#else
- fresh_new_count_view->setVisible(FALSE);
-#endif
- }
- else
- {
- getChild<LLButton>("inbox_btn")->setLabel(getString("InboxLabelNoArg"));
-
- fresh_new_count_view->setVisible(FALSE);
- }
-
- LLPanel::draw();
-}
+/** + * @file llpanelmarketplaceinbox.cpp + * @brief Panel for marketplace inbox + * +* $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelmarketplaceinbox.h" +#include "llpanelmarketplaceinboxinventory.h" + +#include "llappviewer.h" +#include "llbutton.h" +#include "llinventorypanel.h" +#include "llfolderview.h" +#include "llsidepanelinventory.h" +#include "llviewercontrol.h" + + +static LLRegisterPanelClassWrapper<LLPanelMarketplaceInbox> t_panel_marketplace_inbox("panel_marketplace_inbox"); + +const LLPanelMarketplaceInbox::Params& LLPanelMarketplaceInbox::getDefaultParams() +{ + return LLUICtrlFactory::getDefaultParams<LLPanelMarketplaceInbox>(); +} + +// protected +LLPanelMarketplaceInbox::LLPanelMarketplaceInbox(const Params& p) + : LLPanel(p) + , mInventoryPanel(NULL) +{ +} + +LLPanelMarketplaceInbox::~LLPanelMarketplaceInbox() +{ +} + +// virtual +BOOL LLPanelMarketplaceInbox::postBuild() +{ + LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLPanelMarketplaceInbox::handleLoginComplete, this)); + + LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLPanelMarketplaceInbox::onFocusReceived, this)); + + return TRUE; +} + +void LLPanelMarketplaceInbox::onSelectionChange() +{ + LLSidepanelInventory* sidepanel_inventory = dynamic_cast<LLSidepanelInventory*>(LLSideTray::getInstance()->getPanel("sidepanel_inventory")); + + sidepanel_inventory->updateVerbs(); +} + + +void LLPanelMarketplaceInbox::handleLoginComplete() +{ + // Set us up as the class to drive the badge value for the sidebar_inventory button + LLSideTray::getInstance()->setTabButtonBadgeDriver("sidebar_inventory", this); +} + +LLInventoryPanel * LLPanelMarketplaceInbox::setupInventoryPanel() +{ + LLView * inbox_inventory_placeholder = getChild<LLView>("inbox_inventory_placeholder"); + LLView * inbox_inventory_parent = inbox_inventory_placeholder->getParent(); + + mInventoryPanel = + LLUICtrlFactory::createFromFile<LLInventoryPanel>("panel_inbox_inventory.xml", + inbox_inventory_parent, + LLInventoryPanel::child_registry_t::instance()); + + llassert(mInventoryPanel); + + // Reshape the inventory to the proper size + LLRect inventory_placeholder_rect = inbox_inventory_placeholder->getRect(); + mInventoryPanel->setShape(inventory_placeholder_rect); + + // Set the sort order newest to oldest + mInventoryPanel->setSortOrder(LLInventoryFilter::SO_DATE); + + // Set selection callback for proper update of inventory status buttons + mInventoryPanel->setSelectCallback(boost::bind(&LLPanelMarketplaceInbox::onSelectionChange, this)); + + // Set up the note to display when the inbox is empty + mInventoryPanel->getFilter()->setEmptyLookupMessage("InventoryInboxNoItems"); + + // Hide the placeholder text + inbox_inventory_placeholder->setVisible(FALSE); + + return mInventoryPanel; +} + +void LLPanelMarketplaceInbox::onFocusReceived() +{ + LLSidepanelInventory * sidepanel_inventory = LLSideTray::getInstance()->getPanel<LLSidepanelInventory>("sidepanel_inventory"); + + sidepanel_inventory->clearSelections(true, false, true); + + gSavedPerAccountSettings.setString("LastInventoryInboxActivity", LLDate::now().asString()); +} + +BOOL LLPanelMarketplaceInbox::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string& tooltip_msg) +{ + *accept = ACCEPT_NO; + return TRUE; +} + +U32 LLPanelMarketplaceInbox::getFreshItemCount() const +{ +#if SUPPORTING_FRESH_ITEM_COUNT + + // + // NOTE: When turning this on, be sure to test the no inbox/outbox case because this code probably + // will return "2" for the Inventory and LIBRARY top-levels when that happens. + // + + U32 fresh_item_count = 0; + + if (mInventoryPanel) + { + const LLFolderViewFolder * inbox_folder = mInventoryPanel->getRootFolder(); + + if (inbox_folder) + { + LLFolderViewFolder::folders_t::const_iterator folders_it = inbox_folder->getFoldersBegin(); + LLFolderViewFolder::folders_t::const_iterator folders_end = inbox_folder->getFoldersEnd(); + + for (; folders_it != folders_end; ++folders_it) + { + const LLFolderViewFolder * folder_view = *folders_it; + const LLInboxFolderViewFolder * inbox_folder_view = dynamic_cast<const LLInboxFolderViewFolder*>(folder_view); + + if (inbox_folder_view && inbox_folder_view->isFresh()) + { + fresh_item_count++; + } + } + } + } + + return fresh_item_count; +#else + return getTotalItemCount(); +#endif +} + +U32 LLPanelMarketplaceInbox::getTotalItemCount() const +{ + U32 item_count = 0; + + if (mInventoryPanel) + { + const LLFolderViewFolder * inbox_folder = mInventoryPanel->getRootFolder(); + + if (inbox_folder) + { + item_count += inbox_folder->getFoldersCount(); + } + } + + return item_count; +} + +std::string LLPanelMarketplaceInbox::getBadgeString() const +{ + std::string item_count_str(""); + + // If the inbox is visible, and the side panel is collapsed or expanded and not the inventory panel + if (getParent()->getVisible() && + (LLSideTray::getInstance()->getCollapsed() || !LLSideTray::getInstance()->isPanelActive("sidepanel_inventory"))) + { + U32 item_count = getFreshItemCount(); + + if (item_count) + { + item_count_str = llformat("%d", item_count); + } + } + + return item_count_str; +} + +void LLPanelMarketplaceInbox::draw() +{ + U32 item_count = getTotalItemCount(); + + LLView * fresh_new_count_view = getChildView("inbox_fresh_new_count"); + + if (item_count > 0) + { + std::string item_count_str = llformat("%d", item_count); + + LLStringUtil::format_map_t args; + args["[NUM]"] = item_count_str; + getChild<LLButton>("inbox_btn")->setLabel(getString("InboxLabelWithArg", args)); + +#if SUPPORTING_FRESH_ITEM_COUNT + // set green text to fresh item count + U32 fresh_item_count = getFreshItemCount(); + fresh_new_count_view->setVisible((fresh_item_count > 0)); + + if (fresh_item_count > 0) + { + getChild<LLUICtrl>("inbox_fresh_new_count")->setTextArg("[NUM]", llformat("%d", fresh_item_count)); + } +#else + fresh_new_count_view->setVisible(FALSE); +#endif + } + else + { + getChild<LLButton>("inbox_btn")->setLabel(getString("InboxLabelNoArg")); + + fresh_new_count_view->setVisible(FALSE); + } + + LLPanel::draw(); +} diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index e1e1f5459b..6feeab393b 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -92,8 +92,8 @@ private: void onMouseEnterVolume(); void onMouseEnterNearbyMedia(); void onClickScreen(S32 x, S32 y); - void onModeChange(const LLSD& original_value, const LLSD& new_value);
- void onModeChangeConfirm(const LLSD& original_value, const LLSD& new_value, const LLSD& notification, const LLSD& response);
+ void onModeChange(const LLSD& original_value, const LLSD& new_value); + void onModeChangeConfirm(const LLSD& original_value, const LLSD& new_value, const LLSD& notification, const LLSD& response); static void onClickMediaToggle(void* data); static void onClickBalance(void* data); diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index d5a99cefb2..3e5ce427a8 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -2062,10 +2062,10 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory( return ACCEPT_NO; } - const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false);
- if(gInventory.isObjectDescendentOf(category->getUUID(), outbox_id))
- {
- return ACCEPT_NO;
+ const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); + if(gInventory.isObjectDescendentOf(category->getUUID(), outbox_id)) + { + return ACCEPT_NO; } if(drop) |