diff options
author | callum <none@none> | 2011-05-13 17:09:40 -0700 |
---|---|---|
committer | callum <none@none> | 2011-05-13 17:09:40 -0700 |
commit | 889f6cc3b3603bc65ba3cfe19f919e87b3f12366 (patch) | |
tree | 7cd1dbda844d3a837df476738dabc255c8951a0a | |
parent | e4a9704d4157151442accca1116ad70f7f63ae95 (diff) | |
parent | 1e6d1879a01d57e8949add79fa4f3ef5d11c1c43 (diff) |
Merge with tip
88 files changed, 4335 insertions, 4382 deletions
diff --git a/autobuild.xml b/autobuild.xml index 9d4fe8382b..ba0eb75f16 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -2101,7 +2101,6 @@ <string>-G</string> <string>"Visual Studio 10"</string> <string>-DUNATTENDED:BOOL=ON</string> - <string>-DUSE_PRECOMPILED_HEADERS=ON</string> <string>-DINSTALL_PROPRIETARY=TRUE</string> <string>-DUSE_KDU=FALSE</string> <string>-DFMOD=FALSE</string> @@ -2179,7 +2178,6 @@ <string>-G</string> <string>"Visual Studio 10"</string> <string>-DUNATTENDED:BOOL=ON</string> - <string>-DUSE_PRECOMPILED_HEADERS=ON</string> <string>-DINSTALL_PROPRIETARY=TRUE</string> <string>-DUSE_KDU=FALSE</string> <string>-DFMOD=FALSE</string> @@ -2256,7 +2254,6 @@ <string>-G</string> <string>"Visual Studio 10"</string> <string>-DUNATTENDED:BOOL=ON</string> - <string>-DUSE_PRECOMPILED_HEADERS=ON</string> <string>-DINSTALL_PROPRIETARY=TRUE</string> <string>-DUSE_KDU=FALSE</string> <string>-DFMOD=FALSE</string> @@ -58,7 +58,6 @@ pre_build() "$AUTOBUILD" configure -c $variant -- \ -DPACKAGE:BOOL=ON \ -DRELEASE_CRASH_REPORTING:BOOL=ON \ - -DUSE_PRECOMPILED_HEADERS=FALSE \ -DVIEWER_CHANNEL:STRING="\"$viewer_channel\"" \ -DVIEWER_LOGIN_CHANNEL:STRING="\"$viewer_login_channel\"" \ -DGRID:STRING="\"$viewer_grid\"" \ diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 310e6cbdd4..d1042d6e86 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -35,8 +35,10 @@ endif (NOT CMAKE_BUILD_TYPE) # For the library installation process; # see cmake/Prebuild.cmake for the counterpart code. -file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/temp) -file(WRITE ${CMAKE_BINARY_DIR}/temp/sentinel_installed "0") +if ("${CMAKE_SOURCE_DIR}/../autobuild.xml" IS_NEWER_THAN "${CMAKE_BINARY_DIR}/temp/sentinel_installed") + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/temp) + file(WRITE ${CMAKE_BINARY_DIR}/temp/sentinel_installed "0") +endif ("${CMAKE_SOURCE_DIR}/../autobuild.xml" IS_NEWER_THAN "${CMAKE_BINARY_DIR}/temp/sentinel_installed") add_subdirectory(cmake) add_subdirectory(${LIBS_OPEN_PREFIX}llaudio) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 15b827b217..faffdc8ccd 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -36,6 +36,13 @@ if (WINDOWS) # Don't build DLLs. set(BUILD_SHARED_LIBS OFF) + # for "backwards compatibility", cmake sneaks in the Zm1000 option which royally + # screws incredibuild. this hack disables it. + # for details see: http://connect.microsoft.com/VisualStudio/feedback/details/368107/clxx-fatal-error-c1027-inconsistent-values-for-ym-between-creation-and-use-of-precompiled-headers + # http://www.ogre3d.org/forums/viewtopic.php?f=2&t=60015 + # http://www.cmake.org/pipermail/cmake/2009-September/032143.html + string(REPLACE "/Zm1000" " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd /MP -D_SCL_SECURE_NO_WARNINGS=1" CACHE STRING "C++ compiler debug options" FORCE) set(CMAKE_CXX_FLAGS_RELWITHDEBINFO diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake index 3f259f6382..08feab6e36 100644 --- a/indra/cmake/LLAddBuildTest.cmake +++ b/indra/cmake/LLAddBuildTest.cmake @@ -95,7 +95,7 @@ INCLUDE(GoogleMock) IF(${name}_test_additional_INCLUDE_DIRS MATCHES NOTFOUND) SET(${name}_test_additional_INCLUDE_DIRS "") ENDIF(${name}_test_additional_INCLUDE_DIRS MATCHES NOTFOUND) - INCLUDE_DIRECTORIES(${alltest_INCLUDE_DIRS} ${name}_test_additional_INCLUDE_DIRS ) + INCLUDE_DIRECTORIES(${alltest_INCLUDE_DIRS} ${${name}_test_additional_INCLUDE_DIRS} ) IF(LL_TEST_VERBOSE) MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_INCLUDE_DIRS ${${name}_test_additional_INCLUDE_DIRS}") ENDIF(LL_TEST_VERBOSE) diff --git a/indra/cmake/Prebuilt.cmake b/indra/cmake/Prebuilt.cmake index 1b60d176f1..dbb4dfc46c 100644 --- a/indra/cmake/Prebuilt.cmake +++ b/indra/cmake/Prebuilt.cmake @@ -1,35 +1,49 @@ # -*- cmake -*- include(FindAutobuild) +if(INSTALL_PROPRIETARY) + include(FindSCP) +endif(INSTALL_PROPRIETARY) +# The use_prebuilt_binary macro handles automated installation of package +# dependencies using autobuild. The goal is that 'autobuild install' should +# only be run when we know we need to install a new package. This should be +# the case in a clean checkout, or if autobuild.xml has been updated since the +# last run (encapsulated by the file ${CMAKE_BINARY_DIR}/temp/sentinel_installed), +# or if a previous attempt to install the package has failed (the exit status +# of previous attempts is serialized in the file +# ${CMAKE_BINARY_DIR}/temp/${_binary}_installed) macro (use_prebuilt_binary _binary) if (NOT DEFINED STANDALONE_${_binary}) set(STANDALONE_${_binary} ${STANDALONE}) endif (NOT DEFINED STANDALONE_${_binary}) if (NOT STANDALONE_${_binary}) - if(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed) - if(INSTALL_PROPRIETARY) - include(FindSCP) - endif(INSTALL_PROPRIETARY) - if(DEBUG_PREBUILT) - message("cd ${CMAKE_SOURCE_DIR} && ${AUTOBUILD_EXECUTABLE} install - --install-dir=${AUTOBUILD_INSTALL_DIR} - --skip-license-check - ${_binary} ") - endif(DEBUG_PREBUILT) - execute_process(COMMAND "${AUTOBUILD_EXECUTABLE}" - install - --install-dir=${AUTOBUILD_INSTALL_DIR} - --skip-license-check - ${_binary} - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" - RESULT_VARIABLE ${_binary}_installed - ) + if("${${_binary}_installed}" STREQUAL "" AND EXISTS "${CMAKE_BINARY_DIR}/temp/${_binary}_installed") + file(READ ${CMAKE_BINARY_DIR}/temp/${_binary}_installed "${_binary}_installed") + if(DEBUG_PREBUILT) + message(STATUS "${_binary}_installed: \"${${_binary}_installed}\"") + endif(DEBUG_PREBUILT) + endif("${${_binary}_installed}" STREQUAL "" AND EXISTS "${CMAKE_BINARY_DIR}/temp/${_binary}_installed") + + if(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed OR NOT ${${_binary}_installed} EQUAL 0) + if(DEBUG_PREBUILT) + message("cd ${CMAKE_SOURCE_DIR} && ${AUTOBUILD_EXECUTABLE} install + --install-dir=${AUTOBUILD_INSTALL_DIR} + --skip-license-check + ${_binary} ") + endif(DEBUG_PREBUILT) + execute_process(COMMAND "${AUTOBUILD_EXECUTABLE}" + install + --install-dir=${AUTOBUILD_INSTALL_DIR} + --skip-license-check + ${_binary} + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + RESULT_VARIABLE ${_binary}_installed + ) file(WRITE ${CMAKE_BINARY_DIR}/temp/${_binary}_installed "${${_binary}_installed}") - else(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed) - set(${_binary}_installed 0) - endif(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed) + endif(${CMAKE_BINARY_DIR}/temp/sentinel_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/${_binary}_installed OR NOT ${${_binary}_installed} EQUAL 0) + if(NOT ${_binary}_installed EQUAL 0) message(FATAL_ERROR "Failed to download or unpack prebuilt '${_binary}'." diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index 03428691cf..2f23e7c307 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -151,7 +151,7 @@ For more information, please see JIRA DEV-14943 - Cmake Linux cannot build both endif (LINUX AND SERVER AND VIEWER) -set(USE_PRECOMPILED_HEADERS OFF CACHE BOOL "Enable use of precompiled header directives where supported.") +set(USE_PRECOMPILED_HEADERS ON CACHE BOOL "Enable use of precompiled header directives where supported.") source_group("CMake Rules" FILES CMakeLists.txt) diff --git a/indra/integration_tests/llui_libtest/llui_libtest.cpp b/indra/integration_tests/llui_libtest/llui_libtest.cpp index c34115ee80..217e26c3ca 100644 --- a/indra/integration_tests/llui_libtest/llui_libtest.cpp +++ b/indra/integration_tests/llui_libtest/llui_libtest.cpp @@ -33,6 +33,7 @@ // linden library includes #include "llcontrol.h" // LLControlGroup #include "lldir.h" +#include "lldiriterator.h" #include "llerrorcontrol.h" #include "llfloater.h" #include "llfontfreetype.h" @@ -174,7 +175,9 @@ void export_test_floaters() std::string delim = gDirUtilp->getDirDelimiter(); std::string xui_dir = get_xui_dir() + "en" + delim; std::string filename; - while (gDirUtilp->getNextFileInDir(xui_dir, "floater_test_*.xml", filename)) + + LLDirIterator iter(xui_dir, "floater_test_*.xml"); + while (iter.next(filename)) { if (filename.find("_new.xml") != std::string::npos) { diff --git a/indra/linux_updater/linux_updater.cpp b/indra/linux_updater/linux_updater.cpp index a81de0223c..eed00ac06e 100644 --- a/indra/linux_updater/linux_updater.cpp +++ b/indra/linux_updater/linux_updater.cpp @@ -33,6 +33,7 @@ #include "llerrorcontrol.h" #include "llfile.h" #include "lldir.h" +#include "lldiriterator.h" #include "llxmlnode.h" #include "lltrans.h" @@ -55,6 +56,8 @@ typedef struct _updater_app_state { std::string strings_dirs; std::string strings_file; + LLDirIterator *image_dir_iter; + GtkWidget *window; GtkWidget *progress_bar; GtkWidget *image; @@ -115,7 +118,7 @@ bool translate_init(std::string comma_delim_path_list, void updater_app_ui_init(void); void updater_app_quit(UpdaterAppState *app_state); void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state); -std::string next_image_filename(std::string& image_path); +std::string next_image_filename(std::string& image_path, LLDirIterator& iter); void display_error(GtkWidget *parent, std::string title, std::string message); BOOL install_package(std::string package_file, std::string destination); BOOL spawn_viewer(UpdaterAppState *app_state); @@ -181,7 +184,7 @@ void updater_app_ui_init(UpdaterAppState *app_state) // load the first image app_state->image = gtk_image_new_from_file - (next_image_filename(app_state->image_dir).c_str()); + (next_image_filename(app_state->image_dir, *app_state->image_dir_iter).c_str()); gtk_widget_set_size_request(app_state->image, 340, 310); gtk_container_add(GTK_CONTAINER(frame), app_state->image); @@ -212,7 +215,7 @@ gboolean rotate_image_cb(gpointer data) llassert(data != NULL); app_state = (UpdaterAppState *) data; - filename = next_image_filename(app_state->image_dir); + filename = next_image_filename(app_state->image_dir, *app_state->image_dir_iter); gdk_threads_enter(); gtk_image_set_from_file(GTK_IMAGE(app_state->image), filename.c_str()); @@ -221,10 +224,10 @@ gboolean rotate_image_cb(gpointer data) return TRUE; } -std::string next_image_filename(std::string& image_path) +std::string next_image_filename(std::string& image_path, LLDirIterator& iter) { std::string image_filename; - gDirUtilp->getNextFileInDir(image_path, "/*.jpg", image_filename); + iter.next(image_filename); return image_path + "/" + image_filename; } @@ -748,6 +751,7 @@ void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state) else if ((!strcmp(argv[i], "--image-dir")) && (++i < argc)) { app_state->image_dir = argv[i]; + app_state->image_dir_iter = new LLDirIterator(argv[i], "/*.jpg"); } else if ((!strcmp(argv[i], "--dest")) && (++i < argc)) { @@ -832,6 +836,7 @@ int main(int argc, char **argv) } bool success = !app_state->failure; + delete app_state->image_dir_iter; delete app_state; return success ? 0 : 1; } diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index 39daefd1ad..ed192a9975 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -24,6 +24,10 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + +#include "llapp.h" + #include <cstdlib> #ifdef LL_DARWIN @@ -32,9 +36,6 @@ #include <sys/sysctl.h> #endif -#include "linden_common.h" -#include "llapp.h" - #include "llcommon.h" #include "llapr.h" #include "llerrorcontrol.h" diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 16aa49b653..0cfc393e05 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -27,7 +27,6 @@ #ifndef LL_LLBUTTON_H #define LL_LLBUTTON_H -#include "lluuid.h" #include "llcontrol.h" #include "lluictrl.h" #include "v4color.h" @@ -53,6 +52,8 @@ S32 round_up(S32 grid, S32 value); class LLUICtrlFactory; +class LLUIImage; +class LLUUID; // // Classes diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h index 94387fb41a..8414b92113 100644 --- a/indra/llui/llfloaterreg.h +++ b/indra/llui/llfloaterreg.h @@ -27,14 +27,9 @@ #define LLFLOATERREG_H /// llcommon -#include "llboost.h" #include "llrect.h" -#include "llstl.h" #include "llsd.h" -/// llui -#include "lluictrl.h" - #include <boost/function.hpp> //******************************************************* @@ -43,6 +38,7 @@ // class LLFloater; +class LLUICtrl; typedef boost::function<LLFloater* (const LLSD& key)> LLFloaterBuildFunc; diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp index 43e5f6b051..724d190307 100644 --- a/indra/llui/llfocusmgr.cpp +++ b/indra/llui/llfocusmgr.cpp @@ -113,6 +113,16 @@ boost::signals2::connection LLFocusableElement::setTopLostCallback(const focus_s +typedef std::list<LLHandle<LLView> > view_handle_list_t; +typedef std::map<LLHandle<LLView>, LLHandle<LLView> > focus_history_map_t; +struct LLFocusMgr::Impl +{ + // caching list of keyboard focus ancestors for calling onFocusReceived and onFocusLost + view_handle_list_t mCachedKeyboardFocusList; + + focus_history_map_t mFocusHistory; +}; + LLFocusMgr gFocusMgr; LLFocusMgr::LLFocusMgr() @@ -123,10 +133,17 @@ LLFocusMgr::LLFocusMgr() mDefaultKeyboardFocus( NULL ), mKeystrokesOnly(FALSE), mTopCtrl( NULL ), - mAppHasFocus(TRUE) // Macs don't seem to notify us that we've gotten focus, so default to true + mAppHasFocus(TRUE), // Macs don't seem to notify us that we've gotten focus, so default to true + mImpl(new LLFocusMgr::Impl) { } +LLFocusMgr::~LLFocusMgr() +{ + mImpl->mFocusHistory.clear(); + delete mImpl; + mImpl = NULL; +} void LLFocusMgr::releaseFocusIfNeeded( LLView* view ) { @@ -179,7 +196,7 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL mKeyboardFocus = new_focus; // list of the focus and it's ancestors - view_handle_list_t old_focus_list = mCachedKeyboardFocusList; + view_handle_list_t old_focus_list = mImpl->mCachedKeyboardFocusList; view_handle_list_t new_focus_list; // walk up the tree to root and add all views to the new_focus_list @@ -206,7 +223,7 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL LLView* old_focus_view = old_focus_iter->get(); if (old_focus_view) { - mCachedKeyboardFocusList.pop_front(); + mImpl->mCachedKeyboardFocusList.pop_front(); old_focus_view->onFocusLost(); } } @@ -219,7 +236,7 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL LLView* new_focus_view = new_focus_riter->get(); if (new_focus_view) { - mCachedKeyboardFocusList.push_front(new_focus_view->getHandle()); + mImpl->mCachedKeyboardFocusList.push_front(new_focus_view->getHandle()); new_focus_view->onFocusReceived(); } } @@ -254,7 +271,7 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL if (focus_subtree) { LLView* focused_view = dynamic_cast<LLView*>(mKeyboardFocus); - mFocusHistory[focus_subtree->getHandle()] = focused_view ? focused_view->getHandle() : LLHandle<LLView>(); + mImpl->mFocusHistory[focus_subtree->getHandle()] = focused_view ? focused_view->getHandle() : LLHandle<LLView>(); } } @@ -456,8 +473,8 @@ LLUICtrl* LLFocusMgr::getLastFocusForGroup(LLView* subtree_root) const { if (subtree_root) { - focus_history_map_t::const_iterator found_it = mFocusHistory.find(subtree_root->getHandle()); - if (found_it != mFocusHistory.end()) + focus_history_map_t::const_iterator found_it = mImpl->mFocusHistory.find(subtree_root->getHandle()); + if (found_it != mImpl->mFocusHistory.end()) { // found last focus for this subtree return static_cast<LLUICtrl*>(found_it->second.get()); @@ -470,6 +487,6 @@ void LLFocusMgr::clearLastFocusForGroup(LLView* subtree_root) { if (subtree_root) { - mFocusHistory.erase(subtree_root->getHandle()); + mImpl->mFocusHistory.erase(subtree_root->getHandle()); } } diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h index 22c1895075..25ae1d2579 100644 --- a/indra/llui/llfocusmgr.h +++ b/indra/llui/llfocusmgr.h @@ -74,7 +74,7 @@ class LLFocusMgr { public: LLFocusMgr(); - ~LLFocusMgr() { mFocusHistory.clear(); } + ~LLFocusMgr(); // Mouse Captor void setMouseCapture(LLMouseHandler* new_captor); // new_captor = NULL to release the mouse. @@ -120,6 +120,8 @@ public: bool keyboardFocusHasAccelerators() const; + struct Impl; + private: LLUICtrl* mLockedView; @@ -132,10 +134,6 @@ private: LLFocusableElement* mDefaultKeyboardFocus; BOOL mKeystrokesOnly; - // caching list of keyboard focus ancestors for calling onFocusReceived and onFocusLost - typedef std::list<LLHandle<LLView> > view_handle_list_t; - view_handle_list_t mCachedKeyboardFocusList; - // Top View LLUICtrl* mTopCtrl; @@ -143,8 +141,7 @@ private: BOOL mAppHasFocus; - typedef std::map<LLHandle<LLView>, LLHandle<LLView> > focus_history_map_t; - focus_history_map_t mFocusHistory; + Impl * mImpl; }; extern LLFocusMgr gFocusMgr; diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h index 669e126266..efa0925a4a 100644 --- a/indra/llui/lliconctrl.h +++ b/indra/llui/lliconctrl.h @@ -30,6 +30,7 @@ #include "lluuid.h" #include "v4color.h" #include "lluictrl.h" +#include "lluiimage.h" #include "stdenums.h" class LLTextBox; diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index 7b5fa218f2..fe191e5971 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -41,6 +41,7 @@ #include "lleditmenuhandler.h" #include "lluictrl.h" +#include "lluiimage.h" #include "lluistring.h" #include "llviewborder.h" diff --git a/indra/llui/llloadingindicator.h b/indra/llui/llloadingindicator.h index c0cb1cc74a..4c47cc267c 100644 --- a/indra/llui/llloadingindicator.h +++ b/indra/llui/llloadingindicator.h @@ -28,6 +28,7 @@ #define LL_LLLOADINGINDICATOR_H #include "lluictrl.h" +#include "lluiimage.h" /////////////////////////////////////////////////////////////////////////////// // class LLLoadingIndicator diff --git a/indra/llui/llmultislider.cpp b/indra/llui/llmultislider.cpp index d4e6091ee0..f744e9db41 100644 --- a/indra/llui/llmultislider.cpp +++ b/indra/llui/llmultislider.cpp @@ -35,6 +35,7 @@ #include "llkeyboard.h" // for the MASK constants #include "llcontrol.h" #include "lluictrlfactory.h" +#include "lluiimage.h" #include <sstream> diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index c1a1a06f39..7bbbeaf709 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -32,6 +32,7 @@ #include "llcallbackmap.h" #include "lluictrl.h" #include "llviewborder.h" +#include "lluiimage.h" #include "lluistring.h" #include "v4color.h" #include <list> diff --git a/indra/llui/llprogressbar.cpp b/indra/llui/llprogressbar.cpp index ead22686bc..84a890edfa 100644 --- a/indra/llui/llprogressbar.cpp +++ b/indra/llui/llprogressbar.cpp @@ -38,6 +38,7 @@ #include "llfocusmgr.h" #include "lluictrlfactory.h" +#include "lluiimage.h" static LLDefaultChildRegistry::Register<LLProgressBar> r("progress_bar"); diff --git a/indra/llui/llprogressbar.h b/indra/llui/llprogressbar.h index 3f308e7496..a8ec83ea00 100644 --- a/indra/llui/llprogressbar.h +++ b/indra/llui/llprogressbar.h @@ -27,8 +27,9 @@ #ifndef LL_LLPROGRESSBAR_H #define LL_LLPROGRESSBAR_H -#include "lluictrl.h" #include "llframetimer.h" +#include "lluictrl.h" +#include "lluiimage.h" class LLProgressBar : public LLUICtrl diff --git a/indra/llui/llslider.h b/indra/llui/llslider.h index 68823ed68e..700c17ea3e 100644 --- a/indra/llui/llslider.h +++ b/indra/llui/llslider.h @@ -29,6 +29,7 @@ #include "llf32uictrl.h" #include "v4color.h" +#include "lluiimage.h" class LLSlider : public LLF32UICtrl { diff --git a/indra/llui/llstyle.cpp b/indra/llui/llstyle.cpp index 28a064e6b6..bb731f4f7e 100644 --- a/indra/llui/llstyle.cpp +++ b/indra/llui/llstyle.cpp @@ -88,7 +88,7 @@ void LLStyle::setVisible(BOOL is_visible) mVisible = is_visible; } -LLUIImagePtr LLStyle::getImage() const +LLPointer<LLUIImage> LLStyle::getImage() const { return mImagep; } diff --git a/indra/llui/llstyle.h b/indra/llui/llstyle.h index 322edc343c..9f1eba79d8 100644 --- a/indra/llui/llstyle.h +++ b/indra/llui/llstyle.h @@ -30,6 +30,7 @@ #include "v4color.h" #include "llui.h" #include "llinitparam.h" +#include "lluiimage.h" class LLFontGL; @@ -72,7 +73,7 @@ public: void setLinkHREF(const std::string& href); BOOL isLink() const; - LLUIImagePtr getImage() const; + LLPointer<LLUIImage> getImage() const; void setImage(const LLUUID& src); void setImage(const std::string& name); @@ -108,7 +109,7 @@ private: const LLFontGL* mFont; std::string mLink; bool mIsLink; - LLUIImagePtr mImagep; + LLPointer<LLUIImage> mImagep; }; typedef LLPointer<LLStyle> LLStyleSP; diff --git a/indra/llui/lltransutil.cpp b/indra/llui/lltransutil.cpp index 9d0ff9d5cb..58fa8a0828 100644 --- a/indra/llui/lltransutil.cpp +++ b/indra/llui/lltransutil.cpp @@ -26,10 +26,11 @@ #include "linden_common.h" +#include "lltransutil.h" + #include "lltrans.h" #include "lluictrlfactory.h" - -#include "lltransutil.h" +#include "llxmlnode.h" bool LLTransUtil::parseStrings(const std::string& xml_filename, const std::set<std::string>& default_args) diff --git a/indra/llui/llui.h b/indra/llui/llui.h index 6a43477693..c583d58d5a 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -33,15 +33,12 @@ #include "llrect.h" #include "llcontrol.h" #include "llcoord.h" -#include "lluiimage.h" // *TODO: break this dependency, need to add #include "lluiimage.h" to all widgets that hold an Optional<LLUIImage*> in their paramblocks #include "llinitparam.h" #include "llregistry.h" #include "lluicolor.h" #include "lluicolortable.h" #include <boost/signals2.hpp> #include "lllazyvalue.h" -#include "llhandle.h" // *TODO: remove this dependency, added as a - // convenience when LLHandle moved to llhandle.h #include "llframetimer.h" // LLUIFactory @@ -265,8 +262,6 @@ private: // Moved LLLocalClipRect to lllocalcliprect.h -// Moved all LLHandle-related code to llhandle.h - //RN: maybe this needs to moved elsewhere? class LLImageProviderInterface { diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 61dc4b8030..8f167959b9 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -34,6 +34,7 @@ #include "stdtypes.h" #include "llcoord.h" #include "llfontgl.h" +#include "llhandle.h" #include "llmortician.h" #include "llmousehandler.h" #include "llstring.h" diff --git a/indra/llui/llviewborder.cpp b/indra/llui/llviewborder.cpp index 89cd34c37c..32d7ea7c25 100644 --- a/indra/llui/llviewborder.cpp +++ b/indra/llui/llviewborder.cpp @@ -28,6 +28,7 @@ #include "llrender.h" #include "llfocusmgr.h" #include "lluictrlfactory.h" +#include "lluiimage.h" static LLDefaultChildRegistry::Register<LLViewBorder> r("view_border"); diff --git a/indra/llui/llwindowshade.h b/indra/llui/llwindowshade.h index 0047195929..09ffc2cd54 100644 --- a/indra/llui/llwindowshade.h +++ b/indra/llui/llwindowshade.h @@ -29,6 +29,7 @@ #include "lluictrl.h" #include "llnotifications.h" +#include "lluiimage.h" class LLWindowShade : public LLUICtrl { diff --git a/indra/llvfs/CMakeLists.txt b/indra/llvfs/CMakeLists.txt index 722f4e2bfd..a3782d824b 100644 --- a/indra/llvfs/CMakeLists.txt +++ b/indra/llvfs/CMakeLists.txt @@ -12,6 +12,7 @@ include_directories( set(llvfs_SOURCE_FILES lldir.cpp + lldiriterator.cpp lllfsthread.cpp llpidlock.cpp llvfile.cpp @@ -24,6 +25,7 @@ set(llvfs_HEADER_FILES lldir.h lldirguard.h + lldiriterator.h lllfsthread.h llpidlock.h llvfile.h @@ -60,6 +62,11 @@ list(APPEND llvfs_SOURCE_FILES ${llvfs_HEADER_FILES}) add_library (llvfs ${llvfs_SOURCE_FILES}) +target_link_libraries(llvfs + ${BOOST_FILESYSTEM_LIBRARY} + ${BOOST_SYSTEM_LIBRARY} + ) + if (DARWIN) include(CMakeFindFrameworks) find_library(CARBON_LIBRARY Carbon) diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index 341c96f6ea..f3ac17d612 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -40,6 +40,8 @@ #include "lltimer.h" // ms_sleep() #include "lluuid.h" +#include "lldiriterator.h" + #if LL_WINDOWS #include "lldir_win32.h" LLDir_Win32 gDirUtil; @@ -83,7 +85,9 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) std::string filename; std::string fullpath; S32 result; - while (getNextFileInDir(dirname, mask, filename)) + + LLDirIterator iter(dirname, mask); + while (iter.next(filename)) { fullpath = dirname; fullpath += getDirDelimiter(); diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h index 42996fd051..5ee8bdb542 100644 --- a/indra/llvfs/lldir.h +++ b/indra/llvfs/lldir.h @@ -75,31 +75,6 @@ class LLDir // pure virtual functions virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask) = 0; - /// Walk the files in a directory, with file pattern matching - virtual BOOL getNextFileInDir(const std::string& dirname, ///< directory path - must end in trailing slash! - const std::string& mask, ///< file pattern string (use "*" for all) - std::string& fname ///< output: found file name - ) = 0; - /**< - * @returns true if a file was found, false if the entire directory has been scanned. - * - * @note that this function is NOT thread safe - * - * This function may not be used to scan part of a directory, then start a new search of a different - * directory, and then restart the first search where it left off; the entire search must run to - * completion or be abandoned - there is no restart. - * - * @bug: See http://jira.secondlife.com/browse/VWR-23697 - * and/or the tests in test/lldir_test.cpp - * This is known to fail with patterns that have both: - * a wildcard left of a . and more than one sequential ? right of a . - * the pattern foo.??x appears to work - * but *.??x or foo?.??x do not - * - * @todo this really should be rewritten as an iterator object, and the - * filtering should be done in a platform-independent way. - */ - virtual std::string getCurPath() = 0; virtual BOOL fileExists(const std::string &filename) const = 0; diff --git a/indra/llvfs/lldir_linux.cpp b/indra/llvfs/lldir_linux.cpp index 72b54f5380..407f3b93fb 100644 --- a/indra/llvfs/lldir_linux.cpp +++ b/indra/llvfs/lldir_linux.cpp @@ -242,68 +242,6 @@ U32 LLDir_Linux::countFilesInDir(const std::string &dirname, const std::string & return (file_count); } -// get the next file in the directory -BOOL LLDir_Linux::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) -{ - glob_t g; - BOOL result = FALSE; - fname = ""; - - if(!(dirname == mCurrentDir)) - { - // different dir specified, close old search - mCurrentDirIndex = -1; - mCurrentDirCount = -1; - mCurrentDir = dirname; - } - - std::string tmp_str; - tmp_str = dirname; - tmp_str += mask; - - if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) - { - if(g.gl_pathc > 0) - { - if((int)g.gl_pathc != mCurrentDirCount) - { - // Number of matches has changed since the last search, meaning a file has been added or deleted. - // Reset the index. - mCurrentDirIndex = -1; - mCurrentDirCount = g.gl_pathc; - } - - mCurrentDirIndex++; - - if(mCurrentDirIndex < (int)g.gl_pathc) - { -// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; - - // The API wants just the filename, not the full path. - //fname = g.gl_pathv[mCurrentDirIndex]; - - char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); - - if(s == NULL) - s = g.gl_pathv[mCurrentDirIndex]; - else if(s[0] == '/') - s++; - - fname = s; - - result = TRUE; - } - } - - globfree(&g); - } - - return(result); -} - - - - std::string LLDir_Linux::getCurPath() { char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */ diff --git a/indra/llvfs/lldir_linux.h b/indra/llvfs/lldir_linux.h index a34de1241d..7603239867 100644 --- a/indra/llvfs/lldir_linux.h +++ b/indra/llvfs/lldir_linux.h @@ -47,7 +47,6 @@ public: virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); - virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp index f9369b043e..8f48f92e2a 100644 --- a/indra/llvfs/lldir_mac.cpp +++ b/indra/llvfs/lldir_mac.cpp @@ -258,67 +258,6 @@ U32 LLDir_Mac::countFilesInDir(const std::string &dirname, const std::string &ma return (file_count); } -// get the next file in the directory -BOOL LLDir_Mac::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) -{ - glob_t g; - BOOL result = FALSE; - fname = ""; - - if(!(dirname == mCurrentDir)) - { - // different dir specified, close old search - mCurrentDirIndex = -1; - mCurrentDirCount = -1; - mCurrentDir = dirname; - } - - std::string tmp_str; - tmp_str = dirname; - tmp_str += mask; - - if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) - { - if(g.gl_pathc > 0) - { - if(g.gl_pathc != mCurrentDirCount) - { - // Number of matches has changed since the last search, meaning a file has been added or deleted. - // Reset the index. - mCurrentDirIndex = -1; - mCurrentDirCount = g.gl_pathc; - } - - mCurrentDirIndex++; - - if(mCurrentDirIndex < g.gl_pathc) - { -// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; - - // The API wants just the filename, not the full path. - //fname = g.gl_pathv[mCurrentDirIndex]; - - char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); - - if(s == NULL) - s = g.gl_pathv[mCurrentDirIndex]; - else if(s[0] == '/') - s++; - - fname = s; - - result = TRUE; - } - } - - globfree(&g); - } - - return(result); -} - - - S32 LLDir_Mac::deleteFilesInDir(const std::string &dirname, const std::string &mask) { glob_t g; diff --git a/indra/llvfs/lldir_mac.h b/indra/llvfs/lldir_mac.h index b456d3afca..bc3f0fac00 100644 --- a/indra/llvfs/lldir_mac.h +++ b/indra/llvfs/lldir_mac.h @@ -47,7 +47,6 @@ public: virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask); virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); - virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); virtual BOOL fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); diff --git a/indra/llvfs/lldir_solaris.cpp b/indra/llvfs/lldir_solaris.cpp index 515fd66b6e..21f8c3acdb 100644 --- a/indra/llvfs/lldir_solaris.cpp +++ b/indra/llvfs/lldir_solaris.cpp @@ -260,68 +260,6 @@ U32 LLDir_Solaris::countFilesInDir(const std::string &dirname, const std::string return (file_count); } -// get the next file in the directory -BOOL LLDir_Solaris::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) -{ - glob_t g; - BOOL result = FALSE; - fname = ""; - - if(!(dirname == mCurrentDir)) - { - // different dir specified, close old search - mCurrentDirIndex = -1; - mCurrentDirCount = -1; - mCurrentDir = dirname; - } - - std::string tmp_str; - tmp_str = dirname; - tmp_str += mask; - - if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0) - { - if(g.gl_pathc > 0) - { - if((int)g.gl_pathc != mCurrentDirCount) - { - // Number of matches has changed since the last search, meaning a file has been added or deleted. - // Reset the index. - mCurrentDirIndex = -1; - mCurrentDirCount = g.gl_pathc; - } - - mCurrentDirIndex++; - - if(mCurrentDirIndex < (int)g.gl_pathc) - { -// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl; - - // The API wants just the filename, not the full path. - //fname = g.gl_pathv[mCurrentDirIndex]; - - char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/'); - - if(s == NULL) - s = g.gl_pathv[mCurrentDirIndex]; - else if(s[0] == '/') - s++; - - fname = s; - - result = TRUE; - } - } - - globfree(&g); - } - - return(result); -} - - - - std::string LLDir_Solaris::getCurPath() { char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */ diff --git a/indra/llvfs/lldir_solaris.h b/indra/llvfs/lldir_solaris.h index 70fac6f818..0b58a45b15 100644 --- a/indra/llvfs/lldir_solaris.h +++ b/indra/llvfs/lldir_solaris.h @@ -47,7 +47,6 @@ public: virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); - virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) const; private: diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp index 4e2a55f4b3..7709945123 100644 --- a/indra/llvfs/lldir_win32.cpp +++ b/indra/llvfs/lldir_win32.cpp @@ -240,67 +240,6 @@ U32 LLDir_Win32::countFilesInDir(const std::string &dirname, const std::string & return (file_count); } - -// get the next file in the directory -BOOL LLDir_Win32::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) -{ - BOOL fileFound = FALSE; - fname = ""; - - WIN32_FIND_DATAW FileData; - llutf16string pathname = utf8str_to_utf16str(dirname) + utf8str_to_utf16str(mask); - - if (pathname != mCurrentDir) - { - // different dir specified, close old search - if (!mCurrentDir.empty()) - { - FindClose(mDirSearch_h); - } - mCurrentDir = pathname; - - // and open new one - // Check error opening Directory structure - if ((mDirSearch_h = FindFirstFile(pathname.c_str(), &FileData)) != INVALID_HANDLE_VALUE) - { - fileFound = TRUE; - } - } - - // Loop to skip over the current (.) and parent (..) directory entries - // (apparently returned in Win7 but not XP) - do - { - if ( fileFound - && ( (lstrcmp(FileData.cFileName, (LPCTSTR)TEXT(".")) == 0) - ||(lstrcmp(FileData.cFileName, (LPCTSTR)TEXT("..")) == 0) - ) - ) - { - fileFound = FALSE; - } - } while ( mDirSearch_h != INVALID_HANDLE_VALUE - && !fileFound - && (fileFound = FindNextFile(mDirSearch_h, &FileData) - ) - ); - - if (!fileFound && GetLastError() == ERROR_NO_MORE_FILES) - { - // No more files, so reset to beginning of directory - FindClose(mDirSearch_h); - mCurrentDir[0] = '\000'; - } - - if (fileFound) - { - // convert from TCHAR to char - fname = utf16str_to_utf8str(FileData.cFileName); - } - - return fileFound; -} - std::string LLDir_Win32::getCurPath() { WCHAR w_str[MAX_PATH]; diff --git a/indra/llvfs/lldir_win32.h b/indra/llvfs/lldir_win32.h index b170ebbcd7..62fb4713ab 100644 --- a/indra/llvfs/lldir_win32.h +++ b/indra/llvfs/lldir_win32.h @@ -44,15 +44,12 @@ public: /*virtual*/ std::string getCurPath(); /*virtual*/ U32 countFilesInDir(const std::string &dirname, const std::string &mask); - /*virtual*/ BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); /*virtual*/ std::string getLLPluginFilename(std::string base_name); private: - BOOL getNextFileInDir(const llutf16string &dirname, const std::string &mask, std::string &fname); - void* mDirSearch_h; llutf16string mCurrentDir; }; diff --git a/indra/llvfs/tests/lldir_test.cpp b/indra/llvfs/tests/lldir_test.cpp index 8788bd63e8..ea321c5ae9 100644 --- a/indra/llvfs/tests/lldir_test.cpp +++ b/indra/llvfs/tests/lldir_test.cpp @@ -28,6 +28,7 @@ #include "linden_common.h" #include "../lldir.h" +#include "../lldiriterator.h" #include "../test/lltut.h" @@ -259,13 +260,12 @@ namespace tut std::string makeTestFile( const std::string& dir, const std::string& file ) { - std::string delim = gDirUtilp->getDirDelimiter(); - std::string path = dir + delim + file; + std::string path = dir + file; LLFILE* handle = LLFile::fopen( path, "w" ); ensure("failed to open test file '"+path+"'", handle != NULL ); // Harbison & Steele, 4th ed., p. 366: "If an error occurs, fputs // returns EOF; otherwise, it returns some other, nonnegative value." - ensure("failed to write to test file '"+path+"'", fputs("test file", handle) >= 0); + ensure("failed to write to test file '"+path+"'", EOF != fputs("test file", handle) ); fclose(handle); return path; } @@ -290,7 +290,7 @@ namespace tut } static const char* DirScanFilename[5] = { "file1.abc", "file2.abc", "file1.xyz", "file2.xyz", "file1.mno" }; - + void scanTest(const std::string& directory, const std::string& pattern, bool correctResult[5]) { @@ -300,7 +300,8 @@ namespace tut bool filesFound[5] = { false, false, false, false, false }; //std::cerr << "searching '"+directory+"' for '"+pattern+"'\n"; - while ( found <= 5 && gDirUtilp->getNextFileInDir(directory, pattern, scanResult) ) + LLDirIterator iter(directory, pattern); + while ( found <= 5 && iter.next(scanResult) ) { found++; //std::cerr << " found '"+scanResult+"'\n"; @@ -334,15 +335,15 @@ namespace tut template<> template<> void LLDirTest_object_t::test<5>() - // getNextFileInDir + // LLDirIterator::next { std::string delim = gDirUtilp->getDirDelimiter(); std::string dirTemp = LLFile::tmpdir(); // Create the same 5 file names of the two directories - std::string dir1 = makeTestDir(dirTemp + "getNextFileInDir"); - std::string dir2 = makeTestDir(dirTemp + "getNextFileInDir"); + std::string dir1 = makeTestDir(dirTemp + "LLDirIterator"); + std::string dir2 = makeTestDir(dirTemp + "LLDirIterator"); std::string dir1files[5]; std::string dir2files[5]; for (int i=0; i<5; i++) @@ -380,19 +381,17 @@ namespace tut scanTest(dir2, "file?.x?z", expected7); // Scan dir2 and see if any file?.??c files are found - // THESE FAIL ON Mac and Windows, SO ARE COMMENTED OUT FOR NOW - // bool expected8[5] = { true, true, false, false, false }; - // scanTest(dir2, "file?.??c", expected8); - // scanTest(dir2, "*.??c", expected8); + bool expected8[5] = { true, true, false, false, false }; + scanTest(dir2, "file?.??c", expected8); + scanTest(dir2, "*.??c", expected8); // Scan dir1 and see if any *.?n? files are found bool expected9[5] = { false, false, false, false, true }; scanTest(dir1, "*.?n?", expected9); // Scan dir1 and see if any *.???? files are found - // THIS ONE FAILS ON WINDOWS (returns three charater suffixes) SO IS COMMENTED OUT FOR NOW - // bool expected10[5] = { false, false, false, false, false }; - // scanTest(dir1, "*.????", expected10); + bool expected10[5] = { false, false, false, false, false }; + scanTest(dir1, "*.????", expected10); // Scan dir1 and see if any ?????.* files are found bool expected11[5] = { true, true, true, true, true }; @@ -402,6 +401,15 @@ namespace tut bool expected12[5] = { false, false, true, true, false }; scanTest(dir1, "??l??.xyz", expected12); + bool expected13[5] = { true, false, true, false, false }; + scanTest(dir1, "file1.{abc,xyz}", expected13); + + bool expected14[5] = { true, true, false, false, false }; + scanTest(dir1, "file[0-9].abc", expected14); + + bool expected15[5] = { true, true, false, false, false }; + scanTest(dir1, "file[!a-z].abc", expected15); + // clean up all test files and directories for (int i=0; i<5; i++) { diff --git a/indra/llxuixml/lltrans.cpp b/indra/llxuixml/lltrans.cpp index e13d73c640..b403b86048 100644 --- a/indra/llxuixml/lltrans.cpp +++ b/indra/llxuixml/lltrans.cpp @@ -30,6 +30,7 @@ #include "llfasttimer.h" // for call count statistics #include "llxuiparser.h" +#include "llxmlnode.h" #include <map> diff --git a/indra/llxuixml/lltrans.h b/indra/llxuixml/lltrans.h index 5b127b53cf..b7091f77e8 100644 --- a/indra/llxuixml/lltrans.h +++ b/indra/llxuixml/lltrans.h @@ -29,8 +29,10 @@ #include <map> +#include "llpointer.h" #include "llstring.h" -#include "llxmlnode.h" + +class LLXMLNode; /** * @brief String template loaded from strings.xml @@ -61,9 +63,9 @@ public: * @param default_args Set of strings (expected to be in the file) to use as default replacement args, e.g. "SECOND_LIFE" * @returns true if the file was parsed successfully, true if something went wrong */ - static bool parseStrings(LLXMLNodePtr& root, const std::set<std::string>& default_args); + static bool parseStrings(LLPointer<LLXMLNode> & root, const std::set<std::string>& default_args); - static bool parseLanguageStrings(LLXMLNodePtr &root); + static bool parseLanguageStrings(LLPointer<LLXMLNode> & root); /** * @brief Returns a translated string diff --git a/indra/llxuixml/llxuiparser.h b/indra/llxuixml/llxuiparser.h index 7a748d8aea..0c38c4da93 100644 --- a/indra/llxuixml/llxuiparser.h +++ b/indra/llxuixml/llxuiparser.h @@ -28,7 +28,6 @@ #define LLXUIPARSER_H #include "llinitparam.h" -#include "llfasttimer.h" #include "llregistry.h" #include "llpointer.h" @@ -95,6 +94,7 @@ public: }; +class LLXUIParserImpl; class LLXUIParser : public LLInitParam::Parser { @@ -176,6 +176,7 @@ private: // ordering of child elements from base file to localized diff file. Then we can use a pair // of coroutines to perform matching of xml nodes during parsing. Not sure if the overhead // of coroutines would offset the gain from SAX parsing +class LLSimpleXUIParserImpl; class LLSimpleXUIParser : public LLInitParam::Parser { diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 7319c0d902..8f5efcf941 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -25,10 +25,12 @@ */ #include "llviewerprecompiledheaders.h" + #include "llagent.h" #include "pipeline.h" +#include "llagentaccess.h" #include "llagentcamera.h" #include "llagentlistener.h" #include "llagentwearables.h" @@ -36,6 +38,7 @@ #include "llanimationstates.h" #include "llbottomtray.h" #include "llcallingcard.h" +#include "llcapabilitylistener.h" #include "llchannelmanager.h" #include "llconsole.h" #include "llfirstuse.h" @@ -55,8 +58,10 @@ #include "llpaneltopinfobar.h" #include "llparcel.h" #include "llrendersphere.h" +#include "llsdmessage.h" #include "llsdutil.h" #include "llsky.h" +#include "llslurl.h" #include "llsmoothstep.h" #include "llstartup.h" #include "llstatusbar.h" @@ -74,6 +79,7 @@ #include "llviewerobjectlist.h" #include "llviewerparcelmgr.h" #include "llviewerstats.h" +#include "llviewerwindow.h" #include "llvoavatarself.h" #include "llwindow.h" #include "llworld.h" @@ -172,7 +178,8 @@ LLAgent::LLAgent() : mbRunning(false), mbTeleportKeepsLookAt(false), - mAgentAccess(gSavedSettings), + mAgentAccess(new LLAgentAccess(gSavedSettings)), + mTeleportSourceSLURL(new LLSLURL), mTeleportState( TELEPORT_NONE ), mRegionp(NULL), @@ -209,7 +216,7 @@ LLAgent::LLAgent() : mAutoPilotFinishedCallback(NULL), mAutoPilotCallbackData(NULL), - mEffectColor(LLColor4(0.f, 1.f, 1.f, 1.f)), + mEffectColor(new LLUIColor(LLColor4(0.f, 1.f, 1.f, 1.f))), mHaveHomePosition(FALSE), mHomeRegionHandle( 0 ), @@ -251,7 +258,7 @@ void LLAgent::init() setFlying( gSavedSettings.getBOOL("FlyingAtExit") ); - mEffectColor = LLUIColorTable::instance().getColor("EffectColor"); + *mEffectColor = LLUIColorTable::instance().getColor("EffectColor"); gSavedSettings.getControl("PreferredMaturity")->getValidateSignal()->connect(boost::bind(&LLAgent::validateMaturity, this, _2)); gSavedSettings.getControl("PreferredMaturity")->getSignal()->connect(boost::bind(&LLAgent::handleMaturity, this, _2)); @@ -275,9 +282,16 @@ LLAgent::~LLAgent() cleanup(); delete mMouselookModeInSignal; + mMouselookModeInSignal = NULL; delete mMouselookModeOutSignal; + mMouselookModeOutSignal = NULL; - // *Note: this is where LLViewerCamera::getInstance() used to be deleted. + delete mAgentAccess; + mAgentAccess = NULL; + delete mEffectColor; + mEffectColor = NULL; + delete mTeleportSourceSLURL; + mTeleportSourceSLURL = NULL; } // Handle any actions that need to be performed when the main app gains focus @@ -2142,32 +2156,32 @@ void LLAgent::onAnimStop(const LLUUID& id) bool LLAgent::isGodlike() const { - return mAgentAccess.isGodlike(); + return mAgentAccess->isGodlike(); } bool LLAgent::isGodlikeWithoutAdminMenuFakery() const { - return mAgentAccess.isGodlikeWithoutAdminMenuFakery(); + return mAgentAccess->isGodlikeWithoutAdminMenuFakery(); } U8 LLAgent::getGodLevel() const { - return mAgentAccess.getGodLevel(); + return mAgentAccess->getGodLevel(); } bool LLAgent::wantsPGOnly() const { - return mAgentAccess.wantsPGOnly(); + return mAgentAccess->wantsPGOnly(); } bool LLAgent::canAccessMature() const { - return mAgentAccess.canAccessMature(); + return mAgentAccess->canAccessMature(); } bool LLAgent::canAccessAdult() const { - return mAgentAccess.canAccessAdult(); + return mAgentAccess->canAccessAdult(); } bool LLAgent::canAccessMaturityInRegion( U64 region_handle ) const @@ -2202,37 +2216,37 @@ bool LLAgent::canAccessMaturityAtGlobal( LLVector3d pos_global ) const bool LLAgent::prefersPG() const { - return mAgentAccess.prefersPG(); + return mAgentAccess->prefersPG(); } bool LLAgent::prefersMature() const { - return mAgentAccess.prefersMature(); + return mAgentAccess->prefersMature(); } bool LLAgent::prefersAdult() const { - return mAgentAccess.prefersAdult(); + return mAgentAccess->prefersAdult(); } bool LLAgent::isTeen() const { - return mAgentAccess.isTeen(); + return mAgentAccess->isTeen(); } bool LLAgent::isMature() const { - return mAgentAccess.isMature(); + return mAgentAccess->isMature(); } bool LLAgent::isAdult() const { - return mAgentAccess.isAdult(); + return mAgentAccess->isAdult(); } void LLAgent::setTeen(bool teen) { - mAgentAccess.setTeen(teen); + mAgentAccess->setTeen(teen); } //static @@ -2277,37 +2291,37 @@ bool LLAgent::sendMaturityPreferenceToServer(int preferredMaturity) BOOL LLAgent::getAdminOverride() const { - return mAgentAccess.getAdminOverride(); + return mAgentAccess->getAdminOverride(); } void LLAgent::setMaturity(char text) { - mAgentAccess.setMaturity(text); + mAgentAccess->setMaturity(text); } void LLAgent::setAdminOverride(BOOL b) { - mAgentAccess.setAdminOverride(b); + mAgentAccess->setAdminOverride(b); } void LLAgent::setGodLevel(U8 god_level) { - mAgentAccess.setGodLevel(god_level); + mAgentAccess->setGodLevel(god_level); } void LLAgent::setAOTransition() { - mAgentAccess.setTransition(); + mAgentAccess->setTransition(); } const LLAgentAccess& LLAgent::getAgentAccess() { - return mAgentAccess; + return *mAgentAccess; } bool LLAgent::validateMaturity(const LLSD& newvalue) { - return mAgentAccess.canSetMaturity(newvalue.asInteger()); + return mAgentAccess->canSetMaturity(newvalue.asInteger()); } void LLAgent::handleMaturity(const LLSD& newvalue) @@ -2639,12 +2653,12 @@ BOOL LLAgent::allowOperation(PermissionBit op, const LLColor4 &LLAgent::getEffectColor() { - return mEffectColor; + return *mEffectColor; } void LLAgent::setEffectColor(const LLColor4 &color) { - mEffectColor = color; + *mEffectColor = color; } void LLAgent::initOriginGlobal(const LLVector3d &origin_global) @@ -3472,7 +3486,7 @@ void LLAgent::setTeleportState(ETeleportState state) case TELEPORT_MOVING: // We're outa here. Save "back" slurl. - LLAgentUI::buildSLURL(mTeleportSourceSLURL); + LLAgentUI::buildSLURL(*mTeleportSourceSLURL); break; case TELEPORT_ARRIVING: @@ -3805,6 +3819,11 @@ void LLAgent::parseTeleportMessages(const std::string& xml_filename) }//end for (all message sets in xml file) } +const void LLAgent::getTeleportSourceSLURL(LLSLURL& slurl) const +{ + slurl = *mTeleportSourceSLURL; +} + void LLAgent::sendAgentUpdateUserInfo(bool im_via_email, const std::string& directory_visibility ) { gMessageSystem->newMessageFast(_PREHASH_UpdateUserInfo); diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 896408c0dd..54c5649f97 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -29,15 +29,11 @@ #include "indra_constants.h" #include "llevent.h" // LLObservable base class -#include "llagentaccess.h" #include "llagentconstants.h" #include "llagentdata.h" // gAgentID, gAgentSessionID -#include "llcharacter.h" // LLAnimPauseRequest +#include "llcharacter.h" #include "llcoordframe.h" // for mFrameAgent -#include "llpointer.h" -#include "lluicolor.h" #include "llvoavatardefines.h" -#include "llslurl.h" #include <boost/signals2.hpp> @@ -56,6 +52,10 @@ class LLFriendObserver; class LLPickInfo; class LLViewerObject; class LLAgentDropGroupViewerNode; +class LLAgentAccess; +class LLSLURL; +class LLPauseRequestHandle; +class LLUIColor; //-------------------------------------------------------------------- // Types @@ -80,6 +80,8 @@ struct LLGroupData class LLAgentListener; +class LLAgentImpl; + //------------------------------------------------------------------------ // LLAgent //------------------------------------------------------------------------ @@ -420,7 +422,7 @@ private: camera_signal_t* mMouselookModeInSignal; camera_signal_t* mMouselookModeOutSignal; BOOL mCustomAnim; // Current animation is ANIM_AGENT_CUSTOMIZE ? - LLAnimPauseRequest mPauseRequest; + LLPointer<LLPauseRequestHandle> mPauseRequest; BOOL mViewsPushed; // Keep track of whether or not we have pushed views /** Animation @@ -515,13 +517,13 @@ public: public: static void parseTeleportMessages(const std::string& xml_filename); - const void getTeleportSourceSLURL(LLSLURL& slurl) const { slurl = mTeleportSourceSLURL; } + const void getTeleportSourceSLURL(LLSLURL& slurl) const; public: // ! TODO ! Define ERROR and PROGRESS enums here instead of exposing the mappings. static std::map<std::string, std::string> sTeleportErrorMessages; static std::map<std::string, std::string> sTeleportProgressMessages; private: - LLSLURL mTeleportSourceSLURL; // SLURL where last TP began + LLSLURL * mTeleportSourceSLURL; // SLURL where last TP began //-------------------------------------------------------------------- // Teleport Actions @@ -580,7 +582,7 @@ public: // ! BACKWARDS COMPATIBILITY ! This function can go away after the AO transition (see llstartup.cpp). void setAOTransition(); private: - LLAgentAccess mAgentAccess; + LLAgentAccess * mAgentAccess; //-------------------------------------------------------------------- // God @@ -660,7 +662,7 @@ public: const LLColor4 &getEffectColor(); void setEffectColor(const LLColor4 &color); private: - LLUIColor mEffectColor; + LLUIColor * mEffectColor; /** Rendering ** ** diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 9de2941c4a..3a7e8dff64 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -82,13 +82,14 @@ #include "lltextutil.h" #include "lllogininstance.h" #include "llprogressview.h" - +#include "llvocache.h" #include "llweb.h" #include "llsecondlifeurls.h" #include "llupdaterservice.h" // Linden library includes #include "llavatarnamecache.h" +#include "lldiriterator.h" #include "llimagej2c.h" #include "llmemory.h" #include "llprimitive.h" @@ -132,7 +133,6 @@ #include "lltoolmgr.h" #include "llassetstorage.h" #include "llpolymesh.h" -#include "llcachename.h" #include "llaudioengine.h" #include "llstreamingaudio.h" #include "llviewermenu.h" @@ -3432,7 +3432,9 @@ void LLAppViewer::migrateCacheDirectory() S32 file_count = 0; std::string file_name; std::string mask = delimiter + "*.*"; - while (gDirUtilp->getNextFileInDir(old_cache_dir, mask, file_name)) + + LLDirIterator iter(old_cache_dir, mask); + while (iter.next(file_name)) { if (file_name == "." || file_name == "..") continue; std::string source_path = old_cache_dir + delimiter + file_name; @@ -3653,7 +3655,8 @@ bool LLAppViewer::initCache() dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""); std::string found_file; - if (gDirUtilp->getNextFileInDir(dir, mask, found_file)) + LLDirIterator iter(dir, mask); + if (iter.next(found_file)) { old_vfs_data_file = dir + gDirUtilp->getDirDelimiter() + found_file; diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index 523c2e3adf..714e0e6163 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -30,6 +30,7 @@ #include "llcommandlineparser.h" +#include "lldiriterator.h" #include "llmemtype.h" #include "llurldispatcher.h" // SLURL from other app instance #include "llviewernetwork.h" @@ -504,7 +505,9 @@ std::string LLAppViewerLinux::generateSerialNumber() // trawl /dev/disk/by-uuid looking for a good-looking UUID to grab std::string this_name; - while (gDirUtilp->getNextFileInDir(uuiddir, "*", this_name)) + + LLDirIterator iter(uuiddir, "*"); + while (iter.next(this_name)) { if (this_name.length() > best.length() || (this_name.length() == best.length() && diff --git a/indra/newview/lleventnotifier.h b/indra/newview/lleventnotifier.h index 697a708762..3fee46c2f6 100644 --- a/indra/newview/lleventnotifier.h +++ b/indra/newview/lleventnotifier.h @@ -31,6 +31,7 @@ #include "v3dmath.h" class LLEventNotification; +class LLMessageSystem; class LLEventNotifier diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index 7be4ebc690..0d0c1f594d 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -38,6 +38,7 @@ #include "message.h" #include "llagent.h" +#include "llagentaccess.h" #include "llbutton.h" #include "llcheckboxctrl.h" #include "llcombobox.h" diff --git a/indra/newview/llfloaterland.h b/indra/newview/llfloaterland.h index a096fb64cd..8a70fa24d8 100644 --- a/indra/newview/llfloaterland.h +++ b/indra/newview/llfloaterland.h @@ -43,11 +43,12 @@ class LLButton; class LLCheckBoxCtrl; class LLRadioGroup; class LLComboBox; -class LLNameListCtrl; -class LLSpinCtrl; class LLLineEditor; +class LLMessageSystem; +class LLNameListCtrl; class LLRadioGroup; class LLParcelSelectionObserver; +class LLSpinCtrl; class LLTabContainer; class LLTextBox; class LLTextEditor; diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index add591895b..00dc7b1627 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -53,6 +53,7 @@ #include "llfloaterpostcard.h" #include "llcheckboxctrl.h" #include "llradiogroup.h" +#include "llslurl.h" #include "lltoolfocus.h" #include "lltoolmgr.h" #include "llwebsharing.h" diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 0d8601410a..4c9c4cb154 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -35,6 +35,7 @@ #include "llfloateruipreview.h" // Own header // Internal utility +#include "lldiriterator.h" #include "lleventtimer.h" #include "llexternaleditor.h" #include "llrender.h" @@ -481,9 +482,11 @@ BOOL LLFloaterUIPreview::postBuild() std::string language_directory; std::string xui_dir = get_xui_dir(); // directory containing localizations -- don't forget trailing delim mLanguageSelection->removeall(); // clear out anything temporarily in list from XML + + LLDirIterator iter(xui_dir, "*"); while(found) // for every directory { - if((found = gDirUtilp->getNextFileInDir(xui_dir, "*", language_directory))) // get next directory + if((found = iter.next(language_directory))) // get next directory { std::string full_path = xui_dir + language_directory; if(LLFile::isfile(full_path.c_str())) // if it's not a directory, skip it @@ -635,42 +638,51 @@ void LLFloaterUIPreview::refreshList() mFileList->clearRows(); // empty list std::string name; BOOL found = TRUE; + + LLDirIterator floater_iter(getLocalizedDirectory(), "floater_*.xml"); while(found) // for every floater file that matches the pattern { - if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "floater_*.xml", name))) // get next file matching pattern + if((found = floater_iter.next(name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } found = TRUE; + + LLDirIterator inspect_iter(getLocalizedDirectory(), "inspect_*.xml"); while(found) // for every inspector file that matches the pattern { - if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "inspect_*.xml", name))) // get next file matching pattern + if((found = inspect_iter.next(name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } found = TRUE; + + LLDirIterator menu_iter(getLocalizedDirectory(), "menu_*.xml"); while(found) // for every menu file that matches the pattern { - if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "menu_*.xml", name))) // get next file matching pattern + if((found = menu_iter.next(name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } found = TRUE; + + LLDirIterator panel_iter(getLocalizedDirectory(), "panel_*.xml"); while(found) // for every panel file that matches the pattern { - if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "panel_*.xml", name))) // get next file matching pattern + if((found = panel_iter.next(name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } } - found = TRUE; + + LLDirIterator sidepanel_iter(getLocalizedDirectory(), "sidepanel_*.xml"); while(found) // for every sidepanel file that matches the pattern { - if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "sidepanel_*.xml", name))) // get next file matching pattern + if((found = sidepanel_iter.next(name))) // get next file matching pattern { addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) } diff --git a/indra/newview/llfolderviewitem.h b/indra/newview/llfolderviewitem.h index 2006e094a8..fc941510ab 100644 --- a/indra/newview/llfolderviewitem.h +++ b/indra/newview/llfolderviewitem.h @@ -28,6 +28,7 @@ #include "llview.h" #include "lldarray.h" // *TODO: Eliminate, forward declare +#include "lluiimage.h" class LLFontGL; class LLFolderView; diff --git a/indra/newview/lllocationhistory.h b/indra/newview/lllocationhistory.h index 188fbf1f9b..9fef42c5df 100644 --- a/indra/newview/lllocationhistory.h +++ b/indra/newview/lllocationhistory.h @@ -33,6 +33,7 @@ #include <string> #include <map> #include <boost/function.hpp> +#include <boost/signals2.hpp> class LLSD; /** diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 2df683861a..efc4e23838 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -32,6 +32,7 @@ #include "lltrans.h" #include "llviewercontrol.h" +#include "lldiriterator.h" #include "llinstantmessage.h" #include "llsingleton.h" // for LLSingleton @@ -602,7 +603,8 @@ std::string LLLogChat::oldLogFileName(std::string filename) //LL_INFOS("") << "Checking:" << directory << " for " << pattern << LL_ENDL;/* uncomment if you want to verify step, delete on commit */ std::vector<std::string> allfiles; - while (gDirUtilp->getNextFileInDir(directory, pattern, scanResult)) + LLDirIterator iter(directory, pattern); + while (iter.next(scanResult)) { //LL_INFOS("") << "Found :" << scanResult << LL_ENDL; allfiles.push_back(scanResult); diff --git a/indra/newview/lloutputmonitorctrl.h b/indra/newview/lloutputmonitorctrl.h index 026803584d..2d23753d46 100644 --- a/indra/newview/lloutputmonitorctrl.h +++ b/indra/newview/lloutputmonitorctrl.h @@ -31,6 +31,7 @@ #include "llview.h" #include "llmutelist.h" #include "llspeakingindicatormanager.h" +#include "lluiimage.h" class LLTextBox; class LLUICtrlFactory; diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 73c4722b82..d58a1cb663 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -36,6 +36,7 @@ #include "llimview.h" #include "llmenubutton.h" #include "llnotificationsutil.h" +#include "llslurl.h" #include "lltexteditor.h" #include "lltexturectrl.h" #include "lltoggleablemenu.h" diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index ec340dc258..1576ccccdf 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -44,6 +44,7 @@ #include "llnotificationsutil.h" #include "llscrolllistitem.h" #include "llspinctrl.h" +#include "llslurl.h" #include "lltextbox.h" #include "lltexteditor.h" #include "lltexturectrl.h" diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 3dbc637318..fbe331c7ab 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -42,6 +42,7 @@ #include "llscrolllistctrl.h" #include "llscrolllistitem.h" #include "llscrolllistcell.h" +#include "llslurl.h" #include "lltabcontainer.h" #include "lltextbox.h" #include "lltexteditor.h" diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index 8e5beb33ce..9f5c55bad1 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -34,6 +34,7 @@ #include "llassetuploadresponders.h" #include "llcheckboxctrl.h" #include "llcombobox.h" +#include "lldatapacker.h" #include "lldelayedgestureerror.h" #include "llfloaterreg.h" #include "llgesturemgr.h" diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp index c8c6858b81..fbd2f7ca83 100644 --- a/indra/newview/llsidepaneliteminfo.cpp +++ b/indra/newview/llsidepaneliteminfo.cpp @@ -39,6 +39,7 @@ #include "llinventoryobserver.h" #include "lllineeditor.h" #include "llradiogroup.h" +#include "llslurl.h" #include "llviewercontrol.h" #include "llviewerinventory.h" #include "llviewerobjectlist.h" diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index ba243f258a..671a334600 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -35,7 +35,6 @@ #include "llagentwearables.h" #include "llappearancemgr.h" #include "lldictionary.h" -//#include "llfirstuse.h" #include "llfloaterreg.h" #include "llfloatertools.h" #include "llgesturemgr.h" diff --git a/indra/newview/llviewerchat.cpp b/indra/newview/llviewerchat.cpp index e7a0d17c3a..e06fe7bda0 100644 --- a/indra/newview/llviewerchat.cpp +++ b/indra/newview/llviewerchat.cpp @@ -29,6 +29,8 @@ // newview includes #include "llagent.h" // gAgent +#include "llslurl.h" +#include "lluicolor.h" #include "lluicolortable.h" #include "llviewercontrol.h" // gSavedSettings #include "llviewerregion.h" diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h index 925244e89b..ca73212ed1 100644 --- a/indra/newview/llviewerkeyboard.h +++ b/indra/newview/llviewerkeyboard.h @@ -28,6 +28,7 @@ #define LL_LLVIEWERKEYBOARD_H #include "llkeyboard.h" // For EKeystate +#include "llinitparam.h" const S32 MAX_NAMED_FUNCTIONS = 100; const S32 MAX_KEY_BINDINGS = 128; // was 60 diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 62ae7ac6e2..2b9f32f6f5 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1,3742 +1,3744 @@ -/**
- * @file llviewermedia.cpp
- * @brief Client interface to the media engine
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "llviewermedia.h"
-#include "llviewermediafocus.h"
-#include "llmimetypes.h"
-#include "llmediaentry.h"
-#include "llversioninfo.h"
-#include "llviewercontrol.h"
-#include "llviewertexture.h"
-#include "llviewerparcelmedia.h"
-#include "llviewerparcelmgr.h"
-#include "llviewertexturelist.h"
-#include "llvovolume.h"
-#include "llpluginclassmedia.h"
-#include "llplugincookiestore.h"
-#include "llviewerwindow.h"
-#include "llfocusmgr.h"
-#include "llcallbacklist.h"
-#include "llparcel.h"
-#include "llaudioengine.h" // for gAudiop
-#include "llurldispatcher.h"
-#include "llvoavatar.h"
-#include "llvoavatarself.h"
-#include "llviewerregion.h"
-#include "llwebsharing.h" // For LLWebSharing::setOpenIDCookie(), *TODO: find a better way to do this!
-#include "llfilepicker.h"
-#include "llnotifications.h"
-#include "lldir.h"
-#include "llevent.h" // LLSimpleListener
-#include "llnotificationsutil.h"
-#include "lluuid.h"
-#include "llkeyboard.h"
-#include "llmutelist.h"
-#include "llpanelprofile.h"
-#include "llappviewer.h"
-#include "lllogininstance.h"
-//#include "llfirstuse.h"
-#include "llwindow.h"
-
-#include "llfloatermediabrowser.h" // for handling window close requests and geometry change requests in media browser windows.
-#include "llfloaterwebcontent.h" // for handling window close requests and geometry change requests in media browser windows.
-
-#include <boost/bind.hpp> // for SkinFolder listener
-#include <boost/signals2.hpp>
-
-/*static*/ const char* LLViewerMedia::AUTO_PLAY_MEDIA_SETTING = "ParcelMediaAutoPlayEnable";
-/*static*/ const char* LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING = "MediaShowOnOthers";
-/*static*/ const char* LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING = "MediaShowWithinParcel";
-/*static*/ const char* LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING = "MediaShowOutsideParcel";
-
-
-// Move this to its own file.
-
-LLViewerMediaEventEmitter::~LLViewerMediaEventEmitter()
-{
- observerListType::iterator iter = mObservers.begin();
-
- while( iter != mObservers.end() )
- {
- LLViewerMediaObserver *self = *iter;
- iter++;
- remObserver(self);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//
-bool LLViewerMediaEventEmitter::addObserver( LLViewerMediaObserver* observer )
-{
- if ( ! observer )
- return false;
-
- if ( std::find( mObservers.begin(), mObservers.end(), observer ) != mObservers.end() )
- return false;
-
- mObservers.push_back( observer );
- observer->mEmitters.push_back( this );
-
- return true;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//
-bool LLViewerMediaEventEmitter::remObserver( LLViewerMediaObserver* observer )
-{
- if ( ! observer )
- return false;
-
- mObservers.remove( observer );
- observer->mEmitters.remove(this);
-
- return true;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//
-void LLViewerMediaEventEmitter::emitEvent( LLPluginClassMedia* media, LLViewerMediaObserver::EMediaEvent event )
-{
- // Broadcast the event to any observers.
- observerListType::iterator iter = mObservers.begin();
- while( iter != mObservers.end() )
- {
- LLViewerMediaObserver *self = *iter;
- ++iter;
- self->handleMediaEvent( media, event );
- }
-}
-
-// Move this to its own file.
-LLViewerMediaObserver::~LLViewerMediaObserver()
-{
- std::list<LLViewerMediaEventEmitter *>::iterator iter = mEmitters.begin();
-
- while( iter != mEmitters.end() )
- {
- LLViewerMediaEventEmitter *self = *iter;
- iter++;
- self->remObserver( this );
- }
-}
-
-
-// Move this to its own file.
-// helper class that tries to download a URL from a web site and calls a method
-// on the Panel Land Media and to discover the MIME type
-class LLMimeDiscoveryResponder : public LLHTTPClient::Responder
-{
-LOG_CLASS(LLMimeDiscoveryResponder);
-public:
- LLMimeDiscoveryResponder( viewer_media_t media_impl)
- : mMediaImpl(media_impl),
- mInitialized(false)
- {
- if(mMediaImpl->mMimeTypeProbe != NULL)
- {
- llerrs << "impl already has an outstanding responder" << llendl;
- }
-
- mMediaImpl->mMimeTypeProbe = this;
- }
-
- ~LLMimeDiscoveryResponder()
- {
- disconnectOwner();
- }
-
- virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content)
- {
- std::string media_type = content["content-type"].asString();
- std::string::size_type idx1 = media_type.find_first_of(";");
- std::string mime_type = media_type.substr(0, idx1);
-
- lldebugs << "status is " << status << ", media type \"" << media_type << "\"" << llendl;
-
- // 2xx status codes indicate success.
- // Most 4xx status codes are successful enough for our purposes.
- // 499 is the error code for host not found, timeout, etc.
- // 500 means "Internal Server error" but we decided it's okay to
- // accept this and go past it in the MIME type probe
- // 302 means the resource can be found temporarily in a different place - added this for join.secondlife.com
- // 499 is a code specifc to join.secondlife.com (????) apparently safe to ignore
-// if( ((status >= 200) && (status < 300)) ||
-// ((status >= 400) && (status < 499)) ||
-// (status == 500) ||
-// (status == 302) ||
-// (status == 499)
-// )
- // We now no longer check the error code returned from the probe.
- // If we have a mime type, use it. If not, default to the web plugin and let it handle error reporting.
- if(1)
- {
- // The probe was successful.
- if(mime_type.empty())
- {
- // Some sites don't return any content-type header at all.
- // Treat an empty mime type as text/html.
- mime_type = "text/html";
- }
-
- completeAny(status, mime_type);
- }
- else
- {
- llwarns << "responder failed with status " << status << ", reason " << reason << llendl;
-
- if(mMediaImpl)
- {
- mMediaImpl->mMediaSourceFailed = true;
- }
- }
-
- }
-
- void completeAny(U32 status, const std::string& mime_type)
- {
- // the call to initializeMedia may disconnect the responder, which will clear mMediaImpl.
- // Make a local copy so we can call loadURI() afterwards.
- LLViewerMediaImpl *impl = mMediaImpl;
-
- if(impl && !mInitialized && ! mime_type.empty())
- {
- if(impl->initializeMedia(mime_type))
- {
- mInitialized = true;
- impl->loadURI();
- disconnectOwner();
- }
- }
- }
-
- void cancelRequest()
- {
- disconnectOwner();
- }
-
-private:
- void disconnectOwner()
- {
- if(mMediaImpl)
- {
- if(mMediaImpl->mMimeTypeProbe != this)
- {
- llerrs << "internal error: mMediaImpl->mMimeTypeProbe != this" << llendl;
- }
-
- mMediaImpl->mMimeTypeProbe = NULL;
- }
- mMediaImpl = NULL;
- }
-
-
-public:
- LLViewerMediaImpl *mMediaImpl;
- bool mInitialized;
-};
-
-class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder
-{
-LOG_CLASS(LLViewerMediaOpenIDResponder);
-public:
- LLViewerMediaOpenIDResponder( )
- {
- }
-
- ~LLViewerMediaOpenIDResponder()
- {
- }
-
- /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content)
- {
- LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL;
- LL_DEBUGS("MediaAuth") << content << LL_ENDL;
- std::string cookie = content["set-cookie"].asString();
-
- LLViewerMedia::openIDCookieResponse(cookie);
- }
-
- /* virtual */ void completedRaw(
- U32 status,
- const std::string& reason,
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- // This is just here to disable the default behavior (attempting to parse the response as llsd).
- // We don't care about the content of the response, only the set-cookie header.
- }
-
-};
-
-class LLViewerMediaWebProfileResponder : public LLHTTPClient::Responder
-{
-LOG_CLASS(LLViewerMediaWebProfileResponder);
-public:
- LLViewerMediaWebProfileResponder(std::string host)
- {
- mHost = host;
- }
-
- ~LLViewerMediaWebProfileResponder()
- {
- }
-
- /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content)
- {
- LL_WARNS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL;
- LL_WARNS("MediaAuth") << content << LL_ENDL;
-
- std::string cookie = content["set-cookie"].asString();
-
- LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost);
- }
-
- void completedRaw(
- U32 status,
- const std::string& reason,
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- // This is just here to disable the default behavior (attempting to parse the response as llsd).
- // We don't care about the content of the response, only the set-cookie header.
- }
-
- std::string mHost;
-};
-
-
-LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL;
-LLURL LLViewerMedia::sOpenIDURL;
-std::string LLViewerMedia::sOpenIDCookie;
-LLPluginClassMedia* LLViewerMedia::sSpareBrowserMediaSource = NULL;
-static LLViewerMedia::impl_list sViewerMediaImplList;
-static LLViewerMedia::impl_id_map sViewerMediaTextureIDMap;
-static LLTimer sMediaCreateTimer;
-static const F32 LLVIEWERMEDIA_CREATE_DELAY = 1.0f;
-static F32 sGlobalVolume = 1.0f;
-static F64 sLowestLoadableImplInterest = 0.0f;
-static bool sAnyMediaShowing = false;
-static boost::signals2::connection sTeleportFinishConnection;
-static std::string sUpdatedCookies;
-static const char *PLUGIN_COOKIE_FILE_NAME = "plugin_cookies.txt";
-
-//////////////////////////////////////////////////////////////////////////////////////////
-static void add_media_impl(LLViewerMediaImpl* media)
-{
- sViewerMediaImplList.push_back(media);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-static void remove_media_impl(LLViewerMediaImpl* media)
-{
- LLViewerMedia::impl_list::iterator iter = sViewerMediaImplList.begin();
- LLViewerMedia::impl_list::iterator end = sViewerMediaImplList.end();
-
- for(; iter != end; iter++)
- {
- if(media == *iter)
- {
- sViewerMediaImplList.erase(iter);
- return;
- }
- }
-}
-
-class LLViewerMediaMuteListObserver : public LLMuteListObserver
-{
- /* virtual */ void onChange() { LLViewerMedia::muteListChanged();}
-};
-
-static LLViewerMediaMuteListObserver sViewerMediaMuteListObserver;
-static bool sViewerMediaMuteListObserverInitialized = false;
-static bool sInWorldMediaDisabled = false;
-
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// LLViewerMedia
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-viewer_media_t LLViewerMedia::newMediaImpl(
- const LLUUID& texture_id,
- S32 media_width,
- S32 media_height,
- U8 media_auto_scale,
- U8 media_loop)
-{
- LLViewerMediaImpl* media_impl = getMediaImplFromTextureID(texture_id);
- if(media_impl == NULL || texture_id.isNull())
- {
- // Create the media impl
- media_impl = new LLViewerMediaImpl(texture_id, media_width, media_height, media_auto_scale, media_loop);
- }
- else
- {
- media_impl->unload();
- media_impl->setTextureID(texture_id);
- media_impl->mMediaWidth = media_width;
- media_impl->mMediaHeight = media_height;
- media_impl->mMediaAutoScale = media_auto_scale;
- media_impl->mMediaLoop = media_loop;
- }
-
- return media_impl;
-}
-
-viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const std::string& previous_url, bool update_from_self)
-{
- // Try to find media with the same media ID
- viewer_media_t media_impl = getMediaImplFromTextureID(media_entry->getMediaID());
-
- lldebugs << "called, current URL is \"" << media_entry->getCurrentURL()
- << "\", previous URL is \"" << previous_url
- << "\", update_from_self is " << (update_from_self?"true":"false")
- << llendl;
-
- bool was_loaded = false;
- bool needs_navigate = false;
-
- if(media_impl)
- {
- was_loaded = media_impl->hasMedia();
-
- media_impl->setHomeURL(media_entry->getHomeURL());
-
- media_impl->mMediaAutoScale = media_entry->getAutoScale();
- media_impl->mMediaLoop = media_entry->getAutoLoop();
- media_impl->mMediaWidth = media_entry->getWidthPixels();
- media_impl->mMediaHeight = media_entry->getHeightPixels();
- media_impl->mMediaAutoPlay = media_entry->getAutoPlay();
- media_impl->mMediaEntryURL = media_entry->getCurrentURL();
- if (media_impl->mMediaSource)
- {
- media_impl->mMediaSource->setAutoScale(media_impl->mMediaAutoScale);
- media_impl->mMediaSource->setLoop(media_impl->mMediaLoop);
- media_impl->mMediaSource->setSize(media_entry->getWidthPixels(), media_entry->getHeightPixels());
- }
-
- bool url_changed = (media_impl->mMediaEntryURL != previous_url);
- if(media_impl->mMediaEntryURL.empty())
- {
- if(url_changed)
- {
- // The current media URL is now empty. Unload the media source.
- media_impl->unload();
-
- lldebugs << "Unloading media instance (new current URL is empty)." << llendl;
- }
- }
- else
- {
- // The current media URL is not empty.
- // If (the media was already loaded OR the media was set to autoplay) AND this update didn't come from this agent,
- // do a navigate.
- bool auto_play = media_impl->isAutoPlayable();
- if((was_loaded || auto_play) && !update_from_self)
- {
- needs_navigate = url_changed;
- }
-
- lldebugs << "was_loaded is " << (was_loaded?"true":"false")
- << ", auto_play is " << (auto_play?"true":"false")
- << ", needs_navigate is " << (needs_navigate?"true":"false") << llendl;
- }
- }
- else
- {
- media_impl = newMediaImpl(
- media_entry->getMediaID(),
- media_entry->getWidthPixels(),
- media_entry->getHeightPixels(),
- media_entry->getAutoScale(),
- media_entry->getAutoLoop());
-
- media_impl->setHomeURL(media_entry->getHomeURL());
- media_impl->mMediaAutoPlay = media_entry->getAutoPlay();
- media_impl->mMediaEntryURL = media_entry->getCurrentURL();
- if(media_impl->isAutoPlayable())
- {
- needs_navigate = true;
- }
- }
-
- if(media_impl)
- {
- if(needs_navigate)
- {
- media_impl->navigateTo(media_impl->mMediaEntryURL, "", true, true);
- lldebugs << "navigating to URL " << media_impl->mMediaEntryURL << llendl;
- }
- else if(!media_impl->mMediaURL.empty() && (media_impl->mMediaURL != media_impl->mMediaEntryURL))
- {
- // If we already have a non-empty media URL set and we aren't doing a navigate, update the media URL to match the media entry.
- media_impl->mMediaURL = media_impl->mMediaEntryURL;
-
- // If this causes a navigate at some point (such as after a reload), it should be considered server-driven so it isn't broadcast.
- media_impl->mNavigateServerRequest = true;
-
- lldebugs << "updating URL in the media impl to " << media_impl->mMediaEntryURL << llendl;
- }
- }
-
- return media_impl;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-LLViewerMediaImpl* LLViewerMedia::getMediaImplFromTextureID(const LLUUID& texture_id)
-{
- LLViewerMediaImpl* result = NULL;
-
- // Look up the texture ID in the texture id->impl map.
- impl_id_map::iterator iter = sViewerMediaTextureIDMap.find(texture_id);
- if(iter != sViewerMediaTextureIDMap.end())
- {
- result = iter->second;
- }
-
- return result;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-std::string LLViewerMedia::getCurrentUserAgent()
-{
- // Don't use user-visible string to avoid
- // punctuation and strange characters.
- std::string skin_name = gSavedSettings.getString("SkinCurrent");
-
- // Just in case we need to check browser differences in A/B test
- // builds.
- std::string channel = LLVersionInfo::getChannel();
-
- // append our magic version number string to the browser user agent id
- // See the HTTP 1.0 and 1.1 specifications for allowed formats:
- // http://www.ietf.org/rfc/rfc1945.txt section 10.15
- // http://www.ietf.org/rfc/rfc2068.txt section 3.8
- // This was also helpful:
- // http://www.mozilla.org/build/revised-user-agent-strings.html
- std::ostringstream codec;
- codec << "SecondLife/";
- codec << LLVersionInfo::getVersion();
- codec << " (" << channel << "; " << skin_name << " skin)";
- llinfos << codec.str() << llendl;
-
- return codec.str();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::updateBrowserUserAgent()
-{
- std::string user_agent = getCurrentUserAgent();
-
- impl_list::iterator iter = sViewerMediaImplList.begin();
- impl_list::iterator end = sViewerMediaImplList.end();
-
- for(; iter != end; iter++)
- {
- LLViewerMediaImpl* pimpl = *iter;
- if(pimpl->mMediaSource && pimpl->mMediaSource->pluginSupportsMediaBrowser())
- {
- pimpl->mMediaSource->setBrowserUserAgent(user_agent);
- }
- }
-
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-bool LLViewerMedia::handleSkinCurrentChanged(const LLSD& /*newvalue*/)
-{
- // gSavedSettings is already updated when this function is called.
- updateBrowserUserAgent();
- return true;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-bool LLViewerMedia::textureHasMedia(const LLUUID& texture_id)
-{
- impl_list::iterator iter = sViewerMediaImplList.begin();
- impl_list::iterator end = sViewerMediaImplList.end();
-
- for(; iter != end; iter++)
- {
- LLViewerMediaImpl* pimpl = *iter;
- if(pimpl->getMediaTextureID() == texture_id)
- {
- return true;
- }
- }
- return false;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::setVolume(F32 volume)
-{
- if(volume != sGlobalVolume)
- {
- sGlobalVolume = volume;
- impl_list::iterator iter = sViewerMediaImplList.begin();
- impl_list::iterator end = sViewerMediaImplList.end();
-
- for(; iter != end; iter++)
- {
- LLViewerMediaImpl* pimpl = *iter;
- pimpl->updateVolume();
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-F32 LLViewerMedia::getVolume()
-{
- return sGlobalVolume;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::muteListChanged()
-{
- // When the mute list changes, we need to check mute status on all impls.
- impl_list::iterator iter = sViewerMediaImplList.begin();
- impl_list::iterator end = sViewerMediaImplList.end();
-
- for(; iter != end; iter++)
- {
- LLViewerMediaImpl* pimpl = *iter;
- pimpl->mNeedsMuteCheck = true;
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::setInWorldMediaDisabled(bool disabled)
-{
- sInWorldMediaDisabled = disabled;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-bool LLViewerMedia::getInWorldMediaDisabled()
-{
- return sInWorldMediaDisabled;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-bool LLViewerMedia::isInterestingEnough(const LLVOVolume *object, const F64 &object_interest)
-{
- bool result = false;
-
- if (NULL == object)
- {
- result = false;
- }
- // Focused? Then it is interesting!
- else if (LLViewerMediaFocus::getInstance()->getFocusedObjectID() == object->getID())
- {
- result = true;
- }
- // Selected? Then it is interesting!
- // XXX Sadly, 'contains()' doesn't take a const :(
- else if (LLSelectMgr::getInstance()->getSelection()->contains(const_cast<LLVOVolume*>(object)))
- {
- result = true;
- }
- else
- {
- lldebugs << "object interest = " << object_interest << ", lowest loadable = " << sLowestLoadableImplInterest << llendl;
- if(object_interest >= sLowestLoadableImplInterest)
- result = true;
- }
-
- return result;
-}
-
-LLViewerMedia::impl_list &LLViewerMedia::getPriorityList()
-{
- return sViewerMediaImplList;
-}
-
-// This is the predicate function used to sort sViewerMediaImplList by priority.
-bool LLViewerMedia::priorityComparitor(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2)
-{
- if(i1->isForcedUnloaded() && !i2->isForcedUnloaded())
- {
- // Muted or failed items always go to the end of the list, period.
- return false;
- }
- else if(i2->isForcedUnloaded() && !i1->isForcedUnloaded())
- {
- // Muted or failed items always go to the end of the list, period.
- return true;
- }
- else if(i1->hasFocus())
- {
- // The item with user focus always comes to the front of the list, period.
- return true;
- }
- else if(i2->hasFocus())
- {
- // The item with user focus always comes to the front of the list, period.
- return false;
- }
- else if(i1->isParcelMedia())
- {
- // The parcel media impl sorts above all other inworld media, unless one has focus.
- return true;
- }
- else if(i2->isParcelMedia())
- {
- // The parcel media impl sorts above all other inworld media, unless one has focus.
- return false;
- }
- else if(i1->getUsedInUI() && !i2->getUsedInUI())
- {
- // i1 is a UI element, i2 is not. This makes i1 "less than" i2, so it sorts earlier in our list.
- return true;
- }
- else if(i2->getUsedInUI() && !i1->getUsedInUI())
- {
- // i2 is a UI element, i1 is not. This makes i2 "less than" i1, so it sorts earlier in our list.
- return false;
- }
- else if(i1->isPlayable() && !i2->isPlayable())
- {
- // Playable items sort above ones that wouldn't play even if they got high enough priority
- return true;
- }
- else if(!i1->isPlayable() && i2->isPlayable())
- {
- // Playable items sort above ones that wouldn't play even if they got high enough priority
- return false;
- }
- else if(i1->getInterest() == i2->getInterest())
- {
- // Generally this will mean both objects have zero interest. In this case, sort on distance.
- return (i1->getProximityDistance() < i2->getProximityDistance());
- }
- else
- {
- // The object with the larger interest value should be earlier in the list, so we reverse the sense of the comparison here.
- return (i1->getInterest() > i2->getInterest());
- }
-}
-
-static bool proximity_comparitor(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2)
-{
- if(i1->getProximityDistance() < i2->getProximityDistance())
- {
- return true;
- }
- else if(i1->getProximityDistance() > i2->getProximityDistance())
- {
- return false;
- }
- else
- {
- // Both objects have the same distance. This most likely means they're two faces of the same object.
- // They may also be faces on different objects with exactly the same distance (like HUD objects).
- // We don't actually care what the sort order is for this case, as long as it's stable and doesn't change when you enable/disable media.
- // Comparing the impl pointers gives a completely arbitrary ordering, but it will be stable.
- return (i1 < i2);
- }
-}
-
-static LLFastTimer::DeclareTimer FTM_MEDIA_UPDATE("Update Media");
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::updateMedia(void *dummy_arg)
-{
- LLFastTimer t1(FTM_MEDIA_UPDATE);
-
- // Enable/disable the plugin read thread
- LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread"));
-
- // HACK: we always try to keep a spare running webkit plugin around to improve launch times.
- createSpareBrowserMediaSource();
-
- sAnyMediaShowing = false;
- sUpdatedCookies = getCookieStore()->getChangedCookies();
- if(!sUpdatedCookies.empty())
- {
- lldebugs << "updated cookies will be sent to all loaded plugins: " << llendl;
- lldebugs << sUpdatedCookies << llendl;
- }
-
- impl_list::iterator iter = sViewerMediaImplList.begin();
- impl_list::iterator end = sViewerMediaImplList.end();
-
- for(; iter != end;)
- {
- LLViewerMediaImpl* pimpl = *iter++;
- pimpl->update();
- pimpl->calculateInterest();
- }
-
- // Let the spare media source actually launch
- if(sSpareBrowserMediaSource)
- {
- sSpareBrowserMediaSource->idle();
- }
-
- // Sort the static instance list using our interest criteria
- sViewerMediaImplList.sort(priorityComparitor);
-
- // Go through the list again and adjust according to priority.
- iter = sViewerMediaImplList.begin();
- end = sViewerMediaImplList.end();
-
- F64 total_cpu = 0.0f;
- int impl_count_total = 0;
- int impl_count_interest_low = 0;
- int impl_count_interest_normal = 0;
-
- std::vector<LLViewerMediaImpl*> proximity_order;
-
- bool inworld_media_enabled = gSavedSettings.getBOOL("AudioStreamingMedia");
- bool inworld_audio_enabled = gSavedSettings.getBOOL("AudioStreamingMusic");
- U32 max_instances = gSavedSettings.getU32("PluginInstancesTotal");
- U32 max_normal = gSavedSettings.getU32("PluginInstancesNormal");
- U32 max_low = gSavedSettings.getU32("PluginInstancesLow");
- F32 max_cpu = gSavedSettings.getF32("PluginInstancesCPULimit");
- // Setting max_cpu to 0.0 disables CPU usage checking.
- bool check_cpu_usage = (max_cpu != 0.0f);
-
- LLViewerMediaImpl* lowest_interest_loadable = NULL;
-
- // Notes on tweakable params:
- // max_instances must be set high enough to allow the various instances used in the UI (for the help browser, search, etc.) to be loaded.
- // If max_normal + max_low is less than max_instances, things will tend to get unloaded instead of being set to slideshow.
-
- for(; iter != end; iter++)
- {
- LLViewerMediaImpl* pimpl = *iter;
-
- LLPluginClassMedia::EPriority new_priority = LLPluginClassMedia::PRIORITY_NORMAL;
-
- if(pimpl->isForcedUnloaded() || (impl_count_total >= (int)max_instances))
- {
- // Never load muted or failed impls.
- // Hard limit on the number of instances that will be loaded at one time
- new_priority = LLPluginClassMedia::PRIORITY_UNLOADED;
- }
- else if(!pimpl->getVisible())
- {
- new_priority = LLPluginClassMedia::PRIORITY_HIDDEN;
- }
- else if(pimpl->hasFocus())
- {
- new_priority = LLPluginClassMedia::PRIORITY_HIGH;
- impl_count_interest_normal++; // count this against the count of "normal" instances for priority purposes
- }
- else if(pimpl->getUsedInUI())
- {
- new_priority = LLPluginClassMedia::PRIORITY_NORMAL;
- impl_count_interest_normal++;
- }
- else if(pimpl->isParcelMedia())
- {
- new_priority = LLPluginClassMedia::PRIORITY_NORMAL;
- impl_count_interest_normal++;
- }
- else
- {
- // Look at interest and CPU usage for instances that aren't in any of the above states.
-
- // Heuristic -- if the media texture's approximate screen area is less than 1/4 of the native area of the texture,
- // turn it down to low instead of normal. This may downsample for plugins that support it.
- bool media_is_small = false;
- F64 approximate_interest = pimpl->getApproximateTextureInterest();
- if(approximate_interest == 0.0f)
- {
- // this media has no current size, which probably means it's not loaded.
- media_is_small = true;
- }
- else if(pimpl->getInterest() < (approximate_interest / 4))
- {
- media_is_small = true;
- }
-
- if(pimpl->getInterest() == 0.0f)
- {
- // This media is completely invisible, due to being outside the view frustrum or out of range.
- new_priority = LLPluginClassMedia::PRIORITY_HIDDEN;
- }
- else if(check_cpu_usage && (total_cpu > max_cpu))
- {
- // Higher priority plugins have already used up the CPU budget. Set remaining ones to slideshow priority.
- new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW;
- }
- else if((impl_count_interest_normal < (int)max_normal) && !media_is_small)
- {
- // Up to max_normal inworld get normal priority
- new_priority = LLPluginClassMedia::PRIORITY_NORMAL;
- impl_count_interest_normal++;
- }
- else if (impl_count_interest_low + impl_count_interest_normal < (int)max_low + (int)max_normal)
- {
- // The next max_low inworld get turned down
- new_priority = LLPluginClassMedia::PRIORITY_LOW;
- impl_count_interest_low++;
-
- // Set the low priority size for downsampling to approximately the size the texture is displayed at.
- {
- F32 approximate_interest_dimension = fsqrtf(pimpl->getInterest());
-
- pimpl->setLowPrioritySizeLimit(llround(approximate_interest_dimension));
- }
- }
- else
- {
- // Any additional impls (up to max_instances) get very infrequent time
- new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW;
- }
- }
-
- if(!pimpl->getUsedInUI() && (new_priority != LLPluginClassMedia::PRIORITY_UNLOADED))
- {
- // This is a loadable inworld impl -- the last one in the list in this class defines the lowest loadable interest.
- lowest_interest_loadable = pimpl;
-
- impl_count_total++;
- }
-
- // Overrides if the window is minimized or we lost focus (taking care
- // not to accidentally "raise" the priority either)
- if (!gViewerWindow->getActive() /* viewer window minimized? */
- && new_priority > LLPluginClassMedia::PRIORITY_HIDDEN)
- {
- new_priority = LLPluginClassMedia::PRIORITY_HIDDEN;
- }
- else if (!gFocusMgr.getAppHasFocus() /* viewer window lost focus? */
- && new_priority > LLPluginClassMedia::PRIORITY_LOW)
- {
- new_priority = LLPluginClassMedia::PRIORITY_LOW;
- }
-
- if(!inworld_media_enabled)
- {
- // If inworld media is locked out, force all inworld media to stay unloaded.
- if(!pimpl->getUsedInUI())
- {
- new_priority = LLPluginClassMedia::PRIORITY_UNLOADED;
- }
- }
- // update the audio stream here as well
- if( !inworld_audio_enabled)
- {
- if(LLViewerMedia::isParcelAudioPlaying() && gAudiop && LLViewerMedia::hasParcelAudio())
- {
- gAudiop->stopInternetStream();
- }
- }
- pimpl->setPriority(new_priority);
-
- if(pimpl->getUsedInUI())
- {
- // Any impls used in the UI should not be in the proximity list.
- pimpl->mProximity = -1;
- }
- else
- {
- proximity_order.push_back(pimpl);
- }
-
- total_cpu += pimpl->getCPUUsage();
-
- if (!pimpl->getUsedInUI() && pimpl->hasMedia())
- {
- sAnyMediaShowing = true;
- }
-
- }
-
- // Re-calculate this every time.
- sLowestLoadableImplInterest = 0.0f;
-
- // Only do this calculation if we've hit the impl count limit -- up until that point we always need to load media data.
- if(lowest_interest_loadable && (impl_count_total >= (int)max_instances))
- {
- // Get the interest value of this impl's object for use by isInterestingEnough
- LLVOVolume *object = lowest_interest_loadable->getSomeObject();
- if(object)
- {
- // NOTE: Don't use getMediaInterest() here. We want the pixel area, not the total media interest,
- // so that we match up with the calculation done in LLMediaDataClient.
- sLowestLoadableImplInterest = object->getPixelArea();
- }
- }
-
- if(gSavedSettings.getBOOL("MediaPerformanceManagerDebug"))
- {
- // Give impls the same ordering as the priority list
- // they're already in the right order for this.
- }
- else
- {
- // Use a distance-based sort for proximity values.
- std::stable_sort(proximity_order.begin(), proximity_order.end(), proximity_comparitor);
- }
-
- // Transfer the proximity order to the proximity fields in the objects.
- for(int i = 0; i < (int)proximity_order.size(); i++)
- {
- proximity_order[i]->mProximity = i;
- }
-
- LL_DEBUGS("PluginPriority") << "Total reported CPU usage is " << total_cpu << llendl;
-
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-bool LLViewerMedia::isAnyMediaShowing()
-{
- return sAnyMediaShowing;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::setAllMediaEnabled(bool val)
-{
- // Set "tentative" autoplay first. We need to do this here or else
- // re-enabling won't start up the media below.
- gSavedSettings.setBOOL("MediaTentativeAutoPlay", val);
-
- // Then
- impl_list::iterator iter = sViewerMediaImplList.begin();
- impl_list::iterator end = sViewerMediaImplList.end();
-
- for(; iter != end; iter++)
- {
- LLViewerMediaImpl* pimpl = *iter;
- if (!pimpl->getUsedInUI())
- {
- pimpl->setDisabled(!val);
- }
- }
-
- // Also do Parcel Media and Parcel Audio
- if (val)
- {
- if (!LLViewerMedia::isParcelMediaPlaying() && LLViewerMedia::hasParcelMedia())
- {
- LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel());
- }
-
- if (gSavedSettings.getBOOL("AudioStreamingMusic") &&
- !LLViewerMedia::isParcelAudioPlaying() &&
- gAudiop &&
- LLViewerMedia::hasParcelAudio())
- {
- gAudiop->startInternetStream(LLViewerMedia::getParcelAudioURL());
- }
- }
- else {
- // This actually unloads the impl, as opposed to "stop"ping the media
- LLViewerParcelMedia::stop();
- if (gAudiop) gAudiop->stopInternetStream();
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-bool LLViewerMedia::isParcelMediaPlaying()
-{
- return (LLViewerMedia::hasParcelMedia() && LLViewerParcelMedia::getParcelMedia() && LLViewerParcelMedia::getParcelMedia()->hasMedia());
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-bool LLViewerMedia::isParcelAudioPlaying()
-{
- return (LLViewerMedia::hasParcelAudio() && gAudiop && LLAudioEngine::AUDIO_PLAYING == gAudiop->isInternetStreamPlaying());
-}
-
-void LLViewerMedia::onAuthSubmit(const LLSD& notification, const LLSD& response)
-{
- LLViewerMediaImpl *impl = LLViewerMedia::getMediaImplFromTextureID(notification["payload"]["media_id"]);
- if(impl)
- {
- LLPluginClassMedia* media = impl->getMediaPlugin();
- if(media)
- {
- if (response["ok"])
- {
- media->sendAuthResponse(true, response["username"], response["password"]);
- }
- else
- {
- media->sendAuthResponse(false, "", "");
- }
- }
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::clearAllCookies()
-{
- // Clear all cookies for all plugins
- impl_list::iterator iter = sViewerMediaImplList.begin();
- impl_list::iterator end = sViewerMediaImplList.end();
- for (; iter != end; iter++)
- {
- LLViewerMediaImpl* pimpl = *iter;
- if(pimpl->mMediaSource)
- {
- pimpl->mMediaSource->clear_cookies();
- }
- }
-
- // Clear all cookies from the cookie store
- getCookieStore()->setAllCookies("");
-
- // FIXME: this may not be sufficient, since the on-disk cookie file won't get written until some browser instance exits cleanly.
- // It also won't clear cookies for other accounts, or for any account if we're not logged in, and won't do anything at all if there are no webkit plugins loaded.
- // Until such time as we can centralize cookie storage, the following hack should cover these cases:
-
- // HACK: Look for cookie files in all possible places and delete them.
- // NOTE: this assumes knowledge of what happens inside the webkit plugin (it's what adds 'browser_profile' to the path and names the cookie file)
-
- // Places that cookie files can be:
- // <getOSUserAppDir>/browser_profile/cookies
- // <getOSUserAppDir>/first_last/browser_profile/cookies (note that there may be any number of these!)
- // <getOSUserAppDir>/first_last/plugin_cookies.txt (note that there may be any number of these!)
-
- std::string base_dir = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter();
- std::string target;
- std::string filename;
-
- lldebugs << "base dir = " << base_dir << llendl;
-
- // The non-logged-in version is easy
- target = base_dir;
- target += "browser_profile";
- target += gDirUtilp->getDirDelimiter();
- target += "cookies";
- lldebugs << "target = " << target << llendl;
- if(LLFile::isfile(target))
- {
- LLFile::remove(target);
- }
-
- // the hard part: iterate over all user directories and delete the cookie file from each one
- while(gDirUtilp->getNextFileInDir(base_dir, "*_*", filename))
- {
- target = base_dir;
- target += filename;
- target += gDirUtilp->getDirDelimiter();
- target += "browser_profile";
- target += gDirUtilp->getDirDelimiter();
- target += "cookies";
- lldebugs << "target = " << target << llendl;
- if(LLFile::isfile(target))
- {
- LLFile::remove(target);
- }
-
- // Other accounts may have new-style cookie files too -- delete them as well
- target = base_dir;
- target += filename;
- target += gDirUtilp->getDirDelimiter();
- target += PLUGIN_COOKIE_FILE_NAME;
- lldebugs << "target = " << target << llendl;
- if(LLFile::isfile(target))
- {
- LLFile::remove(target);
- }
- }
-
- // If we have an OpenID cookie, re-add it to the cookie store.
- setOpenIDCookie();
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::clearAllCaches()
-{
- // Clear all plugins' caches
- impl_list::iterator iter = sViewerMediaImplList.begin();
- impl_list::iterator end = sViewerMediaImplList.end();
- for (; iter != end; iter++)
- {
- LLViewerMediaImpl* pimpl = *iter;
- pimpl->clearCache();
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::setCookiesEnabled(bool enabled)
-{
- // Set the "cookies enabled" flag for all loaded plugins
- impl_list::iterator iter = sViewerMediaImplList.begin();
- impl_list::iterator end = sViewerMediaImplList.end();
- for (; iter != end; iter++)
- {
- LLViewerMediaImpl* pimpl = *iter;
- if(pimpl->mMediaSource)
- {
- pimpl->mMediaSource->enable_cookies(enabled);
- }
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::setProxyConfig(bool enable, const std::string &host, int port)
-{
- // Set the proxy config for all loaded plugins
- impl_list::iterator iter = sViewerMediaImplList.begin();
- impl_list::iterator end = sViewerMediaImplList.end();
- for (; iter != end; iter++)
- {
- LLViewerMediaImpl* pimpl = *iter;
- if(pimpl->mMediaSource)
- {
- pimpl->mMediaSource->proxy_setup(enable, host, port);
- }
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-LLPluginCookieStore *LLViewerMedia::getCookieStore()
-{
- if(sCookieStore == NULL)
- {
- sCookieStore = new LLPluginCookieStore;
- }
-
- return sCookieStore;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::loadCookieFile()
-{
- // build filename for each user
- std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME);
-
- if (resolved_filename.empty())
- {
- llinfos << "can't get path to plugin cookie file - probably not logged in yet." << llendl;
- return;
- }
-
- // open the file for reading
- llifstream file(resolved_filename);
- if (!file.is_open())
- {
- llwarns << "can't load plugin cookies from file \"" << PLUGIN_COOKIE_FILE_NAME << "\"" << llendl;
- return;
- }
-
- getCookieStore()->readAllCookies(file, true);
-
- file.close();
-
- // send the clear_cookies message to all loaded plugins
- impl_list::iterator iter = sViewerMediaImplList.begin();
- impl_list::iterator end = sViewerMediaImplList.end();
- for (; iter != end; iter++)
- {
- LLViewerMediaImpl* pimpl = *iter;
- if(pimpl->mMediaSource)
- {
- pimpl->mMediaSource->clear_cookies();
- }
- }
-
- // If we have an OpenID cookie, re-add it to the cookie store.
- setOpenIDCookie();
-}
-
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::saveCookieFile()
-{
- // build filename for each user
- std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME);
-
- if (resolved_filename.empty())
- {
- llinfos << "can't get path to plugin cookie file - probably not logged in yet." << llendl;
- return;
- }
-
- // open a file for writing
- llofstream file (resolved_filename);
- if (!file.is_open())
- {
- llwarns << "can't open plugin cookie file \"" << PLUGIN_COOKIE_FILE_NAME << "\" for writing" << llendl;
- return;
- }
-
- getCookieStore()->writePersistentCookies(file);
-
- file.close();
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::addCookie(const std::string &name, const std::string &value, const std::string &domain, const LLDate &expires, const std::string &path, bool secure)
-{
- std::stringstream cookie;
-
- cookie << name << "=" << LLPluginCookieStore::quoteString(value);
-
- if(expires.notNull())
- {
- cookie << "; expires=" << expires.asRFC1123();
- }
-
- cookie << "; domain=" << domain;
-
- cookie << "; path=" << path;
-
- if(secure)
- {
- cookie << "; secure";
- }
-
- getCookieStore()->setCookies(cookie.str());
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::addSessionCookie(const std::string &name, const std::string &value, const std::string &domain, const std::string &path, bool secure)
-{
- // A session cookie just has a NULL date.
- addCookie(name, value, domain, LLDate(), path, secure);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::removeCookie(const std::string &name, const std::string &domain, const std::string &path )
-{
- // To remove a cookie, add one with the same name, domain, and path that expires in the past.
-
- addCookie(name, "", domain, LLDate(LLDate::now().secondsSinceEpoch() - 1.0), path);
-}
-
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::setOpenIDCookie()
-{
- if(!sOpenIDCookie.empty())
- {
- // The LLURL can give me the 'authority', which is of the form: [username[:password]@]hostname[:port]
- // We want just the hostname for the cookie code, but LLURL doesn't seem to have a way to extract that.
- // We therefore do it here.
- std::string authority = sOpenIDURL.mAuthority;
- std::string::size_type host_start = authority.find('@');
- if(host_start == std::string::npos)
- {
- // no username/password
- host_start = 0;
- }
- else
- {
- // Hostname starts after the @.
- // (If the hostname part is empty, this may put host_start at the end of the string. In that case, it will end up passing through an empty hostname, which is correct.)
- ++host_start;
- }
- std::string::size_type host_end = authority.rfind(':');
- if((host_end == std::string::npos) || (host_end < host_start))
- {
- // no port
- host_end = authority.size();
- }
-
- getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(host_start, host_end - host_start));
-
- // *HACK: Doing this here is nasty, find a better way.
- LLWebSharing::instance().setOpenIDCookie(sOpenIDCookie);
-
- // Do a web profile get so we can store the cookie
- LLSD headers = LLSD::emptyMap();
- headers["Accept"] = "*/*";
- headers["Cookie"] = sOpenIDCookie;
- headers["User-Agent"] = getCurrentUserAgent();
-
- std::string profile_url = getProfileURL("");
- LLURL raw_profile_url( profile_url.c_str() );
-
- LLHTTPClient::get(profile_url,
- new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()),
- headers);
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string &openid_token)
-{
- LL_DEBUGS("MediaAuth") << "url = \"" << openid_url << "\", token = \"" << openid_token << "\"" << LL_ENDL;
-
- // post the token to the url
- // the responder will need to extract the cookie(s).
-
- // Save the OpenID URL for later -- we may need the host when adding the cookie.
- sOpenIDURL.init(openid_url.c_str());
-
- // We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies.
- sOpenIDCookie.clear();
-
- LLSD headers = LLSD::emptyMap();
- // Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header
- headers["Accept"] = "*/*";
- // and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream"
- headers["Content-Type"] = "application/x-www-form-urlencoded";
-
- // postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here.
- size_t size = openid_token.size();
- U8 *data = new U8[size];
- memcpy(data, openid_token.data(), size);
-
- LLHTTPClient::postRaw(
- openid_url,
- data,
- size,
- new LLViewerMediaOpenIDResponder(),
- headers);
-
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::openIDCookieResponse(const std::string &cookie)
-{
- LL_DEBUGS("MediaAuth") << "Cookie received: \"" << cookie << "\"" << LL_ENDL;
-
- sOpenIDCookie += cookie;
-
- setOpenIDCookie();
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::proxyWindowOpened(const std::string &target, const std::string &uuid)
-{
- if(uuid.empty())
- return;
-
- for (impl_list::iterator iter = sViewerMediaImplList.begin(); iter != sViewerMediaImplList.end(); iter++)
- {
- if((*iter)->mMediaSource && (*iter)->mMediaSource->pluginSupportsMediaBrowser())
- {
- (*iter)->mMediaSource->proxyWindowOpened(target, uuid);
- }
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::proxyWindowClosed(const std::string &uuid)
-{
- if(uuid.empty())
- return;
-
- for (impl_list::iterator iter = sViewerMediaImplList.begin(); iter != sViewerMediaImplList.end(); iter++)
- {
- if((*iter)->mMediaSource && (*iter)->mMediaSource->pluginSupportsMediaBrowser())
- {
- (*iter)->mMediaSource->proxyWindowClosed(uuid);
- }
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::createSpareBrowserMediaSource()
-{
- // If we don't have a spare browser media source, create one.
- // However, if PluginAttachDebuggerToPlugins is set then don't spawn a spare
- // SLPlugin process in order to not be confused by an unrelated gdb terminal
- // popping up at the moment we start a media plugin.
- if (!sSpareBrowserMediaSource && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))
- {
- // The null owner will keep the browser plugin from fully initializing
- // (specifically, it keeps LLPluginClassMedia from negotiating a size change,
- // which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color)
- sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0);
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// static
-LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource()
-{
- LLPluginClassMedia* result = sSpareBrowserMediaSource;
- sSpareBrowserMediaSource = NULL;
- return result;
-};
-
-bool LLViewerMedia::hasInWorldMedia()
-{
- if (sInWorldMediaDisabled) return false;
- impl_list::iterator iter = sViewerMediaImplList.begin();
- impl_list::iterator end = sViewerMediaImplList.end();
- // This should be quick, because there should be very few non-in-world-media impls
- for (; iter != end; iter++)
- {
- LLViewerMediaImpl* pimpl = *iter;
- if (!pimpl->getUsedInUI() && !pimpl->isParcelMedia())
- {
- // Found an in-world media impl
- return true;
- }
- }
- return false;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-bool LLViewerMedia::hasParcelMedia()
-{
- return !LLViewerParcelMedia::getURL().empty();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-bool LLViewerMedia::hasParcelAudio()
-{
- return !LLViewerMedia::getParcelAudioURL().empty();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-std::string LLViewerMedia::getParcelAudioURL()
-{
- return LLViewerParcelMgr::getInstance()->getAgentParcel()->getMusicURL();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::initClass()
-{
- gIdleCallbacks.addFunction(LLViewerMedia::updateMedia, NULL);
- sTeleportFinishConnection = LLViewerParcelMgr::getInstance()->
- setTeleportFinishedCallback(boost::bind(&LLViewerMedia::onTeleportFinished));
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::cleanupClass()
-{
- gIdleCallbacks.deleteFunction(LLViewerMedia::updateMedia, NULL);
- sTeleportFinishConnection.disconnect();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// static
-void LLViewerMedia::onTeleportFinished()
-{
- // On teleport, clear this setting (i.e. set it to true)
- gSavedSettings.setBOOL("MediaTentativeAutoPlay", true);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// LLViewerMediaImpl
-//////////////////////////////////////////////////////////////////////////////////////////
-LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id,
- S32 media_width,
- S32 media_height,
- U8 media_auto_scale,
- U8 media_loop)
-:
- mMediaSource( NULL ),
- mMovieImageHasMips(false),
- mMediaWidth(media_width),
- mMediaHeight(media_height),
- mMediaAutoScale(media_auto_scale),
- mMediaLoop(media_loop),
- mNeedsNewTexture(true),
- mTextureUsedWidth(0),
- mTextureUsedHeight(0),
- mSuspendUpdates(false),
- mVisible(true),
- mLastSetCursor( UI_CURSOR_ARROW ),
- mMediaNavState( MEDIANAVSTATE_NONE ),
- mInterest(0.0f),
- mUsedInUI(false),
- mHasFocus(false),
- mPriority(LLPluginClassMedia::PRIORITY_UNLOADED),
- mNavigateRediscoverType(false),
- mNavigateServerRequest(false),
- mMediaSourceFailed(false),
- mRequestedVolume(1.0f),
- mIsMuted(false),
- mNeedsMuteCheck(false),
- mPreviousMediaState(MEDIA_NONE),
- mPreviousMediaTime(0.0f),
- mIsDisabled(false),
- mIsParcelMedia(false),
- mProximity(-1),
- mProximityDistance(0.0f),
- mMimeTypeProbe(NULL),
- mMediaAutoPlay(false),
- mInNearbyMediaList(false),
- mClearCache(false),
- mBackgroundColor(LLColor4::white),
- mNavigateSuspended(false),
- mNavigateSuspendedDeferred(false),
- mIsUpdated(false),
- mTrustedBrowser(false)
-{
-
- // Set up the mute list observer if it hasn't been set up already.
- if(!sViewerMediaMuteListObserverInitialized)
- {
- LLMuteList::getInstance()->addObserver(&sViewerMediaMuteListObserver);
- sViewerMediaMuteListObserverInitialized = true;
- }
-
- add_media_impl(this);
-
- setTextureID(texture_id);
-
- // connect this media_impl to the media texture, creating it if it doesn't exist.0
- // This is necessary because we need to be able to use getMaxVirtualSize() even if the media plugin is not loaded.
- LLViewerMediaTexture* media_tex = LLViewerTextureManager::getMediaTexture(mTextureId);
- if(media_tex)
- {
- media_tex->setMediaImpl();
- }
-
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-LLViewerMediaImpl::~LLViewerMediaImpl()
-{
- destroyMediaSource();
-
- LLViewerMediaTexture::removeMediaImplFromTexture(mTextureId) ;
-
- setTextureID();
- remove_media_impl(this);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::emitEvent(LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event)
-{
- // Broadcast to observers using the superclass version
- LLViewerMediaEventEmitter::emitEvent(plugin, event);
-
- // If this media is on one or more LLVOVolume objects, tell them about the event as well.
- std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ;
- while(iter != mObjectList.end())
- {
- LLVOVolume *self = *iter;
- ++iter;
- self->mediaEvent(this, plugin, event);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type)
-{
- bool mimeTypeChanged = (mMimeType != mime_type);
- bool pluginChanged = (LLMIMETypes::implType(mCurrentMimeType) != LLMIMETypes::implType(mime_type));
-
- if(!mMediaSource || pluginChanged)
- {
- // We don't have a plugin at all, or the new mime type is handled by a different plugin than the old mime type.
- (void)initializePlugin(mime_type);
- }
- else if(mimeTypeChanged)
- {
- // The same plugin should be able to handle the new media -- just update the stored mime type.
- mMimeType = mime_type;
- }
-
- return (mMediaSource != NULL);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::createMediaSource()
-{
- if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
- {
- // This media shouldn't be created yet.
- return;
- }
-
- if(! mMediaURL.empty())
- {
- navigateInternal();
- }
- else if(! mMimeType.empty())
- {
- if (!initializeMedia(mMimeType))
- {
- LL_WARNS("Media") << "Failed to initialize media for mime type " << mMimeType << LL_ENDL;
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::destroyMediaSource()
-{
- mNeedsNewTexture = true;
-
- // Tell the viewer media texture it's no longer active
- LLViewerMediaTexture* oldImage = LLViewerTextureManager::findMediaTexture( mTextureId );
- if (oldImage)
- {
- oldImage->setPlaying(FALSE) ;
- }
-
- cancelMimeTypeProbe();
-
- if(mMediaSource)
- {
- mMediaSource->setDeleteOK(true) ;
- delete mMediaSource;
- mMediaSource = NULL;
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::setMediaType(const std::string& media_type)
-{
- mMimeType = media_type;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-/*static*/
-LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target)
-{
- std::string plugin_basename = LLMIMETypes::implType(media_type);
- LLPluginClassMedia* media_source = NULL;
-
- // HACK: we always try to keep a spare running webkit plugin around to improve launch times.
- // If a spare was already created before PluginAttachDebuggerToPlugins was set, don't use it.
- if(plugin_basename == "media_plugin_webkit" && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))
- {
- media_source = LLViewerMedia::getSpareBrowserMediaSource();
- if(media_source)
- {
- media_source->setOwner(owner);
- media_source->setTarget(target);
- media_source->setSize(default_width, default_height);
-
- return media_source;
- }
- }
-
- if(plugin_basename.empty())
- {
- LL_WARNS("Media") << "Couldn't find plugin for media type " << media_type << LL_ENDL;
- }
- else
- {
- std::string launcher_name = gDirUtilp->getLLPluginLauncher();
- std::string plugin_name = gDirUtilp->getLLPluginFilename(plugin_basename);
- std::string user_data_path = gDirUtilp->getOSUserAppDir();
- user_data_path += gDirUtilp->getDirDelimiter();
-
- // Fix for EXT-5960 - make browser profile specific to user (cache, cookies etc.)
- // If the linden username returned is blank, that can only mean we are
- // at the login page displaying login Web page or Web browser test via Develop menu.
- // In this case we just use whatever gDirUtilp->getOSUserAppDir() gives us (this
- // is what we always used before this change)
- std::string linden_user_dir = gDirUtilp->getLindenUserDir();
- if ( ! linden_user_dir.empty() )
- {
- // gDirUtilp->getLindenUserDir() is whole path, not just Linden name
- user_data_path = linden_user_dir;
- user_data_path += gDirUtilp->getDirDelimiter();
- };
-
- // See if the plugin executable exists
- llstat s;
- if(LLFile::stat(launcher_name, &s))
- {
- LL_WARNS("Media") << "Couldn't find launcher at " << launcher_name << LL_ENDL;
- }
- else if(LLFile::stat(plugin_name, &s))
- {
- LL_WARNS("Media") << "Couldn't find plugin at " << plugin_name << LL_ENDL;
- }
- else
- {
- media_source = new LLPluginClassMedia(owner);
- media_source->setSize(default_width, default_height);
- media_source->setUserDataPath(user_data_path);
- media_source->setLanguageCode(LLUI::getLanguage());
-
- // collect 'cookies enabled' setting from prefs and send to embedded browser
- bool cookies_enabled = gSavedSettings.getBOOL( "CookiesEnabled" );
- media_source->enable_cookies( cookies_enabled );
-
- // collect 'plugins enabled' setting from prefs and send to embedded browser
- bool plugins_enabled = gSavedSettings.getBOOL( "BrowserPluginsEnabled" );
- media_source->setPluginsEnabled( plugins_enabled );
-
- // collect 'javascript enabled' setting from prefs and send to embedded browser
- bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" );
- media_source->setJavascriptEnabled( javascript_enabled );
-
- media_source->setTarget(target);
-
- const std::string plugin_dir = gDirUtilp->getLLPluginDir();
- if (media_source->init(launcher_name, plugin_dir, plugin_name, gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")))
- {
- return media_source;
- }
- else
- {
- LL_WARNS("Media") << "Failed to init plugin. Destroying." << LL_ENDL;
- delete media_source;
- }
- }
- }
-
- LL_WARNS("Plugin") << "plugin intialization failed for mime type: " << media_type << LL_ENDL;
- LLSD args;
- args["MIME_TYPE"] = media_type;
- LLNotificationsUtil::add("NoPlugin", args);
-
- return NULL;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
-{
- if(mMediaSource)
- {
- // Save the previous media source's last set size before destroying it.
- mMediaWidth = mMediaSource->getSetWidth();
- mMediaHeight = mMediaSource->getSetHeight();
- }
-
- // Always delete the old media impl first.
- destroyMediaSource();
-
- // and unconditionally set the mime type
- mMimeType = media_type;
-
- if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
- {
- // This impl should not be loaded at this time.
- LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL;
-
- return false;
- }
-
- // If we got here, we want to ignore previous init failures.
- mMediaSourceFailed = false;
-
- // Save the MIME type that really caused the plugin to load
- mCurrentMimeType = mMimeType;
-
- LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight, mTarget);
-
- if (media_source)
- {
- media_source->setDisableTimeout(gSavedSettings.getBOOL("DebugPluginDisableTimeout"));
- media_source->setLoop(mMediaLoop);
- media_source->setAutoScale(mMediaAutoScale);
- media_source->setBrowserUserAgent(LLViewerMedia::getCurrentUserAgent());
- media_source->focus(mHasFocus);
- media_source->setBackgroundColor(mBackgroundColor);
-
- if(gSavedSettings.getBOOL("BrowserIgnoreSSLCertErrors"))
- {
- media_source->ignore_ssl_cert_errors(true);
- }
-
- // the correct way to deal with certs it to load ours from CA.pem and append them to the ones
- // Qt/WebKit loads from your system location.
- // Note: This needs the new CA.pem file with the Equifax Secure Certificate Authority
- // cert at the bottom: (MIIDIDCCAomgAwIBAgIENd70zzANBg)
- std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "CA.pem" );
- media_source->addCertificateFilePath( ca_path );
-
- media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort"));
-
- if(mClearCache)
- {
- mClearCache = false;
- media_source->clear_cache();
- }
-
- // TODO: Only send cookies to plugins that need them
- // Ideally, the plugin should tell us whether it handles cookies or not -- either via the init response or through a separate message.
- // Due to the ordering of messages, it's possible we wouldn't get that information back in time to send cookies before sending a navigate message,
- // which could cause odd race conditions.
- std::string all_cookies = LLViewerMedia::getCookieStore()->getAllCookies();
- lldebugs << "setting cookies: " << all_cookies << llendl;
- if(!all_cookies.empty())
- {
- media_source->set_cookies(all_cookies);
- }
-
- mMediaSource = media_source;
- mMediaSource->setDeleteOK(false) ;
- updateVolume();
-
- return true;
- }
-
- // Make sure the timer doesn't try re-initing this plugin repeatedly until something else changes.
- mMediaSourceFailed = true;
-
- return false;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::loadURI()
-{
- if(mMediaSource)
- {
- // trim whitespace from front and back of URL - fixes EXT-5363
- LLStringUtil::trim( mMediaURL );
-
- // *HACK: we don't know if the URI coming in is properly escaped
- // (the contract doesn't specify whether it is escaped or not.
- // but LLQtWebKit expects it to be, so we do our best to encode
- // special characters)
- // The strings below were taken right from http://www.ietf.org/rfc/rfc1738.txt
- // Note especially that '%' and '/' are there.
- std::string uri = LLURI::escape(mMediaURL,
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- "0123456789"
- "$-_.+"
- "!*'(),"
- "{}|\\^~[]`"
- "<>#%"
- ";/?:@&=",
- false);
- llinfos << "Asking media source to load URI: " << uri << llendl;
-
- mMediaSource->loadURI( uri );
-
- // A non-zero mPreviousMediaTime means that either this media was previously unloaded by the priority code while playing/paused,
- // or a seek happened before the media loaded. In either case, seek to the saved time.
- if(mPreviousMediaTime != 0.0f)
- {
- seek(mPreviousMediaTime);
- }
-
- if(mPreviousMediaState == MEDIA_PLAYING)
- {
- // This media was playing before this instance was unloaded.
- start();
- }
- else if(mPreviousMediaState == MEDIA_PAUSED)
- {
- // This media was paused before this instance was unloaded.
- pause();
- }
- else
- {
- // No relevant previous media play state -- if we're loading the URL, we want to start playing.
- start();
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::setSize(int width, int height)
-{
- mMediaWidth = width;
- mMediaHeight = height;
- if(mMediaSource)
- {
- mMediaSource->setSize(width, height);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::showNotification(LLNotificationPtr notify)
-{
- mNotification = notify;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::hideNotification()
-{
- mNotification.reset();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::play()
-{
- // If the media source isn't there, try to initialize it and load an URL.
- if(mMediaSource == NULL)
- {
- if(!initializeMedia(mMimeType))
- {
- // This may be the case where the plugin's priority is PRIORITY_UNLOADED
- return;
- }
-
- // Only do this if the media source was just loaded.
- loadURI();
- }
-
- // always start the media
- start();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::stop()
-{
- if(mMediaSource)
- {
- mMediaSource->stop();
- // destroyMediaSource();
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::pause()
-{
- if(mMediaSource)
- {
- mMediaSource->pause();
- }
- else
- {
- mPreviousMediaState = MEDIA_PAUSED;
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::start()
-{
- if(mMediaSource)
- {
- mMediaSource->start();
- }
- else
- {
- mPreviousMediaState = MEDIA_PLAYING;
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::seek(F32 time)
-{
- if(mMediaSource)
- {
- mMediaSource->seek(time);
- }
- else
- {
- // Save the seek time to be set when the media is loaded.
- mPreviousMediaTime = time;
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::skipBack(F32 step_scale)
-{
- if(mMediaSource)
- {
- if(mMediaSource->pluginSupportsMediaTime())
- {
- F64 back_step = mMediaSource->getCurrentTime() - (mMediaSource->getDuration()*step_scale);
- if(back_step < 0.0)
- {
- back_step = 0.0;
- }
- mMediaSource->seek(back_step);
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::skipForward(F32 step_scale)
-{
- if(mMediaSource)
- {
- if(mMediaSource->pluginSupportsMediaTime())
- {
- F64 forward_step = mMediaSource->getCurrentTime() + (mMediaSource->getDuration()*step_scale);
- if(forward_step > mMediaSource->getDuration())
- {
- forward_step = mMediaSource->getDuration();
- }
- mMediaSource->seek(forward_step);
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::setVolume(F32 volume)
-{
- mRequestedVolume = volume;
- updateVolume();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::updateVolume()
-{
- if(mMediaSource)
- {
- // always scale the volume by the global media volume
- F32 volume = mRequestedVolume * LLViewerMedia::getVolume();
-
- if (mProximityCamera > 0)
- {
- if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMax"))
- {
- volume = 0;
- }
- else if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMin"))
- {
- // attenuated_volume = 1 / (roll_off_rate * (d - min))^2
- // the +1 is there so that for distance 0 the volume stays the same
- F64 adjusted_distance = mProximityCamera - gSavedSettings.getF32("MediaRollOffMin");
- F64 attenuation = 1.0 + (gSavedSettings.getF32("MediaRollOffRate") * adjusted_distance);
- attenuation = 1.0 / (attenuation * attenuation);
- // the attenuation multiplier should never be more than one since that would increase volume
- volume = volume * llmin(1.0, attenuation);
- }
- }
-
- mMediaSource->setVolume(volume);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-F32 LLViewerMediaImpl::getVolume()
-{
- return mRequestedVolume;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::focus(bool focus)
-{
- mHasFocus = focus;
-
- if (mMediaSource)
- {
- // call focus just for the hell of it, even though this apopears to be a nop
- mMediaSource->focus(focus);
- if (focus)
- {
- // spoof a mouse click to *actually* pass focus
- // Don't do this anymore -- it actually clicks through now.
-// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, 1, 1, 0);
-// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 1, 1, 0);
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-bool LLViewerMediaImpl::hasFocus() const
-{
- // FIXME: This might be able to be a bit smarter by hooking into LLViewerMediaFocus, etc.
- return mHasFocus;
-}
-
-std::string LLViewerMediaImpl::getCurrentMediaURL()
-{
- if(!mCurrentMediaURL.empty())
- {
- return mCurrentMediaURL;
- }
-
- return mMediaURL;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::clearCache()
-{
- if(mMediaSource)
- {
- mMediaSource->clear_cache();
- }
- else
- {
- mClearCache = true;
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::mouseDown(S32 x, S32 y, MASK mask, S32 button)
-{
- scaleMouse(&x, &y);
- mLastMouseX = x;
- mLastMouseY = y;
-// llinfos << "mouse down (" << x << ", " << y << ")" << llendl;
- if (mMediaSource)
- {
- mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, button, x, y, mask);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::mouseUp(S32 x, S32 y, MASK mask, S32 button)
-{
- scaleMouse(&x, &y);
- mLastMouseX = x;
- mLastMouseY = y;
-// llinfos << "mouse up (" << x << ", " << y << ")" << llendl;
- if (mMediaSource)
- {
- mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, button, x, y, mask);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::mouseMove(S32 x, S32 y, MASK mask)
-{
- scaleMouse(&x, &y);
- mLastMouseX = x;
- mLastMouseY = y;
-// llinfos << "mouse move (" << x << ", " << y << ")" << llendl;
- if (mMediaSource)
- {
- mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, x, y, mask);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-//static
-void LLViewerMediaImpl::scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y)
-{
- F32 texture_x = texture_coords.mV[VX];
- F32 texture_y = texture_coords.mV[VY];
-
- // Deal with repeating textures by wrapping the coordinates into the range [0, 1.0)
- texture_x = fmodf(texture_x, 1.0f);
- if(texture_x < 0.0f)
- texture_x = 1.0 + texture_x;
-
- texture_y = fmodf(texture_y, 1.0f);
- if(texture_y < 0.0f)
- texture_y = 1.0 + texture_y;
-
- // scale x and y to texel units.
- *x = llround(texture_x * mMediaSource->getTextureWidth());
- *y = llround((1.0f - texture_y) * mMediaSource->getTextureHeight());
-
- // Adjust for the difference between the actual texture height and the amount of the texture in use.
- *y -= (mMediaSource->getTextureHeight() - mMediaSource->getHeight());
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::mouseDown(const LLVector2& texture_coords, MASK mask, S32 button)
-{
- if(mMediaSource)
- {
- S32 x, y;
- scaleTextureCoords(texture_coords, &x, &y);
-
- mouseDown(x, y, mask, button);
- }
-}
-
-void LLViewerMediaImpl::mouseUp(const LLVector2& texture_coords, MASK mask, S32 button)
-{
- if(mMediaSource)
- {
- S32 x, y;
- scaleTextureCoords(texture_coords, &x, &y);
-
- mouseUp(x, y, mask, button);
- }
-}
-
-void LLViewerMediaImpl::mouseMove(const LLVector2& texture_coords, MASK mask)
-{
- if(mMediaSource)
- {
- S32 x, y;
- scaleTextureCoords(texture_coords, &x, &y);
-
- mouseMove(x, y, mask);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button)
-{
- scaleMouse(&x, &y);
- mLastMouseX = x;
- mLastMouseY = y;
- if (mMediaSource)
- {
- mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOUBLE_CLICK, button, x, y, mask);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::scrollWheel(S32 x, S32 y, MASK mask)
-{
- scaleMouse(&x, &y);
- mLastMouseX = x;
- mLastMouseY = y;
- if (mMediaSource)
- {
- mMediaSource->scrollEvent(x, y, mask);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::onMouseCaptureLost()
-{
- if (mMediaSource)
- {
- mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 0, mLastMouseX, mLastMouseY, 0);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-BOOL LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask)
-{
- // NOTE: this is called when the mouse is released when we have capture.
- // Due to the way mouse coordinates are mapped to the object, we can't use the x and y coordinates that come in with the event.
-
- if(hasMouseCapture())
- {
- // Release the mouse -- this will also send a mouseup to the media
- gFocusMgr.setMouseCapture( FALSE );
- }
-
- return TRUE;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::updateJavascriptObject()
-{
- if ( mMediaSource )
- {
- // flag to expose this information to internal browser or not.
- bool expose_javascript_object = gSavedSettings.getBOOL("BrowserEnableJSObject");
- mMediaSource->jsExposeObjectEvent( expose_javascript_object );
-
- // indicate if the values we have are valid (currently do this blanket-fashion for
- // everything depending on whether you are logged in or not - this may require a
- // more granular approach once variables are added that ARE valid before login
- bool logged_in = LLLoginInstance::getInstance()->authSuccess();
- mMediaSource->jsValuesValidEvent( logged_in );
-
- // current location within a region
- LLVector3 agent_pos = gAgent.getPositionAgent();
- double x = agent_pos.mV[ VX ];
- double y = agent_pos.mV[ VY ];
- double z = agent_pos.mV[ VZ ];
- mMediaSource->jsAgentLocationEvent( x, y, z );
-
- // current region agent is in
- std::string region_name("");
- LLViewerRegion* region = gAgent.getRegion();
- if ( region )
- {
- region_name = region->getName();
- };
- mMediaSource->jsAgentRegionEvent( region_name );
-
- // language code the viewer is set to
- mMediaSource->jsAgentLanguageEvent( LLUI::getLanguage() );
-
- // maturity setting the agent has selected
- if ( gAgent.prefersAdult() )
- mMediaSource->jsAgentMaturityEvent( "GMA" ); // Adult means see adult, mature and general content
- else
- if ( gAgent.prefersMature() )
- mMediaSource->jsAgentMaturityEvent( "GM" ); // Mature means see mature and general content
- else
- if ( gAgent.prefersPG() )
- mMediaSource->jsAgentMaturityEvent( "G" ); // PG means only see General content
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-std::string LLViewerMediaImpl::getName() const
-{
- if (mMediaSource)
- {
- return mMediaSource->getMediaName();
- }
-
- return LLStringUtil::null;
-};
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::navigateBack()
-{
- if (mMediaSource)
- {
- mMediaSource->browse_back();
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::navigateForward()
-{
- if (mMediaSource)
- {
- mMediaSource->browse_forward();
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::navigateReload()
-{
- navigateTo(getCurrentMediaURL(), "", true, false);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::navigateHome()
-{
- bool rediscover_mimetype = mHomeMimeType.empty();
- navigateTo(mHomeURL, mHomeMimeType, rediscover_mimetype, false);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::unload()
-{
- // Unload the media impl and clear its state.
- destroyMediaSource();
- resetPreviousMediaState();
- mMediaURL.clear();
- mMimeType.clear();
- mCurrentMediaURL.clear();
- mCurrentMimeType.clear();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type, bool server_request)
-{
- cancelMimeTypeProbe();
-
- if(mMediaURL != url)
- {
- // Don't carry media play state across distinct URLs.
- resetPreviousMediaState();
- }
-
- // Always set the current URL and MIME type.
- mMediaURL = url;
- mMimeType = mime_type;
-
- // Clear the current media URL, since it will no longer be correct.
- mCurrentMediaURL.clear();
-
- // if mime type discovery was requested, we'll need to do it when the media loads
- mNavigateRediscoverType = rediscover_type;
-
- // and if this was a server request, the navigate on load will also need to be one.
- mNavigateServerRequest = server_request;
-
- // An explicit navigate resets the "failed" flag.
- mMediaSourceFailed = false;
-
- if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
- {
- // Helpful to have media urls in log file. Shouldn't be spammy.
- llinfos << "NOT LOADING media id= " << mTextureId << " url=" << url << " mime_type=" << mime_type << llendl;
-
- // This impl should not be loaded at this time.
- LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL;
-
- return;
- }
-
- navigateInternal();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::navigateInternal()
-{
- // Helpful to have media urls in log file. Shouldn't be spammy.
- llinfos << "media id= " << mTextureId << " url=" << mMediaURL << " mime_type=" << mMimeType << llendl;
-
- if(mNavigateSuspended)
- {
- llwarns << "Deferring navigate." << llendl;
- mNavigateSuspendedDeferred = true;
- return;
- }
-
- if(mMimeTypeProbe != NULL)
- {
- llwarns << "MIME type probe already in progress -- bailing out." << llendl;
- return;
- }
-
- if(mNavigateServerRequest)
- {
- setNavState(MEDIANAVSTATE_SERVER_SENT);
- }
- else
- {
- setNavState(MEDIANAVSTATE_NONE);
- }
-
- // If the caller has specified a non-empty MIME type, look that up in our MIME types list.
- // If we have a plugin for that MIME type, use that instead of attempting auto-discovery.
- // This helps in supporting legacy media content where the server the media resides on returns a bogus MIME type
- // but the parcel owner has correctly set the MIME type in the parcel media settings.
-
- if(!mMimeType.empty() && (mMimeType != LLMIMETypes::getDefaultMimeType()))
- {
- std::string plugin_basename = LLMIMETypes::implType(mMimeType);
- if(!plugin_basename.empty())
- {
- // We have a plugin for this mime type
- mNavigateRediscoverType = false;
- }
- }
-
- if(mNavigateRediscoverType)
- {
-
- LLURI uri(mMediaURL);
- std::string scheme = uri.scheme();
-
- if(scheme.empty() || "http" == scheme || "https" == scheme)
- {
- // If we don't set an Accept header, LLHTTPClient will add one like this:
- // Accept: application/llsd+xml
- // which is really not what we want.
- LLSD headers = LLSD::emptyMap();
- headers["Accept"] = "*/*";
- // Allow cookies in the response, to prevent a redirect loop when accessing join.secondlife.com
- headers["Cookie"] = "";
- LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this), headers, 10.0f);
- }
- else if("data" == scheme || "file" == scheme || "about" == scheme)
- {
- // FIXME: figure out how to really discover the type for these schemes
- // We use "data" internally for a text/html url for loading the login screen
- if(initializeMedia("text/html"))
- {
- loadURI();
- }
- }
- else
- {
- // This catches 'rtsp://' urls
- if(initializeMedia(scheme))
- {
- loadURI();
- }
- }
- }
- else if(initializeMedia(mMimeType))
- {
- loadURI();
- }
- else
- {
- LL_WARNS("Media") << "Couldn't navigate to: " << mMediaURL << " as there is no media type for: " << mMimeType << LL_ENDL;
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::navigateStop()
-{
- if(mMediaSource)
- {
- mMediaSource->browse_stop();
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask)
-{
- bool result = false;
-
- if (mMediaSource)
- {
- // FIXME: THIS IS SO WRONG.
- // Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it...
- if( MASK_CONTROL & mask )
- {
- result = true;
- }
-
- if(!result)
- {
-
- LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData();
-
- result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask, native_key_data);
- // Since the viewer internal event dispatching doesn't give us key-up events, simulate one here.
- (void)mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP ,key, mask, native_key_data);
- }
- }
-
- return result;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char)
-{
- bool result = false;
-
- if (mMediaSource)
- {
- // only accept 'printable' characters, sigh...
- if (uni_char >= 32 // discard 'control' characters
- && uni_char != 127) // SDL thinks this is 'delete' - yuck.
- {
- LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData();
-
- mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE), native_key_data);
- }
- }
-
- return result;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-bool LLViewerMediaImpl::canNavigateForward()
-{
- BOOL result = FALSE;
- if (mMediaSource)
- {
- result = mMediaSource->getHistoryForwardAvailable();
- }
- return result;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-bool LLViewerMediaImpl::canNavigateBack()
-{
- BOOL result = FALSE;
- if (mMediaSource)
- {
- result = mMediaSource->getHistoryBackAvailable();
- }
- return result;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::update()
-{
- if(mMediaSource == NULL)
- {
- if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
- {
- // This media source should not be loaded.
- }
- else if(mPriority <= LLPluginClassMedia::PRIORITY_SLIDESHOW)
- {
- // Don't load new instances that are at PRIORITY_SLIDESHOW or below. They're just kept around to preserve state.
- }
- else if(mMimeTypeProbe != NULL)
- {
- // this media source is doing a MIME type probe -- don't try loading it again.
- }
- else
- {
- // This media may need to be loaded.
- if(sMediaCreateTimer.hasExpired())
- {
- LL_DEBUGS("PluginPriority") << this << ": creating media based on timer expiration" << LL_ENDL;
- createMediaSource();
- sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY);
- }
- else
- {
- LL_DEBUGS("PluginPriority") << this << ": NOT creating media (waiting on timer)" << LL_ENDL;
- }
- }
- }
- else
- {
- updateVolume();
-
- // TODO: this is updated every frame - is this bad?
- updateJavascriptObject();
-
- // If we didn't just create the impl, it may need to get cookie updates.
- if(!sUpdatedCookies.empty())
- {
- // TODO: Only send cookies to plugins that need them
- mMediaSource->set_cookies(sUpdatedCookies);
- }
- }
-
-
- if(mMediaSource == NULL)
- {
- return;
- }
-
- // Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash.
- setNavigateSuspended(true);
-
- mMediaSource->idle();
-
- setNavigateSuspended(false);
-
- if(mMediaSource == NULL)
- {
- return;
- }
-
- if(mMediaSource->isPluginExited())
- {
- resetPreviousMediaState();
- destroyMediaSource();
- return;
- }
-
- if(!mMediaSource->textureValid())
- {
- return;
- }
-
- if(mSuspendUpdates || !mVisible)
- {
- return;
- }
-
- LLViewerMediaTexture* placeholder_image = updatePlaceholderImage();
-
- if(placeholder_image)
- {
- LLRect dirty_rect;
-
- // Since we're updating this texture, we know it's playing. Tell the texture to do its replacement magic so it gets rendered.
- placeholder_image->setPlaying(TRUE);
-
- if(mMediaSource->getDirty(&dirty_rect))
- {
- // Constrain the dirty rect to be inside the texture
- S32 x_pos = llmax(dirty_rect.mLeft, 0);
- S32 y_pos = llmax(dirty_rect.mBottom, 0);
- S32 width = llmin(dirty_rect.mRight, placeholder_image->getWidth()) - x_pos;
- S32 height = llmin(dirty_rect.mTop, placeholder_image->getHeight()) - y_pos;
-
- if(width > 0 && height > 0)
- {
-
- U8* data = mMediaSource->getBitsData();
-
- // Offset the pixels pointer to match x_pos and y_pos
- data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() );
- data += ( y_pos * mMediaSource->getTextureDepth() );
-
- placeholder_image->setSubImage(
- data,
- mMediaSource->getBitsWidth(),
- mMediaSource->getBitsHeight(),
- x_pos,
- y_pos,
- width,
- height);
-
- }
-
- mMediaSource->resetDirty();
- }
- }
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::updateImagesMediaStreams()
-{
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////////
-LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage()
-{
- if(mTextureId.isNull())
- {
- // The code that created this instance will read from the plugin's bits.
- return NULL;
- }
-
- LLViewerMediaTexture* placeholder_image = LLViewerTextureManager::getMediaTexture( mTextureId );
-
- if (mNeedsNewTexture
- || placeholder_image->getUseMipMaps()
- || (placeholder_image->getWidth() != mMediaSource->getTextureWidth())
- || (placeholder_image->getHeight() != mMediaSource->getTextureHeight())
- || (mTextureUsedWidth != mMediaSource->getWidth())
- || (mTextureUsedHeight != mMediaSource->getHeight())
- )
- {
- LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL;
- LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL;
-
- int texture_width = mMediaSource->getTextureWidth();
- int texture_height = mMediaSource->getTextureHeight();
- int texture_depth = mMediaSource->getTextureDepth();
-
- // MEDIAOPT: check to see if size actually changed before doing work
- placeholder_image->destroyGLTexture();
- // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work?
- placeholder_image->reinit(FALSE); // probably not needed
-
- // MEDIAOPT: seems insane that we actually have to make an imageraw then
- // immediately discard it
- LLPointer<LLImageRaw> raw = new LLImageRaw(texture_width, texture_height, texture_depth);
- // Clear the texture to the background color, ignoring alpha.
- // convert background color channels from [0.0, 1.0] to [0, 255];
- raw->clear(int(mBackgroundColor.mV[VX] * 255.0f), int(mBackgroundColor.mV[VY] * 255.0f), int(mBackgroundColor.mV[VZ] * 255.0f), 0xff);
- int discard_level = 0;
-
- // ask media source for correct GL image format constants
- placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(),
- mMediaSource->getTextureFormatPrimary(),
- mMediaSource->getTextureFormatType(),
- mMediaSource->getTextureFormatSwapBytes());
-
- placeholder_image->createGLTexture(discard_level, raw);
-
- // MEDIAOPT: set this dynamically on play/stop
- // FIXME
-// placeholder_image->mIsMediaTexture = true;
- mNeedsNewTexture = false;
-
- // If the amount of the texture being drawn by the media goes down in either width or height,
- // recreate the texture to avoid leaving parts of the old image behind.
- mTextureUsedWidth = mMediaSource->getWidth();
- mTextureUsedHeight = mMediaSource->getHeight();
- }
-
- return placeholder_image;
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////////
-LLUUID LLViewerMediaImpl::getMediaTextureID() const
-{
- return mTextureId;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::setVisible(bool visible)
-{
- mVisible = visible;
-
- if(mVisible)
- {
- if(mMediaSource && mMediaSource->isPluginExited())
- {
- destroyMediaSource();
- }
-
- if(!mMediaSource)
- {
- createMediaSource();
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::mouseCapture()
-{
- gFocusMgr.setMouseCapture(this);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::scaleMouse(S32 *mouse_x, S32 *mouse_y)
-{
-#if 0
- S32 media_width, media_height;
- S32 texture_width, texture_height;
- getMediaSize( &media_width, &media_height );
- getTextureSize( &texture_width, &texture_height );
- S32 y_delta = texture_height - media_height;
-
- *mouse_y -= y_delta;
-#endif
-}
-
-
-
-//////////////////////////////////////////////////////////////////////////////////////////
-bool LLViewerMediaImpl::isMediaTimeBased()
-{
- bool result = false;
-
- if(mMediaSource)
- {
- result = mMediaSource->pluginSupportsMediaTime();
- }
-
- return result;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-bool LLViewerMediaImpl::isMediaPlaying()
-{
- bool result = false;
-
- if(mMediaSource)
- {
- EMediaStatus status = mMediaSource->getStatus();
- if(status == MEDIA_PLAYING || status == MEDIA_LOADING)
- result = true;
- }
-
- return result;
-}
-//////////////////////////////////////////////////////////////////////////////////////////
-bool LLViewerMediaImpl::isMediaPaused()
-{
- bool result = false;
-
- if(mMediaSource)
- {
- if(mMediaSource->getStatus() == MEDIA_PAUSED)
- result = true;
- }
-
- return result;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-//
-bool LLViewerMediaImpl::hasMedia() const
-{
- return mMediaSource != NULL;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-//
-void LLViewerMediaImpl::resetPreviousMediaState()
-{
- mPreviousMediaState = MEDIA_NONE;
- mPreviousMediaTime = 0.0f;
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////////
-//
-void LLViewerMediaImpl::setDisabled(bool disabled, bool forcePlayOnEnable)
-{
- if(mIsDisabled != disabled)
- {
- // Only do this on actual state transitions.
- mIsDisabled = disabled;
-
- if(mIsDisabled)
- {
- // We just disabled this media. Clear all state.
- unload();
- }
- else
- {
- // We just (re)enabled this media. Do a navigate if auto-play is in order.
- if(isAutoPlayable() || forcePlayOnEnable)
- {
- navigateTo(mMediaEntryURL, "", true, true);
- }
- }
-
- }
-};
-
-//////////////////////////////////////////////////////////////////////////////////////////
-//
-bool LLViewerMediaImpl::isForcedUnloaded() const
-{
- if(mIsMuted || mMediaSourceFailed || mIsDisabled)
- {
- return true;
- }
-
- if(sInWorldMediaDisabled)
- {
- // When inworld media is disabled, all instances that aren't marked as "used in UI" will not be loaded.
- if(!mUsedInUI)
- {
- return true;
- }
- }
-
- // If this media's class is not supposed to be shown, unload
- if (!shouldShowBasedOnClass())
- {
- return true;
- }
-
- return false;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-//
-bool LLViewerMediaImpl::isPlayable() const
-{
- if(isForcedUnloaded())
- {
- // All of the forced-unloaded criteria also imply not playable.
- return false;
- }
-
- if(hasMedia())
- {
- // Anything that's already playing is, by definition, playable.
- return true;
- }
-
- if(!mMediaURL.empty())
- {
- // If something has navigated the instance, it's ready to be played.
- return true;
- }
-
- return false;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginClassMediaOwner::EMediaEvent event)
-{
- bool pass_through = true;
- switch(event)
- {
- case MEDIA_EVENT_CLICK_LINK_NOFOLLOW:
- {
- LL_DEBUGS("Media") << "MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is: " << plugin->getClickURL() << LL_ENDL;
- std::string url = plugin->getClickURL();
- std::string nav_type = plugin->getClickNavType();
- LLURLDispatcher::dispatch(url, nav_type, NULL, mTrustedBrowser);
- }
- break;
- case MEDIA_EVENT_CLICK_LINK_HREF:
- {
- LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << plugin->getClickTarget() << "\", uri is " << plugin->getClickURL() << LL_ENDL;
- };
- break;
- case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH:
- {
- // The plugin failed to load properly. Make sure the timer doesn't retry.
- // TODO: maybe mark this plugin as not loadable somehow?
- mMediaSourceFailed = true;
-
- // Reset the last known state of the media to defaults.
- resetPreviousMediaState();
-
- // TODO: may want a different message for this case?
- LLSD args;
- args["PLUGIN"] = LLMIMETypes::implType(mCurrentMimeType);
- LLNotificationsUtil::add("MediaPluginFailed", args);
- }
- break;
-
- case MEDIA_EVENT_PLUGIN_FAILED:
- {
- // The plugin crashed.
- mMediaSourceFailed = true;
-
- // Reset the last known state of the media to defaults.
- resetPreviousMediaState();
-
- LLSD args;
- args["PLUGIN"] = LLMIMETypes::implType(mCurrentMimeType);
- // SJB: This is getting called every frame if the plugin fails to load, continuously respawining the alert!
- //LLNotificationsUtil::add("MediaPluginFailed", args);
- }
- break;
-
- case MEDIA_EVENT_CURSOR_CHANGED:
- {
- LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << plugin->getCursorName() << LL_ENDL;
-
- std::string cursor = plugin->getCursorName();
-
- if(cursor == "arrow")
- mLastSetCursor = UI_CURSOR_ARROW;
- else if(cursor == "ibeam")
- mLastSetCursor = UI_CURSOR_IBEAM;
- else if(cursor == "splith")
- mLastSetCursor = UI_CURSOR_SIZEWE;
- else if(cursor == "splitv")
- mLastSetCursor = UI_CURSOR_SIZENS;
- else if(cursor == "hand")
- mLastSetCursor = UI_CURSOR_HAND;
- else // for anything else, default to the arrow
- mLastSetCursor = UI_CURSOR_ARROW;
- }
- break;
-
- case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_BEGIN:
- {
- LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_BEGIN, uri is: " << plugin->getNavigateURI() << LL_ENDL;
- hideNotification();
-
- if(getNavState() == MEDIANAVSTATE_SERVER_SENT)
- {
- setNavState(MEDIANAVSTATE_SERVER_BEGUN);
- }
- else
- {
- setNavState(MEDIANAVSTATE_BEGUN);
- }
- }
- break;
-
- case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE:
- {
- LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_COMPLETE, uri is: " << plugin->getNavigateURI() << LL_ENDL;
-
- std::string url = plugin->getNavigateURI();
- if(getNavState() == MEDIANAVSTATE_BEGUN)
- {
- if(mCurrentMediaURL == url)
- {
- // This is a navigate that takes us to the same url as the previous navigate.
- setNavState(MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS);
- }
- else
- {
- mCurrentMediaURL = url;
- setNavState(MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED);
- }
- }
- else if(getNavState() == MEDIANAVSTATE_SERVER_BEGUN)
- {
- mCurrentMediaURL = url;
- setNavState(MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED);
- }
- else
- {
- // all other cases need to leave the state alone.
- }
- }
- break;
-
- case LLViewerMediaObserver::MEDIA_EVENT_LOCATION_CHANGED:
- {
- LL_DEBUGS("Media") << "MEDIA_EVENT_LOCATION_CHANGED, uri is: " << plugin->getLocation() << LL_ENDL;
-
- std::string url = plugin->getLocation();
-
- if(getNavState() == MEDIANAVSTATE_BEGUN)
- {
- if(mCurrentMediaURL == url)
- {
- // This is a navigate that takes us to the same url as the previous navigate.
- setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS);
- }
- else
- {
- mCurrentMediaURL = url;
- setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED);
- }
- }
- else if(getNavState() == MEDIANAVSTATE_SERVER_BEGUN)
- {
- mCurrentMediaURL = url;
- setNavState(MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED);
- }
- else
- {
- // Don't track redirects.
- setNavState(MEDIANAVSTATE_NONE);
- }
- }
- break;
-
- case LLViewerMediaObserver::MEDIA_EVENT_PICK_FILE_REQUEST:
- {
- // Display a file picker
- std::string response;
-
- LLFilePicker& picker = LLFilePicker::instance();
- if (!picker.getOpenFile(LLFilePicker::FFLOAD_ALL))
- {
- // The user didn't pick a file -- the empty response string will indicate this.
- }
-
- response = picker.getFirstFile();
-
- plugin->sendPickFileResponse(response);
- }
- break;
-
-
- case LLViewerMediaObserver::MEDIA_EVENT_AUTH_REQUEST:
- {
- LLNotification::Params auth_request_params;
- auth_request_params.name = "AuthRequest";
-
- // pass in host name and realm for site (may be zero length but will always exist)
- LLSD args;
- LLURL raw_url( plugin->getAuthURL().c_str() );
- args["HOST_NAME"] = raw_url.getAuthority();
- args["REALM"] = plugin->getAuthRealm();
- auth_request_params.substitutions = args;
-
- auth_request_params.payload = LLSD().with("media_id", mTextureId);
- auth_request_params.functor.function = boost::bind(&LLViewerMedia::onAuthSubmit, _1, _2);
- LLNotifications::instance().add(auth_request_params);
- };
- break;
-
- case LLViewerMediaObserver::MEDIA_EVENT_CLOSE_REQUEST:
- {
- std::string uuid = plugin->getClickUUID();
-
- llinfos << "MEDIA_EVENT_CLOSE_REQUEST for uuid " << uuid << llendl;
-
- if(uuid.empty())
- {
- // This close request is directed at this instance, let it fall through.
- }
- else
- {
- // This close request is directed at another instance
- pass_through = false;
- LLFloaterMediaBrowser::closeRequest(uuid);
- LLFloaterWebContent::closeRequest(uuid);
- }
- }
- break;
-
- case LLViewerMediaObserver::MEDIA_EVENT_GEOMETRY_CHANGE:
- {
- std::string uuid = plugin->getClickUUID();
-
- llinfos << "MEDIA_EVENT_GEOMETRY_CHANGE for uuid " << uuid << llendl;
-
- if(uuid.empty())
- {
- // This geometry change request is directed at this instance, let it fall through.
- }
- else
- {
- // This request is directed at another instance
- pass_through = false;
- LLFloaterMediaBrowser::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight());
- LLFloaterWebContent::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight());
- }
- }
- break;
-
- default:
- break;
- }
-
- if(pass_through)
- {
- // Just chain the event to observers.
- emitEvent(plugin, event);
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// virtual
-void LLViewerMediaImpl::handleCookieSet(LLPluginClassMedia* self, const std::string &cookie)
-{
- LLViewerMedia::getCookieStore()->setCookies(cookie);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// virtual
-void
-LLViewerMediaImpl::cut()
-{
- if (mMediaSource)
- mMediaSource->cut();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// virtual
-BOOL
-LLViewerMediaImpl::canCut() const
-{
- if (mMediaSource)
- return mMediaSource->canCut();
- else
- return FALSE;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// virtual
-void
-LLViewerMediaImpl::copy()
-{
- if (mMediaSource)
- mMediaSource->copy();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// virtual
-BOOL
-LLViewerMediaImpl::canCopy() const
-{
- if (mMediaSource)
- return mMediaSource->canCopy();
- else
- return FALSE;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// virtual
-void
-LLViewerMediaImpl::paste()
-{
- if (mMediaSource)
- mMediaSource->paste();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// virtual
-BOOL
-LLViewerMediaImpl::canPaste() const
-{
- if (mMediaSource)
- return mMediaSource->canPaste();
- else
- return FALSE;
-}
-
-void LLViewerMediaImpl::setUpdated(BOOL updated)
-{
- mIsUpdated = updated ;
-}
-
-BOOL LLViewerMediaImpl::isUpdated()
-{
- return mIsUpdated ;
-}
-
-void LLViewerMediaImpl::calculateInterest()
-{
- LLViewerMediaTexture* texture = LLViewerTextureManager::findMediaTexture( mTextureId );
-
- if(texture != NULL)
- {
- mInterest = texture->getMaxVirtualSize();
- }
- else
- {
- // This will be a relatively common case now, since it will always be true for unloaded media.
- mInterest = 0.0f;
- }
-
- // Calculate distance from the avatar, for use in the proximity calculation.
- mProximityDistance = 0.0f;
- mProximityCamera = 0.0f;
- if(!mObjectList.empty())
- {
- // Just use the first object in the list. We could go through the list and find the closest object, but this should work well enough.
- std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ;
- LLVOVolume* objp = *iter ;
- llassert_always(objp != NULL) ;
-
- // The distance calculation is invalid for HUD attachments -- leave both mProximityDistance and mProximityCamera at 0 for them.
- if(!objp->isHUDAttachment())
- {
- LLVector3d obj_global = objp->getPositionGlobal() ;
- LLVector3d agent_global = gAgent.getPositionGlobal() ;
- LLVector3d global_delta = agent_global - obj_global ;
- mProximityDistance = global_delta.magVecSquared(); // use distance-squared because it's cheaper and sorts the same.
-
- LLVector3d camera_delta = gAgentCamera.getCameraPositionGlobal() - obj_global;
- mProximityCamera = camera_delta.magVec();
- }
- }
-
- if(mNeedsMuteCheck)
- {
- // Check all objects this instance is associated with, and those objects' owners, against the mute list
- mIsMuted = false;
-
- std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ;
- for(; iter != mObjectList.end() ; ++iter)
- {
- LLVOVolume *obj = *iter;
- llassert(obj);
- if (!obj) continue;
- if(LLMuteList::getInstance() &&
- LLMuteList::getInstance()->isMuted(obj->getID()))
- {
- mIsMuted = true;
- }
- else
- {
- // We won't have full permissions data for all objects. Attempt to mute objects when we can tell their owners are muted.
- if (LLSelectMgr::getInstance())
- {
- LLPermissions* obj_perm = LLSelectMgr::getInstance()->findObjectPermissions(obj);
- if(obj_perm)
- {
- if(LLMuteList::getInstance() &&
- LLMuteList::getInstance()->isMuted(obj_perm->getOwner()))
- mIsMuted = true;
- }
- }
- }
- }
-
- mNeedsMuteCheck = false;
- }
-}
-
-F64 LLViewerMediaImpl::getApproximateTextureInterest()
-{
- F64 result = 0.0f;
-
- if(mMediaSource)
- {
- result = mMediaSource->getFullWidth();
- result *= mMediaSource->getFullHeight();
- }
- else
- {
- // No media source is loaded -- all we have to go on is the texture size that has been set on the impl, if any.
- result = mMediaWidth;
- result *= mMediaHeight;
- }
-
- return result;
-}
-
-void LLViewerMediaImpl::setUsedInUI(bool used_in_ui)
-{
- mUsedInUI = used_in_ui;
-
- // HACK: Force elements used in UI to load right away.
- // This fixes some issues where UI code that uses the browser instance doesn't expect it to be unloaded.
- if(mUsedInUI && (mPriority == LLPluginClassMedia::PRIORITY_UNLOADED))
- {
- if(getVisible())
- {
- setPriority(LLPluginClassMedia::PRIORITY_NORMAL);
- }
- else
- {
- setPriority(LLPluginClassMedia::PRIORITY_HIDDEN);
- }
-
- createMediaSource();
- }
-};
-
-void LLViewerMediaImpl::setBackgroundColor(LLColor4 color)
-{
- mBackgroundColor = color;
-
- if(mMediaSource)
- {
- mMediaSource->setBackgroundColor(mBackgroundColor);
- }
-};
-
-F64 LLViewerMediaImpl::getCPUUsage() const
-{
- F64 result = 0.0f;
-
- if(mMediaSource)
- {
- result = mMediaSource->getCPUUsage();
- }
-
- return result;
-}
-
-void LLViewerMediaImpl::setPriority(LLPluginClassMedia::EPriority priority)
-{
- if(mPriority != priority)
- {
- LL_DEBUGS("PluginPriority")
- << "changing priority of media id " << mTextureId
- << " from " << LLPluginClassMedia::priorityToString(mPriority)
- << " to " << LLPluginClassMedia::priorityToString(priority)
- << LL_ENDL;
- }
-
- mPriority = priority;
-
- if(priority == LLPluginClassMedia::PRIORITY_UNLOADED)
- {
- if(mMediaSource)
- {
- // Need to unload the media source
-
- // First, save off previous media state
- mPreviousMediaState = mMediaSource->getStatus();
- mPreviousMediaTime = mMediaSource->getCurrentTime();
-
- destroyMediaSource();
- }
- }
-
- if(mMediaSource)
- {
- mMediaSource->setPriority(mPriority);
- }
-
- // NOTE: loading (or reloading) media sources whose priority has risen above PRIORITY_UNLOADED is done in update().
-}
-
-void LLViewerMediaImpl::setLowPrioritySizeLimit(int size)
-{
- if(mMediaSource)
- {
- mMediaSource->setLowPrioritySizeLimit(size);
- }
-}
-
-void LLViewerMediaImpl::setNavState(EMediaNavState state)
-{
- mMediaNavState = state;
-
- switch (state)
- {
- case MEDIANAVSTATE_NONE: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_NONE" << llendl; break;
- case MEDIANAVSTATE_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_BEGUN" << llendl; break;
- case MEDIANAVSTATE_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED" << llendl; break;
- case MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS" << llendl; break;
- case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED" << llendl; break;
- case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS" << llendl; break;
- case MEDIANAVSTATE_SERVER_SENT: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_SENT" << llendl; break;
- case MEDIANAVSTATE_SERVER_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_BEGUN" << llendl; break;
- case MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED" << llendl; break;
- case MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED" << llendl; break;
- }
-}
-
-void LLViewerMediaImpl::setNavigateSuspended(bool suspend)
-{
- if(mNavigateSuspended != suspend)
- {
- mNavigateSuspended = suspend;
- if(!suspend)
- {
- // We're coming out of suspend. If someone tried to do a navigate while suspended, do one now instead.
- if(mNavigateSuspendedDeferred)
- {
- mNavigateSuspendedDeferred = false;
- navigateInternal();
- }
- }
- }
-}
-
-void LLViewerMediaImpl::cancelMimeTypeProbe()
-{
- if(mMimeTypeProbe != NULL)
- {
- // There doesn't seem to be a way to actually cancel an outstanding request.
- // Simulate it by telling the LLMimeDiscoveryResponder not to write back any results.
- mMimeTypeProbe->cancelRequest();
-
- // The above should already have set mMimeTypeProbe to NULL.
- if(mMimeTypeProbe != NULL)
- {
- llerrs << "internal error: mMimeTypeProbe is not NULL after cancelling request." << llendl;
- }
- }
-}
-
-void LLViewerMediaImpl::addObject(LLVOVolume* obj)
-{
- std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ;
- for(; iter != mObjectList.end() ; ++iter)
- {
- if(*iter == obj)
- {
- return ; //already in the list.
- }
- }
-
- mObjectList.push_back(obj) ;
- mNeedsMuteCheck = true;
-}
-
-void LLViewerMediaImpl::removeObject(LLVOVolume* obj)
-{
- mObjectList.remove(obj) ;
- mNeedsMuteCheck = true;
-}
-
-const std::list< LLVOVolume* >* LLViewerMediaImpl::getObjectList() const
-{
- return &mObjectList ;
-}
-
-LLVOVolume *LLViewerMediaImpl::getSomeObject()
-{
- LLVOVolume *result = NULL;
-
- std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ;
- if(iter != mObjectList.end())
- {
- result = *iter;
- }
-
- return result;
-}
-
-void LLViewerMediaImpl::setTextureID(LLUUID id)
-{
- if(id != mTextureId)
- {
- if(mTextureId.notNull())
- {
- // Remove this item's entry from the map
- sViewerMediaTextureIDMap.erase(mTextureId);
- }
-
- if(id.notNull())
- {
- sViewerMediaTextureIDMap.insert(LLViewerMedia::impl_id_map::value_type(id, this));
- }
-
- mTextureId = id;
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-//
-bool LLViewerMediaImpl::isAutoPlayable() const
-{
- return (mMediaAutoPlay &&
- gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) &&
- gSavedSettings.getBOOL("MediaTentativeAutoPlay"));
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-//
-bool LLViewerMediaImpl::shouldShowBasedOnClass() const
-{
- // If this is parcel media or in the UI, return true always
- if (getUsedInUI() || isParcelMedia()) return true;
-
- bool attached_to_another_avatar = isAttachedToAnotherAvatar();
- bool inside_parcel = isInAgentParcel();
-
- // llinfos << " hasFocus = " << hasFocus() <<
- // " others = " << (attached_to_another_avatar && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING)) <<
- // " within = " << (inside_parcel && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING)) <<
- // " outside = " << (!inside_parcel && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING)) << llendl;
-
- // If it has focus, we should show it
- // This is incorrect, and causes EXT-6750 (disabled attachment media still plays)
-// if (hasFocus())
-// return true;
-
- // If it is attached to an avatar and the pref is off, we shouldn't show it
- if (attached_to_another_avatar)
- return gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING);
-
- if (inside_parcel)
- return gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING);
- else
- return gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-//
-bool LLViewerMediaImpl::isAttachedToAnotherAvatar() const
-{
- bool result = false;
-
- std::list< LLVOVolume* >::const_iterator iter = mObjectList.begin();
- std::list< LLVOVolume* >::const_iterator end = mObjectList.end();
- for ( ; iter != end; iter++)
- {
- if (isObjectAttachedToAnotherAvatar(*iter))
- {
- result = true;
- break;
- }
- }
- return result;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-//
-//static
-bool LLViewerMediaImpl::isObjectAttachedToAnotherAvatar(LLVOVolume *obj)
-{
- bool result = false;
- LLXform *xform = obj;
- // Walk up parent chain
- while (NULL != xform)
- {
- LLViewerObject *object = dynamic_cast<LLViewerObject*> (xform);
- if (NULL != object)
- {
- LLVOAvatar *avatar = object->asAvatar();
- if ((NULL != avatar) && (avatar != gAgentAvatarp))
- {
- result = true;
- break;
- }
- }
- xform = xform->getParent();
- }
- return result;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-//
-bool LLViewerMediaImpl::isInAgentParcel() const
-{
- bool result = false;
-
- std::list< LLVOVolume* >::const_iterator iter = mObjectList.begin();
- std::list< LLVOVolume* >::const_iterator end = mObjectList.end();
- for ( ; iter != end; iter++)
- {
- LLVOVolume *object = *iter;
- if (LLViewerMediaImpl::isObjectInAgentParcel(object))
- {
- result = true;
- break;
- }
- }
- return result;
-}
-
-LLNotificationPtr LLViewerMediaImpl::getCurrentNotification() const
-{
- return mNotification;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-//
-// static
-bool LLViewerMediaImpl::isObjectInAgentParcel(LLVOVolume *obj)
-{
- return (LLViewerParcelMgr::getInstance()->inAgentParcel(obj->getPositionGlobal()));
-}
+/** + * @file llviewermedia.cpp + * @brief Client interface to the media engine + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llagent.h" +#include "llagentcamera.h" +#include "llviewermedia.h" +#include "llviewermediafocus.h" +#include "llmimetypes.h" +#include "llmediaentry.h" +#include "llversioninfo.h" +#include "llviewercontrol.h" +#include "llviewertexture.h" +#include "llviewerparcelmedia.h" +#include "llviewerparcelmgr.h" +#include "llviewertexturelist.h" +#include "llvovolume.h" +#include "llpluginclassmedia.h" +#include "llplugincookiestore.h" +#include "llviewerwindow.h" +#include "llfocusmgr.h" +#include "llcallbacklist.h" +#include "llparcel.h" +#include "llaudioengine.h" // for gAudiop +#include "llurldispatcher.h" +#include "llvoavatar.h" +#include "llvoavatarself.h" +#include "llviewerregion.h" +#include "llwebsharing.h" // For LLWebSharing::setOpenIDCookie(), *TODO: find a better way to do this! +#include "llfilepicker.h" +#include "llnotifications.h" +#include "lldir.h" +#include "lldiriterator.h" +#include "llevent.h" // LLSimpleListener +#include "llnotificationsutil.h" +#include "lluuid.h" +#include "llkeyboard.h" +#include "llmutelist.h" +#include "llpanelprofile.h" +#include "llappviewer.h" +#include "lllogininstance.h" +//#include "llfirstuse.h" +#include "llwindow.h" + +#include "llfloatermediabrowser.h" // for handling window close requests and geometry change requests in media browser windows. +#include "llfloaterwebcontent.h" // for handling window close requests and geometry change requests in media browser windows. + +#include <boost/bind.hpp> // for SkinFolder listener +#include <boost/signals2.hpp> + +/*static*/ const char* LLViewerMedia::AUTO_PLAY_MEDIA_SETTING = "ParcelMediaAutoPlayEnable"; +/*static*/ const char* LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING = "MediaShowOnOthers"; +/*static*/ const char* LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING = "MediaShowWithinParcel"; +/*static*/ const char* LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING = "MediaShowOutsideParcel"; + + +// Move this to its own file. + +LLViewerMediaEventEmitter::~LLViewerMediaEventEmitter() +{ + observerListType::iterator iter = mObservers.begin(); + + while( iter != mObservers.end() ) + { + LLViewerMediaObserver *self = *iter; + iter++; + remObserver(self); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaEventEmitter::addObserver( LLViewerMediaObserver* observer ) +{ + if ( ! observer ) + return false; + + if ( std::find( mObservers.begin(), mObservers.end(), observer ) != mObservers.end() ) + return false; + + mObservers.push_back( observer ); + observer->mEmitters.push_back( this ); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaEventEmitter::remObserver( LLViewerMediaObserver* observer ) +{ + if ( ! observer ) + return false; + + mObservers.remove( observer ); + observer->mEmitters.remove(this); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// +void LLViewerMediaEventEmitter::emitEvent( LLPluginClassMedia* media, LLViewerMediaObserver::EMediaEvent event ) +{ + // Broadcast the event to any observers. + observerListType::iterator iter = mObservers.begin(); + while( iter != mObservers.end() ) + { + LLViewerMediaObserver *self = *iter; + ++iter; + self->handleMediaEvent( media, event ); + } +} + +// Move this to its own file. +LLViewerMediaObserver::~LLViewerMediaObserver() +{ + std::list<LLViewerMediaEventEmitter *>::iterator iter = mEmitters.begin(); + + while( iter != mEmitters.end() ) + { + LLViewerMediaEventEmitter *self = *iter; + iter++; + self->remObserver( this ); + } +} + + +// Move this to its own file. +// helper class that tries to download a URL from a web site and calls a method +// on the Panel Land Media and to discover the MIME type +class LLMimeDiscoveryResponder : public LLHTTPClient::Responder +{ +LOG_CLASS(LLMimeDiscoveryResponder); +public: + LLMimeDiscoveryResponder( viewer_media_t media_impl) + : mMediaImpl(media_impl), + mInitialized(false) + { + if(mMediaImpl->mMimeTypeProbe != NULL) + { + llerrs << "impl already has an outstanding responder" << llendl; + } + + mMediaImpl->mMimeTypeProbe = this; + } + + ~LLMimeDiscoveryResponder() + { + disconnectOwner(); + } + + virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) + { + std::string media_type = content["content-type"].asString(); + std::string::size_type idx1 = media_type.find_first_of(";"); + std::string mime_type = media_type.substr(0, idx1); + + lldebugs << "status is " << status << ", media type \"" << media_type << "\"" << llendl; + + // 2xx status codes indicate success. + // Most 4xx status codes are successful enough for our purposes. + // 499 is the error code for host not found, timeout, etc. + // 500 means "Internal Server error" but we decided it's okay to + // accept this and go past it in the MIME type probe + // 302 means the resource can be found temporarily in a different place - added this for join.secondlife.com + // 499 is a code specifc to join.secondlife.com (????) apparently safe to ignore +// if( ((status >= 200) && (status < 300)) || +// ((status >= 400) && (status < 499)) || +// (status == 500) || +// (status == 302) || +// (status == 499) +// ) + // We now no longer check the error code returned from the probe. + // If we have a mime type, use it. If not, default to the web plugin and let it handle error reporting. + if(1) + { + // The probe was successful. + if(mime_type.empty()) + { + // Some sites don't return any content-type header at all. + // Treat an empty mime type as text/html. + mime_type = "text/html"; + } + + completeAny(status, mime_type); + } + else + { + llwarns << "responder failed with status " << status << ", reason " << reason << llendl; + + if(mMediaImpl) + { + mMediaImpl->mMediaSourceFailed = true; + } + } + + } + + void completeAny(U32 status, const std::string& mime_type) + { + // the call to initializeMedia may disconnect the responder, which will clear mMediaImpl. + // Make a local copy so we can call loadURI() afterwards. + LLViewerMediaImpl *impl = mMediaImpl; + + if(impl && !mInitialized && ! mime_type.empty()) + { + if(impl->initializeMedia(mime_type)) + { + mInitialized = true; + impl->loadURI(); + disconnectOwner(); + } + } + } + + void cancelRequest() + { + disconnectOwner(); + } + +private: + void disconnectOwner() + { + if(mMediaImpl) + { + if(mMediaImpl->mMimeTypeProbe != this) + { + llerrs << "internal error: mMediaImpl->mMimeTypeProbe != this" << llendl; + } + + mMediaImpl->mMimeTypeProbe = NULL; + } + mMediaImpl = NULL; + } + + +public: + LLViewerMediaImpl *mMediaImpl; + bool mInitialized; +}; + +class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder +{ +LOG_CLASS(LLViewerMediaOpenIDResponder); +public: + LLViewerMediaOpenIDResponder( ) + { + } + + ~LLViewerMediaOpenIDResponder() + { + } + + /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) + { + LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; + LL_DEBUGS("MediaAuth") << content << LL_ENDL; + std::string cookie = content["set-cookie"].asString(); + + LLViewerMedia::openIDCookieResponse(cookie); + } + + /* virtual */ void completedRaw( + U32 status, + const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + // This is just here to disable the default behavior (attempting to parse the response as llsd). + // We don't care about the content of the response, only the set-cookie header. + } + +}; + +class LLViewerMediaWebProfileResponder : public LLHTTPClient::Responder +{ +LOG_CLASS(LLViewerMediaWebProfileResponder); +public: + LLViewerMediaWebProfileResponder(std::string host) + { + mHost = host; + } + + ~LLViewerMediaWebProfileResponder() + { + } + + /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) + { + LL_WARNS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; + LL_WARNS("MediaAuth") << content << LL_ENDL; + + std::string cookie = content["set-cookie"].asString(); + + LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost); + } + + void completedRaw( + U32 status, + const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + // This is just here to disable the default behavior (attempting to parse the response as llsd). + // We don't care about the content of the response, only the set-cookie header. + } + + std::string mHost; +}; + + +LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL; +LLURL LLViewerMedia::sOpenIDURL; +std::string LLViewerMedia::sOpenIDCookie; +LLPluginClassMedia* LLViewerMedia::sSpareBrowserMediaSource = NULL; +static LLViewerMedia::impl_list sViewerMediaImplList; +static LLViewerMedia::impl_id_map sViewerMediaTextureIDMap; +static LLTimer sMediaCreateTimer; +static const F32 LLVIEWERMEDIA_CREATE_DELAY = 1.0f; +static F32 sGlobalVolume = 1.0f; +static F64 sLowestLoadableImplInterest = 0.0f; +static bool sAnyMediaShowing = false; +static boost::signals2::connection sTeleportFinishConnection; +static std::string sUpdatedCookies; +static const char *PLUGIN_COOKIE_FILE_NAME = "plugin_cookies.txt"; + +////////////////////////////////////////////////////////////////////////////////////////// +static void add_media_impl(LLViewerMediaImpl* media) +{ + sViewerMediaImplList.push_back(media); +} + +////////////////////////////////////////////////////////////////////////////////////////// +static void remove_media_impl(LLViewerMediaImpl* media) +{ + LLViewerMedia::impl_list::iterator iter = sViewerMediaImplList.begin(); + LLViewerMedia::impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + if(media == *iter) + { + sViewerMediaImplList.erase(iter); + return; + } + } +} + +class LLViewerMediaMuteListObserver : public LLMuteListObserver +{ + /* virtual */ void onChange() { LLViewerMedia::muteListChanged();} +}; + +static LLViewerMediaMuteListObserver sViewerMediaMuteListObserver; +static bool sViewerMediaMuteListObserverInitialized = false; +static bool sInWorldMediaDisabled = false; + + +////////////////////////////////////////////////////////////////////////////////////////// +// LLViewerMedia + +////////////////////////////////////////////////////////////////////////////////////////// +// static +viewer_media_t LLViewerMedia::newMediaImpl( + const LLUUID& texture_id, + S32 media_width, + S32 media_height, + U8 media_auto_scale, + U8 media_loop) +{ + LLViewerMediaImpl* media_impl = getMediaImplFromTextureID(texture_id); + if(media_impl == NULL || texture_id.isNull()) + { + // Create the media impl + media_impl = new LLViewerMediaImpl(texture_id, media_width, media_height, media_auto_scale, media_loop); + } + else + { + media_impl->unload(); + media_impl->setTextureID(texture_id); + media_impl->mMediaWidth = media_width; + media_impl->mMediaHeight = media_height; + media_impl->mMediaAutoScale = media_auto_scale; + media_impl->mMediaLoop = media_loop; + } + + return media_impl; +} + +viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const std::string& previous_url, bool update_from_self) +{ + // Try to find media with the same media ID + viewer_media_t media_impl = getMediaImplFromTextureID(media_entry->getMediaID()); + + lldebugs << "called, current URL is \"" << media_entry->getCurrentURL() + << "\", previous URL is \"" << previous_url + << "\", update_from_self is " << (update_from_self?"true":"false") + << llendl; + + bool was_loaded = false; + bool needs_navigate = false; + + if(media_impl) + { + was_loaded = media_impl->hasMedia(); + + media_impl->setHomeURL(media_entry->getHomeURL()); + + media_impl->mMediaAutoScale = media_entry->getAutoScale(); + media_impl->mMediaLoop = media_entry->getAutoLoop(); + media_impl->mMediaWidth = media_entry->getWidthPixels(); + media_impl->mMediaHeight = media_entry->getHeightPixels(); + media_impl->mMediaAutoPlay = media_entry->getAutoPlay(); + media_impl->mMediaEntryURL = media_entry->getCurrentURL(); + if (media_impl->mMediaSource) + { + media_impl->mMediaSource->setAutoScale(media_impl->mMediaAutoScale); + media_impl->mMediaSource->setLoop(media_impl->mMediaLoop); + media_impl->mMediaSource->setSize(media_entry->getWidthPixels(), media_entry->getHeightPixels()); + } + + bool url_changed = (media_impl->mMediaEntryURL != previous_url); + if(media_impl->mMediaEntryURL.empty()) + { + if(url_changed) + { + // The current media URL is now empty. Unload the media source. + media_impl->unload(); + + lldebugs << "Unloading media instance (new current URL is empty)." << llendl; + } + } + else + { + // The current media URL is not empty. + // If (the media was already loaded OR the media was set to autoplay) AND this update didn't come from this agent, + // do a navigate. + bool auto_play = media_impl->isAutoPlayable(); + if((was_loaded || auto_play) && !update_from_self) + { + needs_navigate = url_changed; + } + + lldebugs << "was_loaded is " << (was_loaded?"true":"false") + << ", auto_play is " << (auto_play?"true":"false") + << ", needs_navigate is " << (needs_navigate?"true":"false") << llendl; + } + } + else + { + media_impl = newMediaImpl( + media_entry->getMediaID(), + media_entry->getWidthPixels(), + media_entry->getHeightPixels(), + media_entry->getAutoScale(), + media_entry->getAutoLoop()); + + media_impl->setHomeURL(media_entry->getHomeURL()); + media_impl->mMediaAutoPlay = media_entry->getAutoPlay(); + media_impl->mMediaEntryURL = media_entry->getCurrentURL(); + if(media_impl->isAutoPlayable()) + { + needs_navigate = true; + } + } + + if(media_impl) + { + if(needs_navigate) + { + media_impl->navigateTo(media_impl->mMediaEntryURL, "", true, true); + lldebugs << "navigating to URL " << media_impl->mMediaEntryURL << llendl; + } + else if(!media_impl->mMediaURL.empty() && (media_impl->mMediaURL != media_impl->mMediaEntryURL)) + { + // If we already have a non-empty media URL set and we aren't doing a navigate, update the media URL to match the media entry. + media_impl->mMediaURL = media_impl->mMediaEntryURL; + + // If this causes a navigate at some point (such as after a reload), it should be considered server-driven so it isn't broadcast. + media_impl->mNavigateServerRequest = true; + + lldebugs << "updating URL in the media impl to " << media_impl->mMediaEntryURL << llendl; + } + } + + return media_impl; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +LLViewerMediaImpl* LLViewerMedia::getMediaImplFromTextureID(const LLUUID& texture_id) +{ + LLViewerMediaImpl* result = NULL; + + // Look up the texture ID in the texture id->impl map. + impl_id_map::iterator iter = sViewerMediaTextureIDMap.find(texture_id); + if(iter != sViewerMediaTextureIDMap.end()) + { + result = iter->second; + } + + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +std::string LLViewerMedia::getCurrentUserAgent() +{ + // Don't use user-visible string to avoid + // punctuation and strange characters. + std::string skin_name = gSavedSettings.getString("SkinCurrent"); + + // Just in case we need to check browser differences in A/B test + // builds. + std::string channel = LLVersionInfo::getChannel(); + + // append our magic version number string to the browser user agent id + // See the HTTP 1.0 and 1.1 specifications for allowed formats: + // http://www.ietf.org/rfc/rfc1945.txt section 10.15 + // http://www.ietf.org/rfc/rfc2068.txt section 3.8 + // This was also helpful: + // http://www.mozilla.org/build/revised-user-agent-strings.html + std::ostringstream codec; + codec << "SecondLife/"; + codec << LLVersionInfo::getVersion(); + codec << " (" << channel << "; " << skin_name << " skin)"; + llinfos << codec.str() << llendl; + + return codec.str(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::updateBrowserUserAgent() +{ + std::string user_agent = getCurrentUserAgent(); + + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->mMediaSource && pimpl->mMediaSource->pluginSupportsMediaBrowser()) + { + pimpl->mMediaSource->setBrowserUserAgent(user_agent); + } + } + +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::handleSkinCurrentChanged(const LLSD& /*newvalue*/) +{ + // gSavedSettings is already updated when this function is called. + updateBrowserUserAgent(); + return true; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::textureHasMedia(const LLUUID& texture_id) +{ + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->getMediaTextureID() == texture_id) + { + return true; + } + } + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setVolume(F32 volume) +{ + if(volume != sGlobalVolume) + { + sGlobalVolume = volume; + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + pimpl->updateVolume(); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +F32 LLViewerMedia::getVolume() +{ + return sGlobalVolume; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::muteListChanged() +{ + // When the mute list changes, we need to check mute status on all impls. + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + pimpl->mNeedsMuteCheck = true; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setInWorldMediaDisabled(bool disabled) +{ + sInWorldMediaDisabled = disabled; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::getInWorldMediaDisabled() +{ + return sInWorldMediaDisabled; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::isInterestingEnough(const LLVOVolume *object, const F64 &object_interest) +{ + bool result = false; + + if (NULL == object) + { + result = false; + } + // Focused? Then it is interesting! + else if (LLViewerMediaFocus::getInstance()->getFocusedObjectID() == object->getID()) + { + result = true; + } + // Selected? Then it is interesting! + // XXX Sadly, 'contains()' doesn't take a const :( + else if (LLSelectMgr::getInstance()->getSelection()->contains(const_cast<LLVOVolume*>(object))) + { + result = true; + } + else + { + lldebugs << "object interest = " << object_interest << ", lowest loadable = " << sLowestLoadableImplInterest << llendl; + if(object_interest >= sLowestLoadableImplInterest) + result = true; + } + + return result; +} + +LLViewerMedia::impl_list &LLViewerMedia::getPriorityList() +{ + return sViewerMediaImplList; +} + +// This is the predicate function used to sort sViewerMediaImplList by priority. +bool LLViewerMedia::priorityComparitor(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2) +{ + if(i1->isForcedUnloaded() && !i2->isForcedUnloaded()) + { + // Muted or failed items always go to the end of the list, period. + return false; + } + else if(i2->isForcedUnloaded() && !i1->isForcedUnloaded()) + { + // Muted or failed items always go to the end of the list, period. + return true; + } + else if(i1->hasFocus()) + { + // The item with user focus always comes to the front of the list, period. + return true; + } + else if(i2->hasFocus()) + { + // The item with user focus always comes to the front of the list, period. + return false; + } + else if(i1->isParcelMedia()) + { + // The parcel media impl sorts above all other inworld media, unless one has focus. + return true; + } + else if(i2->isParcelMedia()) + { + // The parcel media impl sorts above all other inworld media, unless one has focus. + return false; + } + else if(i1->getUsedInUI() && !i2->getUsedInUI()) + { + // i1 is a UI element, i2 is not. This makes i1 "less than" i2, so it sorts earlier in our list. + return true; + } + else if(i2->getUsedInUI() && !i1->getUsedInUI()) + { + // i2 is a UI element, i1 is not. This makes i2 "less than" i1, so it sorts earlier in our list. + return false; + } + else if(i1->isPlayable() && !i2->isPlayable()) + { + // Playable items sort above ones that wouldn't play even if they got high enough priority + return true; + } + else if(!i1->isPlayable() && i2->isPlayable()) + { + // Playable items sort above ones that wouldn't play even if they got high enough priority + return false; + } + else if(i1->getInterest() == i2->getInterest()) + { + // Generally this will mean both objects have zero interest. In this case, sort on distance. + return (i1->getProximityDistance() < i2->getProximityDistance()); + } + else + { + // The object with the larger interest value should be earlier in the list, so we reverse the sense of the comparison here. + return (i1->getInterest() > i2->getInterest()); + } +} + +static bool proximity_comparitor(const LLViewerMediaImpl* i1, const LLViewerMediaImpl* i2) +{ + if(i1->getProximityDistance() < i2->getProximityDistance()) + { + return true; + } + else if(i1->getProximityDistance() > i2->getProximityDistance()) + { + return false; + } + else + { + // Both objects have the same distance. This most likely means they're two faces of the same object. + // They may also be faces on different objects with exactly the same distance (like HUD objects). + // We don't actually care what the sort order is for this case, as long as it's stable and doesn't change when you enable/disable media. + // Comparing the impl pointers gives a completely arbitrary ordering, but it will be stable. + return (i1 < i2); + } +} + +static LLFastTimer::DeclareTimer FTM_MEDIA_UPDATE("Update Media"); + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::updateMedia(void *dummy_arg) +{ + LLFastTimer t1(FTM_MEDIA_UPDATE); + + // Enable/disable the plugin read thread + LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread")); + + // HACK: we always try to keep a spare running webkit plugin around to improve launch times. + createSpareBrowserMediaSource(); + + sAnyMediaShowing = false; + sUpdatedCookies = getCookieStore()->getChangedCookies(); + if(!sUpdatedCookies.empty()) + { + lldebugs << "updated cookies will be sent to all loaded plugins: " << llendl; + lldebugs << sUpdatedCookies << llendl; + } + + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end;) + { + LLViewerMediaImpl* pimpl = *iter++; + pimpl->update(); + pimpl->calculateInterest(); + } + + // Let the spare media source actually launch + if(sSpareBrowserMediaSource) + { + sSpareBrowserMediaSource->idle(); + } + + // Sort the static instance list using our interest criteria + sViewerMediaImplList.sort(priorityComparitor); + + // Go through the list again and adjust according to priority. + iter = sViewerMediaImplList.begin(); + end = sViewerMediaImplList.end(); + + F64 total_cpu = 0.0f; + int impl_count_total = 0; + int impl_count_interest_low = 0; + int impl_count_interest_normal = 0; + + std::vector<LLViewerMediaImpl*> proximity_order; + + bool inworld_media_enabled = gSavedSettings.getBOOL("AudioStreamingMedia"); + bool inworld_audio_enabled = gSavedSettings.getBOOL("AudioStreamingMusic"); + U32 max_instances = gSavedSettings.getU32("PluginInstancesTotal"); + U32 max_normal = gSavedSettings.getU32("PluginInstancesNormal"); + U32 max_low = gSavedSettings.getU32("PluginInstancesLow"); + F32 max_cpu = gSavedSettings.getF32("PluginInstancesCPULimit"); + // Setting max_cpu to 0.0 disables CPU usage checking. + bool check_cpu_usage = (max_cpu != 0.0f); + + LLViewerMediaImpl* lowest_interest_loadable = NULL; + + // Notes on tweakable params: + // max_instances must be set high enough to allow the various instances used in the UI (for the help browser, search, etc.) to be loaded. + // If max_normal + max_low is less than max_instances, things will tend to get unloaded instead of being set to slideshow. + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + + LLPluginClassMedia::EPriority new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + + if(pimpl->isForcedUnloaded() || (impl_count_total >= (int)max_instances)) + { + // Never load muted or failed impls. + // Hard limit on the number of instances that will be loaded at one time + new_priority = LLPluginClassMedia::PRIORITY_UNLOADED; + } + else if(!pimpl->getVisible()) + { + new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; + } + else if(pimpl->hasFocus()) + { + new_priority = LLPluginClassMedia::PRIORITY_HIGH; + impl_count_interest_normal++; // count this against the count of "normal" instances for priority purposes + } + else if(pimpl->getUsedInUI()) + { + new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + impl_count_interest_normal++; + } + else if(pimpl->isParcelMedia()) + { + new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + impl_count_interest_normal++; + } + else + { + // Look at interest and CPU usage for instances that aren't in any of the above states. + + // Heuristic -- if the media texture's approximate screen area is less than 1/4 of the native area of the texture, + // turn it down to low instead of normal. This may downsample for plugins that support it. + bool media_is_small = false; + F64 approximate_interest = pimpl->getApproximateTextureInterest(); + if(approximate_interest == 0.0f) + { + // this media has no current size, which probably means it's not loaded. + media_is_small = true; + } + else if(pimpl->getInterest() < (approximate_interest / 4)) + { + media_is_small = true; + } + + if(pimpl->getInterest() == 0.0f) + { + // This media is completely invisible, due to being outside the view frustrum or out of range. + new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; + } + else if(check_cpu_usage && (total_cpu > max_cpu)) + { + // Higher priority plugins have already used up the CPU budget. Set remaining ones to slideshow priority. + new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW; + } + else if((impl_count_interest_normal < (int)max_normal) && !media_is_small) + { + // Up to max_normal inworld get normal priority + new_priority = LLPluginClassMedia::PRIORITY_NORMAL; + impl_count_interest_normal++; + } + else if (impl_count_interest_low + impl_count_interest_normal < (int)max_low + (int)max_normal) + { + // The next max_low inworld get turned down + new_priority = LLPluginClassMedia::PRIORITY_LOW; + impl_count_interest_low++; + + // Set the low priority size for downsampling to approximately the size the texture is displayed at. + { + F32 approximate_interest_dimension = fsqrtf(pimpl->getInterest()); + + pimpl->setLowPrioritySizeLimit(llround(approximate_interest_dimension)); + } + } + else + { + // Any additional impls (up to max_instances) get very infrequent time + new_priority = LLPluginClassMedia::PRIORITY_SLIDESHOW; + } + } + + if(!pimpl->getUsedInUI() && (new_priority != LLPluginClassMedia::PRIORITY_UNLOADED)) + { + // This is a loadable inworld impl -- the last one in the list in this class defines the lowest loadable interest. + lowest_interest_loadable = pimpl; + + impl_count_total++; + } + + // Overrides if the window is minimized or we lost focus (taking care + // not to accidentally "raise" the priority either) + if (!gViewerWindow->getActive() /* viewer window minimized? */ + && new_priority > LLPluginClassMedia::PRIORITY_HIDDEN) + { + new_priority = LLPluginClassMedia::PRIORITY_HIDDEN; + } + else if (!gFocusMgr.getAppHasFocus() /* viewer window lost focus? */ + && new_priority > LLPluginClassMedia::PRIORITY_LOW) + { + new_priority = LLPluginClassMedia::PRIORITY_LOW; + } + + if(!inworld_media_enabled) + { + // If inworld media is locked out, force all inworld media to stay unloaded. + if(!pimpl->getUsedInUI()) + { + new_priority = LLPluginClassMedia::PRIORITY_UNLOADED; + } + } + // update the audio stream here as well + if( !inworld_audio_enabled) + { + if(LLViewerMedia::isParcelAudioPlaying() && gAudiop && LLViewerMedia::hasParcelAudio()) + { + gAudiop->stopInternetStream(); + } + } + pimpl->setPriority(new_priority); + + if(pimpl->getUsedInUI()) + { + // Any impls used in the UI should not be in the proximity list. + pimpl->mProximity = -1; + } + else + { + proximity_order.push_back(pimpl); + } + + total_cpu += pimpl->getCPUUsage(); + + if (!pimpl->getUsedInUI() && pimpl->hasMedia()) + { + sAnyMediaShowing = true; + } + + } + + // Re-calculate this every time. + sLowestLoadableImplInterest = 0.0f; + + // Only do this calculation if we've hit the impl count limit -- up until that point we always need to load media data. + if(lowest_interest_loadable && (impl_count_total >= (int)max_instances)) + { + // Get the interest value of this impl's object for use by isInterestingEnough + LLVOVolume *object = lowest_interest_loadable->getSomeObject(); + if(object) + { + // NOTE: Don't use getMediaInterest() here. We want the pixel area, not the total media interest, + // so that we match up with the calculation done in LLMediaDataClient. + sLowestLoadableImplInterest = object->getPixelArea(); + } + } + + if(gSavedSettings.getBOOL("MediaPerformanceManagerDebug")) + { + // Give impls the same ordering as the priority list + // they're already in the right order for this. + } + else + { + // Use a distance-based sort for proximity values. + std::stable_sort(proximity_order.begin(), proximity_order.end(), proximity_comparitor); + } + + // Transfer the proximity order to the proximity fields in the objects. + for(int i = 0; i < (int)proximity_order.size(); i++) + { + proximity_order[i]->mProximity = i; + } + + LL_DEBUGS("PluginPriority") << "Total reported CPU usage is " << total_cpu << llendl; + +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::isAnyMediaShowing() +{ + return sAnyMediaShowing; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setAllMediaEnabled(bool val) +{ + // Set "tentative" autoplay first. We need to do this here or else + // re-enabling won't start up the media below. + gSavedSettings.setBOOL("MediaTentativeAutoPlay", val); + + // Then + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if (!pimpl->getUsedInUI()) + { + pimpl->setDisabled(!val); + } + } + + // Also do Parcel Media and Parcel Audio + if (val) + { + if (!LLViewerMedia::isParcelMediaPlaying() && LLViewerMedia::hasParcelMedia()) + { + LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel()); + } + + if (gSavedSettings.getBOOL("AudioStreamingMusic") && + !LLViewerMedia::isParcelAudioPlaying() && + gAudiop && + LLViewerMedia::hasParcelAudio()) + { + gAudiop->startInternetStream(LLViewerMedia::getParcelAudioURL()); + } + } + else { + // This actually unloads the impl, as opposed to "stop"ping the media + LLViewerParcelMedia::stop(); + if (gAudiop) gAudiop->stopInternetStream(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::isParcelMediaPlaying() +{ + return (LLViewerMedia::hasParcelMedia() && LLViewerParcelMedia::getParcelMedia() && LLViewerParcelMedia::getParcelMedia()->hasMedia()); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::isParcelAudioPlaying() +{ + return (LLViewerMedia::hasParcelAudio() && gAudiop && LLAudioEngine::AUDIO_PLAYING == gAudiop->isInternetStreamPlaying()); +} + +void LLViewerMedia::onAuthSubmit(const LLSD& notification, const LLSD& response) +{ + LLViewerMediaImpl *impl = LLViewerMedia::getMediaImplFromTextureID(notification["payload"]["media_id"]); + if(impl) + { + LLPluginClassMedia* media = impl->getMediaPlugin(); + if(media) + { + if (response["ok"]) + { + media->sendAuthResponse(true, response["username"], response["password"]); + } + else + { + media->sendAuthResponse(false, "", ""); + } + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::clearAllCookies() +{ + // Clear all cookies for all plugins + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->mMediaSource) + { + pimpl->mMediaSource->clear_cookies(); + } + } + + // Clear all cookies from the cookie store + getCookieStore()->setAllCookies(""); + + // FIXME: this may not be sufficient, since the on-disk cookie file won't get written until some browser instance exits cleanly. + // It also won't clear cookies for other accounts, or for any account if we're not logged in, and won't do anything at all if there are no webkit plugins loaded. + // Until such time as we can centralize cookie storage, the following hack should cover these cases: + + // HACK: Look for cookie files in all possible places and delete them. + // NOTE: this assumes knowledge of what happens inside the webkit plugin (it's what adds 'browser_profile' to the path and names the cookie file) + + // Places that cookie files can be: + // <getOSUserAppDir>/browser_profile/cookies + // <getOSUserAppDir>/first_last/browser_profile/cookies (note that there may be any number of these!) + // <getOSUserAppDir>/first_last/plugin_cookies.txt (note that there may be any number of these!) + + std::string base_dir = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter(); + std::string target; + std::string filename; + + lldebugs << "base dir = " << base_dir << llendl; + + // The non-logged-in version is easy + target = base_dir; + target += "browser_profile"; + target += gDirUtilp->getDirDelimiter(); + target += "cookies"; + lldebugs << "target = " << target << llendl; + if(LLFile::isfile(target)) + { + LLFile::remove(target); + } + + // the hard part: iterate over all user directories and delete the cookie file from each one + LLDirIterator dir_iter(base_dir, "*_*"); + while (dir_iter.next(filename)) + { + target = base_dir; + target += filename; + target += gDirUtilp->getDirDelimiter(); + target += "browser_profile"; + target += gDirUtilp->getDirDelimiter(); + target += "cookies"; + lldebugs << "target = " << target << llendl; + if(LLFile::isfile(target)) + { + LLFile::remove(target); + } + + // Other accounts may have new-style cookie files too -- delete them as well + target = base_dir; + target += filename; + target += gDirUtilp->getDirDelimiter(); + target += PLUGIN_COOKIE_FILE_NAME; + lldebugs << "target = " << target << llendl; + if(LLFile::isfile(target)) + { + LLFile::remove(target); + } + } + + // If we have an OpenID cookie, re-add it to the cookie store. + setOpenIDCookie(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::clearAllCaches() +{ + // Clear all plugins' caches + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + pimpl->clearCache(); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setCookiesEnabled(bool enabled) +{ + // Set the "cookies enabled" flag for all loaded plugins + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->mMediaSource) + { + pimpl->mMediaSource->enable_cookies(enabled); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setProxyConfig(bool enable, const std::string &host, int port) +{ + // Set the proxy config for all loaded plugins + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->mMediaSource) + { + pimpl->mMediaSource->proxy_setup(enable, host, port); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +///////////////////////////////////////////////////////////////////////////////////////// +// static +LLPluginCookieStore *LLViewerMedia::getCookieStore() +{ + if(sCookieStore == NULL) + { + sCookieStore = new LLPluginCookieStore; + } + + return sCookieStore; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::loadCookieFile() +{ + // build filename for each user + std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME); + + if (resolved_filename.empty()) + { + llinfos << "can't get path to plugin cookie file - probably not logged in yet." << llendl; + return; + } + + // open the file for reading + llifstream file(resolved_filename); + if (!file.is_open()) + { + llwarns << "can't load plugin cookies from file \"" << PLUGIN_COOKIE_FILE_NAME << "\"" << llendl; + return; + } + + getCookieStore()->readAllCookies(file, true); + + file.close(); + + // send the clear_cookies message to all loaded plugins + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->mMediaSource) + { + pimpl->mMediaSource->clear_cookies(); + } + } + + // If we have an OpenID cookie, re-add it to the cookie store. + setOpenIDCookie(); +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::saveCookieFile() +{ + // build filename for each user + std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME); + + if (resolved_filename.empty()) + { + llinfos << "can't get path to plugin cookie file - probably not logged in yet." << llendl; + return; + } + + // open a file for writing + llofstream file (resolved_filename); + if (!file.is_open()) + { + llwarns << "can't open plugin cookie file \"" << PLUGIN_COOKIE_FILE_NAME << "\" for writing" << llendl; + return; + } + + getCookieStore()->writePersistentCookies(file); + + file.close(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::addCookie(const std::string &name, const std::string &value, const std::string &domain, const LLDate &expires, const std::string &path, bool secure) +{ + std::stringstream cookie; + + cookie << name << "=" << LLPluginCookieStore::quoteString(value); + + if(expires.notNull()) + { + cookie << "; expires=" << expires.asRFC1123(); + } + + cookie << "; domain=" << domain; + + cookie << "; path=" << path; + + if(secure) + { + cookie << "; secure"; + } + + getCookieStore()->setCookies(cookie.str()); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::addSessionCookie(const std::string &name, const std::string &value, const std::string &domain, const std::string &path, bool secure) +{ + // A session cookie just has a NULL date. + addCookie(name, value, domain, LLDate(), path, secure); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::removeCookie(const std::string &name, const std::string &domain, const std::string &path ) +{ + // To remove a cookie, add one with the same name, domain, and path that expires in the past. + + addCookie(name, "", domain, LLDate(LLDate::now().secondsSinceEpoch() - 1.0), path); +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setOpenIDCookie() +{ + if(!sOpenIDCookie.empty()) + { + // The LLURL can give me the 'authority', which is of the form: [username[:password]@]hostname[:port] + // We want just the hostname for the cookie code, but LLURL doesn't seem to have a way to extract that. + // We therefore do it here. + std::string authority = sOpenIDURL.mAuthority; + std::string::size_type host_start = authority.find('@'); + if(host_start == std::string::npos) + { + // no username/password + host_start = 0; + } + else + { + // Hostname starts after the @. + // (If the hostname part is empty, this may put host_start at the end of the string. In that case, it will end up passing through an empty hostname, which is correct.) + ++host_start; + } + std::string::size_type host_end = authority.rfind(':'); + if((host_end == std::string::npos) || (host_end < host_start)) + { + // no port + host_end = authority.size(); + } + + getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(host_start, host_end - host_start)); + + // *HACK: Doing this here is nasty, find a better way. + LLWebSharing::instance().setOpenIDCookie(sOpenIDCookie); + + // Do a web profile get so we can store the cookie + LLSD headers = LLSD::emptyMap(); + headers["Accept"] = "*/*"; + headers["Cookie"] = sOpenIDCookie; + headers["User-Agent"] = getCurrentUserAgent(); + + std::string profile_url = getProfileURL(""); + LLURL raw_profile_url( profile_url.c_str() ); + + LLHTTPClient::get(profile_url, + new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()), + headers); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string &openid_token) +{ + LL_DEBUGS("MediaAuth") << "url = \"" << openid_url << "\", token = \"" << openid_token << "\"" << LL_ENDL; + + // post the token to the url + // the responder will need to extract the cookie(s). + + // Save the OpenID URL for later -- we may need the host when adding the cookie. + sOpenIDURL.init(openid_url.c_str()); + + // We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies. + sOpenIDCookie.clear(); + + LLSD headers = LLSD::emptyMap(); + // Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header + headers["Accept"] = "*/*"; + // and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream" + headers["Content-Type"] = "application/x-www-form-urlencoded"; + + // postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here. + size_t size = openid_token.size(); + U8 *data = new U8[size]; + memcpy(data, openid_token.data(), size); + + LLHTTPClient::postRaw( + openid_url, + data, + size, + new LLViewerMediaOpenIDResponder(), + headers); + +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::openIDCookieResponse(const std::string &cookie) +{ + LL_DEBUGS("MediaAuth") << "Cookie received: \"" << cookie << "\"" << LL_ENDL; + + sOpenIDCookie += cookie; + + setOpenIDCookie(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::proxyWindowOpened(const std::string &target, const std::string &uuid) +{ + if(uuid.empty()) + return; + + for (impl_list::iterator iter = sViewerMediaImplList.begin(); iter != sViewerMediaImplList.end(); iter++) + { + if((*iter)->mMediaSource && (*iter)->mMediaSource->pluginSupportsMediaBrowser()) + { + (*iter)->mMediaSource->proxyWindowOpened(target, uuid); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::proxyWindowClosed(const std::string &uuid) +{ + if(uuid.empty()) + return; + + for (impl_list::iterator iter = sViewerMediaImplList.begin(); iter != sViewerMediaImplList.end(); iter++) + { + if((*iter)->mMediaSource && (*iter)->mMediaSource->pluginSupportsMediaBrowser()) + { + (*iter)->mMediaSource->proxyWindowClosed(uuid); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::createSpareBrowserMediaSource() +{ + // If we don't have a spare browser media source, create one. + // However, if PluginAttachDebuggerToPlugins is set then don't spawn a spare + // SLPlugin process in order to not be confused by an unrelated gdb terminal + // popping up at the moment we start a media plugin. + if (!sSpareBrowserMediaSource && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")) + { + // The null owner will keep the browser plugin from fully initializing + // (specifically, it keeps LLPluginClassMedia from negotiating a size change, + // which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color) + sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource() +{ + LLPluginClassMedia* result = sSpareBrowserMediaSource; + sSpareBrowserMediaSource = NULL; + return result; +}; + +bool LLViewerMedia::hasInWorldMedia() +{ + if (sInWorldMediaDisabled) return false; + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + // This should be quick, because there should be very few non-in-world-media impls + for (; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if (!pimpl->getUsedInUI() && !pimpl->isParcelMedia()) + { + // Found an in-world media impl + return true; + } + } + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::hasParcelMedia() +{ + return !LLViewerParcelMedia::getURL().empty(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::hasParcelAudio() +{ + return !LLViewerMedia::getParcelAudioURL().empty(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +std::string LLViewerMedia::getParcelAudioURL() +{ + return LLViewerParcelMgr::getInstance()->getAgentParcel()->getMusicURL(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::initClass() +{ + gIdleCallbacks.addFunction(LLViewerMedia::updateMedia, NULL); + sTeleportFinishConnection = LLViewerParcelMgr::getInstance()-> + setTeleportFinishedCallback(boost::bind(&LLViewerMedia::onTeleportFinished)); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::cleanupClass() +{ + gIdleCallbacks.deleteFunction(LLViewerMedia::updateMedia, NULL); + sTeleportFinishConnection.disconnect(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::onTeleportFinished() +{ + // On teleport, clear this setting (i.e. set it to true) + gSavedSettings.setBOOL("MediaTentativeAutoPlay", true); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// LLViewerMediaImpl +////////////////////////////////////////////////////////////////////////////////////////// +LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id, + S32 media_width, + S32 media_height, + U8 media_auto_scale, + U8 media_loop) +: + mMediaSource( NULL ), + mMovieImageHasMips(false), + mMediaWidth(media_width), + mMediaHeight(media_height), + mMediaAutoScale(media_auto_scale), + mMediaLoop(media_loop), + mNeedsNewTexture(true), + mTextureUsedWidth(0), + mTextureUsedHeight(0), + mSuspendUpdates(false), + mVisible(true), + mLastSetCursor( UI_CURSOR_ARROW ), + mMediaNavState( MEDIANAVSTATE_NONE ), + mInterest(0.0f), + mUsedInUI(false), + mHasFocus(false), + mPriority(LLPluginClassMedia::PRIORITY_UNLOADED), + mNavigateRediscoverType(false), + mNavigateServerRequest(false), + mMediaSourceFailed(false), + mRequestedVolume(1.0f), + mIsMuted(false), + mNeedsMuteCheck(false), + mPreviousMediaState(MEDIA_NONE), + mPreviousMediaTime(0.0f), + mIsDisabled(false), + mIsParcelMedia(false), + mProximity(-1), + mProximityDistance(0.0f), + mMimeTypeProbe(NULL), + mMediaAutoPlay(false), + mInNearbyMediaList(false), + mClearCache(false), + mBackgroundColor(LLColor4::white), + mNavigateSuspended(false), + mNavigateSuspendedDeferred(false), + mIsUpdated(false), + mTrustedBrowser(false) +{ + + // Set up the mute list observer if it hasn't been set up already. + if(!sViewerMediaMuteListObserverInitialized) + { + LLMuteList::getInstance()->addObserver(&sViewerMediaMuteListObserver); + sViewerMediaMuteListObserverInitialized = true; + } + + add_media_impl(this); + + setTextureID(texture_id); + + // connect this media_impl to the media texture, creating it if it doesn't exist.0 + // This is necessary because we need to be able to use getMaxVirtualSize() even if the media plugin is not loaded. + LLViewerMediaTexture* media_tex = LLViewerTextureManager::getMediaTexture(mTextureId); + if(media_tex) + { + media_tex->setMediaImpl(); + } + +} + +////////////////////////////////////////////////////////////////////////////////////////// +LLViewerMediaImpl::~LLViewerMediaImpl() +{ + destroyMediaSource(); + + LLViewerMediaTexture::removeMediaImplFromTexture(mTextureId) ; + + setTextureID(); + remove_media_impl(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::emitEvent(LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event) +{ + // Broadcast to observers using the superclass version + LLViewerMediaEventEmitter::emitEvent(plugin, event); + + // If this media is on one or more LLVOVolume objects, tell them about the event as well. + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + while(iter != mObjectList.end()) + { + LLVOVolume *self = *iter; + ++iter; + self->mediaEvent(this, plugin, event); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type) +{ + bool mimeTypeChanged = (mMimeType != mime_type); + bool pluginChanged = (LLMIMETypes::implType(mCurrentMimeType) != LLMIMETypes::implType(mime_type)); + + if(!mMediaSource || pluginChanged) + { + // We don't have a plugin at all, or the new mime type is handled by a different plugin than the old mime type. + (void)initializePlugin(mime_type); + } + else if(mimeTypeChanged) + { + // The same plugin should be able to handle the new media -- just update the stored mime type. + mMimeType = mime_type; + } + + return (mMediaSource != NULL); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::createMediaSource() +{ + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + // This media shouldn't be created yet. + return; + } + + if(! mMediaURL.empty()) + { + navigateInternal(); + } + else if(! mMimeType.empty()) + { + if (!initializeMedia(mMimeType)) + { + LL_WARNS("Media") << "Failed to initialize media for mime type " << mMimeType << LL_ENDL; + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::destroyMediaSource() +{ + mNeedsNewTexture = true; + + // Tell the viewer media texture it's no longer active + LLViewerMediaTexture* oldImage = LLViewerTextureManager::findMediaTexture( mTextureId ); + if (oldImage) + { + oldImage->setPlaying(FALSE) ; + } + + cancelMimeTypeProbe(); + + if(mMediaSource) + { + mMediaSource->setDeleteOK(true) ; + delete mMediaSource; + mMediaSource = NULL; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::setMediaType(const std::string& media_type) +{ + mMimeType = media_type; +} + +////////////////////////////////////////////////////////////////////////////////////////// +/*static*/ +LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target) +{ + std::string plugin_basename = LLMIMETypes::implType(media_type); + LLPluginClassMedia* media_source = NULL; + + // HACK: we always try to keep a spare running webkit plugin around to improve launch times. + // If a spare was already created before PluginAttachDebuggerToPlugins was set, don't use it. + if(plugin_basename == "media_plugin_webkit" && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")) + { + media_source = LLViewerMedia::getSpareBrowserMediaSource(); + if(media_source) + { + media_source->setOwner(owner); + media_source->setTarget(target); + media_source->setSize(default_width, default_height); + + return media_source; + } + } + + if(plugin_basename.empty()) + { + LL_WARNS("Media") << "Couldn't find plugin for media type " << media_type << LL_ENDL; + } + else + { + std::string launcher_name = gDirUtilp->getLLPluginLauncher(); + std::string plugin_name = gDirUtilp->getLLPluginFilename(plugin_basename); + std::string user_data_path = gDirUtilp->getOSUserAppDir(); + user_data_path += gDirUtilp->getDirDelimiter(); + + // Fix for EXT-5960 - make browser profile specific to user (cache, cookies etc.) + // If the linden username returned is blank, that can only mean we are + // at the login page displaying login Web page or Web browser test via Develop menu. + // In this case we just use whatever gDirUtilp->getOSUserAppDir() gives us (this + // is what we always used before this change) + std::string linden_user_dir = gDirUtilp->getLindenUserDir(); + if ( ! linden_user_dir.empty() ) + { + // gDirUtilp->getLindenUserDir() is whole path, not just Linden name + user_data_path = linden_user_dir; + user_data_path += gDirUtilp->getDirDelimiter(); + }; + + // See if the plugin executable exists + llstat s; + if(LLFile::stat(launcher_name, &s)) + { + LL_WARNS("Media") << "Couldn't find launcher at " << launcher_name << LL_ENDL; + } + else if(LLFile::stat(plugin_name, &s)) + { + LL_WARNS("Media") << "Couldn't find plugin at " << plugin_name << LL_ENDL; + } + else + { + media_source = new LLPluginClassMedia(owner); + media_source->setSize(default_width, default_height); + media_source->setUserDataPath(user_data_path); + media_source->setLanguageCode(LLUI::getLanguage()); + + // collect 'cookies enabled' setting from prefs and send to embedded browser + bool cookies_enabled = gSavedSettings.getBOOL( "CookiesEnabled" ); + media_source->enable_cookies( cookies_enabled ); + + // collect 'plugins enabled' setting from prefs and send to embedded browser + bool plugins_enabled = gSavedSettings.getBOOL( "BrowserPluginsEnabled" ); + media_source->setPluginsEnabled( plugins_enabled ); + + // collect 'javascript enabled' setting from prefs and send to embedded browser + bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" ); + media_source->setJavascriptEnabled( javascript_enabled ); + + media_source->setTarget(target); + + const std::string plugin_dir = gDirUtilp->getLLPluginDir(); + if (media_source->init(launcher_name, plugin_dir, plugin_name, gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))) + { + return media_source; + } + else + { + LL_WARNS("Media") << "Failed to init plugin. Destroying." << LL_ENDL; + delete media_source; + } + } + } + + LL_WARNS("Plugin") << "plugin intialization failed for mime type: " << media_type << LL_ENDL; + LLSD args; + args["MIME_TYPE"] = media_type; + LLNotificationsUtil::add("NoPlugin", args); + + return NULL; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) +{ + if(mMediaSource) + { + // Save the previous media source's last set size before destroying it. + mMediaWidth = mMediaSource->getSetWidth(); + mMediaHeight = mMediaSource->getSetHeight(); + } + + // Always delete the old media impl first. + destroyMediaSource(); + + // and unconditionally set the mime type + mMimeType = media_type; + + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + // This impl should not be loaded at this time. + LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL; + + return false; + } + + // If we got here, we want to ignore previous init failures. + mMediaSourceFailed = false; + + // Save the MIME type that really caused the plugin to load + mCurrentMimeType = mMimeType; + + LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight, mTarget); + + if (media_source) + { + media_source->setDisableTimeout(gSavedSettings.getBOOL("DebugPluginDisableTimeout")); + media_source->setLoop(mMediaLoop); + media_source->setAutoScale(mMediaAutoScale); + media_source->setBrowserUserAgent(LLViewerMedia::getCurrentUserAgent()); + media_source->focus(mHasFocus); + media_source->setBackgroundColor(mBackgroundColor); + + if(gSavedSettings.getBOOL("BrowserIgnoreSSLCertErrors")) + { + media_source->ignore_ssl_cert_errors(true); + } + + // the correct way to deal with certs it to load ours from CA.pem and append them to the ones + // Qt/WebKit loads from your system location. + // Note: This needs the new CA.pem file with the Equifax Secure Certificate Authority + // cert at the bottom: (MIIDIDCCAomgAwIBAgIENd70zzANBg) + std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "CA.pem" ); + media_source->addCertificateFilePath( ca_path ); + + media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort")); + + if(mClearCache) + { + mClearCache = false; + media_source->clear_cache(); + } + + // TODO: Only send cookies to plugins that need them + // Ideally, the plugin should tell us whether it handles cookies or not -- either via the init response or through a separate message. + // Due to the ordering of messages, it's possible we wouldn't get that information back in time to send cookies before sending a navigate message, + // which could cause odd race conditions. + std::string all_cookies = LLViewerMedia::getCookieStore()->getAllCookies(); + lldebugs << "setting cookies: " << all_cookies << llendl; + if(!all_cookies.empty()) + { + media_source->set_cookies(all_cookies); + } + + mMediaSource = media_source; + mMediaSource->setDeleteOK(false) ; + updateVolume(); + + return true; + } + + // Make sure the timer doesn't try re-initing this plugin repeatedly until something else changes. + mMediaSourceFailed = true; + + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::loadURI() +{ + if(mMediaSource) + { + // trim whitespace from front and back of URL - fixes EXT-5363 + LLStringUtil::trim( mMediaURL ); + + // *HACK: we don't know if the URI coming in is properly escaped + // (the contract doesn't specify whether it is escaped or not. + // but LLQtWebKit expects it to be, so we do our best to encode + // special characters) + // The strings below were taken right from http://www.ietf.org/rfc/rfc1738.txt + // Note especially that '%' and '/' are there. + std::string uri = LLURI::escape(mMediaURL, + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789" + "$-_.+" + "!*'()," + "{}|\\^~[]`" + "<>#%" + ";/?:@&=", + false); + llinfos << "Asking media source to load URI: " << uri << llendl; + + mMediaSource->loadURI( uri ); + + // A non-zero mPreviousMediaTime means that either this media was previously unloaded by the priority code while playing/paused, + // or a seek happened before the media loaded. In either case, seek to the saved time. + if(mPreviousMediaTime != 0.0f) + { + seek(mPreviousMediaTime); + } + + if(mPreviousMediaState == MEDIA_PLAYING) + { + // This media was playing before this instance was unloaded. + start(); + } + else if(mPreviousMediaState == MEDIA_PAUSED) + { + // This media was paused before this instance was unloaded. + pause(); + } + else + { + // No relevant previous media play state -- if we're loading the URL, we want to start playing. + start(); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::setSize(int width, int height) +{ + mMediaWidth = width; + mMediaHeight = height; + if(mMediaSource) + { + mMediaSource->setSize(width, height); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::showNotification(LLNotificationPtr notify) +{ + mNotification = notify; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::hideNotification() +{ + mNotification.reset(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::play() +{ + // If the media source isn't there, try to initialize it and load an URL. + if(mMediaSource == NULL) + { + if(!initializeMedia(mMimeType)) + { + // This may be the case where the plugin's priority is PRIORITY_UNLOADED + return; + } + + // Only do this if the media source was just loaded. + loadURI(); + } + + // always start the media + start(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::stop() +{ + if(mMediaSource) + { + mMediaSource->stop(); + // destroyMediaSource(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::pause() +{ + if(mMediaSource) + { + mMediaSource->pause(); + } + else + { + mPreviousMediaState = MEDIA_PAUSED; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::start() +{ + if(mMediaSource) + { + mMediaSource->start(); + } + else + { + mPreviousMediaState = MEDIA_PLAYING; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::seek(F32 time) +{ + if(mMediaSource) + { + mMediaSource->seek(time); + } + else + { + // Save the seek time to be set when the media is loaded. + mPreviousMediaTime = time; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::skipBack(F32 step_scale) +{ + if(mMediaSource) + { + if(mMediaSource->pluginSupportsMediaTime()) + { + F64 back_step = mMediaSource->getCurrentTime() - (mMediaSource->getDuration()*step_scale); + if(back_step < 0.0) + { + back_step = 0.0; + } + mMediaSource->seek(back_step); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::skipForward(F32 step_scale) +{ + if(mMediaSource) + { + if(mMediaSource->pluginSupportsMediaTime()) + { + F64 forward_step = mMediaSource->getCurrentTime() + (mMediaSource->getDuration()*step_scale); + if(forward_step > mMediaSource->getDuration()) + { + forward_step = mMediaSource->getDuration(); + } + mMediaSource->seek(forward_step); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::setVolume(F32 volume) +{ + mRequestedVolume = volume; + updateVolume(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::updateVolume() +{ + if(mMediaSource) + { + // always scale the volume by the global media volume + F32 volume = mRequestedVolume * LLViewerMedia::getVolume(); + + if (mProximityCamera > 0) + { + if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMax")) + { + volume = 0; + } + else if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMin")) + { + // attenuated_volume = 1 / (roll_off_rate * (d - min))^2 + // the +1 is there so that for distance 0 the volume stays the same + F64 adjusted_distance = mProximityCamera - gSavedSettings.getF32("MediaRollOffMin"); + F64 attenuation = 1.0 + (gSavedSettings.getF32("MediaRollOffRate") * adjusted_distance); + attenuation = 1.0 / (attenuation * attenuation); + // the attenuation multiplier should never be more than one since that would increase volume + volume = volume * llmin(1.0, attenuation); + } + } + + mMediaSource->setVolume(volume); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +F32 LLViewerMediaImpl::getVolume() +{ + return mRequestedVolume; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::focus(bool focus) +{ + mHasFocus = focus; + + if (mMediaSource) + { + // call focus just for the hell of it, even though this apopears to be a nop + mMediaSource->focus(focus); + if (focus) + { + // spoof a mouse click to *actually* pass focus + // Don't do this anymore -- it actually clicks through now. +// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, 1, 1, 0); +// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 1, 1, 0); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::hasFocus() const +{ + // FIXME: This might be able to be a bit smarter by hooking into LLViewerMediaFocus, etc. + return mHasFocus; +} + +std::string LLViewerMediaImpl::getCurrentMediaURL() +{ + if(!mCurrentMediaURL.empty()) + { + return mCurrentMediaURL; + } + + return mMediaURL; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::clearCache() +{ + if(mMediaSource) + { + mMediaSource->clear_cache(); + } + else + { + mClearCache = true; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseDown(S32 x, S32 y, MASK mask, S32 button) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; +// llinfos << "mouse down (" << x << ", " << y << ")" << llendl; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, button, x, y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseUp(S32 x, S32 y, MASK mask, S32 button) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; +// llinfos << "mouse up (" << x << ", " << y << ")" << llendl; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, button, x, y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseMove(S32 x, S32 y, MASK mask) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; +// llinfos << "mouse move (" << x << ", " << y << ")" << llendl; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, x, y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +//static +void LLViewerMediaImpl::scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y) +{ + F32 texture_x = texture_coords.mV[VX]; + F32 texture_y = texture_coords.mV[VY]; + + // Deal with repeating textures by wrapping the coordinates into the range [0, 1.0) + texture_x = fmodf(texture_x, 1.0f); + if(texture_x < 0.0f) + texture_x = 1.0 + texture_x; + + texture_y = fmodf(texture_y, 1.0f); + if(texture_y < 0.0f) + texture_y = 1.0 + texture_y; + + // scale x and y to texel units. + *x = llround(texture_x * mMediaSource->getTextureWidth()); + *y = llround((1.0f - texture_y) * mMediaSource->getTextureHeight()); + + // Adjust for the difference between the actual texture height and the amount of the texture in use. + *y -= (mMediaSource->getTextureHeight() - mMediaSource->getHeight()); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseDown(const LLVector2& texture_coords, MASK mask, S32 button) +{ + if(mMediaSource) + { + S32 x, y; + scaleTextureCoords(texture_coords, &x, &y); + + mouseDown(x, y, mask, button); + } +} + +void LLViewerMediaImpl::mouseUp(const LLVector2& texture_coords, MASK mask, S32 button) +{ + if(mMediaSource) + { + S32 x, y; + scaleTextureCoords(texture_coords, &x, &y); + + mouseUp(x, y, mask, button); + } +} + +void LLViewerMediaImpl::mouseMove(const LLVector2& texture_coords, MASK mask) +{ + if(mMediaSource) + { + S32 x, y; + scaleTextureCoords(texture_coords, &x, &y); + + mouseMove(x, y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOUBLE_CLICK, button, x, y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::scrollWheel(S32 x, S32 y, MASK mask) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; + if (mMediaSource) + { + mMediaSource->scrollEvent(x, y, mask); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::onMouseCaptureLost() +{ + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 0, mLastMouseX, mLastMouseY, 0); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +BOOL LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask) +{ + // NOTE: this is called when the mouse is released when we have capture. + // Due to the way mouse coordinates are mapped to the object, we can't use the x and y coordinates that come in with the event. + + if(hasMouseCapture()) + { + // Release the mouse -- this will also send a mouseup to the media + gFocusMgr.setMouseCapture( FALSE ); + } + + return TRUE; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::updateJavascriptObject() +{ + if ( mMediaSource ) + { + // flag to expose this information to internal browser or not. + bool expose_javascript_object = gSavedSettings.getBOOL("BrowserEnableJSObject"); + mMediaSource->jsExposeObjectEvent( expose_javascript_object ); + + // indicate if the values we have are valid (currently do this blanket-fashion for + // everything depending on whether you are logged in or not - this may require a + // more granular approach once variables are added that ARE valid before login + bool logged_in = LLLoginInstance::getInstance()->authSuccess(); + mMediaSource->jsValuesValidEvent( logged_in ); + + // current location within a region + LLVector3 agent_pos = gAgent.getPositionAgent(); + double x = agent_pos.mV[ VX ]; + double y = agent_pos.mV[ VY ]; + double z = agent_pos.mV[ VZ ]; + mMediaSource->jsAgentLocationEvent( x, y, z ); + + // current region agent is in + std::string region_name(""); + LLViewerRegion* region = gAgent.getRegion(); + if ( region ) + { + region_name = region->getName(); + }; + mMediaSource->jsAgentRegionEvent( region_name ); + + // language code the viewer is set to + mMediaSource->jsAgentLanguageEvent( LLUI::getLanguage() ); + + // maturity setting the agent has selected + if ( gAgent.prefersAdult() ) + mMediaSource->jsAgentMaturityEvent( "GMA" ); // Adult means see adult, mature and general content + else + if ( gAgent.prefersMature() ) + mMediaSource->jsAgentMaturityEvent( "GM" ); // Mature means see mature and general content + else + if ( gAgent.prefersPG() ) + mMediaSource->jsAgentMaturityEvent( "G" ); // PG means only see General content + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +std::string LLViewerMediaImpl::getName() const +{ + if (mMediaSource) + { + return mMediaSource->getMediaName(); + } + + return LLStringUtil::null; +}; + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateBack() +{ + if (mMediaSource) + { + mMediaSource->browse_back(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateForward() +{ + if (mMediaSource) + { + mMediaSource->browse_forward(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateReload() +{ + navigateTo(getCurrentMediaURL(), "", true, false); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateHome() +{ + bool rediscover_mimetype = mHomeMimeType.empty(); + navigateTo(mHomeURL, mHomeMimeType, rediscover_mimetype, false); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::unload() +{ + // Unload the media impl and clear its state. + destroyMediaSource(); + resetPreviousMediaState(); + mMediaURL.clear(); + mMimeType.clear(); + mCurrentMediaURL.clear(); + mCurrentMimeType.clear(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type, bool server_request) +{ + cancelMimeTypeProbe(); + + if(mMediaURL != url) + { + // Don't carry media play state across distinct URLs. + resetPreviousMediaState(); + } + + // Always set the current URL and MIME type. + mMediaURL = url; + mMimeType = mime_type; + + // Clear the current media URL, since it will no longer be correct. + mCurrentMediaURL.clear(); + + // if mime type discovery was requested, we'll need to do it when the media loads + mNavigateRediscoverType = rediscover_type; + + // and if this was a server request, the navigate on load will also need to be one. + mNavigateServerRequest = server_request; + + // An explicit navigate resets the "failed" flag. + mMediaSourceFailed = false; + + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + // Helpful to have media urls in log file. Shouldn't be spammy. + llinfos << "NOT LOADING media id= " << mTextureId << " url=" << url << " mime_type=" << mime_type << llendl; + + // This impl should not be loaded at this time. + LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL; + + return; + } + + navigateInternal(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateInternal() +{ + // Helpful to have media urls in log file. Shouldn't be spammy. + llinfos << "media id= " << mTextureId << " url=" << mMediaURL << " mime_type=" << mMimeType << llendl; + + if(mNavigateSuspended) + { + llwarns << "Deferring navigate." << llendl; + mNavigateSuspendedDeferred = true; + return; + } + + if(mMimeTypeProbe != NULL) + { + llwarns << "MIME type probe already in progress -- bailing out." << llendl; + return; + } + + if(mNavigateServerRequest) + { + setNavState(MEDIANAVSTATE_SERVER_SENT); + } + else + { + setNavState(MEDIANAVSTATE_NONE); + } + + // If the caller has specified a non-empty MIME type, look that up in our MIME types list. + // If we have a plugin for that MIME type, use that instead of attempting auto-discovery. + // This helps in supporting legacy media content where the server the media resides on returns a bogus MIME type + // but the parcel owner has correctly set the MIME type in the parcel media settings. + + if(!mMimeType.empty() && (mMimeType != LLMIMETypes::getDefaultMimeType())) + { + std::string plugin_basename = LLMIMETypes::implType(mMimeType); + if(!plugin_basename.empty()) + { + // We have a plugin for this mime type + mNavigateRediscoverType = false; + } + } + + if(mNavigateRediscoverType) + { + + LLURI uri(mMediaURL); + std::string scheme = uri.scheme(); + + if(scheme.empty() || "http" == scheme || "https" == scheme) + { + // If we don't set an Accept header, LLHTTPClient will add one like this: + // Accept: application/llsd+xml + // which is really not what we want. + LLSD headers = LLSD::emptyMap(); + headers["Accept"] = "*/*"; + // Allow cookies in the response, to prevent a redirect loop when accessing join.secondlife.com + headers["Cookie"] = ""; + LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this), headers, 10.0f); + } + else if("data" == scheme || "file" == scheme || "about" == scheme) + { + // FIXME: figure out how to really discover the type for these schemes + // We use "data" internally for a text/html url for loading the login screen + if(initializeMedia("text/html")) + { + loadURI(); + } + } + else + { + // This catches 'rtsp://' urls + if(initializeMedia(scheme)) + { + loadURI(); + } + } + } + else if(initializeMedia(mMimeType)) + { + loadURI(); + } + else + { + LL_WARNS("Media") << "Couldn't navigate to: " << mMediaURL << " as there is no media type for: " << mMimeType << LL_ENDL; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateStop() +{ + if(mMediaSource) + { + mMediaSource->browse_stop(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask) +{ + bool result = false; + + if (mMediaSource) + { + // FIXME: THIS IS SO WRONG. + // Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it... + if( MASK_CONTROL & mask ) + { + result = true; + } + + if(!result) + { + + LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData(); + + result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask, native_key_data); + // Since the viewer internal event dispatching doesn't give us key-up events, simulate one here. + (void)mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP ,key, mask, native_key_data); + } + } + + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char) +{ + bool result = false; + + if (mMediaSource) + { + // only accept 'printable' characters, sigh... + if (uni_char >= 32 // discard 'control' characters + && uni_char != 127) // SDL thinks this is 'delete' - yuck. + { + LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData(); + + mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE), native_key_data); + } + } + + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::canNavigateForward() +{ + BOOL result = FALSE; + if (mMediaSource) + { + result = mMediaSource->getHistoryForwardAvailable(); + } + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::canNavigateBack() +{ + BOOL result = FALSE; + if (mMediaSource) + { + result = mMediaSource->getHistoryBackAvailable(); + } + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::update() +{ + if(mMediaSource == NULL) + { + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + // This media source should not be loaded. + } + else if(mPriority <= LLPluginClassMedia::PRIORITY_SLIDESHOW) + { + // Don't load new instances that are at PRIORITY_SLIDESHOW or below. They're just kept around to preserve state. + } + else if(mMimeTypeProbe != NULL) + { + // this media source is doing a MIME type probe -- don't try loading it again. + } + else + { + // This media may need to be loaded. + if(sMediaCreateTimer.hasExpired()) + { + LL_DEBUGS("PluginPriority") << this << ": creating media based on timer expiration" << LL_ENDL; + createMediaSource(); + sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY); + } + else + { + LL_DEBUGS("PluginPriority") << this << ": NOT creating media (waiting on timer)" << LL_ENDL; + } + } + } + else + { + updateVolume(); + + // TODO: this is updated every frame - is this bad? + updateJavascriptObject(); + + // If we didn't just create the impl, it may need to get cookie updates. + if(!sUpdatedCookies.empty()) + { + // TODO: Only send cookies to plugins that need them + mMediaSource->set_cookies(sUpdatedCookies); + } + } + + + if(mMediaSource == NULL) + { + return; + } + + // Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash. + setNavigateSuspended(true); + + mMediaSource->idle(); + + setNavigateSuspended(false); + + if(mMediaSource == NULL) + { + return; + } + + if(mMediaSource->isPluginExited()) + { + resetPreviousMediaState(); + destroyMediaSource(); + return; + } + + if(!mMediaSource->textureValid()) + { + return; + } + + if(mSuspendUpdates || !mVisible) + { + return; + } + + LLViewerMediaTexture* placeholder_image = updatePlaceholderImage(); + + if(placeholder_image) + { + LLRect dirty_rect; + + // Since we're updating this texture, we know it's playing. Tell the texture to do its replacement magic so it gets rendered. + placeholder_image->setPlaying(TRUE); + + if(mMediaSource->getDirty(&dirty_rect)) + { + // Constrain the dirty rect to be inside the texture + S32 x_pos = llmax(dirty_rect.mLeft, 0); + S32 y_pos = llmax(dirty_rect.mBottom, 0); + S32 width = llmin(dirty_rect.mRight, placeholder_image->getWidth()) - x_pos; + S32 height = llmin(dirty_rect.mTop, placeholder_image->getHeight()) - y_pos; + + if(width > 0 && height > 0) + { + + U8* data = mMediaSource->getBitsData(); + + // Offset the pixels pointer to match x_pos and y_pos + data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() ); + data += ( y_pos * mMediaSource->getTextureDepth() ); + + placeholder_image->setSubImage( + data, + mMediaSource->getBitsWidth(), + mMediaSource->getBitsHeight(), + x_pos, + y_pos, + width, + height); + + } + + mMediaSource->resetDirty(); + } + } +} + + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::updateImagesMediaStreams() +{ +} + + +////////////////////////////////////////////////////////////////////////////////////////// +LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() +{ + if(mTextureId.isNull()) + { + // The code that created this instance will read from the plugin's bits. + return NULL; + } + + LLViewerMediaTexture* placeholder_image = LLViewerTextureManager::getMediaTexture( mTextureId ); + + if (mNeedsNewTexture + || placeholder_image->getUseMipMaps() + || (placeholder_image->getWidth() != mMediaSource->getTextureWidth()) + || (placeholder_image->getHeight() != mMediaSource->getTextureHeight()) + || (mTextureUsedWidth != mMediaSource->getWidth()) + || (mTextureUsedHeight != mMediaSource->getHeight()) + ) + { + LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL; + LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL; + + int texture_width = mMediaSource->getTextureWidth(); + int texture_height = mMediaSource->getTextureHeight(); + int texture_depth = mMediaSource->getTextureDepth(); + + // MEDIAOPT: check to see if size actually changed before doing work + placeholder_image->destroyGLTexture(); + // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work? + placeholder_image->reinit(FALSE); // probably not needed + + // MEDIAOPT: seems insane that we actually have to make an imageraw then + // immediately discard it + LLPointer<LLImageRaw> raw = new LLImageRaw(texture_width, texture_height, texture_depth); + // Clear the texture to the background color, ignoring alpha. + // convert background color channels from [0.0, 1.0] to [0, 255]; + raw->clear(int(mBackgroundColor.mV[VX] * 255.0f), int(mBackgroundColor.mV[VY] * 255.0f), int(mBackgroundColor.mV[VZ] * 255.0f), 0xff); + int discard_level = 0; + + // ask media source for correct GL image format constants + placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(), + mMediaSource->getTextureFormatPrimary(), + mMediaSource->getTextureFormatType(), + mMediaSource->getTextureFormatSwapBytes()); + + placeholder_image->createGLTexture(discard_level, raw); + + // MEDIAOPT: set this dynamically on play/stop + // FIXME +// placeholder_image->mIsMediaTexture = true; + mNeedsNewTexture = false; + + // If the amount of the texture being drawn by the media goes down in either width or height, + // recreate the texture to avoid leaving parts of the old image behind. + mTextureUsedWidth = mMediaSource->getWidth(); + mTextureUsedHeight = mMediaSource->getHeight(); + } + + return placeholder_image; +} + + +////////////////////////////////////////////////////////////////////////////////////////// +LLUUID LLViewerMediaImpl::getMediaTextureID() const +{ + return mTextureId; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::setVisible(bool visible) +{ + mVisible = visible; + + if(mVisible) + { + if(mMediaSource && mMediaSource->isPluginExited()) + { + destroyMediaSource(); + } + + if(!mMediaSource) + { + createMediaSource(); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseCapture() +{ + gFocusMgr.setMouseCapture(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::scaleMouse(S32 *mouse_x, S32 *mouse_y) +{ +#if 0 + S32 media_width, media_height; + S32 texture_width, texture_height; + getMediaSize( &media_width, &media_height ); + getTextureSize( &texture_width, &texture_height ); + S32 y_delta = texture_height - media_height; + + *mouse_y -= y_delta; +#endif +} + + + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::isMediaTimeBased() +{ + bool result = false; + + if(mMediaSource) + { + result = mMediaSource->pluginSupportsMediaTime(); + } + + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::isMediaPlaying() +{ + bool result = false; + + if(mMediaSource) + { + EMediaStatus status = mMediaSource->getStatus(); + if(status == MEDIA_PLAYING || status == MEDIA_LOADING) + result = true; + } + + return result; +} +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::isMediaPaused() +{ + bool result = false; + + if(mMediaSource) + { + if(mMediaSource->getStatus() == MEDIA_PAUSED) + result = true; + } + + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::hasMedia() const +{ + return mMediaSource != NULL; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +void LLViewerMediaImpl::resetPreviousMediaState() +{ + mPreviousMediaState = MEDIA_NONE; + mPreviousMediaTime = 0.0f; +} + + +////////////////////////////////////////////////////////////////////////////////////////// +// +void LLViewerMediaImpl::setDisabled(bool disabled, bool forcePlayOnEnable) +{ + if(mIsDisabled != disabled) + { + // Only do this on actual state transitions. + mIsDisabled = disabled; + + if(mIsDisabled) + { + // We just disabled this media. Clear all state. + unload(); + } + else + { + // We just (re)enabled this media. Do a navigate if auto-play is in order. + if(isAutoPlayable() || forcePlayOnEnable) + { + navigateTo(mMediaEntryURL, "", true, true); + } + } + + } +}; + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::isForcedUnloaded() const +{ + if(mIsMuted || mMediaSourceFailed || mIsDisabled) + { + return true; + } + + if(sInWorldMediaDisabled) + { + // When inworld media is disabled, all instances that aren't marked as "used in UI" will not be loaded. + if(!mUsedInUI) + { + return true; + } + } + + // If this media's class is not supposed to be shown, unload + if (!shouldShowBasedOnClass()) + { + return true; + } + + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::isPlayable() const +{ + if(isForcedUnloaded()) + { + // All of the forced-unloaded criteria also imply not playable. + return false; + } + + if(hasMedia()) + { + // Anything that's already playing is, by definition, playable. + return true; + } + + if(!mMediaURL.empty()) + { + // If something has navigated the instance, it's ready to be played. + return true; + } + + return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginClassMediaOwner::EMediaEvent event) +{ + bool pass_through = true; + switch(event) + { + case MEDIA_EVENT_CLICK_LINK_NOFOLLOW: + { + LL_DEBUGS("Media") << "MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is: " << plugin->getClickURL() << LL_ENDL; + std::string url = plugin->getClickURL(); + std::string nav_type = plugin->getClickNavType(); + LLURLDispatcher::dispatch(url, nav_type, NULL, mTrustedBrowser); + } + break; + case MEDIA_EVENT_CLICK_LINK_HREF: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << plugin->getClickTarget() << "\", uri is " << plugin->getClickURL() << LL_ENDL; + }; + break; + case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH: + { + // The plugin failed to load properly. Make sure the timer doesn't retry. + // TODO: maybe mark this plugin as not loadable somehow? + mMediaSourceFailed = true; + + // Reset the last known state of the media to defaults. + resetPreviousMediaState(); + + // TODO: may want a different message for this case? + LLSD args; + args["PLUGIN"] = LLMIMETypes::implType(mCurrentMimeType); + LLNotificationsUtil::add("MediaPluginFailed", args); + } + break; + + case MEDIA_EVENT_PLUGIN_FAILED: + { + // The plugin crashed. + mMediaSourceFailed = true; + + // Reset the last known state of the media to defaults. + resetPreviousMediaState(); + + LLSD args; + args["PLUGIN"] = LLMIMETypes::implType(mCurrentMimeType); + // SJB: This is getting called every frame if the plugin fails to load, continuously respawining the alert! + //LLNotificationsUtil::add("MediaPluginFailed", args); + } + break; + + case MEDIA_EVENT_CURSOR_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << plugin->getCursorName() << LL_ENDL; + + std::string cursor = plugin->getCursorName(); + + if(cursor == "arrow") + mLastSetCursor = UI_CURSOR_ARROW; + else if(cursor == "ibeam") + mLastSetCursor = UI_CURSOR_IBEAM; + else if(cursor == "splith") + mLastSetCursor = UI_CURSOR_SIZEWE; + else if(cursor == "splitv") + mLastSetCursor = UI_CURSOR_SIZENS; + else if(cursor == "hand") + mLastSetCursor = UI_CURSOR_HAND; + else // for anything else, default to the arrow + mLastSetCursor = UI_CURSOR_ARROW; + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_BEGIN: + { + LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_BEGIN, uri is: " << plugin->getNavigateURI() << LL_ENDL; + hideNotification(); + + if(getNavState() == MEDIANAVSTATE_SERVER_SENT) + { + setNavState(MEDIANAVSTATE_SERVER_BEGUN); + } + else + { + setNavState(MEDIANAVSTATE_BEGUN); + } + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE: + { + LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_COMPLETE, uri is: " << plugin->getNavigateURI() << LL_ENDL; + + std::string url = plugin->getNavigateURI(); + if(getNavState() == MEDIANAVSTATE_BEGUN) + { + if(mCurrentMediaURL == url) + { + // This is a navigate that takes us to the same url as the previous navigate. + setNavState(MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS); + } + else + { + mCurrentMediaURL = url; + setNavState(MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED); + } + } + else if(getNavState() == MEDIANAVSTATE_SERVER_BEGUN) + { + mCurrentMediaURL = url; + setNavState(MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED); + } + else + { + // all other cases need to leave the state alone. + } + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_LOCATION_CHANGED: + { + LL_DEBUGS("Media") << "MEDIA_EVENT_LOCATION_CHANGED, uri is: " << plugin->getLocation() << LL_ENDL; + + std::string url = plugin->getLocation(); + + if(getNavState() == MEDIANAVSTATE_BEGUN) + { + if(mCurrentMediaURL == url) + { + // This is a navigate that takes us to the same url as the previous navigate. + setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS); + } + else + { + mCurrentMediaURL = url; + setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED); + } + } + else if(getNavState() == MEDIANAVSTATE_SERVER_BEGUN) + { + mCurrentMediaURL = url; + setNavState(MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED); + } + else + { + // Don't track redirects. + setNavState(MEDIANAVSTATE_NONE); + } + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_PICK_FILE_REQUEST: + { + // Display a file picker + std::string response; + + LLFilePicker& picker = LLFilePicker::instance(); + if (!picker.getOpenFile(LLFilePicker::FFLOAD_ALL)) + { + // The user didn't pick a file -- the empty response string will indicate this. + } + + response = picker.getFirstFile(); + + plugin->sendPickFileResponse(response); + } + break; + + + case LLViewerMediaObserver::MEDIA_EVENT_AUTH_REQUEST: + { + LLNotification::Params auth_request_params; + auth_request_params.name = "AuthRequest"; + + // pass in host name and realm for site (may be zero length but will always exist) + LLSD args; + LLURL raw_url( plugin->getAuthURL().c_str() ); + args["HOST_NAME"] = raw_url.getAuthority(); + args["REALM"] = plugin->getAuthRealm(); + auth_request_params.substitutions = args; + + auth_request_params.payload = LLSD().with("media_id", mTextureId); + auth_request_params.functor.function = boost::bind(&LLViewerMedia::onAuthSubmit, _1, _2); + LLNotifications::instance().add(auth_request_params); + }; + break; + + case LLViewerMediaObserver::MEDIA_EVENT_CLOSE_REQUEST: + { + std::string uuid = plugin->getClickUUID(); + + llinfos << "MEDIA_EVENT_CLOSE_REQUEST for uuid " << uuid << llendl; + + if(uuid.empty()) + { + // This close request is directed at this instance, let it fall through. + } + else + { + // This close request is directed at another instance + pass_through = false; + LLFloaterMediaBrowser::closeRequest(uuid); + LLFloaterWebContent::closeRequest(uuid); + } + } + break; + + case LLViewerMediaObserver::MEDIA_EVENT_GEOMETRY_CHANGE: + { + std::string uuid = plugin->getClickUUID(); + + llinfos << "MEDIA_EVENT_GEOMETRY_CHANGE for uuid " << uuid << llendl; + + if(uuid.empty()) + { + // This geometry change request is directed at this instance, let it fall through. + } + else + { + // This request is directed at another instance + pass_through = false; + LLFloaterMediaBrowser::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight()); + LLFloaterWebContent::geometryChanged(uuid, plugin->getGeometryX(), plugin->getGeometryY(), plugin->getGeometryWidth(), plugin->getGeometryHeight()); + } + } + break; + + default: + break; + } + + if(pass_through) + { + // Just chain the event to observers. + emitEvent(plugin, event); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void LLViewerMediaImpl::handleCookieSet(LLPluginClassMedia* self, const std::string &cookie) +{ + LLViewerMedia::getCookieStore()->setCookies(cookie); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::cut() +{ + if (mMediaSource) + mMediaSource->cut(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canCut() const +{ + if (mMediaSource) + return mMediaSource->canCut(); + else + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::copy() +{ + if (mMediaSource) + mMediaSource->copy(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canCopy() const +{ + if (mMediaSource) + return mMediaSource->canCopy(); + else + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::paste() +{ + if (mMediaSource) + mMediaSource->paste(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canPaste() const +{ + if (mMediaSource) + return mMediaSource->canPaste(); + else + return FALSE; +} + +void LLViewerMediaImpl::setUpdated(BOOL updated) +{ + mIsUpdated = updated ; +} + +BOOL LLViewerMediaImpl::isUpdated() +{ + return mIsUpdated ; +} + +void LLViewerMediaImpl::calculateInterest() +{ + LLViewerMediaTexture* texture = LLViewerTextureManager::findMediaTexture( mTextureId ); + + if(texture != NULL) + { + mInterest = texture->getMaxVirtualSize(); + } + else + { + // This will be a relatively common case now, since it will always be true for unloaded media. + mInterest = 0.0f; + } + + // Calculate distance from the avatar, for use in the proximity calculation. + mProximityDistance = 0.0f; + mProximityCamera = 0.0f; + if(!mObjectList.empty()) + { + // Just use the first object in the list. We could go through the list and find the closest object, but this should work well enough. + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + LLVOVolume* objp = *iter ; + llassert_always(objp != NULL) ; + + // The distance calculation is invalid for HUD attachments -- leave both mProximityDistance and mProximityCamera at 0 for them. + if(!objp->isHUDAttachment()) + { + LLVector3d obj_global = objp->getPositionGlobal() ; + LLVector3d agent_global = gAgent.getPositionGlobal() ; + LLVector3d global_delta = agent_global - obj_global ; + mProximityDistance = global_delta.magVecSquared(); // use distance-squared because it's cheaper and sorts the same. + + LLVector3d camera_delta = gAgentCamera.getCameraPositionGlobal() - obj_global; + mProximityCamera = camera_delta.magVec(); + } + } + + if(mNeedsMuteCheck) + { + // Check all objects this instance is associated with, and those objects' owners, against the mute list + mIsMuted = false; + + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + for(; iter != mObjectList.end() ; ++iter) + { + LLVOVolume *obj = *iter; + llassert(obj); + if (!obj) continue; + if(LLMuteList::getInstance() && + LLMuteList::getInstance()->isMuted(obj->getID())) + { + mIsMuted = true; + } + else + { + // We won't have full permissions data for all objects. Attempt to mute objects when we can tell their owners are muted. + if (LLSelectMgr::getInstance()) + { + LLPermissions* obj_perm = LLSelectMgr::getInstance()->findObjectPermissions(obj); + if(obj_perm) + { + if(LLMuteList::getInstance() && + LLMuteList::getInstance()->isMuted(obj_perm->getOwner())) + mIsMuted = true; + } + } + } + } + + mNeedsMuteCheck = false; + } +} + +F64 LLViewerMediaImpl::getApproximateTextureInterest() +{ + F64 result = 0.0f; + + if(mMediaSource) + { + result = mMediaSource->getFullWidth(); + result *= mMediaSource->getFullHeight(); + } + else + { + // No media source is loaded -- all we have to go on is the texture size that has been set on the impl, if any. + result = mMediaWidth; + result *= mMediaHeight; + } + + return result; +} + +void LLViewerMediaImpl::setUsedInUI(bool used_in_ui) +{ + mUsedInUI = used_in_ui; + + // HACK: Force elements used in UI to load right away. + // This fixes some issues where UI code that uses the browser instance doesn't expect it to be unloaded. + if(mUsedInUI && (mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)) + { + if(getVisible()) + { + setPriority(LLPluginClassMedia::PRIORITY_NORMAL); + } + else + { + setPriority(LLPluginClassMedia::PRIORITY_HIDDEN); + } + + createMediaSource(); + } +}; + +void LLViewerMediaImpl::setBackgroundColor(LLColor4 color) +{ + mBackgroundColor = color; + + if(mMediaSource) + { + mMediaSource->setBackgroundColor(mBackgroundColor); + } +}; + +F64 LLViewerMediaImpl::getCPUUsage() const +{ + F64 result = 0.0f; + + if(mMediaSource) + { + result = mMediaSource->getCPUUsage(); + } + + return result; +} + +void LLViewerMediaImpl::setPriority(LLPluginClassMedia::EPriority priority) +{ + if(mPriority != priority) + { + LL_DEBUGS("PluginPriority") + << "changing priority of media id " << mTextureId + << " from " << LLPluginClassMedia::priorityToString(mPriority) + << " to " << LLPluginClassMedia::priorityToString(priority) + << LL_ENDL; + } + + mPriority = priority; + + if(priority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + if(mMediaSource) + { + // Need to unload the media source + + // First, save off previous media state + mPreviousMediaState = mMediaSource->getStatus(); + mPreviousMediaTime = mMediaSource->getCurrentTime(); + + destroyMediaSource(); + } + } + + if(mMediaSource) + { + mMediaSource->setPriority(mPriority); + } + + // NOTE: loading (or reloading) media sources whose priority has risen above PRIORITY_UNLOADED is done in update(). +} + +void LLViewerMediaImpl::setLowPrioritySizeLimit(int size) +{ + if(mMediaSource) + { + mMediaSource->setLowPrioritySizeLimit(size); + } +} + +void LLViewerMediaImpl::setNavState(EMediaNavState state) +{ + mMediaNavState = state; + + switch (state) + { + case MEDIANAVSTATE_NONE: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_NONE" << llendl; break; + case MEDIANAVSTATE_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_BEGUN" << llendl; break; + case MEDIANAVSTATE_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED" << llendl; break; + case MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS" << llendl; break; + case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED" << llendl; break; + case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS" << llendl; break; + case MEDIANAVSTATE_SERVER_SENT: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_SENT" << llendl; break; + case MEDIANAVSTATE_SERVER_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_BEGUN" << llendl; break; + case MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED" << llendl; break; + case MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED" << llendl; break; + } +} + +void LLViewerMediaImpl::setNavigateSuspended(bool suspend) +{ + if(mNavigateSuspended != suspend) + { + mNavigateSuspended = suspend; + if(!suspend) + { + // We're coming out of suspend. If someone tried to do a navigate while suspended, do one now instead. + if(mNavigateSuspendedDeferred) + { + mNavigateSuspendedDeferred = false; + navigateInternal(); + } + } + } +} + +void LLViewerMediaImpl::cancelMimeTypeProbe() +{ + if(mMimeTypeProbe != NULL) + { + // There doesn't seem to be a way to actually cancel an outstanding request. + // Simulate it by telling the LLMimeDiscoveryResponder not to write back any results. + mMimeTypeProbe->cancelRequest(); + + // The above should already have set mMimeTypeProbe to NULL. + if(mMimeTypeProbe != NULL) + { + llerrs << "internal error: mMimeTypeProbe is not NULL after cancelling request." << llendl; + } + } +} + +void LLViewerMediaImpl::addObject(LLVOVolume* obj) +{ + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + for(; iter != mObjectList.end() ; ++iter) + { + if(*iter == obj) + { + return ; //already in the list. + } + } + + mObjectList.push_back(obj) ; + mNeedsMuteCheck = true; +} + +void LLViewerMediaImpl::removeObject(LLVOVolume* obj) +{ + mObjectList.remove(obj) ; + mNeedsMuteCheck = true; +} + +const std::list< LLVOVolume* >* LLViewerMediaImpl::getObjectList() const +{ + return &mObjectList ; +} + +LLVOVolume *LLViewerMediaImpl::getSomeObject() +{ + LLVOVolume *result = NULL; + + std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; + if(iter != mObjectList.end()) + { + result = *iter; + } + + return result; +} + +void LLViewerMediaImpl::setTextureID(LLUUID id) +{ + if(id != mTextureId) + { + if(mTextureId.notNull()) + { + // Remove this item's entry from the map + sViewerMediaTextureIDMap.erase(mTextureId); + } + + if(id.notNull()) + { + sViewerMediaTextureIDMap.insert(LLViewerMedia::impl_id_map::value_type(id, this)); + } + + mTextureId = id; + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::isAutoPlayable() const +{ + return (mMediaAutoPlay && + gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && + gSavedSettings.getBOOL("MediaTentativeAutoPlay")); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::shouldShowBasedOnClass() const +{ + // If this is parcel media or in the UI, return true always + if (getUsedInUI() || isParcelMedia()) return true; + + bool attached_to_another_avatar = isAttachedToAnotherAvatar(); + bool inside_parcel = isInAgentParcel(); + + // llinfos << " hasFocus = " << hasFocus() << + // " others = " << (attached_to_another_avatar && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING)) << + // " within = " << (inside_parcel && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING)) << + // " outside = " << (!inside_parcel && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING)) << llendl; + + // If it has focus, we should show it + // This is incorrect, and causes EXT-6750 (disabled attachment media still plays) +// if (hasFocus()) +// return true; + + // If it is attached to an avatar and the pref is off, we shouldn't show it + if (attached_to_another_avatar) + return gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING); + + if (inside_parcel) + return gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING); + else + return gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::isAttachedToAnotherAvatar() const +{ + bool result = false; + + std::list< LLVOVolume* >::const_iterator iter = mObjectList.begin(); + std::list< LLVOVolume* >::const_iterator end = mObjectList.end(); + for ( ; iter != end; iter++) + { + if (isObjectAttachedToAnotherAvatar(*iter)) + { + result = true; + break; + } + } + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +//static +bool LLViewerMediaImpl::isObjectAttachedToAnotherAvatar(LLVOVolume *obj) +{ + bool result = false; + LLXform *xform = obj; + // Walk up parent chain + while (NULL != xform) + { + LLViewerObject *object = dynamic_cast<LLViewerObject*> (xform); + if (NULL != object) + { + LLVOAvatar *avatar = object->asAvatar(); + if ((NULL != avatar) && (avatar != gAgentAvatarp)) + { + result = true; + break; + } + } + xform = xform->getParent(); + } + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaImpl::isInAgentParcel() const +{ + bool result = false; + + std::list< LLVOVolume* >::const_iterator iter = mObjectList.begin(); + std::list< LLVOVolume* >::const_iterator end = mObjectList.end(); + for ( ; iter != end; iter++) + { + LLVOVolume *object = *iter; + if (LLViewerMediaImpl::isObjectInAgentParcel(object)) + { + result = true; + break; + } + } + return result; +} + +LLNotificationPtr LLViewerMediaImpl::getCurrentNotification() const +{ + return mNotification; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +// static +bool LLViewerMediaImpl::isObjectInAgentParcel(LLVOVolume *obj) +{ + return (LLViewerParcelMgr::getInstance()->inAgentParcel(obj->getPositionGlobal())); +} diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index d958551a0a..b4ec3c135b 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -37,6 +37,7 @@ // newview includes #include "llagent.h" +#include "llagentaccess.h" #include "llagentcamera.h" #include "llagentwearables.h" #include "llagentpilot.h" diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index c84a14f62c..5ae4e872f3 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -42,6 +42,7 @@ // Viewer includes #include "llagent.h" +#include "llagentaccess.h" #include "llviewerwindow.h" #include "llviewercontrol.h" //#include "llfirstuse.h" @@ -54,6 +55,7 @@ #include "llresmgr.h" #include "llsdutil.h" #include "llsdutil_math.h" +#include "llslurl.h" #include "llstatusbar.h" #include "llui.h" #include "llviewertexture.h" diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h index ab07adce5d..45c9b3e91f 100644 --- a/indra/newview/llviewerprecompiledheaders.h +++ b/indra/newview/llviewerprecompiledheaders.h @@ -99,8 +99,6 @@ #include "llcoord.h" #include "llcoordframe.h" #include "llcrc.h" -#include "llinterp.h" -#include "llperlin.h" #include "llplane.h" #include "llquantize.h" #include "llrand.h" @@ -109,7 +107,6 @@ #include "m3math.h" #include "m4math.h" #include "llquaternion.h" -#include "raytrace.h" #include "v2math.h" #include "v3color.h" #include "v3dmath.h" @@ -117,16 +114,12 @@ #include "v4color.h" #include "v4coloru.h" #include "v4math.h" -////#include "vmath.h" #include "xform.h" // Library includes from llvfs #include "lldir.h" - -// Library includes from llmessage project +
+// Library includes from llmessage project
#include "llcachename.h" -// llxuixml -#include "llinitparam.h" - #endif diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index c53fdc3393..8909abf36e 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -46,6 +46,7 @@ #include "llagentcamera.h" #include "llcallingcard.h" #include "llcaphttpsender.h" +#include "llcapabilitylistener.h" #include "llcommandhandler.h" #include "lldir.h" #include "lleventpoll.h" @@ -76,6 +77,71 @@ const F32 WATER_TEXTURE_SCALE = 8.f; // Number of times to repeat the water texture across a region const S16 MAX_MAP_DIST = 10; +typedef std::map<std::string, std::string> CapabilityMap; + +class LLViewerRegionImpl { +public: + LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host) + : mHost(host), + mCompositionp(NULL), + mEventPoll(NULL), + // I'd prefer to set the LLCapabilityListener name to match the region + // name -- it's disappointing that's not available at construction time. + // We could instead store an LLCapabilityListener*, making + // setRegionNameAndZone() replace the instance. Would that pose + // consistency problems? Can we even request a capability before calling + // setRegionNameAndZone()? + // For testability -- the new Michael Feathers paradigm -- + // LLCapabilityListener binds all the globals it expects to need at + // construction time. + mCapabilityListener(host.getString(), gMessageSystem, *region, + gAgent.getID(), gAgent.getSessionID()) + { + } + + // The surfaces and other layers + LLSurface* mLandp; + + // Region geometry data + LLVector3d mOriginGlobal; // Location of southwest corner of region (meters) + LLVector3d mCenterGlobal; // Location of center in world space (meters) + LLHost mHost; + + // The unique ID for this region. + LLUUID mRegionID; + + // region/estate owner - usually null. + LLUUID mOwnerID; + + // Network statistics for the region's circuit... + LLTimer mLastNetUpdate; + + // Misc + LLVLComposition *mCompositionp; // Composition layer for the surface + + LLVOCacheEntry::vocache_entry_map_t mCacheMap; + // time? + // LRU info? + + // Cache ID is unique per-region, across renames, moving locations, + // etc. + LLUUID mCacheID; + + CapabilityMap mCapabilities; + + LLEventPoll* mEventPoll; + + /// Post an event to this LLCapabilityListener to invoke a capability message on + /// this LLViewerRegion's server + /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) + LLCapabilityListener mCapabilityListener; + + //spatial partitions for objects in this region + std::vector<LLSpatialPartition*> mObjectPartition; + + LLHTTPClient::ResponderPtr mHttpResponderPtr ; +}; + // support for secondlife:///app/region/{REGION} SLapps // N.B. this is defined to work exactly like the classic secondlife://{REGION} // However, the later syntax cannot support spaces in the region name because @@ -191,15 +257,12 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, const U32 grids_per_region_edge, const U32 grids_per_patch_edge, const F32 region_width_meters) -: mCenterGlobal(), +: mImpl(new LLViewerRegionImpl(this, host)), mHandle(handle), - mHost( host ), mTimeDilation(1.0f), mName(""), mZoning(""), - mOwnerID(), mIsEstateManager(FALSE), - mCompositionp(NULL), mRegionFlags( REGION_FLAGS_DEFAULT ), mSimAccess( SIM_ACCESS_MIN ), mBillableFactor(1.0), @@ -212,37 +275,27 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, mHttpUrl(""), mCacheLoaded(FALSE), mCacheDirty(FALSE), - mCacheID(), - mEventPoll(NULL), mReleaseNotesRequested(FALSE), - // I'd prefer to set the LLCapabilityListener name to match the region - // name -- it's disappointing that's not available at construction time. - // We could instead store an LLCapabilityListener*, making - // setRegionNameAndZone() replace the instance. Would that pose - // consistency problems? Can we even request a capability before calling - // setRegionNameAndZone()? - // For testability -- the new Michael Feathers paradigm -- - // LLCapabilityListener binds all the globals it expects to need at - // construction time. - mCapabilityListener(host.getString(), gMessageSystem, *this, - gAgent.getID(), gAgent.getSessionID()), mCapabilitiesReceived(false) { mWidth = region_width_meters; - mOriginGlobal = from_region_handle(handle); + mImpl->mOriginGlobal = from_region_handle(handle); updateRenderMatrix(); - mLandp = new LLSurface('l', NULL); + mImpl->mLandp = new LLSurface('l', NULL); // Create the composition layer for the surface - mCompositionp = new LLVLComposition(mLandp, grids_per_region_edge, region_width_meters/grids_per_region_edge); - mCompositionp->setSurface(mLandp); + mImpl->mCompositionp = + new LLVLComposition(mImpl->mLandp, + grids_per_region_edge, + region_width_meters / grids_per_region_edge); + mImpl->mCompositionp->setSurface(mImpl->mLandp); // Create the surfaces - mLandp->setRegion(this); - mLandp->create(grids_per_region_edge, + mImpl->mLandp->setRegion(this); + mImpl->mLandp->create(grids_per_region_edge, grids_per_patch_edge, - mOriginGlobal, + mImpl->mOriginGlobal, mWidth); mParcelOverlay = new LLViewerParcelOverlay(this, region_width_meters); @@ -255,24 +308,24 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, //create object partitions //MUST MATCH declaration of eObjectPartitions - mObjectPartition.push_back(new LLHUDPartition()); //PARTITION_HUD - mObjectPartition.push_back(new LLTerrainPartition()); //PARTITION_TERRAIN - mObjectPartition.push_back(new LLVoidWaterPartition()); //PARTITION_VOIDWATER - mObjectPartition.push_back(new LLWaterPartition()); //PARTITION_WATER - mObjectPartition.push_back(new LLTreePartition()); //PARTITION_TREE - mObjectPartition.push_back(new LLParticlePartition()); //PARTITION_PARTICLE - mObjectPartition.push_back(new LLCloudPartition()); //PARTITION_CLOUD - mObjectPartition.push_back(new LLGrassPartition()); //PARTITION_GRASS - mObjectPartition.push_back(new LLVolumePartition()); //PARTITION_VOLUME - mObjectPartition.push_back(new LLBridgePartition()); //PARTITION_BRIDGE - mObjectPartition.push_back(new LLHUDParticlePartition());//PARTITION_HUD_PARTICLE - mObjectPartition.push_back(NULL); //PARTITION_NONE + mImpl->mObjectPartition.push_back(new LLHUDPartition()); //PARTITION_HUD + mImpl->mObjectPartition.push_back(new LLTerrainPartition()); //PARTITION_TERRAIN + mImpl->mObjectPartition.push_back(new LLVoidWaterPartition()); //PARTITION_VOIDWATER + mImpl->mObjectPartition.push_back(new LLWaterPartition()); //PARTITION_WATER + mImpl->mObjectPartition.push_back(new LLTreePartition()); //PARTITION_TREE + mImpl->mObjectPartition.push_back(new LLParticlePartition()); //PARTITION_PARTICLE + mImpl->mObjectPartition.push_back(new LLCloudPartition()); //PARTITION_CLOUD + mImpl->mObjectPartition.push_back(new LLGrassPartition()); //PARTITION_GRASS + mImpl->mObjectPartition.push_back(new LLVolumePartition()); //PARTITION_VOLUME + mImpl->mObjectPartition.push_back(new LLBridgePartition()); //PARTITION_BRIDGE + mImpl->mObjectPartition.push_back(new LLHUDParticlePartition());//PARTITION_HUD_PARTICLE + mImpl->mObjectPartition.push_back(NULL); //PARTITION_NONE } void LLViewerRegion::initStats() { - mLastNetUpdate.reset(); + mImpl->mLastNetUpdate.reset(); mPacketsIn = 0; mBitsIn = 0; mLastBitsIn = 0; @@ -287,9 +340,9 @@ void LLViewerRegion::initStats() LLViewerRegion::~LLViewerRegion() { - if(mHttpResponderPtr) + if(mImpl->mHttpResponderPtr) { - (static_cast<BaseCapabilitiesComplete*>(mHttpResponderPtr.get()))->setRegion(NULL) ; + (static_cast<BaseCapabilitiesComplete*>(mImpl->mHttpResponderPtr.get()))->setRegion(NULL) ; } gVLManager.cleanupData(this); @@ -301,21 +354,44 @@ LLViewerRegion::~LLViewerRegion() gObjectList.killObjects(this); - delete mCompositionp; + delete mImpl->mCompositionp; delete mParcelOverlay; - delete mLandp; - delete mEventPoll; - LLHTTPSender::clearSender(mHost); + delete mImpl->mLandp; + delete mImpl->mEventPoll; + LLHTTPSender::clearSender(mImpl->mHost); saveObjectCache(); - std::for_each(mObjectPartition.begin(), mObjectPartition.end(), DeletePointer()); + std::for_each(mImpl->mObjectPartition.begin(), mImpl->mObjectPartition.end(), DeletePointer()); + + delete mImpl; + mImpl = NULL; +} + +LLEventPump& LLViewerRegion::getCapAPI() const +{ + return mImpl->mCapabilityListener.getCapAPI(); } /*virtual*/ const LLHost& LLViewerRegion::getHost() const { - return mHost; + return mImpl->mHost; +} + +LLSurface & LLViewerRegion::getLand() const +{ + return *mImpl->mLandp; +} + +const LLUUID& LLViewerRegion::getRegionID() const +{ + return mImpl->mRegionID; +} + +void LLViewerRegion::setRegionID(const LLUUID& region_id) +{ + mImpl->mRegionID = region_id; } void LLViewerRegion::loadObjectCache() @@ -330,7 +406,7 @@ void LLViewerRegion::loadObjectCache() if(LLVOCache::hasInstance()) { - LLVOCache::getInstance()->readFromCache(mHandle, mCacheID, mCacheMap) ; + LLVOCache::getInstance()->readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap) ; } } @@ -342,32 +418,32 @@ void LLViewerRegion::saveObjectCache() return; } - if (mCacheMap.empty()) + if (mImpl->mCacheMap.empty()) { return; } if(LLVOCache::hasInstance()) { - LLVOCache::getInstance()->writeToCache(mHandle, mCacheID, mCacheMap, mCacheDirty) ; + LLVOCache::getInstance()->writeToCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap, mCacheDirty) ; mCacheDirty = FALSE; } - for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mCacheMap.begin(); iter != mCacheMap.end(); ++iter) + for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.begin(); iter != mImpl->mCacheMap.end(); ++iter) { delete iter->second; } - mCacheMap.clear(); + mImpl->mCacheMap.clear(); } void LLViewerRegion::sendMessage() { - gMessageSystem->sendMessage(mHost); + gMessageSystem->sendMessage(mImpl->mHost); } void LLViewerRegion::sendReliableMessage() { - gMessageSystem->sendReliable(mHost); + gMessageSystem->sendReliable(mImpl->mHost); } void LLViewerRegion::setFlags(BOOL b, U32 flags) @@ -384,12 +460,12 @@ void LLViewerRegion::setFlags(BOOL b, U32 flags) void LLViewerRegion::setWaterHeight(F32 water_level) { - mLandp->setWaterHeight(water_level); + mImpl->mLandp->setWaterHeight(water_level); } F32 LLViewerRegion::getWaterHeight() const { - return mLandp->getWaterHeight(); + return mImpl->mLandp->getWaterHeight(); } BOOL LLViewerRegion::isVoiceEnabled() const @@ -405,9 +481,9 @@ void LLViewerRegion::setRegionFlags(U32 flags) void LLViewerRegion::setOriginGlobal(const LLVector3d &origin_global) { - mOriginGlobal = origin_global; + mImpl->mOriginGlobal = origin_global; updateRenderMatrix(); - mLandp->setOriginGlobal(origin_global); + mImpl->mLandp->setOriginGlobal(origin_global); mWind.setOriginGlobal(origin_global); mCloudLayer.setOriginGlobal(origin_global); calculateCenterGlobal(); @@ -423,16 +499,34 @@ void LLViewerRegion::setTimeDilation(F32 time_dilation) mTimeDilation = time_dilation; } +const LLVector3d & LLViewerRegion::getOriginGlobal() const +{ + return mImpl->mOriginGlobal; +} LLVector3 LLViewerRegion::getOriginAgent() const { - return gAgent.getPosAgentFromGlobal(mOriginGlobal); + return gAgent.getPosAgentFromGlobal(mImpl->mOriginGlobal); } +const LLVector3d & LLViewerRegion::getCenterGlobal() const +{ + return mImpl->mCenterGlobal; +} LLVector3 LLViewerRegion::getCenterAgent() const { - return gAgent.getPosAgentFromGlobal(mCenterGlobal); + return gAgent.getPosAgentFromGlobal(mImpl->mCenterGlobal); +} + +void LLViewerRegion::setOwner(const LLUUID& owner_id) +{ + mImpl->mOwnerID = owner_id; +} + +const LLUUID& LLViewerRegion::getOwner() const +{ + return mImpl->mOwnerID; } void LLViewerRegion::setRegionNameAndZone (const std::string& name_zone) @@ -557,7 +651,10 @@ void LLViewerRegion::processRegionInfo(LLMessageSystem* msg, void**) LLFloaterReporter::processRegionInfo(msg); } - +void LLViewerRegion::setCacheID(const LLUUID& id) +{ + mImpl->mCacheID = id; +} S32 LLViewerRegion::renderPropertyLines() { @@ -585,7 +682,7 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time) { LLMemType mt_ivr(LLMemType::MTYPE_IDLE_UPDATE_VIEWER_REGION); // did_update returns TRUE if we did at least one significant update - BOOL did_update = mLandp->idleUpdate(max_update_time); + BOOL did_update = mImpl->mLandp->idleUpdate(max_update_time); if (mParcelOverlay) { @@ -600,7 +697,7 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time) // As above, but forcibly do the update. void LLViewerRegion::forceUpdate() { - mLandp->idleUpdate(0.f); + mImpl->mLandp->idleUpdate(0.f); if (mParcelOverlay) { @@ -610,17 +707,21 @@ void LLViewerRegion::forceUpdate() void LLViewerRegion::connectNeighbor(LLViewerRegion *neighborp, U32 direction) { - mLandp->connectNeighbor(neighborp->mLandp, direction); + mImpl->mLandp->connectNeighbor(neighborp->mImpl->mLandp, direction); mCloudLayer.connectNeighbor(&(neighborp->mCloudLayer), direction); } void LLViewerRegion::disconnectAllNeighbors() { - mLandp->disconnectAllNeighbors(); + mImpl->mLandp->disconnectAllNeighbors(); mCloudLayer.disconnectAllNeighbors(); } +LLVLComposition * LLViewerRegion::getComposition() const +{ + return mImpl->mCompositionp; +} F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const { @@ -714,10 +815,10 @@ F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const void LLViewerRegion::calculateCenterGlobal() { - mCenterGlobal = mOriginGlobal; - mCenterGlobal.mdV[VX] += 0.5 * mWidth; - mCenterGlobal.mdV[VY] += 0.5 * mWidth; - mCenterGlobal.mdV[VZ] = 0.5*mLandp->getMinZ() + mLandp->getMaxZ(); + mImpl->mCenterGlobal = mImpl->mOriginGlobal; + mImpl->mCenterGlobal.mdV[VX] += 0.5 * mWidth; + mImpl->mCenterGlobal.mdV[VY] += 0.5 * mWidth; + mImpl->mCenterGlobal.mdV[VZ] = 0.5 * mImpl->mLandp->getMinZ() + mImpl->mLandp->getMaxZ(); } void LLViewerRegion::calculateCameraDistance() @@ -728,7 +829,7 @@ void LLViewerRegion::calculateCameraDistance() std::ostream& operator<<(std::ostream &s, const LLViewerRegion ®ion) { s << "{ "; - s << region.mHost; + s << region.mImpl->mHost; s << " mOriginGlobal = " << region.getOriginGlobal()<< "\n"; std::string name(region.getName()), zone(region.getZoning()); if (! name.empty()) @@ -748,9 +849,9 @@ std::ostream& operator<<(std::ostream &s, const LLViewerRegion ®ion) void LLViewerRegion::updateNetStats() { - F32 dt = mLastNetUpdate.getElapsedTimeAndResetF32(); + F32 dt = mImpl->mLastNetUpdate.getElapsedTimeAndResetF32(); - LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mHost); + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mImpl->mHost); if (!cdp) { mAlive = false; @@ -779,10 +880,10 @@ void LLViewerRegion::updateNetStats() U32 LLViewerRegion::getPacketsLost() const { - LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mHost); + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mImpl->mHost); if (!cdp) { - llinfos << "LLViewerRegion::getPacketsLost couldn't find circuit for " << mHost << llendl; + llinfos << "LLViewerRegion::getPacketsLost couldn't find circuit for " << mImpl->mHost << llendl; return 0; } else @@ -791,6 +892,16 @@ U32 LLViewerRegion::getPacketsLost() const } } +void LLViewerRegion::setHttpResponderPtrNULL() +{ + mImpl->mHttpResponderPtr = NULL; +} + +const LLHTTPClient::ResponderPtr LLViewerRegion::getHttpResponderPtr() const +{ + return mImpl->mHttpResponderPtr; +} + BOOL LLViewerRegion::pointInRegionGlobal(const LLVector3d &point_global) const { LLVector3 pos_region = getPosRegionFromGlobal(point_global); @@ -817,7 +928,7 @@ BOOL LLViewerRegion::pointInRegionGlobal(const LLVector3d &point_global) const LLVector3 LLViewerRegion::getPosRegionFromGlobal(const LLVector3d &point_global) const { LLVector3 pos_region; - pos_region.setVec(point_global - mOriginGlobal); + pos_region.setVec(point_global - mImpl->mOriginGlobal); return pos_region; } @@ -825,7 +936,7 @@ LLVector3d LLViewerRegion::getPosGlobalFromRegion(const LLVector3 &pos_region) c { LLVector3d pos_region_d; pos_region_d.setVec(pos_region); - return pos_region_d + mOriginGlobal; + return pos_region_d + mImpl->mOriginGlobal; } LLVector3 LLViewerRegion::getPosAgentFromRegion(const LLVector3 &pos_region) const @@ -842,7 +953,7 @@ LLVector3 LLViewerRegion::getPosRegionFromAgent(const LLVector3 &pos_agent) cons F32 LLViewerRegion::getLandHeightRegion(const LLVector3& region_pos) { - return mLandp->resolveHeightRegion( region_pos ); + return mImpl->mLandp->resolveHeightRegion( region_pos ); } bool LLViewerRegion::isAlive() @@ -994,7 +1105,7 @@ void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg) // treat the target specially for the map if(i == target_index) { - LLVector3d global_pos(mOriginGlobal); + LLVector3d global_pos(mImpl->mOriginGlobal); global_pos.mdV[VX] += (F64)(x_pos); global_pos.mdV[VY] += (F64)(y_pos); global_pos.mdV[VZ] += (F64)(z_pos) * 4.0; @@ -1034,7 +1145,7 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObjec U32 local_id = objectp->getLocalID(); U32 crc = objectp->getCRC(); - LLVOCacheEntry* entry = get_if_there(mCacheMap, local_id, (LLVOCacheEntry*)NULL); + LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL); if (entry) { @@ -1047,10 +1158,10 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObjec } // Update the cache entry - mCacheMap.erase(local_id); + mImpl->mCacheMap.erase(local_id); delete entry; entry = new LLVOCacheEntry(local_id, crc, dp); - mCacheMap[local_id] = entry; + mImpl->mCacheMap[local_id] = entry; return CACHE_UPDATE_CHANGED; } @@ -1058,15 +1169,15 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObjec // Create new entry and add to map eCacheUpdateResult result = CACHE_UPDATE_ADDED; - if (mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES) + if (mImpl->mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES) { - mCacheMap.erase(mCacheMap.begin()); + mImpl->mCacheMap.erase(mImpl->mCacheMap.begin()); result = CACHE_UPDATE_REPLACED; } entry = new LLVOCacheEntry(local_id, crc, dp); - mCacheMap[local_id] = entry; + mImpl->mCacheMap[local_id] = entry; return result; } @@ -1076,7 +1187,7 @@ LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type) { llassert(mCacheLoaded); - LLVOCacheEntry* entry = get_if_there(mCacheMap, local_id, (LLVOCacheEntry*)NULL); + LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL); if (entry) { @@ -1203,7 +1314,7 @@ void LLViewerRegion::dumpCache() } LLVOCacheEntry *entry; - for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mCacheMap.begin(); iter != mCacheMap.end(); ++iter) + for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.begin(); iter != mImpl->mCacheMap.end(); ++iter) { entry = iter->second ; @@ -1217,7 +1328,7 @@ void LLViewerRegion::dumpCache() change_bin[changes]++; } - llinfos << "Count " << mCacheMap.size() << llendl; + llinfos << "Count " << mImpl->mCacheMap.size() << llendl; for (i = 0; i < BINS; i++) { llinfos << "Hits " << i << " " << hit_bin[i] << llendl; @@ -1360,10 +1471,10 @@ void LLViewerRegion::setSeedCapability(const std::string& url) return; } - delete mEventPoll; - mEventPoll = NULL; + delete mImpl->mEventPoll; + mImpl->mEventPoll = NULL; - mCapabilities.clear(); + mImpl->mCapabilities.clear(); setCapability("Seed", url); LLSD capabilityNames = LLSD::emptyArray(); @@ -1430,25 +1541,25 @@ void LLViewerRegion::setSeedCapability(const std::string& url) llinfos << "posting to seed " << url << llendl; - mHttpResponderPtr = BaseCapabilitiesComplete::build(this) ; - LLHTTPClient::post(url, capabilityNames, mHttpResponderPtr); + mImpl->mHttpResponderPtr = BaseCapabilitiesComplete::build(this) ; + LLHTTPClient::post(url, capabilityNames, mImpl->mHttpResponderPtr); } void LLViewerRegion::setCapability(const std::string& name, const std::string& url) { if(name == "EventQueueGet") { - delete mEventPoll; - mEventPoll = NULL; - mEventPoll = new LLEventPoll(url, getHost()); + delete mImpl->mEventPoll; + mImpl->mEventPoll = NULL; + mImpl->mEventPoll = new LLEventPoll(url, getHost()); } else if(name == "UntrustedSimulatorMessage") { - LLHTTPSender::setSender(mHost, new LLCapHTTPSender(url)); + LLHTTPSender::setSender(mImpl->mHost, new LLCapHTTPSender(url)); } else { - mCapabilities[name] = url; + mImpl->mCapabilities[name] = url; if(name == "GetTexture") { mHttpUrl = url ; @@ -1463,8 +1574,8 @@ bool LLViewerRegion::isSpecialCapabilityName(const std::string &name) std::string LLViewerRegion::getCapability(const std::string& name) const { - CapabilityMap::const_iterator iter = mCapabilities.find(name); - if(iter == mCapabilities.end()) + CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); + if(iter == mImpl->mCapabilities.end()) { return ""; } @@ -1485,7 +1596,7 @@ void LLViewerRegion::logActiveCapabilities() const { int count = 0; CapabilityMap::const_iterator iter; - for (iter = mCapabilities.begin(); iter != mCapabilities.end(); iter++, count++) + for (iter = mImpl->mCapabilities.begin(); iter != mImpl->mCapabilities.end(); ++iter, ++count) { if (!iter->second.empty()) { @@ -1497,9 +1608,9 @@ void LLViewerRegion::logActiveCapabilities() const LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type) { - if (type < mObjectPartition.size()) + if (type < mImpl->mObjectPartition.size()) { - return mObjectPartition[type]; + return mImpl->mObjectPartition[type]; } return NULL; } diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index dd40b876cd..9c5b85b77f 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -33,20 +33,16 @@ #include "lldarray.h" #include "llwind.h" -#include "llbbox.h" #include "llcloud.h" #include "llstat.h" #include "v3dmath.h" -#include "llhost.h" #include "llstring.h" #include "llregionflags.h" #include "lluuid.h" -#include "lldatapacker.h" -#include "llvocache.h" #include "llweb.h" #include "llcapabilityprovider.h" -#include "llcapabilitylistener.h" #include "m4math.h" // LLMatrix4 +#include "llhttpclient.h" // Surface id's #define LAND 1 @@ -65,6 +61,13 @@ class LLVOCache; class LLVOCacheEntry; class LLSpatialPartition; class LLEventPump; +class LLCapabilityListener; +class LLDataPacker; +class LLDataPackerBinaryBuffer; +class LLHost; +class LLBBox; + +class LLViewerRegionImpl; class LLViewerRegion: public LLCapabilityProvider // implements this interface { @@ -159,19 +162,19 @@ public: F32 getTimeDilation() const { return mTimeDilation; } // Origin height is at zero. - const LLVector3d &getOriginGlobal() const { return mOriginGlobal; } + const LLVector3d &getOriginGlobal() const; LLVector3 getOriginAgent() const; // Center is at the height of the water table. - const LLVector3d &getCenterGlobal() const { return mCenterGlobal; } + const LLVector3d &getCenterGlobal() const; LLVector3 getCenterAgent() const; void setRegionNameAndZone(const std::string& name_and_zone); const std::string& getName() const { return mName; } const std::string& getZoning() const { return mZoning; } - void setOwner(const LLUUID& owner_id) { mOwnerID = owner_id; } - const LLUUID& getOwner() const { return mOwnerID; } + void setOwner(const LLUUID& owner_id); + const LLUUID& getOwner() const; // Is the current agent on the estate manager list for this region? void setIsEstateManager(BOOL b) { mIsEstateManager = b; } @@ -206,7 +209,7 @@ public: // can process the message. static void processRegionInfo(LLMessageSystem* msg, void**); - void setCacheID(const LLUUID& id) { mCacheID = id; } + void setCacheID(const LLUUID& id); F32 getWidth() const { return mWidth; } @@ -222,8 +225,8 @@ public: U32 getPacketsLost() const; - void setHttpResponderPtrNULL() {mHttpResponderPtr = NULL ;} - const LLHTTPClient::ResponderPtr getHttpResponderPtr() const {return mHttpResponderPtr ;} + void setHttpResponderPtrNULL(); + const LLHTTPClient::ResponderPtr getHttpResponderPtr() const; // Get/set named capability URLs for this region. void setSeedCapability(const std::string& url); @@ -238,21 +241,19 @@ public: static bool isSpecialCapabilityName(const std::string &name); void logActiveCapabilities() const; - /// Capability-request exception - typedef LLCapabilityListener::ArgError ArgError; /// Get LLEventPump on which we listen for capability requests /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) - LLEventPump& getCapAPI() { return mCapabilityListener.getCapAPI(); } + LLEventPump& getCapAPI() const; /// implements LLCapabilityProvider /*virtual*/ const LLHost& getHost() const; const U64 &getHandle() const { return mHandle; } - LLSurface &getLand() const { return *mLandp; } + LLSurface &getLand() const; // set and get the region id - const LLUUID& getRegionID() const { return mRegionID; } - void setRegionID(const LLUUID& region_id) { mRegionID = region_id; } + const LLUUID& getRegionID() const; + void setRegionID(const LLUUID& region_id); BOOL pointInRegionGlobal(const LLVector3d &point_global) const; LLVector3 getPosRegionFromGlobal(const LLVector3d &point_global) const; @@ -260,7 +261,7 @@ public: LLVector3 getPosAgentFromRegion(const LLVector3 ®ion_pos) const; LLVector3d getPosGlobalFromRegion(const LLVector3 &offset) const; - LLVLComposition *getComposition() const { return mCompositionp; } + LLVLComposition *getComposition() const; F32 getCompositionXY(const S32 x, const S32 y) const; BOOL isOwnedSelf(const LLVector3& pos); @@ -347,34 +348,19 @@ public: LLDynamicArray<LLUUID> mMapAvatarIDs; private: - // The surfaces and other layers - LLSurface* mLandp; + LLViewerRegionImpl * mImpl; - // Region geometry data - LLVector3d mOriginGlobal; // Location of southwest corner of region (meters) - LLVector3d mCenterGlobal; // Location of center in world space (meters) F32 mWidth; // Width of region on a side (meters) - U64 mHandle; - LLHost mHost; - - // The unique ID for this region. - LLUUID mRegionID; - F32 mTimeDilation; // time dilation of physics simulation on simulator // simulator name std::string mName; std::string mZoning; - // region/estate owner - usually null. - LLUUID mOwnerID; - // Is this agent on the estate managers list for this region? BOOL mIsEstateManager; - // Network statistics for the region's circuit... - LLTimer mLastNetUpdate; U32 mPacketsIn; U32 mBitsIn; U32 mLastBitsIn; @@ -386,9 +372,6 @@ private: U32 mPingDelay; F32 mDeltaTime; // Time since last measurement of lastPackets, Bits, etc - // Misc - LLVLComposition *mCompositionp; // Composition layer for the surface - U32 mRegionFlags; // includes damage flags U8 mSimAccess; F32 mBillableFactor; @@ -398,46 +381,24 @@ private: // Information for Homestead / CR-53 S32 mClassID; S32 mCPURatio; + std::string mColoName; std::string mProductSKU; std::string mProductName; std::string mHttpUrl ; - // Maps local ids to cache entries. // Regions can have order 10,000 objects, so assume // a structure of size 2^14 = 16,000 BOOL mCacheLoaded; BOOL mCacheDirty; - LLVOCacheEntry::vocache_entry_map_t mCacheMap; + LLDynamicArray<U32> mCacheMissFull; LLDynamicArray<U32> mCacheMissCRC; - // time? - // LRU info? - // Cache ID is unique per-region, across renames, moving locations, - // etc. - LLUUID mCacheID; - - typedef std::map<std::string, std::string> CapabilityMap; - CapabilityMap mCapabilities; - - LLEventPoll* mEventPoll; - - /// Post an event to this LLCapabilityListener to invoke a capability message on - /// this LLViewerRegion's server - /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) - LLCapabilityListener mCapabilityListener; - -private: bool mAlive; // can become false if circuit disconnects bool mCapabilitiesReceived; - //spatial partitions for objects in this region - std::vector<LLSpatialPartition*> mObjectPartition; - - LLHTTPClient::ResponderPtr mHttpResponderPtr ; - BOOL mReleaseNotesRequested; }; diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index 27aab0c081..d02b6be6b5 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -217,24 +217,24 @@ class LLUIImageList : public LLImageProviderInterface, public LLSingleton<LLUIIm { public: // LLImageProviderInterface - /*virtual*/ LLUIImagePtr getUIImageByID(const LLUUID& id, S32 priority); - /*virtual*/ LLUIImagePtr getUIImage(const std::string& name, S32 priority); + /*virtual*/ LLPointer<LLUIImage> getUIImageByID(const LLUUID& id, S32 priority); + /*virtual*/ LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority); void cleanUp(); bool initFromFile(); - LLUIImagePtr preloadUIImage(const std::string& name, const std::string& filename, BOOL use_mips, const LLRect& scale_rect); + LLPointer<LLUIImage> preloadUIImage(const std::string& name, const std::string& filename, BOOL use_mips, const LLRect& scale_rect); static void onUIImageLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ); private: - LLUIImagePtr loadUIImageByName(const std::string& name, const std::string& filename, + LLPointer<LLUIImage> loadUIImageByName(const std::string& name, const std::string& filename, BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null, LLViewerTexture::EBoostLevel boost_priority = LLViewerTexture::BOOST_UI); - LLUIImagePtr loadUIImageByID(const LLUUID& id, + LLPointer<LLUIImage> loadUIImageByID(const LLUUID& id, BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null, LLViewerTexture::EBoostLevel boost_priority = LLViewerTexture::BOOST_UI); - LLUIImagePtr loadUIImage(LLViewerFetchedTexture* imagep, const std::string& name, BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null); + LLPointer<LLUIImage> loadUIImage(LLViewerFetchedTexture* imagep, const std::string& name, BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null); struct LLUIImageLoadData diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index e020296842..7728958ed8 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -79,6 +79,7 @@ #include "lltooltip.h" #include "llmediaentry.h" #include "llurldispatcher.h" +#include "raytrace.h" // newview includes #include "llagent.h" @@ -234,17 +235,12 @@ BOOL gDisplayCameraPos = FALSE; BOOL gDisplayFOV = FALSE; BOOL gDisplayBadge = FALSE; -S32 CHAT_BAR_HEIGHT = 28; -S32 OVERLAY_BAR_HEIGHT = 20; - -const U8 NO_FACE = 255; +static const U8 NO_FACE = 255; BOOL gQuietSnapshot = FALSE; const F32 MIN_AFK_TIME = 2.f; // minimum time after setting away state before coming back -const F32 MAX_FAST_FRAME_TIME = 0.5f; -const F32 FAST_FRAME_INCREMENT = 0.1f; -const F32 MIN_DISPLAY_SCALE = 0.75f; +static const F32 MIN_DISPLAY_SCALE = 0.75f; std::string LLViewerWindow::sSnapshotBaseName; std::string LLViewerWindow::sSnapshotDir; diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 5eeb02b080..bb0023b787 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -38,13 +38,12 @@ #include "v3dmath.h" #include "v2math.h" +#include "llcursortypes.h" #include "llwindowcallbacks.h" #include "lltimer.h" #include "llstat.h" #include "llmousehandler.h" -#include "llcursortypes.h" #include "llhandle.h" -#include "llimage.h" #include <boost/function.hpp> #include <boost/signals2.hpp> @@ -59,6 +58,7 @@ class LLTool; class LLVelocityBar; class LLPanel; class LLImageRaw; +class LLImageFormatted; class LLHUDIcon; class LLWindow; class LLRootView; @@ -465,12 +465,6 @@ private: LLPointer<LLViewerObject> mDragHoveredObject; }; -void toggle_flying(void*); -void toggle_first_person(); -void toggle_build(void*); -void reset_viewer_state_on_sim(void); -void update_saved_window_size(const std::string& control,S32 delta_width, S32 delta_height); - // // Globals // @@ -487,8 +481,6 @@ extern LLVector3 gDebugRaycastNormal; extern LLVector3 gDebugRaycastBinormal; extern S32 gDebugRaycastFaceHit; -extern S32 CHAT_BAR_HEIGHT; - extern BOOL gDisplayCameraPos; extern BOOL gDisplayWindInfo; extern BOOL gDisplayFOV; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index f1934933b5..79866dc5d2 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -38,9 +38,9 @@ #include <ctype.h> #include "llaudioengine.h" -#include "llcachename.h" #include "noise.h" #include "sound_ids.h" +#include "raytrace.h" #include "llagent.h" // Get state values from here #include "llagentcamera.h" diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index 37a974be28..46025b46be 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -50,6 +50,7 @@ #include "pipeline.h" #include "llspatialpartition.h" #include "llnotificationsutil.h" +#include "raytrace.h" extern LLPipeline gPipeline; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index a207d3e050..ee54a938ba 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -63,6 +63,8 @@ #include "llmediadataclient.h" #include "llagent.h" #include "llviewermediafocus.h" +#include "lldatapacker.h" +#include "llvocache.h" const S32 MIN_QUIET_FRAMES_COALESCE = 30; const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp index 4b3a9a4dc3..67bb965f99 100644 --- a/indra/newview/llwaterparammanager.cpp +++ b/indra/newview/llwaterparammanager.cpp @@ -33,6 +33,7 @@ #include "pipeline.h" #include "llsky.h" +#include "lldiriterator.h" #include "llfloaterreg.h" #include "llsliderctrl.h" #include "llspinctrl.h" @@ -87,11 +88,12 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name) std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/water", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading Default water settings from " << path_name << LL_ENDL; - bool found = true; + bool found = true; + LLDirIterator app_settings_iter(path_name, "*.xml"); while(found) { std::string name; - found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name); + found = app_settings_iter.next(name); if(found) { @@ -113,11 +115,12 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name) std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/water", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading User water settings from " << path_name2 << LL_ENDL; - found = true; + found = true; + LLDirIterator user_settings_iter(path_name2, "*.xml"); while(found) { std::string name; - found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name); + found = user_settings_iter.next(name); if(found) { name=name.erase(name.length()-4); diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp index e5f52dfc97..848efcbb49 100644 --- a/indra/newview/llwlparammanager.cpp +++ b/indra/newview/llwlparammanager.cpp @@ -31,6 +31,7 @@ #include "pipeline.h" #include "llsky.h" +#include "lldiriterator.h" #include "llfloaterreg.h" #include "llsliderctrl.h" #include "llspinctrl.h" @@ -100,11 +101,12 @@ void LLWLParamManager::loadPresets(const std::string& file_name) std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/skies", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading Default WindLight settings from " << path_name << LL_ENDL; - bool found = true; + bool found = true; + LLDirIterator app_settings_iter(path_name, "*.xml"); while(found) { std::string name; - found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name); + found = app_settings_iter.next(name); if(found) { @@ -126,11 +128,12 @@ void LLWLParamManager::loadPresets(const std::string& file_name) std::string path_name2(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", "")); LL_DEBUGS2("AppInit", "Shaders") << "Loading User WindLight settings from " << path_name2 << LL_ENDL; - found = true; + found = true; + LLDirIterator user_settings_iter(path_name2, "*.xml"); while(found) { std::string name; - found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name); + found = user_settings_iter.next(name); if(found) { name=name.erase(name.length()-4); diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 8f50041474..fd42058c8a 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -50,6 +50,7 @@ #include "llviewerstats.h" #include "llvlcomposition.h" #include "llvoavatar.h" +#include "llvocache.h" #include "llvowater.h" #include "message.h" #include "pipeline.h" diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 85182c1c28..d0603cb30e 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -1856,26 +1856,26 @@ even though the user gets a free copy. <spinner follows="left|top" height="19" - increment="0.025" + increment="0.02" initial_value="0" label="B" label_width="10" layout="topleft" left_delta="0" - max_val="0.95" + max_val="0.98" name="Path Limit Begin" top_pad="3" width="68" /> <spinner follows="left|top" height="19" - increment="0.025" + increment="0.02" initial_value="1" label="E" label_width="10" layout="topleft" left_pad="10" - min_val="0.05" + min_val="0.02" name="Path Limit End" top_delta="0" width="68" /> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 06614dd218..d0dd639249 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6820,7 +6820,7 @@ Deed to group failed. name="ReleaseLandThrottled" type="notifytip"> The parcel [PARCEL_NAME] can not be abandoned at this time. - tag>fail</tag> + <tag>fail</tag> </notification> <notification diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml index 75126e74c5..5a913c4c9d 100644 --- a/indra/newview/skins/default/xui/es/strings.xml +++ b/indra/newview/skins/default/xui/es/strings.xml @@ -3588,6 +3588,9 @@ Si sigues recibiendo este mensaje, contacta con [SUPPORT_SITE]. <string name="conference-title-incoming"> Conferencia con [AGENT_NAME] </string> + <string name="inventory_item_offered-im"> + Ofrecido el item del inventario + </string> <string name="no_session_message"> (La sesión de MI no existe) </string> diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml index 6466f42c75..1dbbcafb0e 100644 --- a/indra/newview/skins/default/xui/pt/strings.xml +++ b/indra/newview/skins/default/xui/pt/strings.xml @@ -3587,6 +3587,9 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. <string name="conference-title-incoming"> Conversa com [AGENT_NAME] </string> + <string name="inventory_item_offered-im"> + Oferta de item de inventário + </string> <string name="no_session_message"> (Sessão de MI inexistente) </string> diff --git a/indra/newview/skins/default/xui/zh/panel_login.xml b/indra/newview/skins/default/xui/zh/panel_login.xml new file mode 100644 index 0000000000..9d094ff731 --- /dev/null +++ b/indra/newview/skins/default/xui/zh/panel_login.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<panel name="panel_login"> + <layout_stack name="login_widgets"> + <layout_panel name="login"> + <text name="username_text"> + 使用者名稱: + </text> + <text name="password_text"> + 密碼: + </text> + <check_box label="記住密碼" name="remember_check"/> + <button label="登入" name="connect_btn"/> + <text name="mode_selection_text"> + 模式: + </text> + <combo_box name="mode_combo" tool_tip="選擇一個登入模式"> + <combo_box.item label="基礎" name="Basic"/> + <combo_box.item label="進階" name="Advanced"/> + </combo_box> + <text name="start_location_text"> + 開始地點: + </text> + <combo_box name="start_location_combo"> + <combo_box.item label="上一次的地點" name="MyLastLocation"/> + <combo_box.item label="我的家" name="MyHome"/> + <combo_box.item label="<輸入區域名>" name="Typeregionname"/> + </combo_box> + </layout_panel> + <layout_panel name="links"> + <text name="create_new_account_text"> + 註冊 + </text> + <text name="forgot_password_text"> + 忘記使用者名稱或密碼? + </text> + <text name="login_help"> + 如何登入? + </text> + </layout_panel> + </layout_stack> +</panel> diff --git a/indra/newview/tests/llremoteparcelrequest_test.cpp b/indra/newview/tests/llremoteparcelrequest_test.cpp index 9a6e08ee84..ed66066b0a 100644 --- a/indra/newview/tests/llremoteparcelrequest_test.cpp +++ b/indra/newview/tests/llremoteparcelrequest_test.cpp @@ -35,7 +35,6 @@ #include "llurlentry.h" namespace { - LLControlGroup s_saved_settings("dummy_settings"); const LLUUID TEST_PARCEL_ID("11111111-1111-1111-1111-111111111111"); } @@ -64,13 +63,12 @@ LLMessageSystem * gMessageSystem; char const* const _PREHASH_AgentID = 0; // never dereferenced during this test char const* const _PREHASH_AgentData = 0; // never dereferenced during this test LLAgent gAgent; -LLAgent::LLAgent() : mAgentAccess(s_saved_settings) { } +LLAgent::LLAgent() : mAgentAccess(NULL) { } LLAgent::~LLAgent() { } void LLAgent::sendReliableMessage(void) { } LLUUID gAgentSessionID; LLUUID gAgentID; LLUIColor::LLUIColor(void) { } -LLAgentAccess::LLAgentAccess(LLControlGroup & settings) : mSavedSettings(settings) { } LLControlGroup::LLControlGroup(std::string const & name) : LLInstanceTracker<LLControlGroup, std::string>(name) { } LLControlGroup::~LLControlGroup(void) { } void LLUrlEntryParcel::processParcelInfo(const LLUrlEntryParcel::LLParcelData& parcel_data) { } diff --git a/indra/newview/tests/llviewerhelputil_test.cpp b/indra/newview/tests/llviewerhelputil_test.cpp index b425b50c8b..710881d811 100644 --- a/indra/newview/tests/llviewerhelputil_test.cpp +++ b/indra/newview/tests/llviewerhelputil_test.cpp @@ -73,11 +73,9 @@ static void substitute_string(std::string &input, const std::string &search, con } #include "../llagent.h" -LLAgent::LLAgent() : mAgentAccess(gSavedSettings) { } +LLAgent::LLAgent() : mAgentAccess(NULL) { } LLAgent::~LLAgent() { } bool LLAgent::isGodlike() const { return FALSE; } -LLAgentAccess::LLAgentAccess(LLControlGroup& settings) : mSavedSettings(settings) { } -LLUIColor::LLUIColor() {} LLAgent gAgent; diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp index 88ab5a2284..e19d5724f1 100644 --- a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp +++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp @@ -59,12 +59,6 @@ class LLDir_Mock : public LLDir return 0; } - BOOL getNextFileInDir(const std::string &dirname, - const std::string &mask, - std::string &fname) - { - return false; - } void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) {} |