PageRenderTime 84ms CodeModel.GetById 17ms app.highlight 59ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/newview/llmediactrl.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1139 lines | 832 code | 172 blank | 135 comment | 96 complexity | df42e761caa94004d94f0750496b0e64 MD5 | raw file
   1/**
   2 * @file LLMediaCtrl.cpp
   3 * @brief Web browser UI control
   4 *
   5 * $LicenseInfo:firstyear=2006&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "llviewerprecompiledheaders.h"
  28#include "lltooltip.h"
  29
  30#include "llmediactrl.h"
  31
  32// viewer includes
  33#include "llfloaterworldmap.h"
  34#include "lluictrlfactory.h"
  35#include "llurldispatcher.h"
  36#include "llviewborder.h"
  37#include "llviewercontrol.h"
  38#include "llviewermedia.h"
  39#include "llviewertexture.h"
  40#include "llviewerwindow.h"
  41#include "lldebugmessagebox.h"
  42#include "llweb.h"
  43#include "llrender.h"
  44#include "llpluginclassmedia.h"
  45#include "llslurl.h"
  46#include "lluictrlfactory.h"	// LLDefaultChildRegistry
  47#include "llkeyboard.h"
  48#include "llviewermenu.h"
  49
  50// linden library includes
  51#include "llfocusmgr.h"
  52#include "llsdutil.h"
  53#include "lllayoutstack.h"
  54#include "lliconctrl.h"
  55#include "lltextbox.h"
  56#include "llbutton.h"
  57#include "llcheckboxctrl.h"
  58#include "llnotifications.h"
  59#include "lllineeditor.h"
  60#include "llfloaterwebcontent.h"
  61#include "llwindowshade.h"
  62
  63extern BOOL gRestoreGL;
  64
  65static LLDefaultChildRegistry::Register<LLMediaCtrl> r("web_browser");
  66
  67LLMediaCtrl::Params::Params()
  68:	start_url("start_url"),
  69	border_visible("border_visible", true),
  70	decouple_texture_size("decouple_texture_size", false),
  71	texture_width("texture_width", 1024),
  72	texture_height("texture_height", 1024),
  73	caret_color("caret_color"),
  74	initial_mime_type("initial_mime_type"),
  75	error_page_url("error_page_url"),
  76	media_id("media_id"),
  77	trusted_content("trusted_content", false),
  78	focus_on_click("focus_on_click", true)
  79{
  80}
  81
  82LLMediaCtrl::LLMediaCtrl( const Params& p) :
  83	LLPanel( p ),
  84	LLInstanceTracker<LLMediaCtrl, LLUUID>(LLUUID::generateNewID()),
  85	mTextureDepthBytes( 4 ),
  86	mBorder(NULL),
  87	mFrequentUpdates( true ),
  88	mForceUpdate( false ),
  89	mHomePageUrl( "" ),
  90	mAlwaysRefresh( false ),
  91	mMediaSource( 0 ),
  92	mTakeFocusOnClick( p.focus_on_click ),
  93	mCurrentNavUrl( "" ),
  94	mStretchToFill( true ),
  95	mMaintainAspectRatio ( true ),
  96	mDecoupleTextureSize ( false ),
  97	mTextureWidth ( 1024 ),
  98	mTextureHeight ( 1024 ),
  99	mClearCache(false),
 100	mHomePageMimeType(p.initial_mime_type),
 101	mErrorPageURL(p.error_page_url),
 102	mTrusted(p.trusted_content),
 103	mWindowShade(NULL),
 104	mHoverTextChanged(false),
 105	mContextMenu(NULL)
 106{
 107	{
 108		LLColor4 color = p.caret_color().get();
 109		setCaretColor( (unsigned int)color.mV[0], (unsigned int)color.mV[1], (unsigned int)color.mV[2] );
 110	}
 111
 112	setHomePageUrl(p.start_url, p.initial_mime_type);
 113	
 114	setBorderVisible(p.border_visible);
 115	
 116	setDecoupleTextureSize(p.decouple_texture_size);
 117	
 118	setTextureSize(p.texture_width, p.texture_height);
 119
 120	if(!getDecoupleTextureSize())
 121	{
 122		S32 screen_width = llround((F32)getRect().getWidth() * LLUI::sGLScaleFactor.mV[VX]);
 123		S32 screen_height = llround((F32)getRect().getHeight() * LLUI::sGLScaleFactor.mV[VY]);
 124			
 125		setTextureSize(screen_width, screen_height);
 126	}
 127	
 128	mMediaTextureID = getKey();
 129	
 130	// We don't need to create the media source up front anymore unless we have a non-empty home URL to navigate to.
 131	if(!mHomePageUrl.empty())
 132	{
 133		navigateHome();
 134	}
 135		
 136	LLWindowShade::Params params;
 137	params.name = "notification_shade";
 138	params.rect = getLocalRect();
 139	params.follows.flags = FOLLOWS_ALL;
 140	params.modal = true;
 141
 142	mWindowShade = LLUICtrlFactory::create<LLWindowShade>(params);
 143
 144	addChild(mWindowShade);
 145}
 146
 147LLMediaCtrl::~LLMediaCtrl()
 148{
 149	if (mMediaSource)
 150	{
 151		mMediaSource->remObserver( this );
 152		mMediaSource = NULL;
 153	}
 154}
 155
 156////////////////////////////////////////////////////////////////////////////////
 157//
 158void LLMediaCtrl::setBorderVisible( BOOL border_visible )
 159{
 160	if ( mBorder )
 161	{
 162		mBorder->setVisible( border_visible );
 163	};
 164};
 165
 166////////////////////////////////////////////////////////////////////////////////
 167//
 168void LLMediaCtrl::setTakeFocusOnClick( bool take_focus )
 169{
 170	mTakeFocusOnClick = take_focus;
 171}
 172
 173////////////////////////////////////////////////////////////////////////////////
 174//
 175BOOL LLMediaCtrl::handleHover( S32 x, S32 y, MASK mask )
 176{
 177	if (LLPanel::handleHover(x, y, mask)) return TRUE;
 178	convertInputCoords(x, y);
 179
 180	if (mMediaSource)
 181	{
 182		mMediaSource->mouseMove(x, y, mask);
 183		gViewerWindow->setCursor(mMediaSource->getLastSetCursor());
 184	}
 185	
 186	// TODO: Is this the right way to handle hover text changes driven by the plugin?
 187	if(mHoverTextChanged)
 188	{
 189		mHoverTextChanged = false;
 190		handleToolTip(x, y, mask);
 191	}
 192
 193	return TRUE;
 194}
 195
 196////////////////////////////////////////////////////////////////////////////////
 197//
 198BOOL LLMediaCtrl::handleScrollWheel( S32 x, S32 y, S32 clicks )
 199{
 200	if (LLPanel::handleScrollWheel(x, y, clicks)) return TRUE;
 201	if (mMediaSource && mMediaSource->hasMedia())
 202		mMediaSource->getMediaPlugin()->scrollEvent(0, clicks, gKeyboard->currentMask(TRUE));
 203
 204	return TRUE;
 205}
 206
 207////////////////////////////////////////////////////////////////////////////////
 208//	virtual 
 209BOOL LLMediaCtrl::handleToolTip(S32 x, S32 y, MASK mask)
 210{
 211	std::string hover_text;
 212	
 213	if (mMediaSource && mMediaSource->hasMedia())
 214		hover_text = mMediaSource->getMediaPlugin()->getHoverText();
 215	
 216	if(hover_text.empty())
 217	{
 218		return FALSE;
 219	}
 220	else
 221	{
 222		S32 screen_x, screen_y;
 223
 224		localPointToScreen(x, y, &screen_x, &screen_y);
 225		LLRect sticky_rect_screen;
 226		sticky_rect_screen.setCenterAndSize(screen_x, screen_y, 20, 20);
 227
 228		LLToolTipMgr::instance().show(LLToolTip::Params()
 229			.message(hover_text)
 230			.sticky_rect(sticky_rect_screen));		
 231	}
 232
 233	return TRUE;
 234}
 235
 236////////////////////////////////////////////////////////////////////////////////
 237//
 238BOOL LLMediaCtrl::handleMouseUp( S32 x, S32 y, MASK mask )
 239{
 240	if (LLPanel::handleMouseUp(x, y, mask)) return TRUE;
 241	convertInputCoords(x, y);
 242
 243	if (mMediaSource)
 244	{
 245		mMediaSource->mouseUp(x, y, mask);
 246	}
 247	
 248	gFocusMgr.setMouseCapture( NULL );
 249
 250	return TRUE;
 251}
 252
 253////////////////////////////////////////////////////////////////////////////////
 254//
 255BOOL LLMediaCtrl::handleMouseDown( S32 x, S32 y, MASK mask )
 256{
 257	if (LLPanel::handleMouseDown(x, y, mask)) return TRUE;
 258	convertInputCoords(x, y);
 259
 260	if (mMediaSource)
 261		mMediaSource->mouseDown(x, y, mask);
 262	
 263	gFocusMgr.setMouseCapture( this );
 264
 265	if (mTakeFocusOnClick)
 266	{
 267		setFocus( TRUE );
 268	}
 269
 270	return TRUE;
 271}
 272
 273////////////////////////////////////////////////////////////////////////////////
 274//
 275BOOL LLMediaCtrl::handleRightMouseUp( S32 x, S32 y, MASK mask )
 276{
 277	if (LLPanel::handleRightMouseUp(x, y, mask)) return TRUE;
 278	convertInputCoords(x, y);
 279
 280	if (mMediaSource)
 281	{
 282		mMediaSource->mouseUp(x, y, mask, 1);
 283
 284		// *HACK: LLMediaImplLLMozLib automatically takes focus on mouseup,
 285		// in addition to the onFocusReceived() call below.  Undo this. JC
 286		if (!mTakeFocusOnClick)
 287		{
 288			mMediaSource->focus(false);
 289			gViewerWindow->focusClient();
 290		}
 291	}
 292	
 293	gFocusMgr.setMouseCapture( NULL );
 294
 295	return TRUE;
 296}
 297
 298////////////////////////////////////////////////////////////////////////////////
 299//
 300BOOL LLMediaCtrl::handleRightMouseDown( S32 x, S32 y, MASK mask )
 301{
 302	if (LLPanel::handleRightMouseDown(x, y, mask)) return TRUE;
 303
 304	S32 media_x = x, media_y = y;
 305	convertInputCoords(media_x, media_y);
 306
 307	if (mMediaSource)
 308		mMediaSource->mouseDown(media_x, media_y, mask, 1);
 309	
 310	gFocusMgr.setMouseCapture( this );
 311
 312	if (mTakeFocusOnClick)
 313	{
 314		setFocus( TRUE );
 315	}
 316
 317	if (mContextMenu)
 318	{
 319		// hide/show debugging options
 320		bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging");
 321		mContextMenu->setItemVisible("open_webinspector", media_plugin_debugging_enabled );
 322		mContextMenu->setItemVisible("debug_separator", media_plugin_debugging_enabled );
 323
 324		mContextMenu->show(x, y);
 325		LLMenuGL::showPopup(this, mContextMenu, x, y);
 326	}
 327
 328	return TRUE;
 329}
 330
 331////////////////////////////////////////////////////////////////////////////////
 332//
 333BOOL LLMediaCtrl::handleDoubleClick( S32 x, S32 y, MASK mask )
 334{
 335	if (LLPanel::handleDoubleClick(x, y, mask)) return TRUE;
 336	convertInputCoords(x, y);
 337
 338	if (mMediaSource)
 339		mMediaSource->mouseDoubleClick( x, y, mask);
 340
 341	gFocusMgr.setMouseCapture( this );
 342
 343	if (mTakeFocusOnClick)
 344	{
 345		setFocus( TRUE );
 346	}
 347
 348	return TRUE;
 349}
 350
 351////////////////////////////////////////////////////////////////////////////////
 352//
 353void LLMediaCtrl::onFocusReceived()
 354{
 355	if (mMediaSource)
 356	{
 357		mMediaSource->focus(true);
 358		
 359		// Set focus for edit menu items
 360		LLEditMenuHandler::gEditMenuHandler = mMediaSource;
 361	}
 362	
 363	LLPanel::onFocusReceived();
 364}
 365
 366////////////////////////////////////////////////////////////////////////////////
 367//
 368void LLMediaCtrl::onFocusLost()
 369{
 370	if (mMediaSource)
 371	{
 372		mMediaSource->focus(false);
 373
 374		if( LLEditMenuHandler::gEditMenuHandler == mMediaSource )
 375		{
 376			// Clear focus for edit menu items
 377			LLEditMenuHandler::gEditMenuHandler = NULL;
 378		}
 379	}
 380
 381	gViewerWindow->focusClient();
 382
 383	LLPanel::onFocusLost();
 384}
 385
 386////////////////////////////////////////////////////////////////////////////////
 387//
 388BOOL LLMediaCtrl::postBuild ()
 389{
 390	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar;
 391	registar.add("Open.WebInspector", boost::bind(&LLMediaCtrl::onOpenWebInspector, this));
 392
 393	mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(
 394		"menu_media_ctrl.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
 395	setVisibleCallback(boost::bind(&LLMediaCtrl::onVisibilityChange, this, _2));
 396
 397	return TRUE;
 398}
 399
 400void LLMediaCtrl::onOpenWebInspector()
 401{
 402	if (mMediaSource && mMediaSource->hasMedia())
 403		mMediaSource->getMediaPlugin()->showWebInspector( true );
 404}
 405
 406////////////////////////////////////////////////////////////////////////////////
 407//
 408BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask )
 409{
 410	BOOL result = FALSE;
 411	
 412	if (mMediaSource)
 413	{
 414		result = mMediaSource->handleKeyHere(key, mask);
 415	}
 416	
 417	if ( ! result )
 418		result = LLPanel::handleKeyHere(key, mask);
 419		
 420	return result;
 421}
 422
 423////////////////////////////////////////////////////////////////////////////////
 424//
 425void LLMediaCtrl::handleVisibilityChange ( BOOL new_visibility )
 426{
 427	llinfos << "visibility changed to " << (new_visibility?"true":"false") << llendl;
 428	if(mMediaSource)
 429	{
 430		mMediaSource->setVisible( new_visibility );
 431	}
 432}
 433
 434////////////////////////////////////////////////////////////////////////////////
 435//
 436BOOL LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char)
 437{
 438	BOOL result = FALSE;
 439	
 440	if (mMediaSource)
 441	{
 442		result = mMediaSource->handleUnicodeCharHere(uni_char);
 443	}
 444
 445	if ( ! result )
 446		result = LLPanel::handleUnicodeCharHere(uni_char);
 447
 448	return result;
 449}
 450
 451////////////////////////////////////////////////////////////////////////////////
 452//
 453void LLMediaCtrl::onVisibilityChange ( const LLSD& new_visibility )
 454{
 455	// set state of frequent updates automatically if visibility changes
 456	if ( new_visibility.asBoolean() )
 457	{
 458		mFrequentUpdates = true;
 459	}
 460	else
 461	{
 462		mFrequentUpdates = false;
 463	}
 464}
 465
 466////////////////////////////////////////////////////////////////////////////////
 467//
 468void LLMediaCtrl::reshape( S32 width, S32 height, BOOL called_from_parent )
 469{
 470	if(!getDecoupleTextureSize())
 471	{
 472		S32 screen_width = llround((F32)width * LLUI::sGLScaleFactor.mV[VX]);
 473		S32 screen_height = llround((F32)height * LLUI::sGLScaleFactor.mV[VY]);
 474
 475		// when floater is minimized, these sizes are negative
 476		if ( screen_height > 0 && screen_width > 0 )
 477		{
 478			setTextureSize(screen_width, screen_height);
 479		}
 480	}
 481	
 482	LLUICtrl::reshape( width, height, called_from_parent );
 483}
 484
 485////////////////////////////////////////////////////////////////////////////////
 486//
 487void LLMediaCtrl::navigateBack()
 488{
 489	if (mMediaSource && mMediaSource->hasMedia())
 490	{
 491		mMediaSource->getMediaPlugin()->browse_back();
 492	}
 493}
 494
 495////////////////////////////////////////////////////////////////////////////////
 496//
 497void LLMediaCtrl::navigateForward()
 498{
 499	if (mMediaSource && mMediaSource->hasMedia())
 500	{
 501		mMediaSource->getMediaPlugin()->browse_forward();
 502	}
 503}
 504
 505////////////////////////////////////////////////////////////////////////////////
 506//
 507bool LLMediaCtrl::canNavigateBack()
 508{
 509	if (mMediaSource)
 510		return mMediaSource->canNavigateBack();
 511	else
 512		return false;
 513}
 514
 515////////////////////////////////////////////////////////////////////////////////
 516//
 517bool LLMediaCtrl::canNavigateForward()
 518{
 519	if (mMediaSource)
 520		return mMediaSource->canNavigateForward();
 521	else
 522		return false;
 523}
 524
 525////////////////////////////////////////////////////////////////////////////////
 526//
 527void LLMediaCtrl::clearCache()
 528{
 529	if(mMediaSource)
 530	{
 531		mMediaSource->clearCache();
 532	}
 533	else
 534	{
 535		mClearCache = true;
 536	}
 537
 538}
 539
 540////////////////////////////////////////////////////////////////////////////////
 541//
 542void LLMediaCtrl::navigateTo( std::string url_in, std::string mime_type)
 543{
 544	// don't browse to anything that starts with secondlife:// or sl://
 545	const std::string protocol1 = "secondlife://";
 546	const std::string protocol2 = "sl://";
 547	if ((LLStringUtil::compareInsensitive(url_in.substr(0, protocol1.length()), protocol1) == 0) ||
 548	    (LLStringUtil::compareInsensitive(url_in.substr(0, protocol2.length()), protocol2) == 0))
 549	{
 550		// TODO: Print out/log this attempt?
 551		// llinfos << "Rejecting attempt to load restricted website :" << urlIn << llendl;
 552		return;
 553	}
 554	
 555	if (ensureMediaSourceExists())
 556	{
 557		mCurrentNavUrl = url_in;
 558		mMediaSource->setSize(mTextureWidth, mTextureHeight);
 559		mMediaSource->navigateTo(url_in, mime_type, mime_type.empty());
 560	}
 561}
 562
 563////////////////////////////////////////////////////////////////////////////////
 564//
 565void LLMediaCtrl::navigateToLocalPage( const std::string& subdir, const std::string& filename_in )
 566{
 567	std::string language = LLUI::getLanguage();
 568	std::string delim = gDirUtilp->getDirDelimiter();
 569	std::string filename;
 570
 571	filename += subdir;
 572	filename += delim;
 573	filename += filename_in;
 574
 575	std::string expanded_filename = gDirUtilp->findSkinnedFilename("html", language, filename);
 576
 577	if (! gDirUtilp->fileExists(expanded_filename))
 578	{
 579		if (language != "en")
 580		{
 581			expanded_filename = gDirUtilp->findSkinnedFilename("html", "en", filename);
 582			if (! gDirUtilp->fileExists(expanded_filename))
 583			{
 584				llwarns << "File " << subdir << delim << filename_in << "not found" << llendl;
 585				return;
 586			}
 587		}
 588		else
 589		{
 590			llwarns << "File " << subdir << delim << filename_in << "not found" << llendl;
 591			return;
 592		}
 593	}
 594	if (ensureMediaSourceExists())
 595	{
 596		mCurrentNavUrl = expanded_filename;
 597		mMediaSource->setSize(mTextureWidth, mTextureHeight);
 598		mMediaSource->navigateTo(expanded_filename, "text/html", false);
 599	}
 600
 601}
 602
 603////////////////////////////////////////////////////////////////////////////////
 604//
 605void LLMediaCtrl::navigateHome()
 606{
 607	if (ensureMediaSourceExists())
 608	{
 609		mMediaSource->setSize(mTextureWidth, mTextureHeight);
 610		mMediaSource->navigateHome();
 611	}
 612}
 613
 614////////////////////////////////////////////////////////////////////////////////
 615//
 616void LLMediaCtrl::setHomePageUrl( const std::string& urlIn, const std::string& mime_type )
 617{
 618	mHomePageUrl = urlIn;
 619	if (mMediaSource)
 620	{
 621		mMediaSource->setHomeURL(mHomePageUrl, mime_type);
 622	}
 623}
 624
 625void LLMediaCtrl::setTarget(const std::string& target)
 626{
 627	mTarget = target;
 628	if (mMediaSource)
 629	{
 630		mMediaSource->setTarget(mTarget);
 631	}
 632}
 633
 634void LLMediaCtrl::setErrorPageURL(const std::string& url)
 635{
 636	mErrorPageURL = url;
 637}
 638
 639const std::string& LLMediaCtrl::getErrorPageURL()
 640{
 641	return mErrorPageURL;
 642}
 643
 644////////////////////////////////////////////////////////////////////////////////
 645//
 646bool LLMediaCtrl::setCaretColor(unsigned int red, unsigned int green, unsigned int blue)
 647{
 648	//NOOP
 649	return false;
 650}
 651
 652////////////////////////////////////////////////////////////////////////////////
 653//
 654void LLMediaCtrl::setTextureSize(S32 width, S32 height)
 655{
 656	mTextureWidth = width;
 657	mTextureHeight = height;
 658	
 659	if(mMediaSource)
 660	{
 661		mMediaSource->setSize(mTextureWidth, mTextureHeight);
 662		mForceUpdate = true;
 663	}
 664}
 665
 666////////////////////////////////////////////////////////////////////////////////
 667//
 668std::string LLMediaCtrl::getHomePageUrl()
 669{
 670	return 	mHomePageUrl;
 671}
 672
 673////////////////////////////////////////////////////////////////////////////////
 674//
 675bool LLMediaCtrl::ensureMediaSourceExists()
 676{	
 677	if(mMediaSource.isNull())
 678	{
 679		// If we don't already have a media source, try to create one.
 680		mMediaSource = LLViewerMedia::newMediaImpl(mMediaTextureID, mTextureWidth, mTextureHeight);
 681		if ( mMediaSource )
 682		{
 683			mMediaSource->setUsedInUI(true);
 684			mMediaSource->setHomeURL(mHomePageUrl, mHomePageMimeType);
 685			mMediaSource->setTarget(mTarget);
 686			mMediaSource->setVisible( getVisible() );
 687			mMediaSource->addObserver( this );
 688			mMediaSource->setBackgroundColor( getBackgroundColor() );
 689			mMediaSource->setTrustedBrowser(mTrusted);
 690			mMediaSource->setPageZoomFactor( LLUI::sGLScaleFactor.mV[ VX ] );
 691
 692			if(mClearCache)
 693			{
 694				mMediaSource->clearCache();
 695				mClearCache = false;
 696			}
 697		}
 698		else
 699		{
 700			llwarns << "media source create failed " << llendl;
 701			// return;
 702		}
 703	}
 704	
 705	return !mMediaSource.isNull();
 706}
 707
 708////////////////////////////////////////////////////////////////////////////////
 709//
 710void LLMediaCtrl::unloadMediaSource()
 711{
 712	mMediaSource = NULL;
 713}
 714
 715////////////////////////////////////////////////////////////////////////////////
 716//
 717LLPluginClassMedia* LLMediaCtrl::getMediaPlugin()
 718{ 
 719	return mMediaSource.isNull() ? NULL : mMediaSource->getMediaPlugin(); 
 720}
 721
 722////////////////////////////////////////////////////////////////////////////////
 723//
 724void LLMediaCtrl::draw()
 725{
 726	F32 alpha = getDrawContext().mAlpha;
 727
 728	if ( gRestoreGL == 1 )
 729	{
 730		LLRect r = getRect();
 731		reshape( r.getWidth(), r.getHeight(), FALSE );
 732		return;
 733	}
 734
 735	// NOTE: optimization needed here - probably only need to do this once
 736	// unless tearoffs change the parent which they probably do.
 737	const LLUICtrl* ptr = findRootMostFocusRoot();
 738	if ( ptr && ptr->hasFocus() )
 739	{
 740		setFrequentUpdates( true );
 741	}
 742	else
 743	{
 744		setFrequentUpdates( false );
 745	};
 746	
 747	bool draw_media = false;
 748	
 749	LLPluginClassMedia* media_plugin = NULL;
 750	LLViewerMediaTexture* media_texture = NULL;
 751	
 752	if(mMediaSource && mMediaSource->hasMedia())
 753	{
 754		media_plugin = mMediaSource->getMediaPlugin();
 755
 756		if(media_plugin && (media_plugin->textureValid()))
 757		{
 758			media_texture = LLViewerTextureManager::findMediaTexture(mMediaTextureID);
 759			if(media_texture)
 760			{
 761				draw_media = true;
 762			}
 763		}
 764	}
 765	
 766	bool background_visible = isBackgroundVisible();
 767	bool background_opaque = isBackgroundOpaque();
 768	
 769	if(draw_media)
 770	{
 771		gGL.pushUIMatrix();
 772		{
 773			mMediaSource->setPageZoomFactor( LLUI::sGLScaleFactor.mV[ VX ] );
 774
 775			// scale texture to fit the space using texture coords
 776			gGL.getTexUnit(0)->bind(media_texture);
 777			LLColor4 media_color = LLColor4::white % alpha;
 778			gGL.color4fv( media_color.mV );
 779			F32 max_u = ( F32 )media_plugin->getWidth() / ( F32 )media_plugin->getTextureWidth();
 780			F32 max_v = ( F32 )media_plugin->getHeight() / ( F32 )media_plugin->getTextureHeight();
 781
 782			LLRect r = getRect();
 783			S32 width, height;
 784			S32 x_offset = 0;
 785			S32 y_offset = 0;
 786			
 787			if(mStretchToFill)
 788			{
 789				if(mMaintainAspectRatio)
 790				{
 791					F32 media_aspect = (F32)(media_plugin->getWidth()) / (F32)(media_plugin->getHeight());
 792					F32 view_aspect = (F32)(r.getWidth()) / (F32)(r.getHeight());
 793					if(media_aspect > view_aspect)
 794					{
 795						// max width, adjusted height
 796						width = r.getWidth();
 797						height = llmin(llmax(llround(width / media_aspect), 0), r.getHeight());
 798					}
 799					else
 800					{
 801						// max height, adjusted width
 802						height = r.getHeight();
 803						width = llmin(llmax(llround(height * media_aspect), 0), r.getWidth());
 804					}
 805				}
 806				else
 807				{
 808					width = r.getWidth();
 809					height = r.getHeight();
 810				}
 811			}
 812			else
 813			{
 814				width = llmin(media_plugin->getWidth(), r.getWidth());
 815				height = llmin(media_plugin->getHeight(), r.getHeight());
 816			}
 817			
 818			x_offset = (r.getWidth() - width) / 2;
 819			y_offset = (r.getHeight() - height) / 2;		
 820
 821			// draw the browser
 822			gGL.begin( LLRender::QUADS );
 823			if (! media_plugin->getTextureCoordsOpenGL())
 824			{
 825				// render using web browser reported width and height, instead of trying to invert GL scale
 826				gGL.texCoord2f( max_u, 0.f );
 827				gGL.vertex2i( x_offset + width, y_offset + height );
 828
 829				gGL.texCoord2f( 0.f, 0.f );
 830				gGL.vertex2i( x_offset, y_offset + height );
 831
 832				gGL.texCoord2f( 0.f, max_v );
 833				gGL.vertex2i( x_offset, y_offset );
 834
 835				gGL.texCoord2f( max_u, max_v );
 836				gGL.vertex2i( x_offset + width, y_offset );
 837			}
 838			else
 839			{
 840				// render using web browser reported width and height, instead of trying to invert GL scale
 841				gGL.texCoord2f( max_u, max_v );
 842				gGL.vertex2i( x_offset + width, y_offset + height );
 843
 844				gGL.texCoord2f( 0.f, max_v );
 845				gGL.vertex2i( x_offset, y_offset + height );
 846
 847				gGL.texCoord2f( 0.f, 0.f );
 848				gGL.vertex2i( x_offset, y_offset );
 849
 850				gGL.texCoord2f( max_u, 0.f );
 851				gGL.vertex2i( x_offset + width, y_offset );
 852			}
 853			gGL.end();
 854		}
 855		gGL.popUIMatrix();
 856	
 857	}
 858	else
 859	{
 860		// Setting these will make LLPanel::draw draw the opaque background color.
 861		setBackgroundVisible(true);
 862		setBackgroundOpaque(true);
 863	}
 864	
 865	// highlight if keyboard focus here. (TODO: this needs some work)
 866	if ( mBorder && mBorder->getVisible() )
 867		mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus( this ) );
 868
 869	LLPanel::draw();
 870
 871	// Restore the previous values
 872	setBackgroundVisible(background_visible);
 873	setBackgroundOpaque(background_opaque);
 874}
 875
 876////////////////////////////////////////////////////////////////////////////////
 877//
 878void LLMediaCtrl::convertInputCoords(S32& x, S32& y)
 879{
 880	bool coords_opengl = false;
 881	
 882	if(mMediaSource && mMediaSource->hasMedia())
 883	{
 884		coords_opengl = mMediaSource->getMediaPlugin()->getTextureCoordsOpenGL();
 885	}
 886	
 887	x = llround((F32)x * LLUI::sGLScaleFactor.mV[VX]);
 888	if ( ! coords_opengl )
 889	{
 890		y = llround((F32)(y) * LLUI::sGLScaleFactor.mV[VY]);
 891	}
 892	else
 893	{
 894		y = llround((F32)(getRect().getHeight() - y) * LLUI::sGLScaleFactor.mV[VY]);
 895	};
 896}
 897
 898////////////////////////////////////////////////////////////////////////////////
 899// inherited from LLViewerMediaObserver
 900//virtual 
 901void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
 902{
 903	switch(event)
 904	{
 905		case MEDIA_EVENT_CONTENT_UPDATED:
 906		{
 907			// LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_CONTENT_UPDATED " << LL_ENDL;
 908		};
 909		break;
 910		
 911		case MEDIA_EVENT_TIME_DURATION_UPDATED:
 912		{
 913			// LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_TIME_DURATION_UPDATED, time is " << self->getCurrentTime() << " of " << self->getDuration() << LL_ENDL;
 914		};
 915		break;
 916		
 917		case MEDIA_EVENT_SIZE_CHANGED:
 918		{
 919			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_SIZE_CHANGED " << LL_ENDL;
 920			LLRect r = getRect();
 921			reshape( r.getWidth(), r.getHeight(), FALSE );
 922		};
 923		break;
 924		
 925		case MEDIA_EVENT_CURSOR_CHANGED:
 926		{
 927			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << self->getCursorName() << LL_ENDL;
 928		}
 929		break;
 930			
 931		case MEDIA_EVENT_NAVIGATE_BEGIN:
 932		{
 933			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_NAVIGATE_BEGIN, url is " << self->getNavigateURI() << LL_ENDL;
 934			hideNotification();
 935		};
 936		break;
 937		
 938		case MEDIA_EVENT_NAVIGATE_COMPLETE:
 939		{
 940			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_NAVIGATE_COMPLETE, result string is: " << self->getNavigateResultString() << LL_ENDL;
 941			if(mHidingInitialLoad)
 942			{
 943				mHidingInitialLoad = false;
 944			}
 945		};
 946		break;
 947
 948		case MEDIA_EVENT_PROGRESS_UPDATED:
 949		{
 950			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_PROGRESS_UPDATED, loading at " << self->getProgressPercent() << "%" << LL_ENDL;
 951		};
 952		break;
 953
 954		case MEDIA_EVENT_STATUS_TEXT_CHANGED:
 955		{
 956			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_STATUS_TEXT_CHANGED, new status text is: " << self->getStatusText() << LL_ENDL;
 957		};
 958		break;
 959
 960		case MEDIA_EVENT_LOCATION_CHANGED:
 961		{
 962			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_LOCATION_CHANGED, new uri is: " << self->getLocation() << LL_ENDL;
 963		};
 964		break;
 965
 966		case MEDIA_EVENT_NAVIGATE_ERROR_PAGE:
 967		{
 968			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_NAVIGATE_ERROR_PAGE" << LL_ENDL;
 969			if ( mErrorPageURL.length() > 0 )
 970			{
 971				navigateTo(mErrorPageURL, "text/html");
 972			};
 973		};
 974		break;
 975
 976		case MEDIA_EVENT_CLICK_LINK_HREF:
 977		{
 978			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL;
 979			// retrieve the event parameters
 980			std::string url = self->getClickURL();
 981			std::string target = self->getClickTarget();
 982			std::string uuid = self->getClickUUID();
 983
 984			LLNotification::Params notify_params;
 985			notify_params.name = "PopupAttempt";
 986			notify_params.payload = LLSD().with("target", target).with("url", url).with("uuid", uuid).with("media_id", mMediaTextureID);
 987			notify_params.functor.function = boost::bind(&LLMediaCtrl::onPopup, this, _1, _2);
 988
 989			if (mTrusted)
 990			{
 991				LLNotifications::instance().forceResponse(notify_params, 0);
 992			}
 993			else
 994			{
 995				LLNotifications::instance().add(notify_params);
 996			}
 997			break;
 998		};
 999
1000		case MEDIA_EVENT_CLICK_LINK_NOFOLLOW:
1001		{
1002			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is " << self->getClickURL() << LL_ENDL;
1003		};
1004		break;
1005
1006		case MEDIA_EVENT_PLUGIN_FAILED:
1007		{
1008			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_PLUGIN_FAILED" << LL_ENDL;
1009		};
1010		break;
1011
1012		case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH:
1013		{
1014			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_PLUGIN_FAILED_LAUNCH" << LL_ENDL;
1015		};
1016		break;
1017		
1018		case MEDIA_EVENT_NAME_CHANGED:
1019		{
1020			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_NAME_CHANGED" << LL_ENDL;
1021		};
1022		break;
1023		
1024		case MEDIA_EVENT_CLOSE_REQUEST:
1025		{
1026			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_CLOSE_REQUEST" << LL_ENDL;
1027		}
1028		break;
1029		
1030		case MEDIA_EVENT_PICK_FILE_REQUEST:
1031		{
1032			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_PICK_FILE_REQUEST" << LL_ENDL;
1033		}
1034		break;
1035		
1036		case MEDIA_EVENT_GEOMETRY_CHANGE:
1037		{
1038			LL_DEBUGS("Media") << "Media event:  MEDIA_EVENT_GEOMETRY_CHANGE, uuid is " << self->getClickUUID() << LL_ENDL;
1039		}
1040		break;
1041
1042		case MEDIA_EVENT_AUTH_REQUEST:
1043		{
1044			LLNotification::Params auth_request_params;
1045			auth_request_params.name = "AuthRequest";
1046
1047			// pass in host name and realm for site (may be zero length but will always exist)
1048			LLSD args;
1049			LLURL raw_url( self->getAuthURL().c_str() );
1050			args["HOST_NAME"] = raw_url.getAuthority();
1051			args["REALM"] = self->getAuthRealm();
1052			auth_request_params.substitutions = args;
1053
1054			auth_request_params.payload = LLSD().with("media_id", mMediaTextureID);
1055			auth_request_params.functor.function = boost::bind(&LLViewerMedia::onAuthSubmit, _1, _2);
1056			LLNotifications::instance().add(auth_request_params);
1057		};
1058		break;
1059
1060		case MEDIA_EVENT_LINK_HOVERED:
1061		{
1062			LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << LL_ENDL;
1063			mHoverTextChanged = true;
1064		};
1065		break;
1066
1067		case MEDIA_EVENT_DEBUG_MESSAGE:
1068		{
1069			LL_INFOS("media") << self->getDebugMessageText() << LL_ENDL; 
1070		};
1071		break;
1072	};
1073
1074	// chain all events to any potential observers of this object.
1075	emitEvent(self, event);
1076}
1077
1078////////////////////////////////////////////////////////////////////////////////
1079// 
1080std::string LLMediaCtrl::getCurrentNavUrl()
1081{
1082	return mCurrentNavUrl;
1083}
1084
1085void LLMediaCtrl::onPopup(const LLSD& notification, const LLSD& response)
1086{
1087	if (response["open"])
1088	{
1089		LLWeb::loadURL(notification["payload"]["url"], notification["payload"]["target"], notification["payload"]["uuid"]);
1090	}
1091	else
1092	{
1093		// Make sure the opening instance knows its window open request was denied, so it can clean things up.
1094		LLViewerMedia::proxyWindowClosed(notification["payload"]["uuid"]);
1095	}
1096}
1097
1098void LLMediaCtrl::showNotification(LLNotificationPtr notify)
1099{
1100	LLWindowShade* shade = getChild<LLWindowShade>("notification_shade");
1101
1102	if (notify->getIcon() == "Popup_Caution")
1103	{
1104		shade->setBackgroundImage(LLUI::getUIImage("Yellow_Gradient"));
1105		shade->setTextColor(LLColor4::black);
1106		shade->setCanClose(true);
1107	}
1108	else if (notify->getName() == "AuthRequest")
1109	{
1110		shade->setBackgroundImage(LLUI::getUIImage("Yellow_Gradient"));
1111		shade->setTextColor(LLColor4::black);
1112		shade->setCanClose(false);
1113	}
1114	else
1115	{
1116		//HACK: make this a property of the notification itself, "cancellable"
1117		shade->setCanClose(false);
1118		shade->setTextColor(LLUIColorTable::instance().getColor("LabelTextColor"));
1119	}
1120
1121	mWindowShade->show(notify);
1122}
1123
1124void LLMediaCtrl::hideNotification()
1125{
1126	if (mWindowShade)
1127	{
1128		mWindowShade->hide();
1129	}
1130}
1131
1132void LLMediaCtrl::setTrustedContent(bool trusted)
1133{
1134	mTrusted = trusted;
1135	if (mMediaSource)
1136	{
1137		mMediaSource->setTrustedBrowser(trusted);
1138	}
1139}