PageRenderTime 1980ms CodeModel.GetById 166ms app.highlight 1385ms RepoModel.GetById 154ms app.codeStats 3ms

/indra/llplugin/llpluginclassmedia.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1453 lines | 1129 code | 225 blank | 99 comment | 212 complexity | 9b58ee054176d8bbbba0af7b70a5069b MD5 | raw file
   1/** 
   2 * @file llpluginclassmedia.cpp
   3 * @brief LLPluginClassMedia handles a plugin which knows about the "media" message class.
   4 *
   5 * @cond
   6 * $LicenseInfo:firstyear=2008&license=viewerlgpl$
   7 * Second Life Viewer Source Code
   8 * Copyright (C) 2010, Linden Research, Inc.
   9 * 
  10 * This library is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU Lesser General Public
  12 * License as published by the Free Software Foundation;
  13 * version 2.1 of the License only.
  14 * 
  15 * This library is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18 * Lesser General Public License for more details.
  19 * 
  20 * You should have received a copy of the GNU Lesser General Public
  21 * License along with this library; if not, write to the Free Software
  22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  23 * 
  24 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  25 * $/LicenseInfo$
  26 * @endcond
  27 */
  28
  29#include "linden_common.h"
  30#include "indra_constants.h"
  31
  32#include "llpluginclassmedia.h"
  33#include "llpluginmessageclasses.h"
  34
  35#include "llqtwebkit.h"
  36
  37static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256;
  38
  39static int nextPowerOf2( int value )
  40{
  41	int next_power_of_2 = 1;
  42	while ( next_power_of_2 < value )
  43	{
  44		next_power_of_2 <<= 1;
  45	}
  46	
  47	return next_power_of_2;
  48}
  49
  50LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner)
  51{
  52	mOwner = owner;
  53	mPlugin = NULL;
  54	reset();
  55
  56	//debug use
  57	mDeleteOK = true ;
  58}
  59
  60
  61LLPluginClassMedia::~LLPluginClassMedia()
  62{
  63	llassert_always(mDeleteOK) ;
  64	reset();
  65}
  66
  67bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug)
  68{	
  69	LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL;
  70	LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL;
  71	LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL;
  72	
  73	mPlugin = new LLPluginProcessParent(this);
  74	mPlugin->setSleepTime(mSleepTime);
  75	
  76	// Queue up the media init message -- it will be sent after all the currently queued messages.
  77	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init");
  78	message.setValue("target", mTarget);
  79	sendMessage(message);
  80	
  81	mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug);
  82
  83	return true;
  84}
  85
  86
  87void LLPluginClassMedia::reset()
  88{
  89	if(mPlugin != NULL)
  90	{
  91		delete mPlugin;
  92		mPlugin = NULL;
  93	}
  94
  95	mTextureParamsReceived = false;
  96	mRequestedTextureDepth = 0;
  97	mRequestedTextureInternalFormat = 0;
  98	mRequestedTextureFormat = 0;
  99	mRequestedTextureType = 0;
 100	mRequestedTextureSwapBytes = false;
 101	mRequestedTextureCoordsOpenGL = false;
 102	mTextureSharedMemorySize = 0;
 103	mTextureSharedMemoryName.clear();
 104	mDefaultMediaWidth = 0;
 105	mDefaultMediaHeight = 0;
 106	mNaturalMediaWidth = 0;
 107	mNaturalMediaHeight = 0;
 108	mSetMediaWidth = -1;
 109	mSetMediaHeight = -1;
 110	mRequestedMediaWidth = 0;
 111	mRequestedMediaHeight = 0;
 112	mRequestedTextureWidth = 0;
 113	mRequestedTextureHeight = 0;
 114	mFullMediaWidth = 0;
 115	mFullMediaHeight = 0;
 116	mTextureWidth = 0;
 117	mTextureHeight = 0;
 118	mMediaWidth = 0;
 119	mMediaHeight = 0;
 120	mDirtyRect = LLRect::null;	
 121	mAutoScaleMedia = false;
 122	mRequestedVolume = 1.0f;
 123	mPriority = PRIORITY_NORMAL;
 124	mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT;
 125	mAllowDownsample = false;
 126	mPadding = 0;
 127	mLastMouseX = 0;
 128	mLastMouseY = 0;
 129	mStatus = LLPluginClassMediaOwner::MEDIA_NONE;
 130	mSleepTime = 1.0f / 100.0f;
 131	mCanCut = false;
 132	mCanCopy = false;
 133	mCanPaste = false;
 134	mMediaName.clear();
 135	mMediaDescription.clear();
 136	mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f);
 137	
 138	// media_browser class
 139	mNavigateURI.clear();
 140	mNavigateResultCode = -1;
 141	mNavigateResultString.clear();
 142	mHistoryBackAvailable = false;
 143	mHistoryForwardAvailable = false;
 144	mStatusText.clear();
 145	mProgressPercent = 0;	
 146	mClickURL.clear();
 147	mClickNavType.clear();
 148	mClickTarget.clear();
 149	mClickUUID.clear();
 150	mStatusCode = 0;
 151	
 152	// media_time class
 153	mCurrentTime = 0.0f;
 154	mDuration = 0.0f;
 155	mCurrentRate = 0.0f;
 156	mLoadedDuration = 0.0f;
 157}
 158
 159void LLPluginClassMedia::idle(void)
 160{
 161	if(mPlugin)
 162	{
 163		mPlugin->idle();
 164	}
 165	
 166	if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL))
 167	{
 168		// Can't process a size change at this time
 169	}
 170	else if((mRequestedMediaWidth != mMediaWidth) || (mRequestedMediaHeight != mMediaHeight))
 171	{
 172		// Calculate the correct size for the media texture
 173		mRequestedTextureHeight = mRequestedMediaHeight;
 174		if(mPadding < 0)
 175		{
 176			// negative values indicate the plugin wants a power of 2
 177			mRequestedTextureWidth = nextPowerOf2(mRequestedMediaWidth);
 178		}
 179		else
 180		{
 181			mRequestedTextureWidth = mRequestedMediaWidth;
 182			
 183			if(mPadding > 1)
 184			{
 185				// Pad up to a multiple of the specified number of bytes per row
 186				int rowbytes = mRequestedTextureWidth * mRequestedTextureDepth;
 187				int pad = rowbytes % mPadding;
 188				if(pad != 0)
 189				{
 190					rowbytes += mPadding - pad;
 191				}
 192				
 193				if(rowbytes % mRequestedTextureDepth == 0)
 194				{
 195					mRequestedTextureWidth = rowbytes / mRequestedTextureDepth;
 196				}
 197				else
 198				{
 199					LL_WARNS("Plugin") << "Unable to pad texture width, padding size " << mPadding << "is not a multiple of pixel size " << mRequestedTextureDepth << LL_ENDL;
 200				}
 201			}
 202		}
 203
 204		
 205		// Size change has been requested but not initiated yet.
 206		size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth;
 207
 208		// Add an extra line for padding, just in case.
 209		newsize += mRequestedTextureWidth * mRequestedTextureDepth;
 210
 211		if(newsize != mTextureSharedMemorySize)
 212		{
 213			if(!mTextureSharedMemoryName.empty())
 214			{
 215				// Tell the plugin to remove the old memory segment
 216				mPlugin->removeSharedMemory(mTextureSharedMemoryName);
 217				mTextureSharedMemoryName.clear();
 218			}
 219			
 220			mTextureSharedMemorySize = newsize;
 221			mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize);
 222			if(!mTextureSharedMemoryName.empty())
 223			{
 224				void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
 225				
 226				// clear texture memory to avoid random screen visual fuzz from uninitialized texture data
 227				memset( addr, 0x00, newsize );
 228				
 229				// We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin,
 230				// so it may not be worthwhile.
 231				// mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight);
 232			}
 233		}
 234		
 235		// This is our local indicator that a change is in progress.
 236		mTextureWidth = -1;
 237		mTextureHeight = -1;
 238		mMediaWidth = -1;
 239		mMediaHeight = -1;
 240
 241		// This invalidates any existing dirty rect.
 242		resetDirty();
 243		
 244		// Send a size change message to the plugin
 245		{
 246			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change");
 247			message.setValue("name", mTextureSharedMemoryName);
 248			message.setValueS32("width", mRequestedMediaWidth);
 249			message.setValueS32("height", mRequestedMediaHeight);
 250			message.setValueS32("texture_width", mRequestedTextureWidth);
 251			message.setValueS32("texture_height", mRequestedTextureHeight);
 252			message.setValueReal("background_r", mBackgroundColor.mV[VX]);
 253			message.setValueReal("background_g", mBackgroundColor.mV[VY]);
 254			message.setValueReal("background_b", mBackgroundColor.mV[VZ]);
 255			message.setValueReal("background_a", mBackgroundColor.mV[VW]);
 256			mPlugin->sendMessage(message);	// DO NOT just use sendMessage() here -- we want this to jump ahead of the queue.
 257			
 258			LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL;
 259		}
 260	}
 261	
 262	if(mPlugin && mPlugin->isRunning())
 263	{
 264		// Send queued messages
 265		while(!mSendQueue.empty())
 266		{
 267			LLPluginMessage message = mSendQueue.front();
 268			mSendQueue.pop();
 269			mPlugin->sendMessage(message);
 270		}
 271	}
 272}
 273
 274int LLPluginClassMedia::getTextureWidth() const
 275{
 276	return nextPowerOf2(mTextureWidth);
 277}
 278
 279int LLPluginClassMedia::getTextureHeight() const
 280{
 281	return nextPowerOf2(mTextureHeight);
 282}
 283
 284unsigned char* LLPluginClassMedia::getBitsData()
 285{
 286	unsigned char *result = NULL;
 287	if((mPlugin != NULL) && !mTextureSharedMemoryName.empty())
 288	{
 289		result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
 290	}
 291	return result;
 292}
 293
 294void LLPluginClassMedia::setSize(int width, int height)
 295{
 296	if((width > 0) && (height > 0))
 297	{
 298		mSetMediaWidth = width;
 299		mSetMediaHeight = height;
 300	}
 301	else
 302	{
 303		mSetMediaWidth = -1;
 304		mSetMediaHeight = -1;
 305	}
 306
 307	setSizeInternal();
 308}
 309
 310void LLPluginClassMedia::setSizeInternal(void)
 311{
 312	if((mSetMediaWidth > 0) && (mSetMediaHeight > 0))
 313	{
 314		mRequestedMediaWidth = mSetMediaWidth;
 315		mRequestedMediaHeight = mSetMediaHeight;
 316	}
 317	else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0))
 318	{
 319		mRequestedMediaWidth = mNaturalMediaWidth;
 320		mRequestedMediaHeight = mNaturalMediaHeight;
 321	}
 322	else
 323	{
 324		mRequestedMediaWidth = mDefaultMediaWidth;
 325		mRequestedMediaHeight = mDefaultMediaHeight;
 326	}
 327	
 328	// Save these for size/interest calculations
 329	mFullMediaWidth = mRequestedMediaWidth;
 330	mFullMediaHeight = mRequestedMediaHeight;
 331	
 332	if(mAllowDownsample)
 333	{
 334		switch(mPriority)
 335		{
 336			case PRIORITY_SLIDESHOW:
 337			case PRIORITY_LOW:
 338				// Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit
 339				while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit))
 340				{
 341					mRequestedMediaWidth /= 2;
 342					mRequestedMediaHeight /= 2;
 343				}
 344			break;
 345			
 346			default:
 347				// Don't adjust texture size
 348			break;
 349		}
 350	}
 351	
 352	if(mAutoScaleMedia)
 353	{
 354		mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth);
 355		mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight);
 356	}
 357	
 358	if(mRequestedMediaWidth > 2048)
 359		mRequestedMediaWidth = 2048;
 360
 361	if(mRequestedMediaHeight > 2048)
 362		mRequestedMediaHeight = 2048;
 363}
 364
 365void LLPluginClassMedia::setAutoScale(bool auto_scale)
 366{
 367	if(auto_scale != mAutoScaleMedia)
 368	{
 369		mAutoScaleMedia = auto_scale;
 370		setSizeInternal();
 371	}
 372}
 373
 374bool LLPluginClassMedia::textureValid(void)
 375{
 376	if(
 377		!mTextureParamsReceived ||
 378		mTextureWidth <= 0 ||
 379		mTextureHeight <= 0 ||
 380		mMediaWidth <= 0 ||
 381		mMediaHeight <= 0 ||
 382		mRequestedMediaWidth != mMediaWidth ||
 383		mRequestedMediaHeight != mMediaHeight ||
 384		getBitsData() == NULL
 385	)	
 386		return false;
 387	
 388	return true;
 389}
 390
 391bool LLPluginClassMedia::getDirty(LLRect *dirty_rect)
 392{
 393	bool result = !mDirtyRect.isEmpty();
 394
 395	if(dirty_rect != NULL)
 396	{
 397		*dirty_rect = mDirtyRect;
 398	}
 399
 400	return result;
 401}
 402
 403void LLPluginClassMedia::resetDirty(void)
 404{
 405	mDirtyRect = LLRect::null;
 406}
 407
 408std::string LLPluginClassMedia::translateModifiers(MASK modifiers)
 409{
 410	std::string result;
 411	
 412	
 413	if(modifiers & MASK_CONTROL)
 414	{
 415		result += "control|";
 416	}
 417
 418	if(modifiers & MASK_ALT)
 419	{
 420		result += "alt|";
 421	}
 422
 423	if(modifiers & MASK_SHIFT)
 424	{
 425		result += "shift|";
 426	}
 427
 428	// TODO: should I deal with platform differences here or in callers?
 429	// TODO: how do we deal with the Mac "command" key?
 430/*
 431	if(modifiers & MASK_SOMETHING)
 432	{
 433		result += "meta|";
 434	}
 435*/	
 436	return result;
 437}
 438
 439void LLPluginClassMedia::jsEnableObject( bool enable )
 440{
 441	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 442	{
 443		return;
 444	}
 445
 446	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_enable_object");
 447	message.setValueBoolean( "enable", enable );
 448	sendMessage( message );
 449}
 450
 451void LLPluginClassMedia::jsAgentLocationEvent( double x, double y, double z )
 452{
 453	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 454	{
 455		return;
 456	}
 457
 458	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_location");
 459	message.setValueReal( "x", x );
 460	message.setValueReal( "y", y );
 461	message.setValueReal( "z", z );
 462	sendMessage( message );
 463}
 464
 465void LLPluginClassMedia::jsAgentGlobalLocationEvent( double x, double y, double z )
 466{
 467	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 468	{
 469		return;
 470	}
 471
 472	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_global_location");
 473	message.setValueReal( "x", x );
 474	message.setValueReal( "y", y );
 475	message.setValueReal( "z", z );
 476	sendMessage( message );
 477}
 478
 479void LLPluginClassMedia::jsAgentOrientationEvent( double angle )
 480{
 481	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 482	{
 483		return;
 484	}
 485
 486	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_orientation");
 487	message.setValueReal( "angle", angle );
 488
 489	sendMessage( message );
 490}
 491
 492void LLPluginClassMedia::jsAgentLanguageEvent( const std::string& language )
 493{
 494	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 495	{
 496		return;
 497	}
 498
 499	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_language");
 500	message.setValue( "language", language );
 501	sendMessage( message );
 502}
 503
 504void LLPluginClassMedia::jsAgentRegionEvent( const std::string& region )
 505{
 506	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 507	{
 508		return;
 509	}
 510
 511	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_region");
 512	message.setValue( "region", region );
 513	sendMessage( message );
 514}
 515
 516void LLPluginClassMedia::jsAgentMaturityEvent( const std::string& maturity )
 517{
 518	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 519	{
 520		return;
 521	}
 522
 523	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_maturity");
 524	message.setValue( "maturity", maturity );
 525	sendMessage( message );
 526}
 527
 528void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers)
 529{
 530	if(type == MOUSE_EVENT_MOVE)
 531	{
 532		if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked())
 533		{
 534			// Don't queue up mouse move events that can't be delivered.
 535			return;
 536		}
 537
 538		if((x == mLastMouseX) && (y == mLastMouseY))
 539		{
 540			// Don't spam unnecessary mouse move events.
 541			return;
 542		}
 543		
 544		mLastMouseX = x;
 545		mLastMouseY = y;
 546	}
 547	
 548	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event");
 549	std::string temp;
 550	switch(type)
 551	{
 552		case MOUSE_EVENT_DOWN:			temp = "down";			break;
 553		case MOUSE_EVENT_UP:			temp = "up";			break;
 554		case MOUSE_EVENT_MOVE:			temp = "move";			break;
 555		case MOUSE_EVENT_DOUBLE_CLICK:	temp = "double_click";	break;
 556	}
 557	message.setValue("event", temp);
 558
 559	message.setValueS32("button", button);
 560
 561	message.setValueS32("x", x);
 562	
 563	// Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it.
 564	if(!mRequestedTextureCoordsOpenGL)
 565	{
 566		// TODO: Should I use mMediaHeight or mRequestedMediaHeight here?
 567		y = mMediaHeight - y;
 568	}
 569	message.setValueS32("y", y);
 570
 571	message.setValue("modifiers", translateModifiers(modifiers));
 572	
 573	sendMessage(message);
 574}
 575
 576bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data)
 577{
 578	bool result = true;
 579	
 580	// FIXME:
 581	// HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode.
 582	// For now, return false for the ones the webkit plugin won't handle properly.
 583	
 584	switch(key_code)
 585	{
 586		case KEY_BACKSPACE:		
 587		case KEY_TAB:			
 588		case KEY_RETURN:		
 589		case KEY_PAD_RETURN:	
 590		case KEY_SHIFT:			
 591		case KEY_CONTROL:		
 592		case KEY_ALT:			
 593		case KEY_CAPSLOCK:		
 594		case KEY_ESCAPE:		
 595		case KEY_PAGE_UP:		
 596		case KEY_PAGE_DOWN:		
 597		case KEY_END:			
 598		case KEY_HOME:			
 599		case KEY_LEFT:			
 600		case KEY_UP:			
 601		case KEY_RIGHT:			
 602		case KEY_DOWN:			
 603		case KEY_INSERT:		
 604		case KEY_DELETE:
 605			// These will be handled		
 606		break;
 607		
 608		default:
 609			// regular ASCII characters will also be handled
 610			if(key_code >= KEY_SPECIAL)
 611			{
 612				// Other "special" codes will not work properly.
 613				result = false;
 614			}
 615		break;
 616	}
 617
 618#if LL_DARWIN	
 619	if(modifiers & MASK_ALT)
 620	{
 621		// Option-key modified characters should be handled by the unicode input path instead of this one.
 622		result = false;
 623	}
 624#endif
 625
 626	if(result)
 627	{
 628		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event");
 629		std::string temp;
 630		switch(type)
 631		{
 632			case KEY_EVENT_DOWN:			temp = "down";			break;
 633			case KEY_EVENT_UP:				temp = "up";			break;
 634			case KEY_EVENT_REPEAT:			temp = "repeat";		break;
 635		}
 636		message.setValue("event", temp);
 637		
 638		message.setValueS32("key", key_code);
 639
 640		message.setValue("modifiers", translateModifiers(modifiers));
 641		message.setValueLLSD("native_key_data", native_key_data);
 642		
 643		sendMessage(message);
 644	}
 645		
 646	return result;
 647}
 648
 649void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers)
 650{
 651	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event");
 652
 653	message.setValueS32("x", x);
 654	message.setValueS32("y", y);
 655	message.setValue("modifiers", translateModifiers(modifiers));
 656	
 657	sendMessage(message);
 658}
 659	
 660bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data)
 661{
 662	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event");
 663
 664	message.setValue("text", text);
 665	message.setValue("modifiers", translateModifiers(modifiers));
 666	message.setValueLLSD("native_key_data", native_key_data);
 667	
 668	sendMessage(message);
 669	
 670	return true;
 671}
 672
 673void LLPluginClassMedia::loadURI(const std::string &uri)
 674{
 675	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri");
 676
 677	message.setValue("uri", uri);
 678	
 679	sendMessage(message);
 680}
 681
 682const char* LLPluginClassMedia::priorityToString(EPriority priority)
 683{
 684	const char* result = "UNKNOWN";
 685	switch(priority)
 686	{
 687		case PRIORITY_UNLOADED:		result = "unloaded";	break;
 688		case PRIORITY_STOPPED:		result = "stopped";		break;
 689		case PRIORITY_HIDDEN:		result = "hidden";		break;
 690		case PRIORITY_SLIDESHOW:	result = "slideshow";	break;
 691		case PRIORITY_LOW:			result = "low";			break;
 692		case PRIORITY_NORMAL:		result = "normal";		break;
 693		case PRIORITY_HIGH:			result = "high";		break;
 694	}
 695	
 696	return result;
 697}
 698
 699void LLPluginClassMedia::setPriority(EPriority priority)
 700{
 701	if(mPriority != priority)
 702	{
 703		mPriority = priority;
 704
 705		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority");
 706		
 707		std::string priority_string = priorityToString(priority);
 708		switch(priority)
 709		{
 710			case PRIORITY_UNLOADED:	
 711				mSleepTime = 1.0f;
 712			break;
 713			case PRIORITY_STOPPED:	
 714				mSleepTime = 1.0f;
 715			break;
 716			case PRIORITY_HIDDEN:	
 717				mSleepTime = 1.0f;
 718			break;
 719			case PRIORITY_SLIDESHOW:
 720				mSleepTime = 1.0f;
 721			break;
 722			case PRIORITY_LOW:		
 723				mSleepTime = 1.0f / 25.0f;
 724			break;
 725			case PRIORITY_NORMAL:	
 726				mSleepTime = 1.0f / 50.0f;
 727			break;
 728			case PRIORITY_HIGH:		
 729				mSleepTime = 1.0f / 100.0f;
 730			break;
 731		}
 732		
 733		message.setValue("priority", priority_string);
 734
 735		sendMessage(message);
 736		
 737		if(mPlugin)
 738		{
 739			mPlugin->setSleepTime(mSleepTime);
 740		}
 741		
 742		LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL;
 743		
 744		// This may affect the calculated size, so recalculate it here.
 745		setSizeInternal();
 746	}
 747}
 748
 749void LLPluginClassMedia::setLowPrioritySizeLimit(int size)
 750{
 751	int power = nextPowerOf2(size);
 752	if(mLowPrioritySizeLimit != power)
 753	{
 754		mLowPrioritySizeLimit = power;
 755
 756		// This may affect the calculated size, so recalculate it here.
 757		setSizeInternal();
 758	}
 759}
 760
 761F64 LLPluginClassMedia::getCPUUsage()
 762{
 763	F64 result = 0.0f;
 764	
 765	if(mPlugin)
 766	{
 767		result = mPlugin->getCPUUsage();
 768	}
 769	
 770	return result;
 771}
 772
 773void LLPluginClassMedia::sendPickFileResponse(const std::string &file)
 774{
 775	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response");
 776	message.setValue("file", file);
 777	if(mPlugin && mPlugin->isBlocked())
 778	{
 779		// If the plugin sent a blocking pick-file request, the response should unblock it.
 780		message.setValueBoolean("blocking_response", true);
 781	}
 782	sendMessage(message);
 783}
 784
 785void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, const std::string &password)
 786{
 787	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response");
 788	message.setValueBoolean("ok", ok);
 789	message.setValue("username", username);
 790	message.setValue("password", password);
 791	if(mPlugin && mPlugin->isBlocked())
 792	{
 793		// If the plugin sent a blocking pick-file request, the response should unblock it.
 794		message.setValueBoolean("blocking_response", true);
 795	}
 796	sendMessage(message);
 797}
 798
 799void LLPluginClassMedia::cut()
 800{
 801	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut");
 802	sendMessage(message);
 803}
 804
 805void LLPluginClassMedia::copy()
 806{
 807	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_copy");
 808	sendMessage(message);
 809}
 810
 811void LLPluginClassMedia::paste()
 812{
 813	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_paste");
 814	sendMessage(message);
 815}
 816
 817void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path)
 818{
 819	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path");
 820	message.setValue("path", user_data_path);
 821	sendMessage(message);
 822}
 823
 824void LLPluginClassMedia::setLanguageCode(const std::string &language_code)
 825{
 826	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_language_code");
 827	message.setValue("language", language_code);
 828	sendMessage(message);
 829}
 830
 831void LLPluginClassMedia::setPluginsEnabled(const bool enabled)
 832{
 833	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled");
 834	message.setValueBoolean("enable", enabled);
 835	sendMessage(message);
 836}
 837
 838void LLPluginClassMedia::setJavascriptEnabled(const bool enabled)
 839{
 840	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled");
 841	message.setValueBoolean("enable", enabled);
 842	sendMessage(message);
 843}
 844
 845
 846void LLPluginClassMedia::enableMediaPluginDebugging( bool enable )
 847{
 848	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "enable_media_plugin_debugging");
 849	message.setValueBoolean( "enable", enable );
 850	sendMessage( message );
 851}
 852
 853void LLPluginClassMedia::setTarget(const std::string &target)
 854{
 855	mTarget = target;
 856}
 857
 858/* virtual */ 
 859void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 860{
 861	std::string message_class = message.getClass();
 862	
 863	if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
 864	{
 865		std::string message_name = message.getName();
 866		if(message_name == "texture_params")
 867		{
 868			mRequestedTextureDepth = message.getValueS32("depth");
 869			mRequestedTextureInternalFormat = message.getValueU32("internalformat");
 870			mRequestedTextureFormat = message.getValueU32("format");
 871			mRequestedTextureType = message.getValueU32("type");
 872			mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes");
 873			mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl");			
 874			
 875			// These two are optional, and will default to 0 if they're not specified.
 876			mDefaultMediaWidth = message.getValueS32("default_width");
 877			mDefaultMediaHeight = message.getValueS32("default_height");
 878			
 879			mAllowDownsample = message.getValueBoolean("allow_downsample");
 880			mPadding = message.getValueS32("padding");
 881
 882			setSizeInternal();
 883			
 884			mTextureParamsReceived = true;
 885		}
 886		else if(message_name == "updated")
 887		{			
 888			if(message.hasValue("left"))
 889			{
 890				LLRect newDirtyRect;
 891				newDirtyRect.mLeft = message.getValueS32("left");
 892				newDirtyRect.mTop = message.getValueS32("top");
 893				newDirtyRect.mRight = message.getValueS32("right");
 894				newDirtyRect.mBottom = message.getValueS32("bottom");
 895							
 896				// The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion.
 897				// If they're backwards, swap them.
 898				if(newDirtyRect.mTop < newDirtyRect.mBottom)
 899				{
 900					S32 temp = newDirtyRect.mTop;
 901					newDirtyRect.mTop = newDirtyRect.mBottom;
 902					newDirtyRect.mBottom = temp;
 903				}
 904				
 905				if(mDirtyRect.isEmpty())
 906				{
 907					mDirtyRect = newDirtyRect;
 908				}
 909				else
 910				{
 911					mDirtyRect.unionWith(newDirtyRect);
 912				}
 913
 914				LL_DEBUGS("Plugin") << "adjusted incoming rect is: (" 
 915					<< newDirtyRect.mLeft << ", "
 916					<< newDirtyRect.mTop << ", "
 917					<< newDirtyRect.mRight << ", "
 918					<< newDirtyRect.mBottom << "), new dirty rect is: ("
 919					<< mDirtyRect.mLeft << ", "
 920					<< mDirtyRect.mTop << ", "
 921					<< mDirtyRect.mRight << ", "
 922					<< mDirtyRect.mBottom << ")"
 923					<< LL_ENDL;
 924				
 925				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED);
 926			}			
 927			
 928
 929			bool time_duration_updated = false;
 930			int previous_percent = mProgressPercent;
 931
 932			if(message.hasValue("current_time"))
 933			{
 934				mCurrentTime = message.getValueReal("current_time");
 935				time_duration_updated = true;
 936			}
 937			if(message.hasValue("duration"))
 938			{
 939				mDuration = message.getValueReal("duration");
 940				time_duration_updated = true;
 941			}
 942
 943			if(message.hasValue("current_rate"))
 944			{
 945				mCurrentRate = message.getValueReal("current_rate");
 946			}
 947			
 948			if(message.hasValue("loaded_duration"))
 949			{
 950				mLoadedDuration = message.getValueReal("loaded_duration");
 951				time_duration_updated = true;
 952			}
 953			else
 954			{
 955				// If the message doesn't contain a loaded_duration param, assume it's equal to duration
 956				mLoadedDuration = mDuration;
 957			}
 958			
 959			// Calculate a percentage based on the loaded duration and total duration.
 960			if(mDuration != 0.0f)	// Don't divide by zero.
 961			{
 962				mProgressPercent = (int)((mLoadedDuration * 100.0f)/mDuration);
 963			}
 964
 965			if(time_duration_updated)
 966			{
 967				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED);
 968			}
 969			
 970			if(previous_percent != mProgressPercent)
 971			{
 972				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
 973			}
 974		}
 975		else if(message_name == "media_status")
 976		{
 977			std::string status = message.getValue("status");
 978			
 979			LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL;
 980			
 981			if(status == "loading")
 982			{
 983				mStatus = LLPluginClassMediaOwner::MEDIA_LOADING;
 984			}
 985			else if(status == "loaded")
 986			{
 987				mStatus = LLPluginClassMediaOwner::MEDIA_LOADED;
 988			}
 989			else if(status == "error")
 990			{
 991				mStatus = LLPluginClassMediaOwner::MEDIA_ERROR;
 992			}
 993			else if(status == "playing")
 994			{
 995				mStatus = LLPluginClassMediaOwner::MEDIA_PLAYING;
 996			}
 997			else if(status == "paused")
 998			{
 999				mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED;
1000			}
1001			else if(status == "done")
1002			{
1003				mStatus = LLPluginClassMediaOwner::MEDIA_DONE;
1004			}
1005			else
1006			{
1007				// empty string or any unknown string
1008				mStatus = LLPluginClassMediaOwner::MEDIA_NONE;
1009			}
1010		}
1011		else if(message_name == "size_change_request")
1012		{
1013			S32 width = message.getValueS32("width");
1014			S32 height = message.getValueS32("height");
1015			std::string name = message.getValue("name");
1016
1017			// TODO: check that name matches?
1018			mNaturalMediaWidth = width;
1019			mNaturalMediaHeight = height;
1020			
1021			setSizeInternal();
1022		}
1023		else if(message_name == "size_change_response")
1024		{
1025			std::string name = message.getValue("name");
1026			
1027			// TODO: check that name matches?
1028			
1029			mTextureWidth = message.getValueS32("texture_width");
1030			mTextureHeight = message.getValueS32("texture_height");
1031			mMediaWidth = message.getValueS32("width");
1032			mMediaHeight = message.getValueS32("height");
1033			
1034			// This invalidates any existing dirty rect.
1035			resetDirty();
1036			
1037			// TODO: should we verify that the plugin sent back the right values?  
1038			// Two size changes in a row may cause them to not match, due to queueing, etc.
1039
1040			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED);
1041		}
1042		else if(message_name == "cursor_changed")
1043		{
1044			mCursorName = message.getValue("name");
1045
1046			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CURSOR_CHANGED);
1047		}
1048		else if(message_name == "edit_state")
1049		{
1050			if(message.hasValue("cut"))
1051			{
1052				mCanCut = message.getValueBoolean("cut");
1053			}
1054			if(message.hasValue("copy"))
1055			{
1056				mCanCopy = message.getValueBoolean("copy");
1057			}
1058			if(message.hasValue("paste"))
1059			{
1060				mCanPaste = message.getValueBoolean("paste");
1061			}
1062		}
1063		else if(message_name == "name_text")
1064		{
1065			mMediaName = message.getValue("name");
1066			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED);
1067		}
1068		else if(message_name == "pick_file")
1069		{
1070			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST);
1071		}
1072		else if(message_name == "auth_request")
1073		{
1074			mAuthURL = message.getValue("url");
1075			mAuthRealm = message.getValue("realm");
1076			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST);
1077		}		
1078		else if(message_name == "debug_message")
1079		{
1080			mDebugMessageText = message.getValue("message_text");
1081			mDebugMessageLevel = message.getValue("message_level");
1082			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_DEBUG_MESSAGE);
1083		}
1084		else
1085		{
1086			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
1087		}
1088	}
1089	else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
1090	{
1091		std::string message_name = message.getName();
1092		if(message_name == "navigate_begin")
1093		{
1094			mNavigateURI = message.getValue("uri");
1095			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_BEGIN);
1096		}
1097		else if(message_name == "navigate_complete")
1098		{
1099			mNavigateURI = message.getValue("uri");
1100			mNavigateResultCode = message.getValueS32("result_code");
1101			mNavigateResultString = message.getValue("result_string");
1102			mHistoryBackAvailable = message.getValueBoolean("history_back_available");
1103			mHistoryForwardAvailable = message.getValueBoolean("history_forward_available");
1104			
1105			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE);
1106		}
1107		else if(message_name == "progress")
1108		{
1109			mProgressPercent = message.getValueS32("percent");
1110			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
1111		}
1112		else if(message_name == "status_text")
1113		{
1114			mStatusText = message.getValue("status");
1115			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_STATUS_TEXT_CHANGED);
1116		}
1117		else if(message_name == "location_changed")
1118		{
1119			mLocation = message.getValue("uri");
1120			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LOCATION_CHANGED);
1121		}
1122		else if(message_name == "click_href")
1123		{
1124			mClickURL = message.getValue("uri");
1125			mClickTarget = message.getValue("target");
1126			mClickUUID = message.getValue("uuid");
1127			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF);
1128		}
1129		else if(message_name == "click_nofollow")
1130		{
1131			mClickURL = message.getValue("uri");
1132			mClickNavType = message.getValue("nav_type");
1133			mClickTarget.clear();
1134			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW);
1135		}
1136		else if(message_name == "navigate_error_page")
1137		{
1138			mStatusCode = message.getValueS32("status_code");
1139			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_ERROR_PAGE);
1140		}
1141		else if(message_name == "cookie_set")
1142		{
1143			if(mOwner)
1144			{
1145				mOwner->handleCookieSet(this, message.getValue("cookie"));
1146			}
1147		}
1148		else if(message_name == "close_request")
1149		{
1150			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLOSE_REQUEST);
1151		}
1152		else if(message_name == "geometry_change")
1153		{
1154			mClickUUID = message.getValue("uuid");
1155			mGeometryX = message.getValueS32("x");
1156			mGeometryY = message.getValueS32("y");
1157			mGeometryWidth = message.getValueS32("width");
1158			mGeometryHeight = message.getValueS32("height");
1159				
1160			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE);
1161		}
1162		else if(message_name == "link_hovered")
1163		{
1164			// text is not currently used -- the tooltip hover text is taken from the "title".
1165			mHoverLink = message.getValue("link");
1166			mHoverText = message.getValue("title");
1167			// message.getValue("text");
1168				
1169			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED);
1170		}
1171		else
1172		{
1173			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
1174		}
1175	}
1176	else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
1177	{
1178		std::string message_name = message.getName();
1179
1180		// This class hasn't defined any incoming messages yet.
1181//		if(message_name == "message_name")
1182//		{
1183//		}
1184//		else 
1185		{
1186			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
1187		}
1188	}
1189
1190}
1191
1192/* virtual */ 
1193void LLPluginClassMedia::pluginLaunchFailed()
1194{
1195	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH);
1196}
1197
1198/* virtual */ 
1199void LLPluginClassMedia::pluginDied()
1200{
1201	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED);
1202}
1203
1204void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event)
1205{
1206	if(mOwner)
1207	{
1208		mOwner->handleMediaEvent(this, event);
1209	}
1210}
1211
1212void LLPluginClassMedia::sendMessage(const LLPluginMessage &message)
1213{
1214	if(mPlugin && mPlugin->isRunning())
1215	{
1216		mPlugin->sendMessage(message);
1217	}
1218	else
1219	{
1220		// The plugin isn't set up yet -- queue this message to be sent after initialization.
1221		mSendQueue.push(message);
1222	}
1223}
1224
1225////////////////////////////////////////////////////////////
1226// MARK: media_browser class functions
1227bool LLPluginClassMedia::pluginSupportsMediaBrowser(void)
1228{
1229	std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER);
1230	return !version.empty();
1231}
1232
1233void LLPluginClassMedia::focus(bool focused)
1234{
1235	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus");
1236
1237	message.setValueBoolean("focused", focused);
1238	
1239	sendMessage(message);
1240}
1241
1242void LLPluginClassMedia::set_page_zoom_factor( double factor )
1243{
1244	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_page_zoom_factor");
1245
1246	message.setValueReal("factor", factor);
1247	sendMessage(message);
1248}
1249
1250void LLPluginClassMedia::clear_cache()
1251{
1252	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache");
1253	sendMessage(message);
1254}
1255
1256void LLPluginClassMedia::clear_cookies()
1257{
1258	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cookies");
1259	sendMessage(message);
1260}
1261
1262void LLPluginClassMedia::set_cookies(const std::string &cookies)
1263{
1264	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies");
1265	message.setValue("cookies", cookies);	
1266	sendMessage(message);
1267}
1268
1269void LLPluginClassMedia::enable_cookies(bool enable)
1270{
1271	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies");
1272	message.setValueBoolean("enable", enable);
1273	sendMessage(message);
1274}
1275
1276void LLPluginClassMedia::proxy_setup(bool enable, const std::string &host, int port)
1277{
1278	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup");
1279
1280	message.setValueBoolean("enable", enable);
1281	message.setValue("host", host);
1282	message.setValueS32("port", port);
1283
1284	sendMessage(message);
1285}
1286
1287void LLPluginClassMedia::browse_stop()
1288{
1289	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_stop");
1290	sendMessage(message);
1291}
1292
1293void LLPluginClassMedia::browse_reload(bool ignore_cache)
1294{
1295	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload");
1296
1297	message.setValueBoolean("ignore_cache", ignore_cache);
1298	
1299	sendMessage(message);
1300}
1301
1302void LLPluginClassMedia::browse_forward()
1303{
1304	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_forward");
1305	sendMessage(message);
1306}
1307
1308void LLPluginClassMedia::browse_back()
1309{
1310	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_back");
1311	sendMessage(message);
1312}
1313
1314void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent)
1315{
1316	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent");
1317
1318	message.setValue("user_agent", user_agent);
1319
1320	sendMessage(message);
1321}
1322
1323void LLPluginClassMedia::showWebInspector( bool show )
1324{
1325	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "show_web_inspector");
1326	message.setValueBoolean("show", true);	// only open for now - closed manually by user
1327	sendMessage(message);
1328}
1329
1330void LLPluginClassMedia::proxyWindowOpened(const std::string &target, const std::string &uuid)
1331{
1332	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_opened");
1333
1334	message.setValue("target", target);
1335	message.setValue("uuid", uuid);
1336
1337	sendMessage(message);
1338}
1339
1340void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid)
1341{
1342	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_closed");
1343
1344	message.setValue("uuid", uuid);
1345
1346	sendMessage(message);
1347}
1348
1349void LLPluginClassMedia::ignore_ssl_cert_errors(bool ignore)
1350{
1351	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors");
1352	message.setValueBoolean("ignore", ignore);
1353	sendMessage(message);
1354}
1355
1356void LLPluginClassMedia::addCertificateFilePath(const std::string& path)
1357{
1358	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "add_certificate_file_path");
1359	message.setValue("path", path);
1360	sendMessage(message);
1361}
1362
1363void LLPluginClassMedia::crashPlugin()
1364{
1365	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash");
1366
1367	sendMessage(message);
1368}
1369
1370void LLPluginClassMedia::hangPlugin()
1371{
1372	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hang");
1373
1374	sendMessage(message);
1375}
1376
1377
1378////////////////////////////////////////////////////////////
1379// MARK: media_time class functions
1380bool LLPluginClassMedia::pluginSupportsMediaTime(void)
1381{
1382	std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME);
1383	return !version.empty();
1384}
1385
1386void LLPluginClassMedia::stop()
1387{
1388	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "stop");
1389	sendMessage(message);
1390}
1391
1392void LLPluginClassMedia::start(float rate)
1393{
1394	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "start");
1395
1396	message.setValueReal("rate", rate);
1397
1398	sendMessage(message);
1399}
1400
1401void LLPluginClassMedia::pause()
1402{
1403	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "pause");
1404	sendMessage(message);
1405}
1406
1407void LLPluginClassMedia::seek(float time)
1408{
1409	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek");
1410
1411	message.setValueReal("time", time);
1412	
1413	sendMessage(message);
1414}
1415
1416void LLPluginClassMedia::setLoop(bool loop)
1417{
1418	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_loop");
1419
1420	message.setValueBoolean("loop", loop);
1421
1422	sendMessage(message);
1423}
1424
1425void LLPluginClassMedia::setVolume(float volume)
1426{
1427	if(volume != mRequestedVolume)
1428	{
1429		mRequestedVolume = volume;
1430		
1431		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume");
1432
1433		message.setValueReal("volume", volume);
1434		
1435		sendMessage(message);
1436	}
1437}
1438
1439float LLPluginClassMedia::getVolume()
1440{
1441	return mRequestedVolume;
1442}
1443
1444void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history)
1445{
1446	// Send URL history to plugin
1447	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "init_history");
1448	message.setValueLLSD("history", url_history);
1449	sendMessage(message);
1450
1451	LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL;
1452}
1453