From d341c400fc2e1991416bd6857a34b5a306a9144f Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Mon, 29 Aug 2011 17:13:29 -0700
Subject: [PATCH] EXP-1122 FIX (Viewer) LLQtWebKit should support a
 JavaScript/content debugger to help content creators Viewer side changes to
 enable Web debugger.

---
 autobuild.xml                                 |    8 +-
 indra/llplugin/llpluginclassmedia.cpp         | 2873 +++++++++--------
 indra/llplugin/llpluginclassmedia.h           |    1 +
 .../webkit/media_plugin_webkit.cpp            | 2865 ++++++++--------
 indra/newview/llmediactrl.cpp                 |   23 +-
 indra/newview/llmediactrl.h                   |    3 +
 .../skins/default/xui/en/menu_media_ctrl.xml  |   12 +
 7 files changed, 2916 insertions(+), 2869 deletions(-)

diff --git a/autobuild.xml b/autobuild.xml
index 6872af0661e..6179e405d54 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -1206,9 +1206,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>a7c80fd8516df3b879b669b2b220067f</string>
+              <string>8fb1d0fa5a7f5e4b7e6acd635a9411cf</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/232420/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20110608.tar.bz2</string>
+              <string>'http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/239670/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20110829.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin</string>
@@ -1230,9 +1230,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>b9cc0333cc274c9cc40256ab7146b4fc</string>
+              <string>ab9393795515cbbe9526bde33b41bf2a</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/232420/arch/CYGWIN/installer/llqtwebkit-4.7.1-windows-20110608.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/239670/arch/CYGWIN/installer/llqtwebkit-4.7.1-windows-20110829.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index 5a208ece71f..9cd3216ab27 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -1,1438 +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);
+/** 
+ * @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::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;
-}
-
+			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/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index 84a3dbed6d3..754ea5c88bf 100644
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -212,6 +212,7 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	void browse_forward();
 	void browse_back();
 	void setBrowserUserAgent(const std::string& user_agent);
+	void showWebInspector( bool show );
 	void proxyWindowOpened(const std::string &target, const std::string &uuid);
 	void proxyWindowClosed(const std::string &uuid);
 	void ignore_ssl_cert_errors(bool ignore);
diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp
index b87af85bcf9..430ae9d4dc1 100644
--- a/indra/media_plugins/webkit/media_plugin_webkit.cpp
+++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp
@@ -1,125 +1,125 @@
-/** 
- * @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;
-
+/** 
+ * @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 )
@@ -130,1309 +130,1318 @@ class MediaPluginWebKit :
 			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 == "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;
-}
-
-
+	
+	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/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index 90267c173c4..5bbef78dd4d 100644
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -319,6 +319,11 @@ BOOL LLMediaCtrl::handleRightMouseDown( S32 x, S32 y, MASK mask )
 
 	if (mContextMenu)
 	{
+		// hide/show debugging options
+		bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging");
+		mContextMenu->setItemVisible("open_webinspector", media_plugin_debugging_enabled );
+		mContextMenu->setItemVisible("debug_separator", media_plugin_debugging_enabled );
+
 		mContextMenu->show(x, y);
 		LLMenuGL::showPopup(this, mContextMenu, x, y);
 	}
@@ -385,12 +390,22 @@ void LLMediaCtrl::onFocusLost()
 //
 BOOL LLMediaCtrl::postBuild ()
 {
+	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar;
+	registar.add("Open.WebInspector", boost::bind(&LLMediaCtrl::onOpenWebInspector, this));
+
 	mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(
 		"menu_media_ctrl.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
 	setVisibleCallback(boost::bind(&LLMediaCtrl::onVisibilityChange, this, _2));
+
 	return TRUE;
 }
 
+void LLMediaCtrl::onOpenWebInspector()
+{
+	if (mMediaSource && mMediaSource->hasMedia())
+		mMediaSource->getMediaPlugin()->showWebInspector( true );
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 //
 BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask )
@@ -1066,10 +1081,10 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
 		};
 		break;
 
-		case MEDIA_EVENT_DEBUG_MESSAGE:
-		{
-			LL_INFOS("media") << self->getDebugMessageText() << LL_ENDL; 
-		};
+		case MEDIA_EVENT_DEBUG_MESSAGE:
+		{
+			LL_INFOS("media") << self->getDebugMessageText() << LL_ENDL; 
+		};
 		break;
 	};
 
diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h
index 0e4a5b1d65c..3c0436e27a4 100644
--- a/indra/newview/llmediactrl.h
+++ b/indra/newview/llmediactrl.h
@@ -166,6 +166,9 @@ class LLMediaCtrl :
 		// Incoming media event dispatcher
 		virtual void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
 
+		// right click debugging item
+		void onOpenWebInspector();
+
 		LLUUID getTextureID() {return mMediaTextureID;}
 
 	protected:
diff --git a/indra/newview/skins/default/xui/en/menu_media_ctrl.xml b/indra/newview/skins/default/xui/en/menu_media_ctrl.xml
index c39c26f25f5..960da4bd7a2 100644
--- a/indra/newview/skins/default/xui/en/menu_media_ctrl.xml
+++ b/indra/newview/skins/default/xui/en/menu_media_ctrl.xml
@@ -28,4 +28,16 @@
     <menu_item_call.on_enable
      function="Edit.EnablePaste" />
   </menu_item_call>
+  <menu_item_separator
+   layout="topleft"
+   name="debug_separator"
+   visible="false" />
+  <menu_item_call
+   label="Open Web Inspector"
+   layout="topleft"
+   name="open_webinspector"
+   visible="false">
+    <menu_item_call.on_click
+     function="Open.WebInspector" />
+  </menu_item_call>
 </context_menu>
-- 
GitLab