summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/llcommon/llversionserver.h2
-rw-r--r--indra/llcommon/llversionviewer.h2
-rw-r--r--indra/llplugin/llpluginclassmedia.cpp5
-rw-r--r--indra/llplugin/llpluginclassmediaowner.h1
-rw-r--r--indra/media_plugins/quicktime/media_plugin_quicktime.cpp2072
-rw-r--r--indra/media_plugins/webkit/media_plugin_webkit.cpp13
-rw-r--r--indra/newview/English.lproj/InfoPlist.strings4
-rw-r--r--indra/newview/Info-SecondLife.plist2
-rw-r--r--indra/newview/llfloatermediasettings.cpp26
-rw-r--r--indra/newview/llfloatermediasettings.h2
-rw-r--r--indra/newview/llfloatertools.cpp8
-rw-r--r--indra/newview/llpanelmediasettingsgeneral.cpp22
-rw-r--r--indra/newview/llpanelmediasettingsgeneral.h3
-rw-r--r--indra/newview/llpanelmediasettingssecurity.cpp584
-rw-r--r--indra/newview/llpanelmediasettingssecurity.h7
-rw-r--r--indra/newview/llviewermediafocus.cpp31
-rw-r--r--indra/newview/res/viewerRes.rc8
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml13
-rw-r--r--indra/test_apps/llplugintest/llmediaplugintest.cpp7
19 files changed, 1549 insertions, 1263 deletions
diff --git a/indra/llcommon/llversionserver.h b/indra/llcommon/llversionserver.h
index aee7c6ee1e..71c6fc0591 100644
--- a/indra/llcommon/llversionserver.h
+++ b/indra/llcommon/llversionserver.h
@@ -36,7 +36,7 @@
const S32 LL_VERSION_MAJOR = 1;
const S32 LL_VERSION_MINOR = 31;
const S32 LL_VERSION_PATCH = 0;
-const S32 LL_VERSION_BUILD = 2822;
+const S32 LL_VERSION_BUILD = 3256;
const char * const LL_CHANNEL = "Second Life Server";
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index 2c3e9c7333..082d054ba2 100644
--- a/indra/llcommon/llversionviewer.h
+++ b/indra/llcommon/llversionviewer.h
@@ -36,7 +36,7 @@
const S32 LL_VERSION_MAJOR = 2;
const S32 LL_VERSION_MINOR = 0;
const S32 LL_VERSION_PATCH = 0;
-const S32 LL_VERSION_BUILD = 0;
+const S32 LL_VERSION_BUILD = 3256;
const char * const LL_CHANNEL = "Second Life Developer";
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index 2a343fd0c9..fc58b48a7b 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -835,6 +835,11 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
mCanPaste = message.getValueBoolean("paste");
}
}
+ else if(message_name == "name_text")
+ {
+ mMediaName = message.getValue("name");
+ mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED);
+ }
else
{
LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h
index cfee847080..4690f09172 100644
--- a/indra/llplugin/llpluginclassmediaowner.h
+++ b/indra/llplugin/llpluginclassmediaowner.h
@@ -52,6 +52,7 @@ public:
MEDIA_EVENT_NAVIGATE_COMPLETE, // browser has finished navigation
MEDIA_EVENT_PROGRESS_UPDATED, // browser has updated loading progress
MEDIA_EVENT_STATUS_TEXT_CHANGED, // browser has updated the status text
+ MEDIA_EVENT_NAME_CHANGED, // browser has updated the name of the media (typically <title> tag)
MEDIA_EVENT_LOCATION_CHANGED, // browser location (URL) has changed (maybe due to internal navagation/frames/etc)
MEDIA_EVENT_CLICK_LINK_HREF, // I'm not entirely sure what the semantics of these two are
MEDIA_EVENT_CLICK_LINK_NOFOLLOW,
diff --git a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp
index 556865f771..7100d03f05 100644
--- a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp
+++ b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp
@@ -1,995 +1,1077 @@
-/**
- * @file media_plugin_quicktime.cpp
- * @brief QuickTime plugin for LLMedia API plugin system
- *
- * $LicenseInfo:firstyear=2008&license=viewergpl$
- *
- * Copyright (c) 2008, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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 "linden_common.h"
-
-#include "llgl.h"
-
-#include "llplugininstance.h"
-#include "llpluginmessage.h"
-#include "llpluginmessageclasses.h"
-#include "media_plugin_base.h"
-
-#if LL_QUICKTIME_ENABLED
-
-#if defined(LL_DARWIN)
- #include <QuickTime/QuickTime.h>
-#elif defined(LL_WINDOWS)
- #include "MacTypes.h"
- #include "QTML.h"
- #include "Movies.h"
- #include "QDoffscreen.h"
- #include "FixMath.h"
-#endif
-
-// TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint
-////////////////////////////////////////////////////////////////////////////////
-//
-class MediaPluginQuickTime : public MediaPluginBase
-{
-public:
- MediaPluginQuickTime(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
- ~MediaPluginQuickTime();
-
- /* virtual */ void receiveMessage(const char *message_string);
-
-private:
-
- int mNaturalWidth;
- int mNaturalHeight;
- Movie mMovieHandle;
- GWorldPtr mGWorldHandle;
- ComponentInstance mMovieController;
- int mCurVolume;
- bool mMediaSizeChanging;
- bool mIsLooping;
- const int mMinWidth;
- const int mMaxWidth;
- const int mMinHeight;
- const int mMaxHeight;
- F64 mPlayRate;
-
- enum ECommand {
- COMMAND_NONE,
- COMMAND_STOP,
- COMMAND_PLAY,
- COMMAND_FAST_FORWARD,
- COMMAND_FAST_REWIND,
- COMMAND_PAUSE,
- COMMAND_SEEK,
- };
- ECommand mCommand;
-
- // Override this to add current time and duration to the message
- /*virtual*/ void setDirty(int left, int top, int right, int bottom)
- {
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated");
-
- message.setValueS32("left", left);
- message.setValueS32("top", top);
- message.setValueS32("right", right);
- message.setValueS32("bottom", bottom);
-
- if(mMovieHandle)
- {
- message.setValueReal("current_time", getCurrentTime());
- message.setValueReal("duration", getDuration());
- message.setValueReal("current_rate", Fix2X(GetMovieRate(mMovieHandle)));
- message.setValueReal("loaded_duration", getLoadedDuration());
- }
-
- sendMessage(message);
- }
-
-
- static Rect rectFromSize(int width, int height)
- {
- Rect result;
-
-
- result.left = 0;
- result.top = 0;
- result.right = width;
- result.bottom = height;
-
- return result;
- }
-
- Fixed getPlayRate(void)
- {
- Fixed result;
- if(mPlayRate == 0.0f)
- {
- // Default to the movie's preferred rate
- result = GetMoviePreferredRate(mMovieHandle);
- if(result == 0)
- {
- // Don't return a 0 play rate, ever.
- std::cerr << "Movie's preferred rate is 0, forcing to 1.0." << std::endl;
- result = X2Fix(1.0f);
- }
- }
- else
- {
- result = X2Fix(mPlayRate);
- }
-
- return result;
- }
-
- void load( const std::string url )
- {
- if ( url.empty() )
- return;
-
- // Stop and unload any existing movie before starting another one.
- unload();
-
- setStatus(STATUS_LOADING);
-
- //In case std::string::c_str() makes a copy of the url data,
- //make sure there is memory to hold it before allocating memory for handle.
- //if fails, NewHandleClear(...) should return NULL.
- const char* url_string = url.c_str() ;
- Handle handle = NewHandleClear( ( Size )( url.length() + 1 ) );
- if ( NULL == handle || noErr != MemError() || NULL == *handle )
- {
- setStatus(STATUS_ERROR);
- return;
- }
-
- BlockMove( url_string, *handle, ( Size )( url.length() + 1 ) );
-
- OSErr err = NewMovieFromDataRef( &mMovieHandle, newMovieActive | newMovieDontInteractWithUser | newMovieAsyncOK | newMovieIdleImportOK, nil, handle, URLDataHandlerSubType );
- DisposeHandle( handle );
- if ( noErr != err )
- {
- setStatus(STATUS_ERROR);
- return;
- };
-
- // do pre-roll actions (typically fired for streaming movies but not always)
- PrePrerollMovie( mMovieHandle, 0, getPlayRate(), moviePrePrerollCompleteCallback, ( void * )this );
-
- Rect movie_rect = rectFromSize(mWidth, mHeight);
-
- // make a new movie controller
- mMovieController = NewMovieController( mMovieHandle, &movie_rect, mcNotVisible | mcTopLeftMovie );
-
- // movie controller
- MCSetActionFilterWithRefCon( mMovieController, mcActionFilterCallBack, ( long )this );
-
- SetMoviePlayHints( mMovieHandle, hintsAllowDynamicResize, hintsAllowDynamicResize );
-
- // function that gets called when a frame is drawn
- SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, movieDrawingCompleteCallback, ( long )this );
-
- setStatus(STATUS_LOADED);
-
- sizeChanged();
- };
-
- bool unload()
- {
- if ( mMovieHandle )
- {
- StopMovie( mMovieHandle );
- if ( mMovieController )
- {
- MCMovieChanged( mMovieController, mMovieHandle );
- };
- };
-
- if ( mMovieController )
- {
- MCSetActionFilterWithRefCon( mMovieController, NULL, (long)this );
- DisposeMovieController( mMovieController );
- mMovieController = NULL;
- };
-
- if ( mMovieHandle )
- {
- SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, nil, ( long )this );
- DisposeMovie( mMovieHandle );
- mMovieHandle = NULL;
- };
-
- if ( mGWorldHandle )
- {
- DisposeGWorld( mGWorldHandle );
- mGWorldHandle = NULL;
- };
-
- setStatus(STATUS_NONE);
-
- return true;
- }
-
- bool navigateTo( const std::string url )
- {
- unload();
- load( url );
-
- return true;
- };
-
- bool sizeChanged()
- {
- if ( ! mMovieHandle )
- return false;
-
- // Check to see whether the movie's natural size has updated
- {
- int width, height;
- getMovieNaturalSize(&width, &height);
- if((width != 0) && (height != 0) && ((width != mNaturalWidth) || (height != mNaturalHeight)))
- {
- mNaturalWidth = width;
- mNaturalHeight = height;
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request");
- message.setValue("name", mTextureSegmentName);
- message.setValueS32("width", width);
- message.setValueS32("height", height);
- sendMessage(message);
- //std::cerr << "<--- Sending size change request to application with name: " << mTextureSegmentName << " - size is " << width << " x " << height << std::endl;
- }
- }
-
- // sanitize destination size
- Rect dest_rect = rectFromSize(mWidth, mHeight);
-
- // media depth won't change
- int depth_bits = mDepth * 8;
- long rowbytes = mDepth * mTextureWidth;
-
- GWorldPtr old_gworld_handle = mGWorldHandle;
-
- if(mPixels != NULL)
- {
- // We have pixels. Set up a GWorld pointing at the texture.
- OSErr result = NewGWorldFromPtr( &mGWorldHandle, depth_bits, &dest_rect, NULL, NULL, 0, (Ptr)mPixels, rowbytes);
- if ( noErr != result )
- {
- // TODO: unrecoverable?? throw exception? return something?
- return false;
- }
- }
- else
- {
- // We don't have pixels. Create a fake GWorld we can point the movie at when it's not safe to render normally.
- Rect tempRect = rectFromSize(1, 1);
- OSErr result = NewGWorld( &mGWorldHandle, depth_bits, &tempRect, NULL, NULL, 0);
- if ( noErr != result )
- {
- // TODO: unrecoverable?? throw exception? return something?
- return false;
- }
- }
-
- SetMovieGWorld( mMovieHandle, mGWorldHandle, GetGWorldDevice( mGWorldHandle ) );
-
- // If the GWorld was already set up, delete it.
- if(old_gworld_handle != NULL)
- {
- DisposeGWorld( old_gworld_handle );
- }
-
- // Set up the movie display matrix
- {
- // scale movie to fit rect and invert vertically to match opengl image format
- MatrixRecord transform;
- SetIdentityMatrix( &transform ); // transforms are additive so start from identify matrix
- double scaleX = (double) mWidth / mNaturalWidth;
- double scaleY = -1.0 * (double) mHeight / mNaturalHeight;
- double centerX = mWidth / 2.0;
- double centerY = mHeight / 2.0;
- ScaleMatrix( &transform, X2Fix( scaleX ), X2Fix( scaleY ), X2Fix( centerX ), X2Fix( centerY ) );
- SetMovieMatrix( mMovieHandle, &transform );
- }
-
- // update movie controller
- if ( mMovieController )
- {
- MCSetControllerPort( mMovieController, mGWorldHandle );
- MCPositionController( mMovieController, &dest_rect, &dest_rect,
- mcTopLeftMovie | mcPositionDontInvalidate );
- MCMovieChanged( mMovieController, mMovieHandle );
- }
-
-
- // Emit event with size change so the calling app knows about it too
- // TODO:
- //LLMediaEvent event( this );
- //mEventEmitter.update( &LLMediaObserver::onMediaSizeChange, event );
-
- return true;
- }
-
- static Boolean mcActionFilterCallBack( MovieController mc, short action, void *params, long ref )
- {
- Boolean result = false;
-
- MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref;
-
- switch( action )
- {
- // handle window resizing
- case mcActionControllerSizeChanged:
- // Ensure that the movie draws correctly at the new size
- self->sizeChanged();
- break;
-
- // Block any movie controller actions that open URLs.
- case mcActionLinkToURL:
- case mcActionGetNextURL:
- case mcActionLinkToURLExtended:
- // Prevent the movie controller from handling the message
- result = true;
- break;
-
- default:
- break;
- };
-
- return result;
- };
-
- static OSErr movieDrawingCompleteCallback( Movie call_back_movie, long ref )
- {
- MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref;
-
- // IMPORTANT: typically, a consumer who is observing this event will set a flag
- // when this event is fired then render later. Be aware that the media stream
- // can change during this period - dimensions, depth, format etc.
- //LLMediaEvent event( self );
-// self->updateQuickTime();
- // TODO ^^^
-
- if ( self->mWidth > 0 && self->mHeight > 0 )
- self->setDirty( 0, 0, self->mWidth, self->mHeight );
-
- return noErr;
- };
-
- static void moviePrePrerollCompleteCallback( Movie movie, OSErr preroll_err, void *ref )
- {
- //MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref;
-
- // TODO:
- //LLMediaEvent event( self );
- //self->mEventEmitter.update( &LLMediaObserver::onMediaPreroll, event );
- };
-
-
- void rewind()
- {
- GoToBeginningOfMovie( mMovieHandle );
- MCMovieChanged( mMovieController, mMovieHandle );
- };
-
- bool processState()
- {
- if ( mCommand == COMMAND_PLAY )
- {
- if ( mStatus == STATUS_LOADED || mStatus == STATUS_PAUSED || mStatus == STATUS_PLAYING )
- {
- long state = GetMovieLoadState( mMovieHandle );
-
- if ( state >= kMovieLoadStatePlaythroughOK )
- {
- // if the movie is at the end (generally because it reached it naturally)
- // and we play is requested, jump back to the start of the movie.
- // note: this is different from having loop flag set.
- if ( IsMovieDone( mMovieHandle ) )
- {
- Fixed rate = X2Fix( 0.0 );
- MCDoAction( mMovieController, mcActionPlay, (void*)rate );
- rewind();
- };
-
- MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)getPlayRate() );
- MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
- setStatus(STATUS_PLAYING);
- mCommand = COMMAND_NONE;
- };
- };
- }
- else
- if ( mCommand == COMMAND_STOP )
- {
- if ( mStatus == STATUS_PLAYING || mStatus == STATUS_PAUSED )
- {
- if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK )
- {
- Fixed rate = X2Fix( 0.0 );
- MCDoAction( mMovieController, mcActionPlay, (void*)rate );
- rewind();
-
- setStatus(STATUS_LOADED);
- mCommand = COMMAND_NONE;
- };
- };
- }
- else
- if ( mCommand == COMMAND_PAUSE )
- {
- if ( mStatus == STATUS_PLAYING )
- {
- if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK )
- {
- Fixed rate = X2Fix( 0.0 );
- MCDoAction( mMovieController, mcActionPlay, (void*)rate );
- setStatus(STATUS_PAUSED);
- mCommand = COMMAND_NONE;
- };
- };
- };
-
- return true;
- };
-
- void play(F64 rate)
- {
- mPlayRate = rate;
- mCommand = COMMAND_PLAY;
- };
-
- void stop()
- {
- mCommand = COMMAND_STOP;
- };
-
- void pause()
- {
- mCommand = COMMAND_PAUSE;
- };
-
- void getMovieNaturalSize(int *movie_width, int *movie_height)
- {
- Rect rect;
-
- GetMovieNaturalBoundsRect( mMovieHandle, &rect );
-
- int width = ( rect.right - rect.left );
- int height = ( rect.bottom - rect.top );
-
- // make sure width and height fall in valid range
- if ( width < mMinWidth )
- width = mMinWidth;
-
- if ( width > mMaxWidth )
- width = mMaxWidth;
-
- if ( height < mMinHeight )
- height = mMinHeight;
-
- if ( height > mMaxHeight )
- height = mMaxHeight;
-
- // return the new rect
- *movie_width = width;
- *movie_height = height;
- }
-
- void updateQuickTime(int milliseconds)
- {
- if ( ! mMovieHandle )
- return;
-
- if ( ! mMovieController )
- return;
-
- // service QuickTime
- // Calling it this way doesn't have good behavior on Windows...
-// MoviesTask( mMovieHandle, milliseconds );
- // This was the original, but I think using both MoviesTask and MCIdle is redundant. Trying with only MCIdle.
-// MoviesTask( mMovieHandle, 0 );
-
- MCIdle( mMovieController );
-
- if ( ! mGWorldHandle )
- return;
-
- if ( mMediaSizeChanging )
- return;
-
- // update state machine
- processState();
-
- // special code for looping - need to rewind at the end of the movie
- if ( mIsLooping )
- {
- // QT call to see if we are at the end - can't do with controller
- if ( IsMovieDone( mMovieHandle ) )
- {
- // go back to start
- rewind();
-
- if ( mMovieController )
- {
- // kick off new play
- MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)getPlayRate() );
-
- // set the volume
- MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
- };
- };
- };
- };
-
- int getDataWidth() const
- {
- if ( mGWorldHandle )
- {
- int depth = mDepth;
-
- if (depth < 1)
- depth = 1;
-
- // ALWAYS use the row bytes from the PixMap if we have a GWorld because
- // sometimes it's not the same as mMediaDepth * mMediaWidth !
- PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle );
- return QTGetPixMapHandleRowBytes( pix_map_handle ) / depth;
- }
- else
- {
- // TODO : return LLMediaImplCommon::getaDataWidth();
- return 0;
- }
- };
-
- void seek( F64 time )
- {
- if ( mMovieController )
- {
- TimeRecord when;
- when.scale = GetMovieTimeScale( mMovieHandle );
- when.base = 0;
-
- // 'time' is in (floating point) seconds. The timebase time will be in 'units', where
- // there are 'scale' units per second.
- SInt64 raw_time = ( SInt64 )( time * (double)( when.scale ) );
-
- when.value.hi = ( SInt32 )( raw_time >> 32 );
- when.value.lo = ( SInt32 )( ( raw_time & 0x00000000FFFFFFFF ) );
-
- MCDoAction( mMovieController, mcActionGoToTime, &when );
- };
- };
-
- F64 getDuration()
- {
- TimeValue duration = GetMovieDuration( mMovieHandle );
- TimeValue scale = GetMovieTimeScale( mMovieHandle );
-
- return (F64)duration / (F64)scale;
- };
-
- F64 getLoadedDuration()
- {
- TimeValue duration;
- if(GetMaxLoadedTimeInMovie( mMovieHandle, &duration ) != noErr)
- {
- // If GetMaxLoadedTimeInMovie returns an error, return the full duration of the movie.
- duration = GetMovieDuration( mMovieHandle );
- }
- TimeValue scale = GetMovieTimeScale( mMovieHandle );
-
- return (F64)duration / (F64)scale;
- };
-
- F64 getCurrentTime()
- {
- TimeValue curr_time = GetMovieTime( mMovieHandle, 0 );
- TimeValue scale = GetMovieTimeScale( mMovieHandle );
-
- return (F64)curr_time / (F64)scale;
- };
-
- void setVolume( F64 volume )
- {
- mCurVolume = (short)(volume * ( double ) 0x100 );
-
- if ( mMovieController )
- {
- MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
- };
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- void update(int milliseconds = 0)
- {
- updateQuickTime(milliseconds);
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- void mouseDown( int x, int y )
- {
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- void mouseUp( int x, int y )
- {
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- void mouseMove( int x, int y )
- {
- };
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- void keyPress( unsigned char key )
- {
- };
-
-};
-
-MediaPluginQuickTime::MediaPluginQuickTime(
- LLPluginInstance::sendMessageFunction host_send_func,
- void *host_user_data ) :
- MediaPluginBase(host_send_func, host_user_data),
- mMinWidth( 0 ),
- mMaxWidth( 2048 ),
- mMinHeight( 0 ),
- mMaxHeight( 2048 )
-{
-// std::cerr << "MediaPluginQuickTime constructor" << std::endl;
-
- mNaturalWidth = -1;
- mNaturalHeight = -1;
- mMovieHandle = 0;
- mGWorldHandle = 0;
- mMovieController = 0;
- mCurVolume = 0x99;
- mMediaSizeChanging = false;
- mIsLooping = false;
- mCommand = COMMAND_NONE;
- mPlayRate = 0.0f;
- mStatus = STATUS_NONE;
-}
-
-MediaPluginQuickTime::~MediaPluginQuickTime()
-{
-// std::cerr << "MediaPluginQuickTime destructor" << std::endl;
-
- ExitMovies();
-
-#ifdef LL_WINDOWS
- TerminateQTML();
-// std::cerr << "QuickTime closing down" << std::endl;
-#endif
-}
-
-
-void MediaPluginQuickTime::receiveMessage(const char *message_string)
-{
-// std::cerr << "MediaPluginQuickTime::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
- LLPluginMessage message_in;
-
- if(message_in.parse(message_string) >= 0)
- {
- std::string message_class = message_in.getClass();
- std::string message_name = message_in.getName();
- if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
- {
- if(message_name == "init")
- {
- LLPluginMessage message("base", "init_response");
- LLSD versions = LLSD::emptyMap();
- versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
- versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
- // Normally a plugin would only specify one of these two subclasses, but this is a demo...
-// versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
- versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION;
- message.setValueLLSD("versions", versions);
-
- #ifdef LL_WINDOWS
- if ( InitializeQTML( 0L ) != noErr )
- {
- //TODO: If no QT on Windows, this fails - respond accordingly.
- //return false;
- }
- else
- {
-// std::cerr << "QuickTime initialized" << std::endl;
- };
- #endif
-
- EnterMovies();
-
- std::string plugin_version = "QuickTime media plugin, QuickTime version ";
-
- long version = 0;
- Gestalt( gestaltQuickTimeVersion, &version );
- std::ostringstream codec( "" );
- codec << std::hex << version << std::dec;
- plugin_version += codec.str();
- message.setValue("plugin_version", plugin_version);
- sendMessage(message);
-
- // Plugin gets to decide the texture parameters to use.
- message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
- #if defined(LL_WINDOWS)
- // Values for Windows
- mDepth = 3;
- message.setValueU32("format", GL_RGB);
- message.setValueU32("type", GL_UNSIGNED_BYTE);
-
- // We really want to pad the texture width to a multiple of 32 bytes, but since we're using 3-byte pixels, it doesn't come out even.
- // Padding to a multiple of 3*32 guarantees it'll divide out properly.
- message.setValueU32("padding", 32 * 3);
- #else
- // Values for Mac
- mDepth = 4;
- message.setValueU32("format", GL_BGRA_EXT);
- #ifdef __BIG_ENDIAN__
- message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV );
- #else
- message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8);
- #endif
-
- // Pad texture width to a multiple of 32 bytes, to line up with cache lines.
- message.setValueU32("padding", 32);
- #endif
- message.setValueS32("depth", mDepth);
- message.setValueU32("internalformat", GL_RGB);
- message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left.
- message.setValueBoolean("allow_downsample", true);
- sendMessage(message);
- }
- else if(message_name == "idle")
- {
- // no response is necessary here.
- F64 time = message_in.getValueReal("time");
-
- // Convert time to milliseconds for update()
- update((int)(time * 1000.0f));
- }
- else if(message_name == "cleanup")
- {
- // TODO: clean up here
- }
- else if(message_name == "shm_added")
- {
- SharedSegmentInfo info;
- info.mAddress = message_in.getValuePointer("address");
- info.mSize = (size_t)message_in.getValueS32("size");
- std::string name = message_in.getValue("name");
-
-
-// std::cerr << "MediaPluginQuickTime::receiveMessage: shared memory added, name: " << name
-// << ", size: " << info.mSize
-// << ", address: " << info.mAddress
-// << std::endl;
-
- mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
-
- }
- else if(message_name == "shm_remove")
- {
- std::string name = message_in.getValue("name");
-
-// std::cerr << "MediaPluginQuickTime::receiveMessage: shared memory remove, name = " << name << std::endl;
-
- SharedSegmentMap::iterator iter = mSharedSegments.find(name);
- if(iter != mSharedSegments.end())
- {
- if(mPixels == iter->second.mAddress)
- {
- // This is the currently active pixel buffer. Make sure we stop drawing to it.
- mPixels = NULL;
- mTextureSegmentName.clear();
-
- // Make sure the movie GWorld is no longer pointed at the shared segment.
- sizeChanged();
- }
- mSharedSegments.erase(iter);
- }
- else
- {
-// std::cerr << "MediaPluginQuickTime::receiveMessage: unknown shared memory region!" << std::endl;
- }
-
- // Send the response so it can be cleaned up.
- LLPluginMessage message("base", "shm_remove_response");
- message.setValue("name", name);
- sendMessage(message);
- }
- else
- {
-// std::cerr << "MediaPluginQuickTime::receiveMessage: unknown base message: " << message_name << std::endl;
- }
- }
- else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
- {
- if(message_name == "size_change")
- {
- std::string name = message_in.getValue("name");
- S32 width = message_in.getValueS32("width");
- S32 height = message_in.getValueS32("height");
- S32 texture_width = message_in.getValueS32("texture_width");
- S32 texture_height = message_in.getValueS32("texture_height");
-
- //std::cerr << "---->Got size change instruction from application with name: " << name << " - size is " << width << " x " << height << std::endl;
-
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
- message.setValue("name", name);
- message.setValueS32("width", width);
- message.setValueS32("height", height);
- message.setValueS32("texture_width", texture_width);
- message.setValueS32("texture_height", texture_height);
- sendMessage(message);
-
- if(!name.empty())
- {
- // Find the shared memory region with this name
- SharedSegmentMap::iterator iter = mSharedSegments.find(name);
- if(iter != mSharedSegments.end())
- {
-// std::cerr << "%%% Got size change, new size is " << width << " by " << height << std::endl;
-// std::cerr << "%%%% texture size is " << texture_width << " by " << texture_height << std::endl;
-
- mPixels = (unsigned char*)iter->second.mAddress;
- mTextureSegmentName = name;
- mWidth = width;
- mHeight = height;
-
- mTextureWidth = texture_width;
- mTextureHeight = texture_height;
-
- mMediaSizeChanging = false;
-
- sizeChanged();
-
- update();
- };
- };
- }
- else if(message_name == "load_uri")
- {
- std::string uri = message_in.getValue("uri");
- load( uri );
- sendStatus();
- }
- else if(message_name == "mouse_event")
- {
- std::string event = message_in.getValue("event");
- S32 x = message_in.getValueS32("x");
- S32 y = message_in.getValueS32("y");
-
- if(event == "down")
- {
- mouseDown(x, y);
- }
- else if(event == "up")
- {
- mouseUp(x, y);
- }
- else if(event == "move")
- {
- mouseMove(x, y);
- };
- };
- }
- else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
- {
- if(message_name == "stop")
- {
- stop();
- }
- else if(message_name == "start")
- {
- F64 rate = 0.0;
- if(message_in.hasValue("rate"))
- {
- rate = message_in.getValueReal("rate");
- }
- play(rate);
- }
- else if(message_name == "pause")
- {
- pause();
- }
- else if(message_name == "seek")
- {
- F64 time = message_in.getValueReal("time");
- seek(time);
- }
- else if(message_name == "set_loop")
- {
- bool loop = message_in.getValueBoolean("loop");
- mIsLooping = loop;
- }
- else if(message_name == "set_volume")
- {
- F64 volume = message_in.getValueReal("volume");
- setVolume(volume);
- }
- }
- else
- {
-// std::cerr << "MediaPluginQuickTime::receiveMessage: unknown message class: " << message_class << std::endl;
- };
- };
-}
-
-int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
-{
- MediaPluginQuickTime *self = new MediaPluginQuickTime(host_send_func, host_user_data);
- *plugin_send_func = MediaPluginQuickTime::staticReceiveMessage;
- *plugin_user_data = (void*)self;
-
- return 0;
-}
-
-#else // LL_QUICKTIME_ENABLED
-
-// Stubbed-out class with constructor/destructor (necessary or windows linker
-// will just think its dead code and optimize it all out)
-class MediaPluginQuickTime : public MediaPluginBase
-{
-public:
- MediaPluginQuickTime(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
- ~MediaPluginQuickTime();
- /* virtual */ void receiveMessage(const char *message_string);
-};
-
-MediaPluginQuickTime::MediaPluginQuickTime(
- LLPluginInstance::sendMessageFunction host_send_func,
- void *host_user_data ) :
- MediaPluginBase(host_send_func, host_user_data)
-{
- // no-op
-}
-
-MediaPluginQuickTime::~MediaPluginQuickTime()
-{
- // no-op
-}
-
-void MediaPluginQuickTime::receiveMessage(const char *message_string)
-{
- // no-op
-}
-
-// We're building without quicktime enabled. Just refuse to initialize.
-int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
-{
- return -1;
-}
-
-#endif // LL_QUICKTIME_ENABLED
+/**
+ * @file media_plugin_quicktime.cpp
+ * @brief QuickTime plugin for LLMedia API plugin system
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ *
+ * Copyright (c) 2008, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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 "linden_common.h"
+
+#include "llgl.h"
+
+#include "llplugininstance.h"
+#include "llpluginmessage.h"
+#include "llpluginmessageclasses.h"
+#include "media_plugin_base.h"
+
+#if LL_QUICKTIME_ENABLED
+
+#if defined(LL_DARWIN)
+ #include <QuickTime/QuickTime.h>
+#elif defined(LL_WINDOWS)
+ #include "MacTypes.h"
+ #include "QTML.h"
+ #include "Movies.h"
+ #include "QDoffscreen.h"
+ #include "FixMath.h"
+ #include "QTLoadLibraryUtils.h"
+#endif
+
+// TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint
+////////////////////////////////////////////////////////////////////////////////
+//
+class MediaPluginQuickTime : public MediaPluginBase
+{
+public:
+ MediaPluginQuickTime(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
+ ~MediaPluginQuickTime();
+
+ /* virtual */ void receiveMessage(const char *message_string);
+
+private:
+
+ int mNaturalWidth;
+ int mNaturalHeight;
+ Movie mMovieHandle;
+ GWorldPtr mGWorldHandle;
+ ComponentInstance mMovieController;
+ int mCurVolume;
+ bool mMediaSizeChanging;
+ bool mIsLooping;
+ std::string mMovieTitle;
+ bool mReceivedTitle;
+ const int mMinWidth;
+ const int mMaxWidth;
+ const int mMinHeight;
+ const int mMaxHeight;
+ F64 mPlayRate;
+
+ enum ECommand {
+ COMMAND_NONE,
+ COMMAND_STOP,
+ COMMAND_PLAY,
+ COMMAND_FAST_FORWARD,
+ COMMAND_FAST_REWIND,
+ COMMAND_PAUSE,
+ COMMAND_SEEK,
+ };
+ ECommand mCommand;
+
+ // Override this to add current time and duration to the message
+ /*virtual*/ void setDirty(int left, int top, int right, int bottom)
+ {
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated");
+
+ message.setValueS32("left", left);
+ message.setValueS32("top", top);
+ message.setValueS32("right", right);
+ message.setValueS32("bottom", bottom);
+
+ if(mMovieHandle)
+ {
+ message.setValueReal("current_time", getCurrentTime());
+ message.setValueReal("duration", getDuration());
+ message.setValueReal("current_rate", Fix2X(GetMovieRate(mMovieHandle)));
+ }
+
+ sendMessage(message);
+ }
+
+
+ static Rect rectFromSize(int width, int height)
+ {
+ Rect result;
+
+
+ result.left = 0;
+ result.top = 0;
+ result.right = width;
+ result.bottom = height;
+
+ return result;
+ }
+
+ Fixed getPlayRate(void)
+ {
+ Fixed result;
+ if(mPlayRate == 0.0f)
+ {
+ // Default to the movie's preferred rate
+ result = GetMoviePreferredRate(mMovieHandle);
+ if(result == 0)
+ {
+ // Don't return a 0 play rate, ever.
+ std::cerr << "Movie's preferred rate is 0, forcing to 1.0." << std::endl;
+ result = X2Fix(1.0f);
+ }
+ }
+ else
+ {
+ result = X2Fix(mPlayRate);
+ }
+
+ return result;
+ }
+
+ void load( const std::string url )
+ {
+
+ if ( url.empty() )
+ return;
+
+ // Stop and unload any existing movie before starting another one.
+ unload();
+
+ setStatus(STATUS_LOADING);
+
+ //In case std::string::c_str() makes a copy of the url data,
+ //make sure there is memory to hold it before allocating memory for handle.
+ //if fails, NewHandleClear(...) should return NULL.
+ const char* url_string = url.c_str() ;
+ Handle handle = NewHandleClear( ( Size )( url.length() + 1 ) );
+
+ if ( NULL == handle || noErr != MemError() || NULL == *handle )
+ {
+ setStatus(STATUS_ERROR);
+ return;
+ }
+
+ BlockMove( url_string, *handle, ( Size )( url.length() + 1 ) );
+
+ OSErr err = NewMovieFromDataRef( &mMovieHandle, newMovieActive | newMovieDontInteractWithUser | newMovieAsyncOK | newMovieIdleImportOK, nil, handle, URLDataHandlerSubType );
+ DisposeHandle( handle );
+ if ( noErr != err )
+ {
+ setStatus(STATUS_ERROR);
+ return;
+ };
+
+ // do pre-roll actions (typically fired for streaming movies but not always)
+ PrePrerollMovie( mMovieHandle, 0, getPlayRate(), moviePrePrerollCompleteCallback, ( void * )this );
+
+ Rect movie_rect = rectFromSize(mWidth, mHeight);
+
+ // make a new movie controller
+ mMovieController = NewMovieController( mMovieHandle, &movie_rect, mcNotVisible | mcTopLeftMovie );
+
+ // movie controller
+ MCSetActionFilterWithRefCon( mMovieController, mcActionFilterCallBack, ( long )this );
+
+ SetMoviePlayHints( mMovieHandle, hintsAllowDynamicResize, hintsAllowDynamicResize );
+
+ // function that gets called when a frame is drawn
+ SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, movieDrawingCompleteCallback, ( long )this );
+
+ setStatus(STATUS_LOADED);
+
+ sizeChanged();
+ };
+
+ bool unload()
+ {
+ // new movie and have to get title again
+ mReceivedTitle = false;
+
+ if ( mMovieHandle )
+ {
+ StopMovie( mMovieHandle );
+ if ( mMovieController )
+ {
+ MCMovieChanged( mMovieController, mMovieHandle );
+ };
+ };
+
+ if ( mMovieController )
+ {
+ MCSetActionFilterWithRefCon( mMovieController, NULL, (long)this );
+ DisposeMovieController( mMovieController );
+ mMovieController = NULL;
+ };
+
+ if ( mMovieHandle )
+ {
+ SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, nil, ( long )this );
+ DisposeMovie( mMovieHandle );
+ mMovieHandle = NULL;
+ };
+
+ if ( mGWorldHandle )
+ {
+ DisposeGWorld( mGWorldHandle );
+ mGWorldHandle = NULL;
+ };
+
+ setStatus(STATUS_NONE);
+
+ return true;
+ }
+
+ bool navigateTo( const std::string url )
+ {
+ unload();
+ load( url );
+
+ return true;
+ };
+
+ bool sizeChanged()
+ {
+ if ( ! mMovieHandle )
+ return false;
+
+ // Check to see whether the movie's natural size has updated
+ {
+ int width, height;
+ getMovieNaturalSize(&width, &height);
+ if((width != 0) && (height != 0) && ((width != mNaturalWidth) || (height != mNaturalHeight)))
+ {
+ mNaturalWidth = width;
+ mNaturalHeight = height;
+
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request");
+ message.setValue("name", mTextureSegmentName);
+ message.setValueS32("width", width);
+ message.setValueS32("height", height);
+ sendMessage(message);
+ //std::cerr << "<--- Sending size change request to application with name: " << mTextureSegmentName << " - size is " << width << " x " << height << std::endl;
+ }
+ }
+
+ // sanitize destination size
+ Rect dest_rect = rectFromSize(mWidth, mHeight);
+
+ // media depth won't change
+ int depth_bits = mDepth * 8;
+ long rowbytes = mDepth * mTextureWidth;
+
+ GWorldPtr old_gworld_handle = mGWorldHandle;
+
+ if(mPixels != NULL)
+ {
+ // We have pixels. Set up a GWorld pointing at the texture.
+ OSErr result = NewGWorldFromPtr( &mGWorldHandle, depth_bits, &dest_rect, NULL, NULL, 0, (Ptr)mPixels, rowbytes);
+ if ( noErr != result )
+ {
+ // TODO: unrecoverable?? throw exception? return something?
+ return false;
+ }
+ }
+ else
+ {
+ // We don't have pixels. Create a fake GWorld we can point the movie at when it's not safe to render normally.
+ Rect tempRect = rectFromSize(1, 1);
+ OSErr result = NewGWorld( &mGWorldHandle, depth_bits, &tempRect, NULL, NULL, 0);
+ if ( noErr != result )
+ {
+ // TODO: unrecoverable?? throw exception? return something?
+ return false;
+ }
+ }
+
+ SetMovieGWorld( mMovieHandle, mGWorldHandle, GetGWorldDevice( mGWorldHandle ) );
+
+ // If the GWorld was already set up, delete it.
+ if(old_gworld_handle != NULL)
+ {
+ DisposeGWorld( old_gworld_handle );
+ }
+
+ // Set up the movie display matrix
+ {
+ // scale movie to fit rect and invert vertically to match opengl image format
+ MatrixRecord transform;
+ SetIdentityMatrix( &transform ); // transforms are additive so start from identify matrix
+ double scaleX = (double) mWidth / mNaturalWidth;
+ double scaleY = -1.0 * (double) mHeight / mNaturalHeight;
+ double centerX = mWidth / 2.0;
+ double centerY = mHeight / 2.0;
+ ScaleMatrix( &transform, X2Fix( scaleX ), X2Fix( scaleY ), X2Fix( centerX ), X2Fix( centerY ) );
+ SetMovieMatrix( mMovieHandle, &transform );
+ }
+
+ // update movie controller
+ if ( mMovieController )
+ {
+ MCSetControllerPort( mMovieController, mGWorldHandle );
+ MCPositionController( mMovieController, &dest_rect, &dest_rect,
+ mcTopLeftMovie | mcPositionDontInvalidate );
+ MCMovieChanged( mMovieController, mMovieHandle );
+ }
+
+
+ // Emit event with size change so the calling app knows about it too
+ // TODO:
+ //LLMediaEvent event( this );
+ //mEventEmitter.update( &LLMediaObserver::onMediaSizeChange, event );
+
+ return true;
+ }
+ static Boolean mcActionFilterCallBack( MovieController mc, short action, void *params, long ref )
+ {
+ Boolean result = false;
+
+ MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref;
+
+ switch( action )
+ {
+ // handle window resizing
+ case mcActionControllerSizeChanged:
+ // Ensure that the movie draws correctly at the new size
+ self->sizeChanged();
+ break;
+
+ // Block any movie controller actions that open URLs.
+ case mcActionLinkToURL:
+ case mcActionGetNextURL:
+ case mcActionLinkToURLExtended:
+ // Prevent the movie controller from handling the message
+ result = true;
+ break;
+
+ default:
+ break;
+ };
+
+ return result;
+ };
+
+ static OSErr movieDrawingCompleteCallback( Movie call_back_movie, long ref )
+ {
+ MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref;
+
+ // IMPORTANT: typically, a consumer who is observing this event will set a flag
+ // when this event is fired then render later. Be aware that the media stream
+ // can change during this period - dimensions, depth, format etc.
+ //LLMediaEvent event( self );
+// self->updateQuickTime();
+ // TODO ^^^
+
+
+ if ( self->mWidth > 0 && self->mHeight > 0 )
+ self->setDirty( 0, 0, self->mWidth, self->mHeight );
+
+ return noErr;
+ };
+
+ static void moviePrePrerollCompleteCallback( Movie movie, OSErr preroll_err, void *ref )
+ {
+ //MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref;
+
+ // TODO:
+ //LLMediaEvent event( self );
+ //self->mEventEmitter.update( &LLMediaObserver::onMediaPreroll, event );
+ };
+
+
+ void rewind()
+ {
+ GoToBeginningOfMovie( mMovieHandle );
+ MCMovieChanged( mMovieController, mMovieHandle );
+ };
+
+ bool processState()
+ {
+ if ( mCommand == COMMAND_PLAY )
+ {
+ if ( mStatus == STATUS_LOADED || mStatus == STATUS_PAUSED || mStatus == STATUS_PLAYING )
+ {
+ long state = GetMovieLoadState( mMovieHandle );
+
+ if ( state >= kMovieLoadStatePlaythroughOK )
+ {
+ // if the movie is at the end (generally because it reached it naturally)
+ // and we play is requested, jump back to the start of the movie.
+ // note: this is different from having loop flag set.
+ if ( IsMovieDone( mMovieHandle ) )
+ {
+ Fixed rate = X2Fix( 0.0 );
+ MCDoAction( mMovieController, mcActionPlay, (void*)rate );
+ rewind();
+ };
+
+ MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)getPlayRate() );
+ MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
+ setStatus(STATUS_PLAYING);
+ mCommand = COMMAND_NONE;
+ };
+ };
+ }
+ else
+ if ( mCommand == COMMAND_STOP )
+ {
+ if ( mStatus == STATUS_PLAYING || mStatus == STATUS_PAUSED )
+ {
+ if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK )
+ {
+ Fixed rate = X2Fix( 0.0 );
+ MCDoAction( mMovieController, mcActionPlay, (void*)rate );
+ rewind();
+
+ setStatus(STATUS_LOADED);
+ mCommand = COMMAND_NONE;
+ };
+ };
+ }
+ else
+ if ( mCommand == COMMAND_PAUSE )
+ {
+ if ( mStatus == STATUS_PLAYING )
+ {
+ if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK )
+ {
+ Fixed rate = X2Fix( 0.0 );
+ MCDoAction( mMovieController, mcActionPlay, (void*)rate );
+ setStatus(STATUS_PAUSED);
+ mCommand = COMMAND_NONE;
+ };
+ };
+ };
+
+ return true;
+ };
+
+ void play(F64 rate)
+ {
+ mPlayRate = rate;
+ mCommand = COMMAND_PLAY;
+ };
+
+ void stop()
+ {
+ mCommand = COMMAND_STOP;
+ };
+
+ void pause()
+ {
+ mCommand = COMMAND_PAUSE;
+ };
+
+ void getMovieNaturalSize(int *movie_width, int *movie_height)
+ {
+ Rect rect;
+
+ GetMovieNaturalBoundsRect( mMovieHandle, &rect );
+
+ int width = ( rect.right - rect.left );
+ int height = ( rect.bottom - rect.top );
+
+ // make sure width and height fall in valid range
+ if ( width < mMinWidth )
+ width = mMinWidth;
+
+ if ( width > mMaxWidth )
+ width = mMaxWidth;
+
+ if ( height < mMinHeight )
+ height = mMinHeight;
+
+ if ( height > mMaxHeight )
+ height = mMaxHeight;
+
+ // return the new rect
+ *movie_width = width;
+ *movie_height = height;
+ }
+
+ void updateQuickTime(int milliseconds)
+ {
+ if ( ! mMovieHandle )
+ return;
+
+ if ( ! mMovieController )
+ return;
+
+ // service QuickTime
+ // Calling it this way doesn't have good behavior on Windows...
+// MoviesTask( mMovieHandle, milliseconds );
+ // This was the original, but I think using both MoviesTask and MCIdle is redundant. Trying with only MCIdle.
+// MoviesTask( mMovieHandle, 0 );
+
+ MCIdle( mMovieController );
+
+ if ( ! mGWorldHandle )
+ return;
+
+ if ( mMediaSizeChanging )
+ return;
+
+ // update state machine
+ processState();
+
+ // see if title arrived and if so, update member variable with contents
+ checkTitle();
+
+ // special code for looping - need to rewind at the end of the movie
+ if ( mIsLooping )
+ {
+ // QT call to see if we are at the end - can't do with controller
+ if ( IsMovieDone( mMovieHandle ) )
+ {
+ // go back to start
+ rewind();
+
+ if ( mMovieController )
+ {
+ // kick off new play
+ MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)getPlayRate() );
+
+ // set the volume
+ MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
+ };
+ };
+ };
+ };
+
+ int getDataWidth() const
+ {
+ if ( mGWorldHandle )
+ {
+ int depth = mDepth;
+
+ if (depth < 1)
+ depth = 1;
+
+ // ALWAYS use the row bytes from the PixMap if we have a GWorld because
+ // sometimes it's not the same as mMediaDepth * mMediaWidth !
+ PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle );
+ return QTGetPixMapHandleRowBytes( pix_map_handle ) / depth;
+ }
+ else
+ {
+ // TODO : return LLMediaImplCommon::getaDataWidth();
+ return 0;
+ }
+ };
+
+ void seek( F64 time )
+ {
+ if ( mMovieController )
+ {
+ TimeRecord when;
+ when.scale = GetMovieTimeScale( mMovieHandle );
+ when.base = 0;
+
+ // 'time' is in (floating point) seconds. The timebase time will be in 'units', where
+ // there are 'scale' units per second.
+ SInt64 raw_time = ( SInt64 )( time * (double)( when.scale ) );
+
+ when.value.hi = ( SInt32 )( raw_time >> 32 );
+ when.value.lo = ( SInt32 )( ( raw_time & 0x00000000FFFFFFFF ) );
+
+ MCDoAction( mMovieController, mcActionGoToTime, &when );
+ };
+ };
+
+ F64 getLoadedDuration()
+ {
+ TimeValue duration;
+ if(GetMaxLoadedTimeInMovie( mMovieHandle, &duration ) != noErr)
+ {
+ // If GetMaxLoadedTimeInMovie returns an error, return the full duration of the movie.
+ duration = GetMovieDuration( mMovieHandle );
+ }
+ TimeValue scale = GetMovieTimeScale( mMovieHandle );
+
+ return (F64)duration / (F64)scale;
+ };
+
+ F64 getDuration()
+ {
+ TimeValue duration = GetMovieDuration( mMovieHandle );
+ TimeValue scale = GetMovieTimeScale( mMovieHandle );
+
+ return (F64)duration / (F64)scale;
+ };
+
+ F64 getCurrentTime()
+ {
+ TimeValue curr_time = GetMovieTime( mMovieHandle, 0 );
+ TimeValue scale = GetMovieTimeScale( mMovieHandle );
+
+ return (F64)curr_time / (F64)scale;
+ };
+
+ void setVolume( F64 volume )
+ {
+ mCurVolume = (short)(volume * ( double ) 0x100 );
+
+ if ( mMovieController )
+ {
+ MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
+ };
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ //
+ void update(int milliseconds = 0)
+ {
+ updateQuickTime(milliseconds);
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ //
+ void mouseDown( int x, int y )
+ {
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ //
+ void mouseUp( int x, int y )
+ {
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ //
+ void mouseMove( int x, int y )
+ {
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ //
+ void keyPress( unsigned char key )
+ {
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Grab movie title into mMovieTitle - should be called repeatedly
+ // until it returns true since movie title takes a while to become
+ // available.
+ const bool getMovieTitle()
+ {
+ // grab meta data from movie
+ QTMetaDataRef media_data_ref;
+ OSErr result = QTCopyMovieMetaData( mMovieHandle, &media_data_ref );
+ if ( noErr != result )
+ return false;
+
+ // look up "Display Name" in meta data
+ OSType meta_data_key = kQTMetaDataCommonKeyDisplayName;
+ QTMetaDataItem item = kQTMetaDataItemUninitialized;
+ result = QTMetaDataGetNextItem( media_data_ref, kQTMetaDataStorageFormatWildcard,
+ 0, kQTMetaDataKeyFormatCommon,
+ (const UInt8 *)&meta_data_key,
+ sizeof( meta_data_key ), &item );
+ if ( noErr != result )
+ return false;
+
+ // find the size of the title
+ ByteCount size;
+ result = QTMetaDataGetItemValue( media_data_ref, item, NULL, 0, &size );
+ if ( noErr != result || size <= 0 )
+ return false;
+
+ // allocate some space and grab it
+ UInt8* item_data = new UInt8( size );
+ memset( item_data, 0, size * sizeof( UInt8* ) );
+ result = QTMetaDataGetItemValue( media_data_ref, item, item_data, size, NULL );
+ if ( noErr != result )
+ return false;
+
+ // save it
+ mMovieTitle = std::string( (char* )item_data );
+
+ // clean up
+ delete [] item_data;
+
+ return true;
+ };
+
+ // called regularly to see if title changed
+ void checkTitle()
+ {
+ // we did already receive title so keep checking
+ if ( ! mReceivedTitle )
+ {
+ // grab title from movie meta data
+ if ( getMovieTitle() )
+ {
+ // pass back to host application
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
+ message.setValue("name", mMovieTitle );
+ sendMessage( message );
+
+ // stop looking once we find a title for this movie.
+ // TODO: this may to be reset if movie title changes
+ // during playback but this is okay for now
+ mReceivedTitle = true;
+ };
+ };
+ };
+};
+
+MediaPluginQuickTime::MediaPluginQuickTime(
+ LLPluginInstance::sendMessageFunction host_send_func,
+ void *host_user_data ) :
+ MediaPluginBase(host_send_func, host_user_data),
+ mMinWidth( 0 ),
+ mMaxWidth( 2048 ),
+ mMinHeight( 0 ),
+ mMaxHeight( 2048 )
+{
+// std::cerr << "MediaPluginQuickTime constructor" << std::endl;
+
+ mNaturalWidth = -1;
+ mNaturalHeight = -1;
+ mMovieHandle = 0;
+ mGWorldHandle = 0;
+ mMovieController = 0;
+ mCurVolume = 0x99;
+ mMediaSizeChanging = false;
+ mIsLooping = false;
+ mMovieTitle = std::string();
+ mReceivedTitle = false;
+ mCommand = COMMAND_NONE;
+ mPlayRate = 0.0f;
+ mStatus = STATUS_NONE;
+}
+
+MediaPluginQuickTime::~MediaPluginQuickTime()
+{
+// std::cerr << "MediaPluginQuickTime destructor" << std::endl;
+
+ ExitMovies();
+
+#ifdef LL_WINDOWS
+ TerminateQTML();
+// std::cerr << "QuickTime closing down" << std::endl;
+#endif
+}
+
+
+void MediaPluginQuickTime::receiveMessage(const char *message_string)
+{
+// std::cerr << "MediaPluginQuickTime::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
+ LLPluginMessage message_in;
+
+ if(message_in.parse(message_string) >= 0)
+ {
+ std::string message_class = message_in.getClass();
+ std::string message_name = message_in.getName();
+ if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
+ {
+ if(message_name == "init")
+ {
+ LLPluginMessage message("base", "init_response");
+ LLSD versions = LLSD::emptyMap();
+ versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
+ versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
+ // Normally a plugin would only specify one of these two subclasses, but this is a demo...
+ versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION;
+ message.setValueLLSD("versions", versions);
+
+ #ifdef LL_WINDOWS
+
+ // QuickTime 7.6.4 has an issue (that was not present in 7.6.2) with initializing QuickTime
+ // according to this article: http://lists.apple.com/archives/QuickTime-API/2009/Sep/msg00097.html
+ // The solution presented there appears to work.
+ QTLoadLibrary("qtcf.dll");
+
+ // main initialization for QuickTime - only required on Windows
+ OSErr result = InitializeQTML( 0L );
+ if ( result != noErr )
+ {
+ //TODO: If no QT on Windows, this fails - respond accordingly.
+ }
+ else
+ {
+ //std::cerr << "QuickTime initialized" << std::endl;
+ };
+ #endif
+
+ // required for both Windows and Mac
+ EnterMovies();
+
+ std::string plugin_version = "QuickTime media plugin, QuickTime version ";
+
+ long version = 0;
+ Gestalt( gestaltQuickTimeVersion, &version );
+ std::ostringstream codec( "" );
+ codec << std::hex << version << std::dec;
+ plugin_version += codec.str();
+ message.setValue("plugin_version", plugin_version);
+ sendMessage(message);
+
+ // Plugin gets to decide the texture parameters to use.
+ message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
+ #if defined(LL_WINDOWS)
+ // Values for Windows
+ mDepth = 3;
+ message.setValueU32("format", GL_RGB);
+ message.setValueU32("type", GL_UNSIGNED_BYTE);
+
+ // We really want to pad the texture width to a multiple of 32 bytes, but since we're using 3-byte pixels, it doesn't come out even.
+ // Padding to a multiple of 3*32 guarantees it'll divide out properly.
+ message.setValueU32("padding", 32 * 3);
+ #else
+ // Values for Mac
+ mDepth = 4;
+ message.setValueU32("format", GL_BGRA_EXT);
+ #ifdef __BIG_ENDIAN__
+ message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV );
+ #else
+ message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8);
+ #endif
+
+ // Pad texture width to a multiple of 32 bytes, to line up with cache lines.
+ message.setValueU32("padding", 32);
+ #endif
+ message.setValueS32("depth", mDepth);
+ message.setValueU32("internalformat", GL_RGB);
+ message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left.
+ message.setValueBoolean("allow_downsample", true);
+ sendMessage(message);
+ }
+ else if(message_name == "idle")
+ {
+ // no response is necessary here.
+ F64 time = message_in.getValueReal("time");
+
+ // Convert time to milliseconds for update()
+ update((int)(time * 1000.0f));
+ }
+ else if(message_name == "cleanup")
+ {
+ // TODO: clean up here
+ }
+ else if(message_name == "shm_added")
+ {
+ SharedSegmentInfo info;
+ info.mAddress = message_in.getValuePointer("address");
+ info.mSize = (size_t)message_in.getValueS32("size");
+ std::string name = message_in.getValue("name");
+// std::cerr << "MediaPluginQuickTime::receiveMessage: shared memory added, name: " << name
+// << ", size: " << info.mSize
+// << ", address: " << info.mAddress
+// << std::endl;
+
+ mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
+
+ }
+ else if(message_name == "shm_remove")
+ {
+ std::string name = message_in.getValue("name");
+
+// std::cerr << "MediaPluginQuickTime::receiveMessage: shared memory remove, name = " << name << std::endl;
+
+ SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+ if(iter != mSharedSegments.end())
+ {
+ if(mPixels == iter->second.mAddress)
+ {
+ // This is the currently active pixel buffer. Make sure we stop drawing to it.
+ mPixels = NULL;
+ mTextureSegmentName.clear();
+
+ // Make sure the movie GWorld is no longer pointed at the shared segment.
+ sizeChanged();
+ }
+ mSharedSegments.erase(iter);
+ }
+ else
+ {
+// std::cerr << "MediaPluginQuickTime::receiveMessage: unknown shared memory region!" << std::endl;
+ }
+
+ // Send the response so it can be cleaned up.
+ LLPluginMessage message("base", "shm_remove_response");
+ message.setValue("name", name);
+ sendMessage(message);
+ }
+ else
+ {
+// std::cerr << "MediaPluginQuickTime::receiveMessage: unknown base message: " << message_name << std::endl;
+ }
+ }
+ else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
+ {
+ if(message_name == "size_change")
+ {
+ std::string name = message_in.getValue("name");
+ S32 width = message_in.getValueS32("width");
+ S32 height = message_in.getValueS32("height");
+ S32 texture_width = message_in.getValueS32("texture_width");
+ S32 texture_height = message_in.getValueS32("texture_height");
+
+ //std::cerr << "---->Got size change instruction from application with name: " << name << " - size is " << width << " x " << height << std::endl;
+
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
+ message.setValue("name", name);
+ message.setValueS32("width", width);
+ message.setValueS32("height", height);
+ message.setValueS32("texture_width", texture_width);
+ message.setValueS32("texture_height", texture_height);
+ sendMessage(message);
+
+ if(!name.empty())
+ {
+ // Find the shared memory region with this name
+ SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+ if(iter != mSharedSegments.end())
+ {
+// std::cerr << "%%% Got size change, new size is " << width << " by " << height << std::endl;
+// std::cerr << "%%%% texture size is " << texture_width << " by " << texture_height << std::endl;
+
+ mPixels = (unsigned char*)iter->second.mAddress;
+ mTextureSegmentName = name;
+ mWidth = width;
+ mHeight = height;
+
+ mTextureWidth = texture_width;
+ mTextureHeight = texture_height;
+
+ mMediaSizeChanging = false;
+
+ sizeChanged();
+
+ update();
+ };
+ };
+ }
+ else if(message_name == "load_uri")
+ {
+ std::string uri = message_in.getValue("uri");
+ load( uri );
+ sendStatus();
+ }
+ else if(message_name == "mouse_event")
+ {
+ std::string event = message_in.getValue("event");
+ S32 x = message_in.getValueS32("x");
+ S32 y = message_in.getValueS32("y");
+
+ if(event == "down")
+ {
+ mouseDown(x, y);
+ }
+ else if(event == "up")
+ {
+ mouseUp(x, y);
+ }
+ else if(event == "move")
+ {
+ mouseMove(x, y);
+ };
+ };
+ }
+ else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
+ {
+ if(message_name == "stop")
+ {
+ stop();
+ }
+ else if(message_name == "start")
+ {
+ F64 rate = 0.0;
+ if(message_in.hasValue("rate"))
+ {
+ rate = message_in.getValueReal("rate");
+ }
+ play(rate);
+ }
+ else if(message_name == "pause")
+ {
+ pause();
+ }
+ else if(message_name == "seek")
+ {
+ F64 time = message_in.getValueReal("time");
+ seek(time);
+ }
+ else if(message_name == "set_loop")
+ {
+ bool loop = message_in.getValueBoolean("loop");
+ mIsLooping = loop;
+ }
+ else if(message_name == "set_volume")
+ {
+ F64 volume = message_in.getValueReal("volume");
+ setVolume(volume);
+ }
+ }
+ else
+ {
+// std::cerr << "MediaPluginQuickTime::receiveMessage: unknown message class: " << message_class << std::endl;
+ };
+ };
+}
+
+int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
+{
+ MediaPluginQuickTime *self = new MediaPluginQuickTime(host_send_func, host_user_data);
+ *plugin_send_func = MediaPluginQuickTime::staticReceiveMessage;
+ *plugin_user_data = (void*)self;
+
+ return 0;
+}
+
+#else // LL_QUICKTIME_ENABLED
+
+// Stubbed-out class with constructor/destructor (necessary or windows linker
+// will just think its dead code and optimize it all out)
+class MediaPluginQuickTime : public MediaPluginBase
+{
+public:
+ MediaPluginQuickTime(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
+ ~MediaPluginQuickTime();
+ /* virtual */ void receiveMessage(const char *message_string);
+};
+
+MediaPluginQuickTime::MediaPluginQuickTime(
+ LLPluginInstance::sendMessageFunction host_send_func,
+ void *host_user_data ) :
+ MediaPluginBase(host_send_func, host_user_data)
+{
+ // no-op
+}
+
+MediaPluginQuickTime::~MediaPluginQuickTime()
+{
+ // no-op
+}
+
+void MediaPluginQuickTime::receiveMessage(const char *message_string)
+{
+ // no-op
+}
+
+// We're building without quicktime enabled. Just refuse to initialize.
+int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
+{
+ return -1;
+}
+
+#endif // LL_QUICKTIME_ENABLED
diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp
index 1b71ba1769..65872e1596 100644
--- a/indra/media_plugins/webkit/media_plugin_webkit.cpp
+++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp
@@ -183,7 +183,7 @@ private:
#if LL_WINDOWS
// Enable plugins
- LLQtWebKit::getInstance()->enablePlugins(false);
+ LLQtWebKit::getInstance()->enablePlugins(true);
#elif LL_DARWIN
// Disable plugins
LLQtWebKit::getInstance()->enablePlugins(false);
@@ -308,7 +308,16 @@ private:
message.setValue("status", event.getStringValue());
sendMessage(message);
}
-
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // virtual
+ void onTitleChange(const EventType& event)
+ {
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
+ message.setValue("name", event.getStringValue());
+ sendMessage(message);
+ }
+
////////////////////////////////////////////////////////////////////////////////
// virtual
void onLocationChange(const EventType& event)
diff --git a/indra/newview/English.lproj/InfoPlist.strings b/indra/newview/English.lproj/InfoPlist.strings
index afa5a877b5..dceaba9a43 100644
--- a/indra/newview/English.lproj/InfoPlist.strings
+++ b/indra/newview/English.lproj/InfoPlist.strings
@@ -2,6 +2,6 @@
CFBundleName = "Second Life";
-CFBundleShortVersionString = "Second Life version 2.0.0.2822";
-CFBundleGetInfoString = "Second Life version 2.0.0.2822, Copyright 2004-2009 Linden Research, Inc.";
+CFBundleShortVersionString = "Second Life version 2.0.0.3256";
+CFBundleGetInfoString = "Second Life version 2.0.0.3256, Copyright 2004-2009 Linden Research, Inc.";
diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist
index 1df5102f5f..7aec8a343d 100644
--- a/indra/newview/Info-SecondLife.plist
+++ b/indra/newview/Info-SecondLife.plist
@@ -32,7 +32,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
- <string>2.0.0.2822</string>
+ <string>2.0.0.3256</string>
<key>CSResourcesFileMapped</key>
<true/>
</dict>
diff --git a/indra/newview/llfloatermediasettings.cpp b/indra/newview/llfloatermediasettings.cpp
index aa457de2d8..d941f24f49 100644
--- a/indra/newview/llfloatermediasettings.cpp
+++ b/indra/newview/llfloatermediasettings.cpp
@@ -118,6 +118,7 @@ BOOL LLFloaterMediaSettings::postBuild()
mTabContainer->addTabPanel(
LLTabContainer::TabPanelParams().
panel(mPanelMediaSettingsSecurity));
+ mPanelMediaSettingsSecurity->setParent( this );
// restore the last tab viewed from persistance variable storage
if (!mTabContainer->selectTab(gSavedSettings.getS32("LastMediaSettingsTab")))
@@ -248,3 +249,28 @@ void LLFloaterMediaSettings::enableOkApplyBtns( bool enable )
childSetEnabled( "OK", enable );
childSetEnabled( "Apply", enable );
}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+const std::string LLFloaterMediaSettings::getHomeUrl()
+{
+ if ( mPanelMediaSettingsGeneral )
+ return mPanelMediaSettingsGeneral->getHomeUrl();
+ else
+ return std::string( "" );
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+bool LLFloaterMediaSettings::passesWhiteList( const std::string& test_url )
+{
+ // sanity check - don't think this can happen
+ if ( mPanelMediaSettingsSecurity )
+ // version in security dialog code is specialized so we pass in
+ // empty string for first parameter since it's not used
+ return mPanelMediaSettingsSecurity->passesWhiteList( "", test_url );
+ else
+ // this is all we can do
+ return false;
+}
diff --git a/indra/newview/llfloatermediasettings.h b/indra/newview/llfloatermediasettings.h
index e2683039cc..17a47cb0f5 100644
--- a/indra/newview/llfloatermediasettings.h
+++ b/indra/newview/llfloatermediasettings.h
@@ -56,6 +56,8 @@ public:
static void clearValues( bool editable);
void enableOkApplyBtns( bool enable );
LLPanelMediaSettingsSecurity* getPanelSecurity(){return mPanelMediaSettingsSecurity;};
+ const std::string getHomeUrl();
+ bool passesWhiteList( const std::string& test_url );
bool mIdenticalHasMediaInfo;
bool mMultipleMedia;
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index 320647ff1a..f2385307db 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -1114,8 +1114,8 @@ void LLFloaterTools::getMediaState()
// Media data is valid
if(media_data_get!=default_media_data)
{
- //TODO: get Meida title
- //media_title = media_data_get->getTile();
+ //TODO: get media title
+ //media_title = media_data_get->getTitle();
//LLFloaterMediaSettings::getInstance()->mIdenticalValidMedia = true;
media_title = media_data_get.getHomeURL();
}
@@ -1149,8 +1149,8 @@ void LLFloaterTools::getMediaState()
// Media data is valid
if(media_data_get!=default_media_data)
{
- //TODO: get Meida title
- //media_title = media_data_get->getTile();
+ //TODO: get media title
+ //media_title = media_data_get->getTitle();
media_title = media_data_get.getHomeURL();
}
diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp
index a33d9604fe..16e1901bfd 100644
--- a/indra/newview/llpanelmediasettingsgeneral.cpp
+++ b/indra/newview/llpanelmediasettingsgeneral.cpp
@@ -32,6 +32,7 @@
#include "llviewerprecompiledheaders.h"
+#include "llagent.h"
#include "llpanelmediasettingsgeneral.h"
#include "llcombobox.h"
#include "llcheckboxctrl.h"
@@ -47,6 +48,7 @@
#include "llmediaentry.h"
#include "llmediactrl.h"
#include "llpanelcontents.h"
+#include "llpermissions.h"
#include "llpluginclassmedia.h"
#include "llfloatermediasettings.h"
#include "llfloatertools.h"
@@ -159,8 +161,7 @@ void LLPanelMediaSettingsGeneral::draw()
// current URL can change over time.
// updateCurrentURL();
- // enable/disable RESRET button depending on permissions
- // since this is the same as a navigate action
+ LLPermissions perm;
bool user_can_press_reset = gFloaterTools->selectedMediaEditable();
// several places modify this widget so we must collect states in one place
@@ -350,6 +351,16 @@ void LLPanelMediaSettingsGeneral::onClose(bool app_quitting)
void LLPanelMediaSettingsGeneral::onCommitHomeURL( LLUICtrl* ctrl, void *userdata )
{
LLPanelMediaSettingsGeneral* self =(LLPanelMediaSettingsGeneral *)userdata;
+
+ // check url user is trying to enter for home URL will pass whitelist
+ // and decline to accept it if it doesn't.
+ std::string home_url = self->mHomeURL->getValue().asString();
+ if ( ! self->mParent->passesWhiteList( home_url ) )
+ {
+ LLNotifications::instance().add("WhiteListInvalidatesHomeUrl");
+ return;
+ };
+
self->updateMediaPreview();
}
@@ -398,3 +409,10 @@ void LLPanelMediaSettingsGeneral::setParent( LLFloaterMediaSettings* parent )
{
mParent = parent;
};
+
+////////////////////////////////////////////////////////////////////////////////
+//
+const std::string LLPanelMediaSettingsGeneral::getHomeUrl()
+{
+ return mHomeURL->getValue().asString();
+}
diff --git a/indra/newview/llpanelmediasettingsgeneral.h b/indra/newview/llpanelmediasettingsgeneral.h
index 5acfa39181..c404ad127f 100644
--- a/indra/newview/llpanelmediasettingsgeneral.h
+++ b/indra/newview/llpanelmediasettingsgeneral.h
@@ -63,6 +63,8 @@ public:
void updateMediaPreview();
void updateCurrentURL();
+
+ const std::string getHomeUrl();
protected:
LLFloaterMediaSettings* mParent;
@@ -74,7 +76,6 @@ private:
LLComboBox* mControls;
LLCheckBoxCtrl* mAutoLoop;
LLCheckBoxCtrl* mFirstClick;
-// LLTextureCtrl* mMediaPreview;
LLCheckBoxCtrl* mAutoZoom;
LLCheckBoxCtrl* mAutoPlay;
LLCheckBoxCtrl* mAutoScale;
diff --git a/indra/newview/llpanelmediasettingssecurity.cpp b/indra/newview/llpanelmediasettingssecurity.cpp
index cea105d7de..f5607aa287 100644
--- a/indra/newview/llpanelmediasettingssecurity.cpp
+++ b/indra/newview/llpanelmediasettingssecurity.cpp
@@ -1,255 +1,343 @@
-/**
- * @file llpanelmediasettingssecurity.cpp
- * @brief LLPanelMediaSettingsSecurity class implementation
- *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- *
- * Copyright (c) 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 "llfloaterreg.h"
-#include "llpanelmediasettingssecurity.h"
-#include "llpanelcontents.h"
-#include "llcheckboxctrl.h"
-#include "llscrolllistctrl.h"
-#include "llscrolllistitem.h"
-#include "lluictrlfactory.h"
-#include "llwindow.h"
-#include "llviewerwindow.h"
-#include "llsdutil.h"
-#include "llselectmgr.h"
-#include "llmediaentry.h"
-#include "llfloaterwhitelistentry.h"
-#include "llfloatermediasettings.h"
-////////////////////////////////////////////////////////////////////////////////
-//
-LLPanelMediaSettingsSecurity::LLPanelMediaSettingsSecurity()
-{
- // build dialog from XML
- LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_settings_security.xml");
- mCommitCallbackRegistrar.add("Media.whitelistAdd", boost::bind(&LLPanelMediaSettingsSecurity::onBtnAdd, this));
- mCommitCallbackRegistrar.add("Media.whitelistDelete", boost::bind(&LLPanelMediaSettingsSecurity::onBtnDel, this));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-BOOL LLPanelMediaSettingsSecurity::postBuild()
-{
- mEnableWhiteList = getChild< LLCheckBoxCtrl >( LLMediaEntry::WHITELIST_ENABLE_KEY );
- mWhiteListList = getChild< LLScrollListCtrl >( LLMediaEntry::WHITELIST_KEY );
-
- childSetAction("whitelist_add", onBtnAdd, this);
- childSetAction("whitelist_del", onBtnDel, this);
-
- setDefaultBtn("whitelist_add");
-
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// virtual
-LLPanelMediaSettingsSecurity::~LLPanelMediaSettingsSecurity()
-{
-}
-
-////////////////////////////////////////////////////////////////////////////////
-//
-void LLPanelMediaSettingsSecurity::draw()
-{
- // housekeeping
- LLPanel::draw();
-
- // if list is empty, disable DEL button and checkbox to enable use of list
- if ( mWhiteListList->isEmpty() )
- {
- childSetEnabled( "whitelist_del", false );
- childSetEnabled( LLMediaEntry::WHITELIST_KEY, false );
- childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, false );
- }
- else
- {
- childSetEnabled( "whitelist_del", true );
- childSetEnabled( LLMediaEntry::WHITELIST_KEY, true );
- childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, true );
- };
-
- // if nothing is selected, disable DEL button
- if ( mWhiteListList->getSelectedValue().asString().empty() )
- {
- childSetEnabled( "whitelist_del", false );
- }
- else
- {
- childSetEnabled( "whitelist_del", true );
- };
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// static
-void LLPanelMediaSettingsSecurity::initValues( void* userdata, const LLSD& media_settings , bool editable)
-{
- LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata;
-
- if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo )
- {
- if(LLFloaterMediaSettings::getInstance()->mMultipleMedia)
- {
- self->clearValues(self, editable);
- // only show multiple
- return;
- }
-
- }
- else
- {
- if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia)
- {
- self->clearValues(self, editable);
- // only show multiple
- return;
- }
-
- }
- std::string base_key( "" );
- std::string tentative_key( "" );
-
- struct
- {
- std::string key_name;
- LLUICtrl* ctrl_ptr;
- std::string ctrl_type;
-
- } data_set [] =
+/**
+ * @file llpanelmediasettingssecurity.cpp
+ * @brief LLPanelMediaSettingsSecurity class implementation
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ *
+ * Copyright (c) 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 "llfloaterreg.h"
+#include "llpanelmediasettingssecurity.h"
+#include "llpanelcontents.h"
+#include "llcheckboxctrl.h"
+#include "llscrolllistctrl.h"
+#include "llscrolllistitem.h"
+#include "lluictrlfactory.h"
+#include "llwindow.h"
+#include "llviewerwindow.h"
+#include "llsdutil.h"
+#include "llselectmgr.h"
+#include "llmediaentry.h"
+#include "llfloaterwhitelistentry.h"
+#include "llfloatermediasettings.h"
+////////////////////////////////////////////////////////////////////////////////
+//
+LLPanelMediaSettingsSecurity::LLPanelMediaSettingsSecurity() :
+ mParent( NULL )
+{
+ // build dialog from XML
+ LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_settings_security.xml");
+ mCommitCallbackRegistrar.add("Media.whitelistAdd", boost::bind(&LLPanelMediaSettingsSecurity::onBtnAdd, this));
+ mCommitCallbackRegistrar.add("Media.whitelistDelete", boost::bind(&LLPanelMediaSettingsSecurity::onBtnDel, this));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+BOOL LLPanelMediaSettingsSecurity::postBuild()
+{
+ mEnableWhiteList = getChild< LLCheckBoxCtrl >( LLMediaEntry::WHITELIST_ENABLE_KEY );
+ mWhiteListList = getChild< LLScrollListCtrl >( LLMediaEntry::WHITELIST_KEY );
+
+ childSetAction("whitelist_add", onBtnAdd, this);
+ childSetAction("whitelist_del", onBtnDel, this);
+
+ setDefaultBtn("whitelist_add");
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// virtual
+LLPanelMediaSettingsSecurity::~LLPanelMediaSettingsSecurity()
+{
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLPanelMediaSettingsSecurity::draw()
+{
+ // housekeeping
+ LLPanel::draw();
+
+ // if list is empty, disable DEL button and checkbox to enable use of list
+ if ( mWhiteListList->isEmpty() )
+ {
+ childSetEnabled( "whitelist_del", false );
+ childSetEnabled( LLMediaEntry::WHITELIST_KEY, false );
+ childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, false );
+ }
+ else
+ {
+ childSetEnabled( "whitelist_del", true );
+ childSetEnabled( LLMediaEntry::WHITELIST_KEY, true );
+ childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, true );
+ };
+
+ // if nothing is selected, disable DEL button
+ if ( mWhiteListList->getSelectedValue().asString().empty() )
+ {
+ childSetEnabled( "whitelist_del", false );
+ }
+ else
+ {
+ childSetEnabled( "whitelist_del", true );
+ };
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// static
+void LLPanelMediaSettingsSecurity::initValues( void* userdata, const LLSD& media_settings , bool editable)
+{
+ LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata;
+
+ if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo )
+ {
+ if(LLFloaterMediaSettings::getInstance()->mMultipleMedia)
+ {
+ self->clearValues(self, editable);
+ // only show multiple
+ return;
+ }
+
+ }
+ else
+ {
+ if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia)
+ {
+ self->clearValues(self, editable);
+ // only show multiple
+ return;
+ }
+
+ }
+ std::string base_key( "" );
+ std::string tentative_key( "" );
+
+ struct
+ {
+ std::string key_name;
+ LLUICtrl* ctrl_ptr;
+ std::string ctrl_type;
+
+ } data_set [] =
+ {
+ { LLMediaEntry::WHITELIST_ENABLE_KEY, self->mEnableWhiteList, "LLCheckBoxCtrl" },
+ { LLMediaEntry::WHITELIST_KEY, self->mWhiteListList, "LLScrollListCtrl" },
+ { "", NULL , "" }
+ };
+
+ for( int i = 0; data_set[ i ].key_name.length() > 0; ++i )
+ {
+ base_key = std::string( data_set[ i ].key_name );
+ tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX );
+
+ // TODO: CP - I bet there is a better way to do this using Boost
+ if ( media_settings[ base_key ].isDefined() )
+ {
+ if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" )
+ {
+ static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )->
+ setValue( media_settings[ base_key ].asBoolean() );
+ }
+ else
+ if ( data_set[ i ].ctrl_type == "LLScrollListCtrl" )
+ {
+ // get control
+ LLScrollListCtrl* list = static_cast< LLScrollListCtrl* >( data_set[ i ].ctrl_ptr );
+ list->deleteAllItems();
+
+ // points to list of white list URLs
+ LLSD url_list = media_settings[ base_key ];
+
+ // iterate over them and add to scroll list
+ LLSD::array_iterator iter = url_list.beginArray();
+ while( iter != url_list.endArray() )
+ {
+ // TODO: is iter guaranteed to be valid here?
+ std::string url = *iter;
+ list->addSimpleElement( url );
+ ++iter;
+ };
+ };
+ data_set[ i ].ctrl_ptr->setEnabled(editable);
+ data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() );
+ };
+ };
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// static
+void LLPanelMediaSettingsSecurity::clearValues( void* userdata , bool editable)
+{
+ LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata;
+ self->mEnableWhiteList->clear();
+ self->mWhiteListList->deleteAllItems();
+ self->mEnableWhiteList->setEnabled(editable);
+ self->mWhiteListList->setEnabled(editable);
+}
+////////////////////////////////////////////////////////////////////////////////
+// static
+void LLPanelMediaSettingsSecurity::apply( void* userdata )
+{
+ LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata;
+
+ // build LLSD Fragment
+ LLSD media_data_security;
+ self->getValues(media_data_security);
+ // this merges contents of LLSD passed in with what's there so this is ok
+ LLSelectMgr::getInstance()->selectionSetMediaData( media_data_security );
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+void LLPanelMediaSettingsSecurity::getValues( LLSD &fill_me_in )
+{
+ fill_me_in[LLMediaEntry::WHITELIST_ENABLE_KEY] = mEnableWhiteList->getValue();
+
+ // iterate over white list and extract items
+ std::vector< LLScrollListItem* > white_list_items = mWhiteListList->getAllData();
+ std::vector< LLScrollListItem* >::iterator iter = white_list_items.begin();
+ fill_me_in[LLMediaEntry::WHITELIST_KEY].clear();
+ while( iter != white_list_items.end() )
+ {
+ std::string white_list_url = (*iter)->getValue().asString();
+ fill_me_in[ LLMediaEntry::WHITELIST_KEY ].append( white_list_url );
+ ++iter;
+ };
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Try to make a valid URL if a fragment (
+// white list list box widget and build a list to test against. Can also
+const std::string LLPanelMediaSettingsSecurity::makeValidUrl( const std::string& src_url )
+{
+ // use LLURI to determine if we have a valid scheme
+ LLURI candidate_url( src_url );
+ if ( candidate_url.scheme().empty() )
{
- { LLMediaEntry::WHITELIST_ENABLE_KEY, self->mEnableWhiteList, "LLCheckBoxCtrl" },
- { LLMediaEntry::WHITELIST_KEY, self->mWhiteListList, "LLScrollListCtrl" },
- { "", NULL , "" }
+ // build a URL comprised of default scheme and the original fragment
+ const std::string default_scheme( "http://" );
+ return default_scheme + src_url;
};
- for( int i = 0; data_set[ i ].key_name.length() > 0; ++i )
- {
- base_key = std::string( data_set[ i ].key_name );
- tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX );
-
- // TODO: CP - I bet there is a better way to do this using Boost
- if ( media_settings[ base_key ].isDefined() )
- {
- if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" )
- {
- static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )->
- setValue( media_settings[ base_key ].asBoolean() );
- }
- else
- if ( data_set[ i ].ctrl_type == "LLScrollListCtrl" )
- {
- // get control
- LLScrollListCtrl* list = static_cast< LLScrollListCtrl* >( data_set[ i ].ctrl_ptr );
- list->deleteAllItems();
-
- // points to list of white list URLs
- LLSD url_list = media_settings[ base_key ];
-
- // iterate over them and add to scroll list
- LLSD::array_iterator iter = url_list.beginArray();
- while( iter != url_list.endArray() )
- {
- // TODO: is iter guaranteed to be valid here?
- std::string url = *iter;
- list->addSimpleElement( url );
- ++iter;
- };
- };
- data_set[ i ].ctrl_ptr->setEnabled(editable);
- data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() );
- };
- };
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// static
-void LLPanelMediaSettingsSecurity::clearValues( void* userdata , bool editable)
-{
- LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata;
- self->mEnableWhiteList->clear();
- self->mWhiteListList->deleteAllItems();
- self->mEnableWhiteList->setEnabled(editable);
- self->mWhiteListList->setEnabled(editable);
-}
-////////////////////////////////////////////////////////////////////////////////
-// static
-void LLPanelMediaSettingsSecurity::apply( void* userdata )
-{
- LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata;
-
- // build LLSD Fragment
- LLSD media_data_security;
- self->getValues(media_data_security);
- // this merges contents of LLSD passed in with what's there so this is ok
- LLSelectMgr::getInstance()->selectionSetMediaData( media_data_security );
-}
-
+ // we *could* test the "default scheme" + "original fragment" URL again
+ // using LLURI to see if it's valid but I think the outcome is the same
+ // in either case - our only option is to return the original URL
+
+ // we *think* the original url passed in was valid
+ return src_url;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// wrapper for testing a URL against the whitelist. We grab entries from
+// white list list box widget and build a list to test against. Can also
+// optionally pass the URL that you are trying to add to the widget since
+// it won't be added until this call returns.
+bool LLPanelMediaSettingsSecurity::passesWhiteList( const std::string& added_url,
+ const std::string& test_url )
+{
+ // the checkUrlAgainstWhitelist(..) function works on a vector
+ // of strings for the white list entries - in this panel, the white list
+ // is stored in the widgets themselves so we need to build something compatible.
+ std::vector< std::string > whitelist_strings;
+ whitelist_strings.clear(); // may not be required - I forget what the spec says.
+
+ // step through whitelist widget entries and grab them as strings
+ std::vector< LLScrollListItem* > white_list_items = mWhiteListList->getAllData();
+ std::vector< LLScrollListItem* >::iterator iter = white_list_items.begin();
+ while( iter != white_list_items.end() )
+ {
+ const std::string whitelist_url = (*iter)->getValue().asString();
+ whitelist_strings.push_back( whitelist_url );
+
+ ++iter;
+ };
+
+ // add in the URL that might be added to the whitelist so we can test that too
+ if ( added_url.length() )
+ whitelist_strings.push_back( added_url );
+
+ // possible the URL is just a fragment so we validize it
+ const std::string valid_url = makeValidUrl( test_url );
+
+ // indicate if the URL passes whitelist
+ return LLMediaEntry::checkUrlAgainstWhitelist( valid_url, whitelist_strings );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
+void LLPanelMediaSettingsSecurity::addWhiteListItem(const std::string& url)
+{
+ // grab home URL from the general panel (via the parent floater)
+ std::string home_url( "" );
+ if ( mParent )
+ home_url = mParent->getHomeUrl();
+
+ // if the home URL is blank (user hasn't entered it yet) then
+ // don't bother to check if it passes the white list
+ if ( home_url.empty() )
+ {
+ mWhiteListList->addSimpleElement( url );
+ return;
+ };
+
+ // if the URL passes the white list, add it
+ if ( passesWhiteList( url, home_url ) )
+ {
+ mWhiteListList->addSimpleElement( url );
+ }
+ else
+ // display a message indicating you can't do that
+ {
+ LLNotifications::instance().add("WhiteListInvalidatesHomeUrl");
+ };
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// static
+void LLPanelMediaSettingsSecurity::onBtnAdd( void* userdata )
+{
+ LLFloaterReg::showInstance("whitelist_entry");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// static
+void LLPanelMediaSettingsSecurity::onBtnDel( void* userdata )
+{
+ LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata;
+
+ self->mWhiteListList->deleteSelectedItems();
+}
+
////////////////////////////////////////////////////////////////////////////////
//
-void LLPanelMediaSettingsSecurity::getValues( LLSD &fill_me_in )
-{
- fill_me_in[LLMediaEntry::WHITELIST_ENABLE_KEY] = mEnableWhiteList->getValue();
-
- // iterate over white list and extract items
- std::vector< LLScrollListItem* > white_list_items = mWhiteListList->getAllData();
- std::vector< LLScrollListItem* >::iterator iter = white_list_items.begin();
- fill_me_in[LLMediaEntry::WHITELIST_KEY].clear();
- while( iter != white_list_items.end() )
- {
- std::string white_list_url = (*iter)->getValue().asString();
- fill_me_in[ LLMediaEntry::WHITELIST_KEY ].append( white_list_url );
- ++iter;
- };
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// static
-void LLPanelMediaSettingsSecurity::addWhiteListItem(const std::string& url)
-{
- mWhiteListList->addSimpleElement( url );
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// static
-void LLPanelMediaSettingsSecurity::onBtnAdd( void* userdata )
-{
- LLFloaterReg::showInstance("whitelist_entry");
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// static
-void LLPanelMediaSettingsSecurity::onBtnDel( void* userdata )
+void LLPanelMediaSettingsSecurity::setParent( LLFloaterMediaSettings* parent )
{
- LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata;
+ mParent = parent;
+};
- self->mWhiteListList->deleteSelectedItems();
-}
diff --git a/indra/newview/llpanelmediasettingssecurity.h b/indra/newview/llpanelmediasettingssecurity.h
index b7cf67c039..b78ee92193 100644
--- a/indra/newview/llpanelmediasettingssecurity.h
+++ b/indra/newview/llpanelmediasettingssecurity.h
@@ -37,6 +37,7 @@
class LLCheckBoxCtrl;
class LLScrollListCtrl;
+class LLFloaterMediaSettings;
class LLPanelMediaSettingsSecurity : public LLPanel
{
@@ -52,6 +53,12 @@ class LLPanelMediaSettingsSecurity : public LLPanel
static void initValues( void* userdata, const LLSD& media_settings,bool editable );
static void clearValues( void* userdata, bool editable);
void addWhiteListItem(const std::string& url);
+ void setParent( LLFloaterMediaSettings* parent );
+ const std::string makeValidUrl( const std::string& src_url );
+ bool passesWhiteList( const std::string& added_url, const std::string& test_url );
+
+ protected:
+ LLFloaterMediaSettings* mParent;
private:
LLCheckBoxCtrl* mEnableWhiteList;
diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp
index db31714f16..d81c332d54 100644
--- a/indra/newview/llviewermediafocus.cpp
+++ b/indra/newview/llviewermediafocus.cpp
@@ -227,8 +227,35 @@ void LLViewerMediaFocus::setCameraZoom(F32 padding_factor)
distance += depth * 0.5;
// Finally animate the camera to this new position and focal point
- gAgent.setCameraPosAndFocusGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal() + LLVector3d(pick.mNormal * distance),
- LLSelectMgr::getInstance()->getSelectionCenterGlobal(), LLSelectMgr::getInstance()->getSelection()->getFirstObject()->mID );
+ LLVector3d camera_pos, target_pos;
+ // The target lookat position is the center of the selection (in global coords)
+ target_pos = LLSelectMgr::getInstance()->getSelectionCenterGlobal();
+ // Target look-from (camera) position is "distance" away from the target along the normal
+ LLVector3d pickNormal = LLVector3d(pick.mNormal);
+ pickNormal.normalize();
+ camera_pos = target_pos + pickNormal * distance;
+ if (pickNormal == LLVector3d::z_axis || pickNormal == LLVector3d::z_axis_neg)
+ {
+ // If the normal points directly up, the camera will "flip" around.
+ // We try to avoid this by adjusting the target camera position a
+ // smidge towards current camera position
+ // *NOTE: this solution is not perfect. All it attempts to solve is the
+ // "looking down" problem where the camera flips around when it animates
+ // to that position. You still are not guaranteed to be looking at the
+ // media in the correct orientation. What this solution does is it will
+ // put the camera into position keeping as best it can the current
+ // orientation with respect to the face. In other words, if before zoom
+ // the media appears "upside down" from the camera, after zooming it will
+ // still be upside down, but at least it will not flip.
+ LLVector3d cur_camera_pos = LLVector3d(gAgent.getCameraPositionGlobal());
+ LLVector3d delta = (cur_camera_pos - camera_pos);
+ F64 len = delta.length();
+ delta.normalize();
+ // Move 1% of the distance towards original camera location
+ camera_pos += 0.01 * len * delta;
+ }
+
+ gAgent.setCameraPosAndFocusGlobal(camera_pos, target_pos, LLSelectMgr::getInstance()->getSelection()->getFirstObject()->mID );
}
}
void LLViewerMediaFocus::onFocusReceived()
diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc
index 63b76d4f5d..433070ce34 100644
--- a/indra/newview/res/viewerRes.rc
+++ b/indra/newview/res/viewerRes.rc
@@ -134,8 +134,8 @@ TOOLMEDIAOPEN CURSOR "toolmediaopen.cur"
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,0,0,2822
- PRODUCTVERSION 2,0,0,2822
+ FILEVERSION 2,0,0,3256
+ PRODUCTVERSION 2,0,0,3256
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -152,12 +152,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Linden Lab"
VALUE "FileDescription", "Second Life"
- VALUE "FileVersion", "2.0.0.2822"
+ VALUE "FileVersion", "2.0.0.3256"
VALUE "InternalName", "Second Life"
VALUE "LegalCopyright", "Copyright © 2001-2008, Linden Research, Inc."
VALUE "OriginalFilename", "SecondLife.exe"
VALUE "ProductName", "Second Life"
- VALUE "ProductVersion", "2.0.0.2822"
+ VALUE "ProductVersion", "2.0.0.3256"
END
END
BLOCK "VarFileInfo"
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index f141a909a8..4c90d9ee8a 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -661,6 +661,19 @@ To place the media on only one face, choose Select Texture and click on the desi
<notification
icon="alertmodal.tga"
+ name="WhiteListInvalidatesHomeUrl"
+ type="alertmodal">
+Adding this entry to the whitelist will invalidate the home URL you
+specified for this instance of media. You are not allowed to do this
+so the entry cannot be added to the whitelist.
+ <usetemplate
+ name="okbutton"
+ yestext="Ok"/>
+ </notification>
+
+
+ <notification
+ icon="alertmodal.tga"
name="MustBeInParcel"
type="alertmodal">
You must be standing inside the land parcel to set its Landing Point.
diff --git a/indra/test_apps/llplugintest/llmediaplugintest.cpp b/indra/test_apps/llplugintest/llmediaplugintest.cpp
index ba66b449f3..234422b68a 100644
--- a/indra/test_apps/llplugintest/llmediaplugintest.cpp
+++ b/indra/test_apps/llplugintest/llmediaplugintest.cpp
@@ -138,6 +138,8 @@ LLMediaPluginTest::LLMediaPluginTest( int app_window, int window_width, int wind
mMediaBrowserControlBackButtonFlag( true ),
mMediaBrowserControlForwardButtonFlag( true ),
mHomeWebUrl( "http://www.google.com/" )
+ //mHomeWebUrl( "file:///C|/Program Files/QuickTime/Sample.mov" )
+ //mHomeWebUrl( "http://movies.apple.com/movies/wb/watchmen/watchmen-tlr2_480p.mov" )
{
// debugging spam
std::cout << std::endl << " GLUT version: " << "3.7.6" << std::endl; // no way to get real version from GLUT
@@ -2008,6 +2010,11 @@ void LLMediaPluginTest::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent e
std::cerr << "Media event: MEDIA_EVENT_STATUS_TEXT_CHANGED, new status text is: " << self->getStatusText() << std::endl;
break;
+ case MEDIA_EVENT_NAME_CHANGED:
+ std::cerr << "Media event: MEDIA_EVENT_NAME_CHANGED, new name is: " << self->getMediaName() << std::endl;
+ glutSetWindowTitle( self->getMediaName().c_str() );
+ break;
+
case MEDIA_EVENT_LOCATION_CHANGED:
{
std::cerr << "Media event: MEDIA_EVENT_LOCATION_CHANGED, new uri is: " << self->getLocation() << std::endl;