summaryrefslogtreecommitdiff
path: root/indra/newview/llmediactrl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llmediactrl.cpp')
-rw-r--r--indra/newview/llmediactrl.cpp937
1 files changed, 937 insertions, 0 deletions
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
new file mode 100644
index 0000000000..62b38f2b4a
--- /dev/null
+++ b/indra/newview/llmediactrl.cpp
@@ -0,0 +1,937 @@
+/**
+ * @file LLMediaCtrl.cpp
+ * @brief Web browser UI control
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ *
+ * Copyright (c) 2006-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+
+#include "llmediactrl.h"
+
+// viewer includes
+#include "llfloaterhtml.h"
+#include "llfloaterworldmap.h"
+#include "lluictrlfactory.h"
+#include "llurldispatcher.h"
+#include "llurlsimstring.h"
+#include "llviewborder.h"
+#include "llviewercontrol.h"
+#include "llviewermedia.h"
+#include "llviewerwindow.h"
+#include "llnotifications.h"
+#include "llweb.h"
+#include "llrender.h"
+#include "llpluginclassmedia.h"
+#include "llslurl.h"
+#include "lluictrlfactory.h" // LLDefaultChildRegistry
+
+// linden library includes
+#include "llfocusmgr.h"
+
+extern BOOL gRestoreGL;
+
+static LLDefaultChildRegistry::Register<LLMediaCtrl> r("web_browser");
+
+LLMediaCtrl::Params::Params()
+: start_url("start_url"),
+ border_visible("border_visible", true),
+ ignore_ui_scale("ignore_ui_scale", true),
+ hide_loading("hide_loading", false),
+ caret_color("caret_color")
+{}
+
+LLMediaCtrl::LLMediaCtrl( const Params& p) :
+ LLPanel( p ),
+ mTextureDepthBytes( 4 ),
+ mBorder(NULL),
+ mFrequentUpdates( true ),
+ mForceUpdate( false ),
+ mOpenLinksInExternalBrowser( false ),
+ mOpenLinksInInternalBrowser( false ),
+ mTrusted( false ),
+ mHomePageUrl( "" ),
+ mIgnoreUIScale( true ),
+ mAlwaysRefresh( false ),
+ mExternalUrl( "" ),
+ mMediaSource( 0 ),
+ mTakeFocusOnClick( true ),
+ mCurrentNavUrl( "" ),
+ mLastSetCursor( UI_CURSOR_ARROW ),
+ mStretchToFill( true ),
+ mMaintainAspectRatio ( true ),
+ mHideLoading (false)
+{
+ {
+ LLColor4 color = p.caret_color().get();
+ setCaretColor( (unsigned int)color.mV[0], (unsigned int)color.mV[1], (unsigned int)color.mV[2] );
+ }
+
+ setIgnoreUIScale(p.ignore_ui_scale());
+
+ setHomePageUrl(p.start_url());
+
+ setBorderVisible(p.border_visible());
+
+ mHideLoading = p.hide_loading();
+
+ S32 screen_width = mIgnoreUIScale ?
+ llround((F32)getRect().getWidth() * LLUI::sGLScaleFactor.mV[VX]) : getRect().getWidth();
+ S32 screen_height = mIgnoreUIScale ?
+ llround((F32)getRect().getHeight() * LLUI::sGLScaleFactor.mV[VY]) : getRect().getHeight();
+
+ mMediaTextureID.generate();
+ mMediaSource = LLViewerMedia::newMediaImpl(mHomePageUrl, mMediaTextureID, screen_width, screen_height, false, false, "text/html");
+ if ( !mMediaSource )
+ {
+ llwarns << "media source create failed " << llendl;
+ // return;
+ }
+
+ mMediaSource->setVisible( getVisible() );
+
+ mMediaSource->addObserver( this );
+
+ // FIXME: How do we create a bevel now?
+// LLRect border_rect( 0, getRect().getHeight() + 2, getRect().getWidth() + 2, 0 );
+// mBorder = new LLViewBorder( std::string("web control border"), border_rect, LLViewBorder::BEVEL_IN );
+// addChild( mBorder );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// note: this is now a singleton and destruction happens via initClass() now
+LLMediaCtrl::~LLMediaCtrl()
+{
+
+ if (mMediaSource)
+ {
+ mMediaSource->remObserver( this );
+ mMediaSource = NULL;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::setBorderVisible( BOOL border_visible )
+{
+ if ( mBorder )
+ {
+ mBorder->setVisible( border_visible );
+ };
+};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::setTakeFocusOnClick( bool take_focus )
+{
+ mTakeFocusOnClick = take_focus;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// set flag that forces the embedded browser to open links in the external system browser
+void LLMediaCtrl::setOpenInExternalBrowser( bool valIn )
+{
+ mOpenLinksInExternalBrowser = valIn;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// set flag that forces the embedded browser to open links in the internal browser floater
+void LLMediaCtrl::setOpenInInternalBrowser( bool valIn )
+{
+ mOpenLinksInInternalBrowser = valIn;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+void LLMediaCtrl::setTrusted( bool valIn )
+{
+ mTrusted = valIn;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+BOOL LLMediaCtrl::handleHover( S32 x, S32 y, MASK mask )
+{
+ convertInputCoords(x, y);
+
+ if (mMediaSource)
+ mMediaSource->mouseMove(x, y);
+
+ gViewerWindow->setCursor(mLastSetCursor);
+
+ return TRUE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+BOOL LLMediaCtrl::handleScrollWheel( S32 x, S32 y, S32 clicks )
+{
+ if (mMediaSource && mMediaSource->hasMedia())
+ mMediaSource->getMediaPlugin()->scrollEvent(0, clicks, MASK_NONE);
+
+ return TRUE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+BOOL LLMediaCtrl::handleMouseUp( S32 x, S32 y, MASK mask )
+{
+ convertInputCoords(x, y);
+
+ if (mMediaSource)
+ {
+ mMediaSource->mouseUp(x, y);
+
+ // *HACK: LLMediaImplLLMozLib automatically takes focus on mouseup,
+ // in addition to the onFocusReceived() call below. Undo this. JC
+ if (!mTakeFocusOnClick)
+ {
+ mMediaSource->focus(false);
+ gViewerWindow->focusClient();
+ }
+ }
+
+ gFocusMgr.setMouseCapture( NULL );
+
+ return TRUE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+BOOL LLMediaCtrl::handleMouseDown( S32 x, S32 y, MASK mask )
+{
+ convertInputCoords(x, y);
+
+ if (mMediaSource)
+ mMediaSource->mouseDown(x, y);
+
+ gFocusMgr.setMouseCapture( this );
+
+ if (mTakeFocusOnClick)
+ {
+ setFocus( TRUE );
+ }
+
+ return TRUE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+BOOL LLMediaCtrl::handleDoubleClick( S32 x, S32 y, MASK mask )
+{
+ convertInputCoords(x, y);
+
+ if (mMediaSource)
+ mMediaSource->mouseLeftDoubleClick( x, y );
+
+ gFocusMgr.setMouseCapture( this );
+
+ if (mTakeFocusOnClick)
+ {
+ setFocus( TRUE );
+ }
+
+ return TRUE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::onFocusReceived()
+{
+ if (mMediaSource)
+ {
+ mMediaSource->focus(true);
+
+ // Set focus for edit menu items
+ LLEditMenuHandler::gEditMenuHandler = mMediaSource;
+ }
+
+ LLPanel::onFocusReceived();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::onFocusLost()
+{
+ if (mMediaSource)
+ {
+ mMediaSource->focus(false);
+
+ if( LLEditMenuHandler::gEditMenuHandler == mMediaSource )
+ {
+ // Clear focus for edit menu items
+ LLEditMenuHandler::gEditMenuHandler = NULL;
+ }
+ }
+
+ gViewerWindow->focusClient();
+
+ LLPanel::onFocusLost();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+BOOL LLMediaCtrl::postBuild ()
+{
+ mVisibleSignal.connect(boost::bind(&LLMediaCtrl::onVisibilityChange, this, _2));
+ return TRUE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask )
+{
+ BOOL result = FALSE;
+
+ // FIXME: THIS IS SO WRONG.
+ // Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it...
+
+ if (mMediaSource)
+ {
+ if( MASK_CONTROL & mask )
+ {
+ if( 'C' == key )
+ {
+ mMediaSource->copy();
+ result = TRUE;
+ }
+ else
+ if( 'V' == key )
+ {
+ mMediaSource->paste();
+ result = TRUE;
+ }
+ else
+ if( 'X' == key )
+ {
+ mMediaSource->cut();
+ result = TRUE;
+ }
+ }
+
+ if(!result)
+ {
+ result = mMediaSource->handleKeyHere(key, mask);
+ }
+ }
+
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::handleVisibilityChange ( BOOL new_visibility )
+{
+ llinfos << "visibility changed to " << (new_visibility?"true":"false") << llendl;
+ if(mMediaSource)
+ {
+ mMediaSource->setVisible( new_visibility );
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+BOOL LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char)
+{
+ BOOL result = FALSE;
+
+ // only accept 'printable' characters, sigh...
+ if (uni_char >= 32 // discard 'control' characters
+ && uni_char != 127) // SDL thinks this is 'delete' - yuck.
+ {
+ if (mMediaSource)
+ result = mMediaSource->handleUnicodeCharHere(uni_char);
+ }
+
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::onVisibilityChange ( const LLSD& new_visibility )
+{
+ // set state of frequent updates automatically if visibility changes
+ if ( new_visibility.asBoolean() )
+ {
+ mFrequentUpdates = true;
+ }
+ else
+ {
+ mFrequentUpdates = false;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::reshape( S32 width, S32 height, BOOL called_from_parent )
+{
+ S32 screen_width = mIgnoreUIScale ? llround((F32)width * LLUI::sGLScaleFactor.mV[VX]) : width;
+ S32 screen_height = mIgnoreUIScale ? llround((F32)height * LLUI::sGLScaleFactor.mV[VY]) : height;
+
+// llinfos << "reshape called with width = " << width << ", height = " << height << llendl;
+
+ // when floater is minimized, these sizes are negative
+ if ( screen_height > 0 && screen_width > 0 )
+ {
+ mMediaSource->setSize(screen_width, screen_height);
+ mForceUpdate = true;
+ }
+
+ LLPanel::reshape( width, height, called_from_parent );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::navigateBack()
+{
+ if (mMediaSource && mMediaSource->hasMedia())
+ {
+ mMediaSource->getMediaPlugin()->browse_back();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::navigateForward()
+{
+ if (mMediaSource && mMediaSource->hasMedia())
+ {
+ mMediaSource->getMediaPlugin()->browse_forward();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+bool LLMediaCtrl::canNavigateBack()
+{
+ if (mMediaSource)
+ return mMediaSource->canNavigateBack();
+ else
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+bool LLMediaCtrl::canNavigateForward()
+{
+ if (mMediaSource)
+ return mMediaSource->canNavigateForward();
+ else
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::set404RedirectUrl( std::string redirect_url )
+{
+ if(mMediaSource && mMediaSource->hasMedia())
+ mMediaSource->getMediaPlugin()->set_status_redirect( 404, redirect_url );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::clr404RedirectUrl()
+{
+ if(mMediaSource && mMediaSource->hasMedia())
+ mMediaSource->getMediaPlugin()->set_status_redirect(404, "");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::navigateTo( std::string url_in, std::string mime_type)
+{
+ // don't browse to anything that starts with secondlife:// or sl://
+ const std::string protocol1 = "secondlife://";
+ const std::string protocol2 = "sl://";
+ if ((LLStringUtil::compareInsensitive(url_in.substr(0, protocol1.length()), protocol1) == 0) ||
+ (LLStringUtil::compareInsensitive(url_in.substr(0, protocol2.length()), protocol2) == 0))
+ {
+ // TODO: Print out/log this attempt?
+ // llinfos << "Rejecting attempt to load restricted website :" << urlIn << llendl;
+ return;
+ }
+
+ if (mMediaSource)
+ {
+ mCurrentNavUrl = url_in;
+ mMediaSource->navigateTo(url_in, mime_type, mime_type.empty());
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::navigateToLocalPage( const std::string& subdir, const std::string& filename_in )
+{
+ std::string language = LLUI::getLanguage();
+ std::string delim = gDirUtilp->getDirDelimiter();
+ std::string filename;
+
+ filename += subdir;
+ filename += delim;
+ filename += filename_in;
+
+ std::string expanded_filename = gDirUtilp->findSkinnedFilename("html", language, filename);
+
+ if (! gDirUtilp->fileExists(expanded_filename))
+ {
+ if (language != "en-us")
+ {
+ expanded_filename = gDirUtilp->findSkinnedFilename("html", "en-us", filename);
+ if (! gDirUtilp->fileExists(expanded_filename))
+ {
+ llwarns << "File " << subdir << delim << filename_in << "not found" << llendl;
+ return;
+ }
+ }
+ else
+ {
+ llwarns << "File " << subdir << delim << filename_in << "not found" << llendl;
+ return;
+ }
+ }
+ if (mMediaSource)
+ {
+ mCurrentNavUrl = expanded_filename;
+ mMediaSource->navigateTo(expanded_filename, "text/html", false);
+ }
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::navigateHome()
+{
+ if( mHomePageUrl.length() )
+ {
+ if (mMediaSource)
+ mMediaSource->navigateTo(mHomePageUrl);
+ };
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::setHomePageUrl( const std::string urlIn )
+{
+ mHomePageUrl = urlIn;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+bool LLMediaCtrl::setCaretColor(unsigned int red, unsigned int green, unsigned int blue)
+{
+ //NOOP
+ return false;
+}
+////////////////////////////////////////////////////////////////////////////////
+//
+std::string LLMediaCtrl::getHomePageUrl()
+{
+ return mHomePageUrl;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+LLPluginClassMedia* LLMediaCtrl::getMediaPlugin()
+{
+ return mMediaSource.isNull() ? NULL : mMediaSource->getMediaPlugin();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::draw()
+{
+ LLPluginClassMedia* media_plugin = NULL;
+
+ if(mMediaSource && mMediaSource->hasMedia())
+ {
+ media_plugin = mMediaSource->getMediaPlugin();
+ }
+ else
+ {
+ return;
+ }
+
+ LLViewerMediaTexture* media_texture = LLViewerTextureManager::findMediaTexture(mMediaTextureID);
+
+ if (!media_texture )
+ {
+ return;
+ }
+
+ if ( gRestoreGL == 1 )
+ {
+ LLRect r = getRect();
+ reshape( r.getWidth(), r.getHeight(), FALSE );
+ return;
+ };
+
+ // NOTE: optimization needed here - probably only need to do this once
+ // unless tearoffs change the parent which they probably do.
+ const LLUICtrl* ptr = findRootMostFocusRoot();
+ if ( ptr && ptr->hasFocus() )
+ {
+ setFrequentUpdates( true );
+ }
+ else
+ {
+ setFrequentUpdates( false );
+ };
+
+ // alpha off for this
+ LLGLSUIDefault gls_ui;
+ LLGLDisable gls_alphaTest( GL_ALPHA_TEST );
+
+ gGL.pushMatrix();
+ {
+ if (mIgnoreUIScale)
+ {
+ glLoadIdentity();
+ // font system stores true screen origin, need to scale this by UI scale factor
+ // to get render origin for this view (with unit scale)
+ gGL.translatef(floorf(LLFontGL::sCurOrigin.mX * LLUI::sGLScaleFactor.mV[VX]),
+ floorf(LLFontGL::sCurOrigin.mY * LLUI::sGLScaleFactor.mV[VY]),
+ LLFontGL::sCurOrigin.mZ);
+ }
+
+ // scale texture to fit the space using texture coords
+ gGL.getTexUnit(0)->bind(media_texture);
+ gGL.color4fv( LLColor4::white.mV );
+ F32 max_u = ( F32 )media_plugin->getWidth() / ( F32 )media_plugin->getTextureWidth();
+ F32 max_v = ( F32 )media_plugin->getHeight() / ( F32 )media_plugin->getTextureHeight();
+
+ LLRect r = getRect();
+ S32 width, height;
+ S32 x_offset = 0;
+ S32 y_offset = 0;
+
+ if(mStretchToFill)
+ {
+ if(mMaintainAspectRatio)
+ {
+ F32 media_aspect = (F32)(media_plugin->getWidth()) / (F32)(media_plugin->getHeight());
+ F32 view_aspect = (F32)(r.getWidth()) / (F32)(r.getHeight());
+ if(media_aspect > view_aspect)
+ {
+ // max width, adjusted height
+ width = r.getWidth();
+ height = llmin(llmax(S32(width / media_aspect), 0), r.getHeight());
+ }
+ else
+ {
+ // max height, adjusted width
+ height = r.getHeight();
+ width = llmin(llmax(S32(height * media_aspect), 0), r.getWidth());
+ }
+ }
+ else
+ {
+ width = r.getWidth();
+ height = r.getHeight();
+ }
+ }
+ else
+ {
+ width = llmin(media_plugin->getWidth(), r.getWidth());
+ height = llmin(media_plugin->getHeight(), r.getHeight());
+ }
+
+ x_offset = (r.getWidth() - width) / 2;
+ y_offset = (r.getHeight() - height) / 2;
+
+ // draw the browser
+ gGL.setSceneBlendType(LLRender::BT_REPLACE);
+ gGL.begin( LLRender::QUADS );
+ if (! media_plugin->getTextureCoordsOpenGL())
+ {
+ // render using web browser reported width and height, instead of trying to invert GL scale
+ gGL.texCoord2f( max_u, 0.f );
+ gGL.vertex2i( x_offset + width, y_offset + height );
+
+ gGL.texCoord2f( 0.f, 0.f );
+ gGL.vertex2i( x_offset, y_offset + height );
+
+ gGL.texCoord2f( 0.f, max_v );
+ gGL.vertex2i( x_offset, y_offset );
+
+ gGL.texCoord2f( max_u, max_v );
+ gGL.vertex2i( x_offset + width, y_offset );
+ }
+ else
+ {
+ // render using web browser reported width and height, instead of trying to invert GL scale
+ gGL.texCoord2f( max_u, max_v );
+ gGL.vertex2i( x_offset + width, y_offset + height );
+
+ gGL.texCoord2f( 0.f, max_v );
+ gGL.vertex2i( x_offset, y_offset + height );
+
+ gGL.texCoord2f( 0.f, 0.f );
+ gGL.vertex2i( x_offset, y_offset );
+
+ gGL.texCoord2f( max_u, 0.f );
+ gGL.vertex2i( x_offset + width, y_offset );
+ }
+ gGL.end();
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ }
+ gGL.popMatrix();
+
+ // highlight if keyboard focus here. (TODO: this needs some work)
+ if ( mBorder && mBorder->getVisible() )
+ mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus( this ) );
+
+
+ LLPanel::draw();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::convertInputCoords(S32& x, S32& y)
+{
+ bool coords_opengl = false;
+
+ if(mMediaSource && mMediaSource->hasMedia())
+ {
+ coords_opengl = mMediaSource->getMediaPlugin()->getTextureCoordsOpenGL();
+ }
+
+ x = mIgnoreUIScale ? llround((F32)x * LLUI::sGLScaleFactor.mV[VX]) : x;
+ if ( ! coords_opengl )
+ {
+ y = mIgnoreUIScale ? llround((F32)(y) * LLUI::sGLScaleFactor.mV[VY]) : y;
+ }
+ else
+ {
+ y = mIgnoreUIScale ? llround((F32)(getRect().getHeight() - y) * LLUI::sGLScaleFactor.mV[VY]) : getRect().getHeight() - y;
+ };
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// static
+bool LLMediaCtrl::onClickLinkExternalTarget(const LLSD& notification, const LLSD& response )
+{
+ S32 option = LLNotification::getSelectedOption(notification, response);
+ if ( 0 == option )
+ {
+ // open in external browser because we don't support
+ // creation of our own secondary browser windows
+ LLWeb::loadURLExternal( notification["payload"]["external_url"].asString() );
+ }
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// inherited from LLViewerMediaObserver
+//virtual
+void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
+{
+ switch(event)
+ {
+ case MEDIA_EVENT_CONTENT_UPDATED:
+ {
+ // LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CONTENT_UPDATED " << LL_ENDL;
+ };
+ break;
+
+ case MEDIA_EVENT_TIME_DURATION_UPDATED:
+ {
+ // LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_TIME_DURATION_UPDATED, time is " << self->getCurrentTime() << " of " << self->getDuration() << LL_ENDL;
+ };
+ break;
+
+ case MEDIA_EVENT_SIZE_CHANGED:
+ {
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_SIZE_CHANGED " << LL_ENDL;
+ LLRect r = getRect();
+ reshape( r.getWidth(), r.getHeight(), FALSE );
+ };
+ break;
+
+ case MEDIA_EVENT_CURSOR_CHANGED:
+ {
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << self->getCursorName() << LL_ENDL;
+
+ std::string cursor = self->getCursorName();
+
+ if(cursor == "arrow")
+ mLastSetCursor = UI_CURSOR_ARROW;
+ else if(cursor == "ibeam")
+ mLastSetCursor = UI_CURSOR_IBEAM;
+ else if(cursor == "splith")
+ mLastSetCursor = UI_CURSOR_SIZEWE;
+ else if(cursor == "splitv")
+ mLastSetCursor = UI_CURSOR_SIZENS;
+ else if(cursor == "hand")
+ mLastSetCursor = UI_CURSOR_HAND;
+ else // for anything else, default to the arrow
+ mLastSetCursor = UI_CURSOR_ARROW;
+ };
+ break;
+
+ case MEDIA_EVENT_NAVIGATE_BEGIN:
+ {
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_BEGIN, url is " << self->getNavigateURI() << LL_ENDL;
+ if(mMediaSource && mHideLoading)
+ {
+ mMediaSource->suspendUpdates(true);
+ }
+ };
+ break;
+
+ case MEDIA_EVENT_NAVIGATE_COMPLETE:
+ {
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_COMPLETE, result string is: " << self->getNavigateResultString() << LL_ENDL;
+ if(mMediaSource && mHideLoading)
+ {
+ mMediaSource->suspendUpdates(false);
+ }
+ };
+ break;
+
+ case MEDIA_EVENT_PROGRESS_UPDATED:
+ {
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PROGRESS_UPDATED, loading at " << self->getProgressPercent() << "%" << LL_ENDL;
+ };
+ break;
+
+ case MEDIA_EVENT_STATUS_TEXT_CHANGED:
+ {
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_STATUS_TEXT_CHANGED, new status text is: " << self->getStatusText() << LL_ENDL;
+ };
+ break;
+
+ case MEDIA_EVENT_LOCATION_CHANGED:
+ {
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_LOCATION_CHANGED, new uri is: " << self->getLocation() << LL_ENDL;
+ };
+ break;
+
+ case MEDIA_EVENT_CLICK_LINK_HREF:
+ {
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL;
+ onClickLinkHref(self);
+ };
+ break;
+
+ case MEDIA_EVENT_CLICK_LINK_NOFOLLOW:
+ {
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is " << self->getClickURL() << LL_ENDL;
+ onClickLinkNoFollow(self);
+ };
+ break;
+
+ case MEDIA_EVENT_PLUGIN_FAILED:
+ {
+ LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED" << LL_ENDL;
+ };
+ break;
+ };
+
+ // chain all events to any potential observers of this object.
+ emitEvent(self, event);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::onClickLinkHref( LLPluginClassMedia* self )
+{
+ // retrieve the event parameters
+ std::string target = self->getClickTarget();
+ std::string url = self->getClickURL();
+
+ // if there is a value for the target
+ if ( !target.empty() )
+ {
+ if ( target == "_external" )
+ {
+ mExternalUrl = url;
+ LLSD payload;
+ payload["external_url"] = mExternalUrl;
+ LLNotifications::instance().add( "WebLaunchExternalTarget", LLSD(), payload, onClickLinkExternalTarget);
+ return;
+ }
+ }
+
+ const std::string protocol1( "http://" );
+ const std::string protocol2( "https://" );
+ if( mOpenLinksInExternalBrowser )
+ {
+ if ( !url.empty() )
+ {
+ if ( LLStringUtil::compareInsensitive( url.substr( 0, protocol1.length() ), protocol1 ) == 0 ||
+ LLStringUtil::compareInsensitive( url.substr( 0, protocol2.length() ), protocol2 ) == 0 )
+ {
+ LLWeb::loadURLExternal( url );
+ }
+ }
+ }
+ else
+ if( mOpenLinksInInternalBrowser )
+ {
+ if ( !url.empty() )
+ {
+ if ( LLStringUtil::compareInsensitive( url.substr( 0, protocol1.length() ), protocol1 ) == 0 ||
+ LLStringUtil::compareInsensitive( url.substr( 0, protocol2.length() ), protocol2 ) == 0 )
+ {
+ // If we spawn a new LLFloaterHTML, assume we want it to
+ // follow this LLMediaCtrl's trust for whether or
+ // not to open secondlife:///app/ links. JC.
+// const bool open_links_externally = false;
+// LLFloaterHtml::getInstance()->show(
+// event_in.mStringPayload,
+// "Second Life Browser",
+// open_links_externally,
+// mTrusted);
+ }
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLMediaCtrl::onClickLinkNoFollow( LLPluginClassMedia* self )
+{
+ std::string url = self->getClickURL();
+ if (LLSLURL::isSLURLCommand(url)
+ && !mTrusted)
+ {
+ // block handling of this secondlife:///app/ URL
+ LLNotifications::instance().add("UnableToOpenCommandURL");
+ return;
+ }
+
+ LLURLDispatcher::dispatch(url, this, mTrusted);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+std::string LLMediaCtrl::getCurrentNavUrl()
+{
+ return mCurrentNavUrl;
+}
+