diff options
45 files changed, 3558 insertions, 3090 deletions
| @@ -184,4 +184,6 @@ f2412ecd6740803ea9452f1d17fd872e263a0df7 3.0.2-start  e5c9af2d7980a99a71650be3a0cf7b2b3c3b897e DRTVWR-86_3.0.2-beta2  e5c9af2d7980a99a71650be3a0cf7b2b3c3b897e 3.0.2-beta2  b95ddac176ac944efdc85cbee94ac2e1eab44c79 3.0.3-start +6694f3f062aa45f64ab391d25a3eb3d5eb1b0871 DRTVWR-85_3.0.3-beta1  586907287be581817b2422b5137971b22d54ea48 3.0.4-start +6694f3f062aa45f64ab391d25a3eb3d5eb1b0871 3.0.3-beta1 diff --git a/autobuild.xml b/autobuild.xml index e5c6b83037..347ef419ed 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1206,9 +1206,9 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>a7c80fd8516df3b879b669b2b220067f</string> +              <string>9cd66e879908f047d9af665b92946ecc</string>                <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/232420/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20110608.tar.bz2</string> +              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/239803/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20110830.tar.bz2</string>              </map>              <key>name</key>              <string>darwin</string> @@ -1230,9 +1230,9 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>b9cc0333cc274c9cc40256ab7146b4fc</string> +              <string>ab9393795515cbbe9526bde33b41bf2a</string>                <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/232420/arch/CYGWIN/installer/llqtwebkit-4.7.1-windows-20110608.tar.bz2</string> +              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/239670/arch/CYGWIN/installer/llqtwebkit-4.7.1-windows-20110829.tar.bz2</string>              </map>              <key>name</key>              <string>windows</string> diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 658eefbab2..6f39aba976 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -322,6 +322,7 @@ if (LL_TESTS)    LL_ADD_INTEGRATION_TEST(llrand "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(llsdserialize "" "${test_libs}"                            "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/setpython.py") +  LL_ADD_INTEGRATION_TEST(llsingleton "" "${test_libs}")                              LL_ADD_INTEGRATION_TEST(llstring "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(lltreeiterators "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(lluri "" "${test_libs}") diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp index f576204511..5dc3ea5d7b 100644 --- a/indra/llcommon/llinstancetracker.cpp +++ b/indra/llcommon/llinstancetracker.cpp @@ -35,14 +35,15 @@  //static   void * & LLInstanceTrackerBase::getInstances(std::type_info const & info)  { -	static std::map<std::string, void *> instances; +	typedef std::map<std::string, void *> InstancesMap; +	static InstancesMap instances; -	std::string k = info.name(); -	if(instances.find(k) == instances.end()) -	{ -		instances[k] = NULL; -	} - -	return instances[k]; +	// std::map::insert() is just what we want here. You attempt to insert a +	// (key, value) pair. If the specified key doesn't yet exist, it inserts +	// the pair and returns a std::pair of (iterator, true). If the specified +	// key DOES exist, insert() simply returns (iterator, false). One lookup +	// handles both cases. +	return instances.insert(InstancesMap::value_type(info.name(), +													 InstancesMap::mapped_type())) +		.first->second;  } - diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index afb714c71c..5a3990a8df 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -29,6 +29,7 @@  #define LL_LLINSTANCETRACKER_H  #include <map> +#include <typeinfo>  #include "string_table.h"  #include <boost/utility.hpp> @@ -37,10 +38,40 @@  #include <boost/iterator/transform_iterator.hpp>  #include <boost/iterator/indirect_iterator.hpp> +/** + * Base class manages "class-static" data that must actually have singleton + * semantics: one instance per process, rather than one instance per module as + * sometimes happens with data simply declared static. + */  class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable  { -	protected: -		static void * & getInstances(std::type_info const & info); +protected: +	/// Get a process-unique void* pointer slot for the specified type_info +	static void * & getInstances(std::type_info const & info); + +	/// Find or create a STATICDATA instance for the specified TRACKED class. +	/// STATICDATA must be default-constructible. +	template<typename STATICDATA, class TRACKED> +	static STATICDATA& getStatic() +	{ +		void *& instances = getInstances(typeid(TRACKED)); +		if (! instances) +		{ +			instances = new STATICDATA; +		} +		return *static_cast<STATICDATA*>(instances); +	} + +    /// It's not essential to derive your STATICDATA (for use with +    /// getStatic()) from StaticBase; it's just that both known +    /// implementations do. +    struct StaticBase +    { +        StaticBase(): +            sIterationNestDepth(0) +        {} +        S32 sIterationNestDepth; +    };  };  /// This mix-in class adds support for tracking all instances of the specified class parameter T @@ -50,8 +81,15 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable  template<typename T, typename KEY = T*>  class LLInstanceTracker : public LLInstanceTrackerBase  { -	typedef typename std::map<KEY, T*> InstanceMap;  	typedef LLInstanceTracker<T, KEY> MyT; +	typedef typename std::map<KEY, T*> InstanceMap; +	struct StaticData: public StaticBase +	{ +		InstanceMap sMap; +	}; +	static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); } +	static InstanceMap& getMap_() { return getStatic().sMap; } +  public:  	class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>  	{ @@ -61,12 +99,12 @@ public:  		instance_iter(const typename InstanceMap::iterator& it)  		:	mIterator(it)  		{ -			++sIterationNestDepth; +			++getStatic().sIterationNestDepth;  		}  		~instance_iter()  		{ -			--sIterationNestDepth; +			--getStatic().sIterationNestDepth;  		} @@ -95,18 +133,18 @@ public:  		key_iter(typename InstanceMap::iterator it)  			:	mIterator(it)  		{ -			++sIterationNestDepth; +			++getStatic().sIterationNestDepth;  		}  		key_iter(const key_iter& other)  			:	mIterator(other.mIterator)  		{ -			++sIterationNestDepth; +			++getStatic().sIterationNestDepth;  		}  		~key_iter()  		{ -			--sIterationNestDepth; +			--getStatic().sIterationNestDepth;  		} @@ -159,8 +197,8 @@ protected:  	virtual ~LLInstanceTracker()   	{   		// it's unsafe to delete instances of this type while all instances are being iterated over. -		llassert(sIterationNestDepth == 0); -		remove_(); 		 +		llassert_always(getStatic().sIterationNestDepth == 0); +		remove_();		  	}  	virtual void setKey(KEY key) { remove_(); add_(key); }  	virtual const KEY& getKey() const { return mInstanceKey; } @@ -176,31 +214,24 @@ private:  		getMap_().erase(mInstanceKey);  	} -    static InstanceMap& getMap_() -    { -		void * & instances = getInstances(typeid(MyT)); -        if (! instances) -        { -            instances = new InstanceMap; -        } -        return * static_cast<InstanceMap*>(instances); -    } -  private: -  	KEY mInstanceKey; -	static S32 sIterationNestDepth;  }; -template <typename T, typename KEY> S32 LLInstanceTracker<T, KEY>::sIterationNestDepth = 0; -  /// explicit specialization for default case where KEY is T*  /// use a simple std::set<T*>  template<typename T>  class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase  { -	typedef typename std::set<T*> InstanceSet;  	typedef LLInstanceTracker<T, T*> MyT; +	typedef typename std::set<T*> InstanceSet; +	struct StaticData: public StaticBase +	{ +		InstanceSet sSet; +	}; +	static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); } +	static InstanceSet& getSet_() { return getStatic().sSet; } +  public:  	/// for completeness of analogy with the generic implementation @@ -213,18 +244,18 @@ public:  		instance_iter(const typename InstanceSet::iterator& it)  		:	mIterator(it)  		{ -			++sIterationNestDepth; +			++getStatic().sIterationNestDepth;  		}  		instance_iter(const instance_iter& other)  		:	mIterator(other.mIterator)  		{ -			++sIterationNestDepth; +			++getStatic().sIterationNestDepth;  		}  		~instance_iter()  		{ -			--sIterationNestDepth; +			--getStatic().sIterationNestDepth;  		}  	private: @@ -250,13 +281,13 @@ public:  protected:  	LLInstanceTracker()  	{ -		// it's safe but unpredictable to create instances of this type while all instances are being iterated over.  I hate unpredictable.  This assert will probably be turned on early in the next development cycle. +		// it's safe but unpredictable to create instances of this type while all instances are being iterated over.  I hate unpredictable.	 This assert will probably be turned on early in the next development cycle.  		getSet_().insert(static_cast<T*>(this));  	}  	virtual ~LLInstanceTracker()  	{  		// it's unsafe to delete instances of this type while all instances are being iterated over. -		llassert(sIterationNestDepth == 0); +		llassert_always(getStatic().sIterationNestDepth == 0);  		getSet_().erase(static_cast<T*>(this));  	} @@ -264,20 +295,6 @@ protected:  	{  		getSet_().insert(static_cast<T*>(this));  	} - -	static InstanceSet& getSet_() -	{ -		void * & instances = getInstances(typeid(MyT)); -		if (! instances) -		{ -			instances = new InstanceSet; -		} -		return * static_cast<InstanceSet *>(instances); -	} - -	static S32 sIterationNestDepth;  }; -template <typename T> S32 LLInstanceTracker<T, T*>::sIterationNestDepth = 0; -  #endif diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 00757be277..49d99f2cd0 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -114,8 +114,7 @@ private:  		~SingletonInstanceData()  		{ -			SingletonInstanceData& data = getData(); -			if (data.mInitState != DELETED) +			if (mInitState != DELETED)  			{  				deleteSingleton();  			} @@ -130,7 +129,26 @@ public:  		data.mInitState = DELETED;  	} -	// Can be used to control when the singleton is deleted.  Not normally needed. +	/** +	 * @brief Immediately delete the singleton. +	 * +	 * A subsequent call to LLProxy::getInstance() will construct a new +	 * instance of the class. +	 * +	 * LLSingletons are normally destroyed after main() has exited and the C++ +	 * runtime is cleaning up statically-constructed objects. Some classes +	 * derived from LLSingleton have objects that are part of a runtime system +	 * that is terminated before main() exits. Calling the destructor of those +	 * objects after the termination of their respective systems can cause +	 * crashes and other problems during termination of the project. Using this +	 * method to destroy the singleton early can prevent these crashes. +	 * +	 * An example where this is needed is for a LLSingleton that has an APR +	 * object as a member that makes APR calls on destruction. The APR system is +	 * shut down explicitly before main() exits. This causes a crash on exit. +	 * Using this method before the call to apr_terminate() and NOT calling +	 * getInstance() again will prevent the crash. +	 */  	static void deleteSingleton()  	{  		delete getData().mSingletonInstance; diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index f3b48b0156..e7fe656808 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -936,13 +936,18 @@ LLStringUtil::size_type LLStringUtil::getSubstitution(const std::string& instr,  {  	const std::string delims (","); -	// Find the first ] -	size_type pos2 = instr.find(']', start); +	// Find the first [ +	size_type pos1 = instr.find('[', start); +	if (pos1 == std::string::npos) +		return std::string::npos; + +	//Find the first ] after the initial [ +	size_type pos2 = instr.find(']', pos1);  	if (pos2 == std::string::npos)  		return std::string::npos; -	// Find the last [ before ] -	size_type pos1 = instr.find_last_of('[', pos2-1); +	// Find the last [ before ] in case of nested [[]] +	pos1 = instr.find_last_of('[', pos2-1);  	if (pos1 == std::string::npos || pos1 < start)  		return std::string::npos; diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp index 80b35bbdc3..b34d1c5fd3 100644 --- a/indra/llcommon/tests/llinstancetracker_test.cpp +++ b/indra/llcommon/tests/llinstancetracker_test.cpp @@ -40,6 +40,7 @@  #include <boost/scoped_ptr.hpp>  // other Linden headers  #include "../test/lltut.h" +#include "wrapllerrs.h"  struct Keyed: public LLInstanceTracker<Keyed, std::string>  { @@ -165,4 +166,67 @@ namespace tut          ensure_equals("unreported instance", instances.size(), 0);      } + +    template<> template<> +    void object::test<5>() +    { +        set_test_name("delete Keyed with outstanding instance_iter"); +        std::string what; +        Keyed* keyed = new Keyed("one"); +        { +            WrapLL_ERRS wrapper; +            Keyed::instance_iter i(Keyed::beginInstances()); +            try +            { +                delete keyed; +            } +            catch (const WrapLL_ERRS::FatalException& e) +            { +                what = e.what(); +            } +        } +        ensure(! what.empty()); +    } + +    template<> template<> +    void object::test<6>() +    { +        set_test_name("delete Keyed with outstanding key_iter"); +        std::string what; +        Keyed* keyed = new Keyed("one"); +        { +            WrapLL_ERRS wrapper; +            Keyed::key_iter i(Keyed::beginKeys()); +            try +            { +                delete keyed; +            } +            catch (const WrapLL_ERRS::FatalException& e) +            { +                what = e.what(); +            } +        } +        ensure(! what.empty()); +    } + +    template<> template<> +    void object::test<7>() +    { +        set_test_name("delete Unkeyed with outstanding instance_iter"); +        std::string what; +        Unkeyed* unkeyed = new Unkeyed; +        { +            WrapLL_ERRS wrapper; +            Unkeyed::instance_iter i(Unkeyed::beginInstances()); +            try +            { +                delete unkeyed; +            } +            catch (const WrapLL_ERRS::FatalException& e) +            { +                what = e.what(); +            } +        } +        ensure(! what.empty()); +    }  } // namespace tut diff --git a/indra/llcommon/tests/llsingleton_test.cpp b/indra/llcommon/tests/llsingleton_test.cpp new file mode 100644 index 0000000000..385289aefe --- /dev/null +++ b/indra/llcommon/tests/llsingleton_test.cpp @@ -0,0 +1,76 @@ +/**  + * @file llsingleton_test.cpp + * @date 2011-08-11 + * @brief Unit test for the LLSingleton class + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, 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 "linden_common.h" + +#include "llsingleton.h" +#include "../test/lltut.h" + +namespace tut +{ +	struct singleton +	{ +		// We need a class created with the LLSingleton template to test with. +		class LLSingletonTest: public LLSingleton<LLSingletonTest> +		{ + +		}; +	}; + +	typedef test_group<singleton> singleton_t; +	typedef singleton_t::object singleton_object_t; +	tut::singleton_t tut_singleton("LLSingleton"); + +	template<> template<> +	void singleton_object_t::test<1>() +	{ + +	} +	template<> template<> +	void singleton_object_t::test<2>() +	{ +		LLSingletonTest* singleton_test = LLSingletonTest::getInstance(); +		ensure(singleton_test); +	} +	template<> template<> +	void singleton_object_t::test<3>() +	{ +		//Construct the instance +		LLSingletonTest::getInstance(); +		ensure(LLSingletonTest::instanceExists()); + +		//Delete the instance +		LLSingletonTest::deleteSingleton(); +		ensure(LLSingletonTest::destroyed()); +		ensure(!LLSingletonTest::instanceExists()); + +		//Construct it again. +		LLSingletonTest* singleton_test = LLSingletonTest::getInstance(); +		ensure(singleton_test); +		ensure(LLSingletonTest::instanceExists()); +	} +} diff --git a/indra/llcommon/tests/llstring_test.cpp b/indra/llcommon/tests/llstring_test.cpp index 304e91ed92..6a1cbf652a 100644 --- a/indra/llcommon/tests/llstring_test.cpp +++ b/indra/llcommon/tests/llstring_test.cpp @@ -624,6 +624,14 @@ namespace tut  		subcount = LLStringUtil::format(s, fmt_map);  		ensure_equals("LLStringUtil::format: Assorted Test2 result", s, "?Am I not a long string?short[A]bbbaaaba[A]");  		ensure_equals("LLStringUtil::format: Assorted Test2 result count", 9, subcount); +		 +		// Test on nested brackets +		std::string srcs6 = "[[TRICK1]][[A]][[B]][[AAA]][[BBB]][[TRICK2]][[KEYLONGER]][[KEYSHORTER]]?[[DELETE]]"; +		s = srcs6; +		subcount = LLStringUtil::format(s, fmt_map); +		ensure_equals("LLStringUtil::format: Assorted Test2 result", s, "[[A]][a][b][aaa][bbb][[A]][short][Am I not a long string?]?[]"); +		ensure_equals("LLStringUtil::format: Assorted Test2 result count", 9, subcount); +  		// Test an assorted substitution  		std::string srcs8 = "foo[DELETE]bar?"; diff --git a/indra/llmath/tests/v3math_test.cpp b/indra/llmath/tests/v3math_test.cpp index df7a77002f..e4ae1c10ef 100644 --- a/indra/llmath/tests/v3math_test.cpp +++ b/indra/llmath/tests/v3math_test.cpp @@ -564,4 +564,22 @@ namespace tut  		z1 = U8_to_F32(F32_to_U8(z, lowerz, upperz), lowerz, upperz);  		ensure("2:quantize8: Fail ", is_approx_equal(x1, vec3a.mV[VX]) && is_approx_equal(y1, vec3a.mV[VY]) && is_approx_equal(z1, vec3a.mV[VZ]));  	} + +	template<> template<> +	void v3math_object::test<35>() +	{ +		LLSD sd = LLSD::emptyArray(); +		sd[0] = 1.f; + +		LLVector3 parsed_1(sd); +		ensure("1:LLSD parse: Fail ", is_approx_equal(parsed_1.mV[VX], 1.f) && is_approx_equal(parsed_1.mV[VY], 0.f) && is_approx_equal(parsed_1.mV[VZ], 0.f)); + +		sd[1] = 2.f; +		LLVector3 parsed_2(sd); +		ensure("2:LLSD parse: Fail ", is_approx_equal(parsed_2.mV[VX], 1.f) && is_approx_equal(parsed_2.mV[VY], 2.f) && is_approx_equal(parsed_2.mV[VZ], 0.f)); + +		sd[2] = 3.f; +		LLVector3 parsed_3(sd); +		ensure("3:LLSD parse: Fail ", is_approx_equal(parsed_3.mV[VX], 1.f) && is_approx_equal(parsed_3.mV[VY], 2.f) && is_approx_equal(parsed_3.mV[VZ], 3.f)); +	}  } diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index a3de178d78..14e169c6b1 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -499,7 +499,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,  	//don't verify host name so urls with scrubbed host names will work (improves DNS performance)  	setopt(CURLOPT_SSL_VERIFYHOST, 0); -	setopt(CURLOPT_TIMEOUT, CURL_REQUEST_TIMEOUT); +	setopt(CURLOPT_TIMEOUT, llmax(time_out, CURL_REQUEST_TIMEOUT));  	setoptString(CURLOPT_URL, url); @@ -1213,3 +1213,13 @@ void LLCurl::cleanupClass()  }  const unsigned int LLCurl::MAX_REDIRECTS = 5; + +// Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace. +void LLCurlFF::check_easy_code(CURLcode code) +{ +	check_curl_code(code); +} +void LLCurlFF::check_multi_code(CURLMcode code) +{ +	check_curl_multi_code(code); +} diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index 5ab4dc35b9..213b281e72 100644 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -371,7 +371,11 @@ private:  	bool mResultReturned;  }; -void check_curl_code(CURLcode code); -void check_curl_multi_code(CURLMcode code); +// Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace. +namespace LLCurlFF +{ +	void check_easy_code(CURLcode code); +	void check_multi_code(CURLMcode code); +}  #endif // LL_LLCURL_H diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp index 7628984de4..fc6e9c5193 100644 --- a/indra/llmessage/llpacketring.cpp +++ b/indra/llmessage/llpacketring.cpp @@ -228,13 +228,13 @@ S32 LLPacketRing::receivePacket (S32 socket, char *datap)  		if (LLProxy::isSOCKSProxyEnabled())  		{  			U8 buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; -			packet_size = receive_packet(socket, reinterpret_cast<char *>(buffer)); +			packet_size = receive_packet(socket, static_cast<char*>(static_cast<void*>(buffer)));  			if (packet_size > SOCKS_HEADER_SIZE)  			{  				// *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6)  				memcpy(datap, buffer + SOCKS_HEADER_SIZE, packet_size - SOCKS_HEADER_SIZE); -				proxywrap_t * header = reinterpret_cast<proxywrap_t *>(buffer); +				proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer));  				mLastSender.setAddress(header->addr);  				mLastSender.setPort(ntohs(header->port)); @@ -353,14 +353,20 @@ BOOL LLPacketRing::sendPacketImpl(int h_socket, const char * send_buffer, S32 bu  		return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort());  	} -	proxywrap_t *socks_header = reinterpret_cast<proxywrap_t *>(&mProxyWrappedSendBuffer); +	char headered_send_buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; + +	proxywrap_t *socks_header = static_cast<proxywrap_t*>(static_cast<void*>(&headered_send_buffer));  	socks_header->rsv   = 0;  	socks_header->addr  = host.getAddress();  	socks_header->port  = htons(host.getPort());  	socks_header->atype = ADDRESS_IPV4;  	socks_header->frag  = 0; -	memcpy(mProxyWrappedSendBuffer + SOCKS_HEADER_SIZE, send_buffer, buf_size); +	memcpy(headered_send_buffer + SOCKS_HEADER_SIZE, send_buffer, buf_size); -	return send_packet(h_socket, (const char*) mProxyWrappedSendBuffer, buf_size + 10, LLProxy::getInstance()->getUDPProxy().getAddress(), LLProxy::getInstance()->getUDPProxy().getPort()); +	return send_packet(	h_socket, +						headered_send_buffer, +						buf_size + SOCKS_HEADER_SIZE, +						LLProxy::getInstance()->getUDPProxy().getAddress(), +						LLProxy::getInstance()->getUDPProxy().getPort());  } diff --git a/indra/llmessage/llpacketring.h b/indra/llmessage/llpacketring.h index 7edcc834db..b214271e78 100644 --- a/indra/llmessage/llpacketring.h +++ b/indra/llmessage/llpacketring.h @@ -83,9 +83,6 @@ protected:  	LLHost mLastSender;  	LLHost mLastReceivingIF; - -	U8 mProxyWrappedSendBuffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; -  private:  	BOOL sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host);  }; diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp index 19f1fc6545..4a7d326c0e 100644 --- a/indra/llmessage/llproxy.cpp +++ b/indra/llmessage/llproxy.cpp @@ -43,7 +43,7 @@  bool LLProxy::sUDPProxyEnabled = false;  // Some helpful TCP static functions. -static S32 tcp_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen); // Do a TCP data handshake +static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen); // Do a TCP data handshake  static LLSocket::ptr_t tcp_open_channel(LLHost host); // Open a TCP channel to a given host  static void tcp_close_channel(LLSocket::ptr_t* handle_ptr); // Close an open TCP channel @@ -63,14 +63,13 @@ LLProxy::LLProxy():  LLProxy::~LLProxy()  {  	stopSOCKSProxy(); -	sUDPProxyEnabled  = false; -	mHTTPProxyEnabled = false; +	disableHTTPProxy();  }  /**   * @brief Open the SOCKS 5 TCP control channel.   * - * Perform a SOCKS 5 authentication and UDP association to the proxy server. + * Perform a SOCKS 5 authentication and UDP association with the proxy server.   *   * @param proxy The SOCKS 5 server to connect to.   * @return SOCKS_OK if successful, otherwise a socks error code from llproxy.h. @@ -83,11 +82,15 @@ S32 LLProxy::proxyHandshake(LLHost proxy)  	socks_auth_request_t  socks_auth_request;  	socks_auth_response_t socks_auth_response; -	socks_auth_request.version     = SOCKS_VERSION;       // SOCKS version 5 -	socks_auth_request.num_methods = 1;                   // Sending 1 method. -	socks_auth_request.methods     = getSelectedAuthMethod(); // Send only the selected method. +	socks_auth_request.version		= SOCKS_VERSION;				// SOCKS version 5 +	socks_auth_request.num_methods	= 1;							// Sending 1 method. +	socks_auth_request.methods		= getSelectedAuthMethod();		// Send only the selected method. -	result = tcp_handshake(mProxyControlChannel, (char*)&socks_auth_request, sizeof(socks_auth_request), (char*)&socks_auth_response, sizeof(socks_auth_response)); +	result = tcp_blocking_handshake(mProxyControlChannel, +									static_cast<char*>(static_cast<void*>(&socks_auth_request)), +									sizeof(socks_auth_request), +									static_cast<char*>(static_cast<void*>(&socks_auth_response)), +									sizeof(socks_auth_response));  	if (result != APR_SUCCESS)  	{  		LL_WARNS("Proxy") << "SOCKS authentication request failed, error on TCP control channel : " << result << LL_ENDL; @@ -97,12 +100,12 @@ S32 LLProxy::proxyHandshake(LLHost proxy)  	if (socks_auth_response.method == AUTH_NOT_ACCEPTABLE)  	{ -		LL_WARNS("Proxy") << "SOCKS 5 server refused all our authentication methods" << LL_ENDL; +		LL_WARNS("Proxy") << "SOCKS 5 server refused all our authentication methods." << LL_ENDL;  		stopSOCKSProxy();  		return SOCKS_NOT_ACCEPTABLE;  	} -	// SOCKS 5 USERNAME/PASSWORD authentication +	/* SOCKS 5 USERNAME/PASSWORD authentication */  	if (socks_auth_response.method == METHOD_PASSWORD)  	{  		// The server has requested a username/password combination @@ -114,11 +117,15 @@ S32 LLProxy::proxyHandshake(LLHost proxy)  		password_auth[1] = socks_username.size();  		memcpy(&password_auth[2], socks_username.c_str(), socks_username.size());  		password_auth[socks_username.size() + 2] = socks_password.size(); -		memcpy(&password_auth[socks_username.size()+3], socks_password.c_str(), socks_password.size()); +		memcpy(&password_auth[socks_username.size() + 3], socks_password.c_str(), socks_password.size());  		authmethod_password_reply_t password_reply; -		result = tcp_handshake(mProxyControlChannel, password_auth, request_size, (char*)&password_reply, sizeof(password_reply)); +		result = tcp_blocking_handshake(mProxyControlChannel, +										password_auth, +										request_size, +										static_cast<char*>(static_cast<void*>(&password_reply)), +										sizeof(password_reply));  		delete[] password_auth;  		if (result != APR_SUCCESS) @@ -150,7 +157,11 @@ S32 LLProxy::proxyHandshake(LLHost proxy)  	// "If the client is not in possession of the information at the time of the UDP ASSOCIATE,  	//  the client MUST use a port number and address of all zeros. RFC 1928" -	result = tcp_handshake(mProxyControlChannel, (char*)&connect_request, sizeof(connect_request), (char*)&connect_reply, sizeof(connect_reply)); +	result = tcp_blocking_handshake(mProxyControlChannel, +									static_cast<char*>(static_cast<void*>(&connect_request)), +									sizeof(connect_request), +									static_cast<char*>(static_cast<void*>(&connect_reply)), +									sizeof(connect_reply));  	if (result != APR_SUCCESS)  	{  		LL_WARNS("Proxy") << "SOCKS connect request failed, error on TCP control channel : " << result << LL_ENDL; @@ -169,6 +180,7 @@ S32 LLProxy::proxyHandshake(LLHost proxy)  	mUDPProxy.setAddress(proxy.getAddress());  	// The connection was successful. We now have the UDP port to send requests that need forwarding to.  	LL_INFOS("Proxy") << "SOCKS 5 UDP proxy connected on " << mUDPProxy << LL_ENDL; +  	return SOCKS_OK;  } @@ -176,7 +188,8 @@ S32 LLProxy::proxyHandshake(LLHost proxy)   * @brief Initiates a SOCKS 5 proxy session.   *   * Performs basic checks on host to verify that it is a valid address. Opens the control channel - * and then negotiates the proxy connection with the server. + * and then negotiates the proxy connection with the server. Closes any existing SOCKS + * connection before proceeding. Also disables an HTTP proxy if it is using SOCKS as the proxy.   *   *   * @param host Socks server to connect to. @@ -184,43 +197,37 @@ S32 LLProxy::proxyHandshake(LLHost proxy)   */  S32 LLProxy::startSOCKSProxy(LLHost host)  { -	S32 status = SOCKS_OK; -  	if (host.isOk())  	{  		mTCPProxy = host;  	}  	else  	{ -		status = SOCKS_INVALID_HOST; +		return SOCKS_INVALID_HOST;  	} -	if (mProxyControlChannel && status == SOCKS_OK) -	{ -		tcp_close_channel(&mProxyControlChannel); -	} +	// Close any running SOCKS connection. +	stopSOCKSProxy(); -	if (status == SOCKS_OK) +	mProxyControlChannel = tcp_open_channel(mTCPProxy); +	if (!mProxyControlChannel)  	{ -		mProxyControlChannel = tcp_open_channel(mTCPProxy); -		if (!mProxyControlChannel) -		{ -			status = SOCKS_HOST_CONNECT_FAILED; -		} +		return SOCKS_HOST_CONNECT_FAILED;  	} -	if (status == SOCKS_OK) -	{ -		status = proxyHandshake(mTCPProxy); -	} -	if (status == SOCKS_OK) +	S32 status = proxyHandshake(mTCPProxy); + +	if (status != SOCKS_OK)  	{ -		sUDPProxyEnabled = true; +		// Shut down the proxy if any of the above steps failed. +		stopSOCKSProxy();  	}  	else  	{ -		stopSOCKSProxy(); +		// Connection was successful. +		sUDPProxyEnabled = true;  	} +  	return status;  } @@ -241,7 +248,7 @@ void LLProxy::stopSOCKSProxy()  	if (LLPROXY_SOCKS == getHTTPProxyType())  	{ -		void disableHTTPProxy(); +		disableHTTPProxy();  	}  	if (mProxyControlChannel) @@ -350,16 +357,6 @@ void LLProxy::disableHTTPProxy()  }  /** - * @brief Get the HTTP proxy address and port - */ -// -LLHost LLProxy::getHTTPProxy() const -{ -	LLMutexLock lock(&mProxyMutex); -	return mHTTPProxy; -} - -/**   * @brief Get the currently selected HTTP proxy type   */  LLHttpProxyType LLProxy::getHTTPProxyType() const @@ -440,21 +437,21 @@ void LLProxy::applyProxySettings(CURL* handle)  		// Now test again to verify that the proxy wasn't disabled between the first check and the lock.  		if (mHTTPProxyEnabled)  		{ -			check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str())); -			check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort())); +			LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str())); +			LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort()));  			if (mProxyType == LLPROXY_SOCKS)  			{ -				check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5)); +				LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5));  				if (mAuthMethodSelected == METHOD_PASSWORD)  				{  					std::string auth_string = mSocksUsername + ":" + mSocksPassword; -					check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str())); +					LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()));  				}  			}  			else  			{ -				check_curl_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP)); +				LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP));  			}  		}  	} @@ -473,7 +470,7 @@ void LLProxy::applyProxySettings(CURL* handle)   * @param maxinlen		Maximum possible length of received data.  Short reads are allowed.   * @return 				Indicates APR status code of exchange. APR_SUCCESS if exchange was successful, -1 if invalid data length was received.   */ -static S32 tcp_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen) +static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen)  {  	apr_socket_t* apr_socket = handle->getSocket();  	apr_status_t rv = APR_SUCCESS; @@ -522,7 +519,6 @@ static S32 tcp_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outl   *   * Checks for a successful connection, and makes sure the connection is closed if it fails.   * - * @param pool		APR pool to pass into the LLSocket.   * @param host		The host to open the connection to.   * @return			The created socket.  Will evaluate as NULL if the connection is unsuccessful.   */ @@ -541,7 +537,7 @@ static LLSocket::ptr_t tcp_open_channel(LLHost host)  /**   * @brief Close the socket.   * - * @param handle_ptr A pointer-to-pointer to avoid increasing the use count. + * @param handle_ptr The handle of the socket being closed. A pointer-to-pointer to avoid increasing the use count.   */  static void tcp_close_channel(LLSocket::ptr_t* handle_ptr)  { diff --git a/indra/llmessage/llproxy.h b/indra/llmessage/llproxy.h index 621debb61d..a919370540 100644 --- a/indra/llmessage/llproxy.h +++ b/indra/llmessage/llproxy.h @@ -36,7 +36,6 @@  #include <string>  // SOCKS error codes returned from the StartProxy method -  #define SOCKS_OK 0  #define SOCKS_CONNECT_ERROR (-1)  #define SOCKS_NOT_PERMITTED (-2) @@ -46,7 +45,6 @@  #define SOCKS_HOST_CONNECT_FAILED (-6)  #define SOCKS_INVALID_HOST (-7) -  #ifndef MAXHOSTNAMELEN  #define	MAXHOSTNAMELEN (255 + 1) /* socks5: 255, +1 for len. */  #endif @@ -225,62 +223,71 @@ class LLProxy: public LLSingleton<LLProxy>  {  	LOG_CLASS(LLProxy);  public: -	// METHODS THAT DO NOT LOCK mProxyMutex! - +	/*########################################################################################### +	METHODS THAT DO NOT LOCK mProxyMutex! +	###########################################################################################*/ +	// Constructor, cannot have parameters due to LLSingleton parent class. Call from main thread only.  	LLProxy(); -	// static check for enabled status for UDP packets +	// Static check for enabled status for UDP packets. Call from main thread only.  	static bool isSOCKSProxyEnabled() { return sUDPProxyEnabled; } -	// check for enabled status for HTTP packets -	// mHTTPProxyEnabled is atomic, so no locking is required for thread safety. -	bool isHTTPProxyEnabled() const { return mHTTPProxyEnabled; } - -	// Get the UDP proxy address and port +	// Get the UDP proxy address and port. Call from main thread only.  	LLHost getUDPProxy() const { return mUDPProxy; } -	// Get the SOCKS 5 TCP control channel address and port -	LLHost getTCPProxy() const { return mTCPProxy; } +	/*########################################################################################### +	END OF NON-LOCKING METHODS +	###########################################################################################*/ -	// END OF NON-LOCKING METHODS +	/*########################################################################################### +	METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED! +	###########################################################################################*/ +	// Destructor, closes open connections. Do not call directly, use cleanupClass(). +	~LLProxy(); -	// METHODS THAT DO LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED! +	// Delete LLProxy singleton. Allows the apr_socket used in the SOCKS 5 control channel to be +	// destroyed before the call to apr_terminate. Call from main thread only. +	static void cleanupClass(); -	~LLProxy(); +	// Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false. +	// Safe to call from any thread. +	void applyProxySettings(CURL* handle); +	void applyProxySettings(LLCurl::Easy* handle); +	void applyProxySettings(LLCurlEasyRequest* handle); -	// Start a connection to the SOCKS 5 proxy +	// Start a connection to the SOCKS 5 proxy. Call from main thread only.  	S32 startSOCKSProxy(LLHost host); -	// Disconnect and clean up any connection to the SOCKS 5 proxy +	// Disconnect and clean up any connection to the SOCKS 5 proxy. Call from main thread only.  	void stopSOCKSProxy(); -	// Delete LLProxy singleton, destroying the APR pool used by the control channel. -	static void cleanupClass(); - -	// Set up to use Password auth when connecting to the SOCKS proxy +	// Use Password auth when connecting to the SOCKS proxy. Call from main thread only.  	bool setAuthPassword(const std::string &username, const std::string &password); -	// Set up to use No Auth when connecting to the SOCKS proxy +	// Disable authentication when connecting to the SOCKS proxy. Call from main thread only.  	void setAuthNone(); -	// Get the currently selected auth method. -	LLSocks5AuthType getSelectedAuthMethod() const; - -	// Proxy HTTP packets via httpHost, which can be a SOCKS 5 or a HTTP proxy -	// as specified in type +	// Proxy HTTP packets via httpHost, which can be a SOCKS 5 or a HTTP proxy. +	// as specified in type. Call from main thread only.  	bool enableHTTPProxy(LLHost httpHost, LLHttpProxyType type);  	bool enableHTTPProxy(); -	// Stop proxying HTTP packets +	// Stop proxying HTTP packets. Call from main thread only.  	void disableHTTPProxy(); -	// Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false. -	void applyProxySettings(CURL* handle); -	void applyProxySettings(LLCurl::Easy* handle); -	void applyProxySettings(LLCurlEasyRequest* handle); +	/*########################################################################################### +	END OF LOCKING METHODS +	###########################################################################################*/ +private: +	/*########################################################################################### +	METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED! +	###########################################################################################*/ -	// Get the HTTP proxy address and port -	LLHost getHTTPProxy() const; +	// Perform a SOCKS 5 authentication and UDP association with the proxy server. +	S32 proxyHandshake(LLHost proxy); + +	// Get the currently selected auth method. +	LLSocks5AuthType getSelectedAuthMethod() const;  	// Get the currently selected HTTP proxy type  	LLHttpProxyType getHTTPProxyType() const; @@ -288,21 +295,21 @@ public:  	std::string getSocksPwd() const;  	std::string getSocksUser() const; -	// END OF LOCKING METHODS -private: -	// Open a communication channel to the SOCKS 5 proxy proxy, at port messagePort -	S32 proxyHandshake(LLHost proxy); +	/*########################################################################################### +	END OF LOCKING METHODS +	###########################################################################################*/  private: -	// Is the HTTP proxy enabled? -	// Safe to read in any thread, do not write directly, -	// use enableHTTPProxy() and disableHTTPProxy() instead. +	// Is the HTTP proxy enabled? Safe to read in any thread, but do not write directly. +	// Instead use enableHTTPProxy() and disableHTTPProxy() instead.  	mutable LLAtomic32<bool> mHTTPProxyEnabled; -	// Mutex to protect shared members in non-main thread calls to applyProxySettings() +	// Mutex to protect shared members in non-main thread calls to applyProxySettings().  	mutable LLMutex mProxyMutex; -	// MEMBERS READ AND WRITTEN ONLY IN THE MAIN THREAD. DO NOT SHARE! +	/*########################################################################################### +	MEMBERS READ AND WRITTEN ONLY IN THE MAIN THREAD. DO NOT SHARE! +	###########################################################################################*/  	// Is the UDP proxy enabled?  	static bool sUDPProxyEnabled; @@ -315,9 +322,13 @@ private:  	// socket handle to proxy TCP control channel  	LLSocket::ptr_t mProxyControlChannel; -	// END OF UNSHARED MEMBERS +	/*########################################################################################### +	END OF UNSHARED MEMBERS +	###########################################################################################*/ -	// MEMBERS WRITTEN IN MAIN THREAD AND READ IN ANY THREAD. ONLY READ OR WRITE AFTER LOCKING mProxyMutex! +	/*########################################################################################### +	MEMBERS WRITTEN IN MAIN THREAD AND READ IN ANY THREAD. ONLY READ OR WRITE AFTER LOCKING mProxyMutex! +	###########################################################################################*/  	// HTTP proxy address and port  	LLHost mHTTPProxy; @@ -325,7 +336,7 @@ private:  	// Currently selected HTTP proxy type. Can be web or socks.  	LLHttpProxyType mProxyType; -	// SOCKS 5 auth method selected +	// SOCKS 5 selected authentication method.  	LLSocks5AuthType mAuthMethodSelected;  	// SOCKS 5 username @@ -333,7 +344,9 @@ private:  	// SOCKS 5 password  	std::string mSocksPassword; -	// END OF SHARED MEMBERS +	/*########################################################################################### +	END OF SHARED MEMBERS +	###########################################################################################*/  };  #endif diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index d081109acc..9cd3216ab2 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -1,1424 +1,1445 @@ -/**  - * @file llpluginclassmedia.cpp - * @brief LLPluginClassMedia handles a plugin which knows about the "media" message class. - * - * @cond - * $LicenseInfo:firstyear=2008&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$ - * @endcond - */ - -#include "linden_common.h" -#include "indra_constants.h" - -#include "llpluginclassmedia.h" -#include "llpluginmessageclasses.h" - -#include "llqtwebkit.h" - -static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256; - -static int nextPowerOf2( int value ) -{ -	int next_power_of_2 = 1; -	while ( next_power_of_2 < value ) -	{ -		next_power_of_2 <<= 1; -	} -	 -	return next_power_of_2; -} - -LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner) -{ -	mOwner = owner; -	mPlugin = NULL; -	reset(); - -	//debug use -	mDeleteOK = true ; -} - - -LLPluginClassMedia::~LLPluginClassMedia() -{ -	llassert_always(mDeleteOK) ; -	reset(); -} - -bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug) -{	 -	LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL; -	LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL; -	LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL; -	 -	mPlugin = new LLPluginProcessParent(this); -	mPlugin->setSleepTime(mSleepTime); -	 -	// Queue up the media init message -- it will be sent after all the currently queued messages. -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init"); -	message.setValue("target", mTarget); -	sendMessage(message); -	 -	mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug); - -	return true; -} - - -void LLPluginClassMedia::reset() -{ -	if(mPlugin != NULL) -	{ -		delete mPlugin; -		mPlugin = NULL; -	} - -	mTextureParamsReceived = false; -	mRequestedTextureDepth = 0; -	mRequestedTextureInternalFormat = 0; -	mRequestedTextureFormat = 0; -	mRequestedTextureType = 0; -	mRequestedTextureSwapBytes = false; -	mRequestedTextureCoordsOpenGL = false; -	mTextureSharedMemorySize = 0; -	mTextureSharedMemoryName.clear(); -	mDefaultMediaWidth = 0; -	mDefaultMediaHeight = 0; -	mNaturalMediaWidth = 0; -	mNaturalMediaHeight = 0; -	mSetMediaWidth = -1; -	mSetMediaHeight = -1; -	mRequestedMediaWidth = 0; -	mRequestedMediaHeight = 0; -	mRequestedTextureWidth = 0; -	mRequestedTextureHeight = 0; -	mFullMediaWidth = 0; -	mFullMediaHeight = 0; -	mTextureWidth = 0; -	mTextureHeight = 0; -	mMediaWidth = 0; -	mMediaHeight = 0; -	mDirtyRect = LLRect::null;	 -	mAutoScaleMedia = false; -	mRequestedVolume = 1.0f; -	mPriority = PRIORITY_NORMAL; -	mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT; -	mAllowDownsample = false; -	mPadding = 0; -	mLastMouseX = 0; -	mLastMouseY = 0; -	mStatus = LLPluginClassMediaOwner::MEDIA_NONE; -	mSleepTime = 1.0f / 100.0f; -	mCanCut = false; -	mCanCopy = false; -	mCanPaste = false; -	mMediaName.clear(); -	mMediaDescription.clear(); -	mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f); -	 -	// media_browser class -	mNavigateURI.clear(); -	mNavigateResultCode = -1; -	mNavigateResultString.clear(); -	mHistoryBackAvailable = false; -	mHistoryForwardAvailable = false; -	mStatusText.clear(); -	mProgressPercent = 0;	 -	mClickURL.clear(); -	mClickNavType.clear(); -	mClickTarget.clear(); -	mClickUUID.clear(); -	mStatusCode = 0; -	 -	// media_time class -	mCurrentTime = 0.0f; -	mDuration = 0.0f; -	mCurrentRate = 0.0f; -	mLoadedDuration = 0.0f; -} - -void LLPluginClassMedia::idle(void) -{ -	if(mPlugin) -	{ -		mPlugin->idle(); -	} -	 -	if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL)) -	{ -		// Can't process a size change at this time -	} -	else if((mRequestedMediaWidth != mMediaWidth) || (mRequestedMediaHeight != mMediaHeight)) -	{ -		// Calculate the correct size for the media texture -		mRequestedTextureHeight = mRequestedMediaHeight; -		if(mPadding < 0) -		{ -			// negative values indicate the plugin wants a power of 2 -			mRequestedTextureWidth = nextPowerOf2(mRequestedMediaWidth); -		} -		else -		{ -			mRequestedTextureWidth = mRequestedMediaWidth; -			 -			if(mPadding > 1) -			{ -				// Pad up to a multiple of the specified number of bytes per row -				int rowbytes = mRequestedTextureWidth * mRequestedTextureDepth; -				int pad = rowbytes % mPadding; -				if(pad != 0) -				{ -					rowbytes += mPadding - pad; -				} -				 -				if(rowbytes % mRequestedTextureDepth == 0) -				{ -					mRequestedTextureWidth = rowbytes / mRequestedTextureDepth; -				} -				else -				{ -					LL_WARNS("Plugin") << "Unable to pad texture width, padding size " << mPadding << "is not a multiple of pixel size " << mRequestedTextureDepth << LL_ENDL; -				} -			} -		} - -		 -		// Size change has been requested but not initiated yet. -		size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth; - -		// Add an extra line for padding, just in case. -		newsize += mRequestedTextureWidth * mRequestedTextureDepth; - -		if(newsize != mTextureSharedMemorySize) -		{ -			if(!mTextureSharedMemoryName.empty()) -			{ -				// Tell the plugin to remove the old memory segment -				mPlugin->removeSharedMemory(mTextureSharedMemoryName); -				mTextureSharedMemoryName.clear(); -			} -			 -			mTextureSharedMemorySize = newsize; -			mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize); -			if(!mTextureSharedMemoryName.empty()) -			{ -				void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); -				 -				// clear texture memory to avoid random screen visual fuzz from uninitialized texture data -				memset( addr, 0x00, newsize ); -				 -				// We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin, -				// so it may not be worthwhile. -				// mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight); -			} -		} -		 -		// This is our local indicator that a change is in progress. -		mTextureWidth = -1; -		mTextureHeight = -1; -		mMediaWidth = -1; -		mMediaHeight = -1; - -		// This invalidates any existing dirty rect. -		resetDirty(); -		 -		// Send a size change message to the plugin -		{ -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change"); -			message.setValue("name", mTextureSharedMemoryName); -			message.setValueS32("width", mRequestedMediaWidth); -			message.setValueS32("height", mRequestedMediaHeight); -			message.setValueS32("texture_width", mRequestedTextureWidth); -			message.setValueS32("texture_height", mRequestedTextureHeight); -			message.setValueReal("background_r", mBackgroundColor.mV[VX]); -			message.setValueReal("background_g", mBackgroundColor.mV[VY]); -			message.setValueReal("background_b", mBackgroundColor.mV[VZ]); -			message.setValueReal("background_a", mBackgroundColor.mV[VW]); -			mPlugin->sendMessage(message);	// DO NOT just use sendMessage() here -- we want this to jump ahead of the queue. -			 -			LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL; -		} -	} -	 -	if(mPlugin && mPlugin->isRunning()) -	{ -		// Send queued messages -		while(!mSendQueue.empty()) -		{ -			LLPluginMessage message = mSendQueue.front(); -			mSendQueue.pop(); -			mPlugin->sendMessage(message); -		} -	} -} - -int LLPluginClassMedia::getTextureWidth() const -{ -	return nextPowerOf2(mTextureWidth); -} - -int LLPluginClassMedia::getTextureHeight() const -{ -	return nextPowerOf2(mTextureHeight); -} - -unsigned char* LLPluginClassMedia::getBitsData() -{ -	unsigned char *result = NULL; -	if((mPlugin != NULL) && !mTextureSharedMemoryName.empty()) -	{ -		result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); -	} -	return result; -} - -void LLPluginClassMedia::setSize(int width, int height) -{ -	if((width > 0) && (height > 0)) -	{ -		mSetMediaWidth = width; -		mSetMediaHeight = height; -	} -	else -	{ -		mSetMediaWidth = -1; -		mSetMediaHeight = -1; -	} - -	setSizeInternal(); -} - -void LLPluginClassMedia::setSizeInternal(void) -{ -	if((mSetMediaWidth > 0) && (mSetMediaHeight > 0)) -	{ -		mRequestedMediaWidth = mSetMediaWidth; -		mRequestedMediaHeight = mSetMediaHeight; -	} -	else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0)) -	{ -		mRequestedMediaWidth = mNaturalMediaWidth; -		mRequestedMediaHeight = mNaturalMediaHeight; -	} -	else -	{ -		mRequestedMediaWidth = mDefaultMediaWidth; -		mRequestedMediaHeight = mDefaultMediaHeight; -	} -	 -	// Save these for size/interest calculations -	mFullMediaWidth = mRequestedMediaWidth; -	mFullMediaHeight = mRequestedMediaHeight; -	 -	if(mAllowDownsample) -	{ -		switch(mPriority) -		{ -			case PRIORITY_SLIDESHOW: -			case PRIORITY_LOW: -				// Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit -				while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit)) -				{ -					mRequestedMediaWidth /= 2; -					mRequestedMediaHeight /= 2; -				} -			break; -			 -			default: -				// Don't adjust texture size -			break; -		} -	} -	 -	if(mAutoScaleMedia) -	{ -		mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth); -		mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight); -	} -	 -	if(mRequestedMediaWidth > 2048) -		mRequestedMediaWidth = 2048; - -	if(mRequestedMediaHeight > 2048) -		mRequestedMediaHeight = 2048; -} - -void LLPluginClassMedia::setAutoScale(bool auto_scale) -{ -	if(auto_scale != mAutoScaleMedia) -	{ -		mAutoScaleMedia = auto_scale; -		setSizeInternal(); -	} -} - -bool LLPluginClassMedia::textureValid(void) -{ -	if( -		!mTextureParamsReceived || -		mTextureWidth <= 0 || -		mTextureHeight <= 0 || -		mMediaWidth <= 0 || -		mMediaHeight <= 0 || -		mRequestedMediaWidth != mMediaWidth || -		mRequestedMediaHeight != mMediaHeight || -		getBitsData() == NULL -	)	 -		return false; -	 -	return true; -} - -bool LLPluginClassMedia::getDirty(LLRect *dirty_rect) -{ -	bool result = !mDirtyRect.isEmpty(); - -	if(dirty_rect != NULL) -	{ -		*dirty_rect = mDirtyRect; -	} - -	return result; -} - -void LLPluginClassMedia::resetDirty(void) -{ -	mDirtyRect = LLRect::null; -} - -std::string LLPluginClassMedia::translateModifiers(MASK modifiers) -{ -	std::string result; -	 -	 -	if(modifiers & MASK_CONTROL) -	{ -		result += "control|"; -	} - -	if(modifiers & MASK_ALT) -	{ -		result += "alt|"; -	} - -	if(modifiers & MASK_SHIFT) -	{ -		result += "shift|"; -	} - -	// TODO: should I deal with platform differences here or in callers? -	// TODO: how do we deal with the Mac "command" key? -/* -	if(modifiers & MASK_SOMETHING) -	{ -		result += "meta|"; -	} -*/	 -	return result; -} - -void LLPluginClassMedia::jsEnableObject( bool enable ) -{ -	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) -	{ -		return; -	} - -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_enable_object"); -	message.setValueBoolean( "enable", enable ); -	sendMessage( message ); -} - -void LLPluginClassMedia::jsAgentLocationEvent( double x, double y, double z ) -{ -	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) -	{ -		return; -	} - -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_location"); -	message.setValueReal( "x", x ); -	message.setValueReal( "y", y ); -	message.setValueReal( "z", z ); -	sendMessage( message ); -} - -void LLPluginClassMedia::jsAgentGlobalLocationEvent( double x, double y, double z ) -{ -	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) -	{ -		return; -	} - -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_global_location"); -	message.setValueReal( "x", x ); -	message.setValueReal( "y", y ); -	message.setValueReal( "z", z ); -	sendMessage( message ); -} - -void LLPluginClassMedia::jsAgentOrientationEvent( double angle ) -{ -	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) -	{ -		return; -	} - -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_orientation"); -	message.setValueReal( "angle", angle ); - -	sendMessage( message ); -} - -void LLPluginClassMedia::jsAgentLanguageEvent( const std::string& language ) -{ -	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) -	{ -		return; -	} - -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_language"); -	message.setValue( "language", language ); -	sendMessage( message ); -} - -void LLPluginClassMedia::jsAgentRegionEvent( const std::string& region ) -{ -	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) -	{ -		return; -	} - -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_region"); -	message.setValue( "region", region ); -	sendMessage( message ); -} - -void LLPluginClassMedia::jsAgentMaturityEvent( const std::string& maturity ) -{ -	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() ) -	{ -		return; -	} - -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_maturity"); -	message.setValue( "maturity", maturity ); -	sendMessage( message ); -} - -void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers) -{ -	if(type == MOUSE_EVENT_MOVE) -	{ -		if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked()) -		{ -			// Don't queue up mouse move events that can't be delivered. -			return; -		} - -		if((x == mLastMouseX) && (y == mLastMouseY)) -		{ -			// Don't spam unnecessary mouse move events. -			return; -		} -		 -		mLastMouseX = x; -		mLastMouseY = y; -	} -	 -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event"); -	std::string temp; -	switch(type) -	{ -		case MOUSE_EVENT_DOWN:			temp = "down";			break; -		case MOUSE_EVENT_UP:			temp = "up";			break; -		case MOUSE_EVENT_MOVE:			temp = "move";			break; -		case MOUSE_EVENT_DOUBLE_CLICK:	temp = "double_click";	break; -	} -	message.setValue("event", temp); - -	message.setValueS32("button", button); - -	message.setValueS32("x", x); -	 -	// Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it. -	if(!mRequestedTextureCoordsOpenGL) -	{ -		// TODO: Should I use mMediaHeight or mRequestedMediaHeight here? -		y = mMediaHeight - y; -	} -	message.setValueS32("y", y); - -	message.setValue("modifiers", translateModifiers(modifiers)); -	 -	sendMessage(message); -} - -bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data) -{ -	bool result = true; -	 -	// FIXME: -	// HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode. -	// For now, return false for the ones the webkit plugin won't handle properly. -	 -	switch(key_code) -	{ -		case KEY_BACKSPACE:		 -		case KEY_TAB:			 -		case KEY_RETURN:		 -		case KEY_PAD_RETURN:	 -		case KEY_SHIFT:			 -		case KEY_CONTROL:		 -		case KEY_ALT:			 -		case KEY_CAPSLOCK:		 -		case KEY_ESCAPE:		 -		case KEY_PAGE_UP:		 -		case KEY_PAGE_DOWN:		 -		case KEY_END:			 -		case KEY_HOME:			 -		case KEY_LEFT:			 -		case KEY_UP:			 -		case KEY_RIGHT:			 -		case KEY_DOWN:			 -		case KEY_INSERT:		 -		case KEY_DELETE: -			// These will be handled		 -		break; -		 -		default: -			// regular ASCII characters will also be handled -			if(key_code >= KEY_SPECIAL) -			{ -				// Other "special" codes will not work properly. -				result = false; -			} -		break; -	} - -#if LL_DARWIN	 -	if(modifiers & MASK_ALT) -	{ -		// Option-key modified characters should be handled by the unicode input path instead of this one. -		result = false; -	} -#endif - -	if(result) -	{ -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event"); -		std::string temp; -		switch(type) -		{ -			case KEY_EVENT_DOWN:			temp = "down";			break; -			case KEY_EVENT_UP:				temp = "up";			break; -			case KEY_EVENT_REPEAT:			temp = "repeat";		break; -		} -		message.setValue("event", temp); -		 -		message.setValueS32("key", key_code); - -		message.setValue("modifiers", translateModifiers(modifiers)); -		message.setValueLLSD("native_key_data", native_key_data); -		 -		sendMessage(message); -	} -		 -	return result; -} - -void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event"); - -	message.setValueS32("x", x); -	message.setValueS32("y", y); -	message.setValue("modifiers", translateModifiers(modifiers)); -	 -	sendMessage(message); -} -	 -bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event"); - -	message.setValue("text", text); -	message.setValue("modifiers", translateModifiers(modifiers)); -	message.setValueLLSD("native_key_data", native_key_data); -	 -	sendMessage(message); -	 -	return true; -} - -void LLPluginClassMedia::loadURI(const std::string &uri) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri"); - -	message.setValue("uri", uri); -	 -	sendMessage(message); -} - -const char* LLPluginClassMedia::priorityToString(EPriority priority) -{ -	const char* result = "UNKNOWN"; -	switch(priority) -	{ -		case PRIORITY_UNLOADED:		result = "unloaded";	break; -		case PRIORITY_STOPPED:		result = "stopped";		break; -		case PRIORITY_HIDDEN:		result = "hidden";		break; -		case PRIORITY_SLIDESHOW:	result = "slideshow";	break; -		case PRIORITY_LOW:			result = "low";			break; -		case PRIORITY_NORMAL:		result = "normal";		break; -		case PRIORITY_HIGH:			result = "high";		break; -	} -	 -	return result; -} - -void LLPluginClassMedia::setPriority(EPriority priority) -{ -	if(mPriority != priority) -	{ -		mPriority = priority; - -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority"); -		 -		std::string priority_string = priorityToString(priority); -		switch(priority) -		{ -			case PRIORITY_UNLOADED:	 -				mSleepTime = 1.0f; -			break; -			case PRIORITY_STOPPED:	 -				mSleepTime = 1.0f; -			break; -			case PRIORITY_HIDDEN:	 -				mSleepTime = 1.0f; -			break; -			case PRIORITY_SLIDESHOW: -				mSleepTime = 1.0f; -			break; -			case PRIORITY_LOW:		 -				mSleepTime = 1.0f / 25.0f; -			break; -			case PRIORITY_NORMAL:	 -				mSleepTime = 1.0f / 50.0f; -			break; -			case PRIORITY_HIGH:		 -				mSleepTime = 1.0f / 100.0f; -			break; -		} -		 -		message.setValue("priority", priority_string); - -		sendMessage(message); -		 -		if(mPlugin) -		{ -			mPlugin->setSleepTime(mSleepTime); -		} -		 -		LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL; -		 -		// This may affect the calculated size, so recalculate it here. -		setSizeInternal(); -	} -} - -void LLPluginClassMedia::setLowPrioritySizeLimit(int size) -{ -	int power = nextPowerOf2(size); -	if(mLowPrioritySizeLimit != power) -	{ -		mLowPrioritySizeLimit = power; - -		// This may affect the calculated size, so recalculate it here. -		setSizeInternal(); -	} -} - -F64 LLPluginClassMedia::getCPUUsage() -{ -	F64 result = 0.0f; -	 -	if(mPlugin) -	{ -		result = mPlugin->getCPUUsage(); -	} -	 -	return result; -} - -void LLPluginClassMedia::sendPickFileResponse(const std::string &file) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response"); -	message.setValue("file", file); -	if(mPlugin && mPlugin->isBlocked()) -	{ -		// If the plugin sent a blocking pick-file request, the response should unblock it. -		message.setValueBoolean("blocking_response", true); -	} -	sendMessage(message); -} - -void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, const std::string &password) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response"); -	message.setValueBoolean("ok", ok); -	message.setValue("username", username); -	message.setValue("password", password); -	if(mPlugin && mPlugin->isBlocked()) -	{ -		// If the plugin sent a blocking pick-file request, the response should unblock it. -		message.setValueBoolean("blocking_response", true); -	} -	sendMessage(message); -} - -void LLPluginClassMedia::cut() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut"); -	sendMessage(message); -} - -void LLPluginClassMedia::copy() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_copy"); -	sendMessage(message); -} - -void LLPluginClassMedia::paste() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_paste"); -	sendMessage(message); -} - -void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path"); -	message.setValue("path", user_data_path); -	sendMessage(message); -} - -void LLPluginClassMedia::setLanguageCode(const std::string &language_code) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_language_code"); -	message.setValue("language", language_code); -	sendMessage(message); -} - -void LLPluginClassMedia::setPluginsEnabled(const bool enabled) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled"); -	message.setValueBoolean("enable", enabled); -	sendMessage(message); -} - -void LLPluginClassMedia::setJavascriptEnabled(const bool enabled) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled"); -	message.setValueBoolean("enable", enabled); -	sendMessage(message); -} - -void LLPluginClassMedia::setTarget(const std::string &target) -{ -	mTarget = target; -} - -/* virtual */  -void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) -{ -	std::string message_class = message.getClass(); -	 -	if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) -	{ -		std::string message_name = message.getName(); -		if(message_name == "texture_params") -		{ -			mRequestedTextureDepth = message.getValueS32("depth"); -			mRequestedTextureInternalFormat = message.getValueU32("internalformat"); -			mRequestedTextureFormat = message.getValueU32("format"); -			mRequestedTextureType = message.getValueU32("type"); -			mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes"); -			mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl");			 -			 -			// These two are optional, and will default to 0 if they're not specified. -			mDefaultMediaWidth = message.getValueS32("default_width"); -			mDefaultMediaHeight = message.getValueS32("default_height"); -			 -			mAllowDownsample = message.getValueBoolean("allow_downsample"); -			mPadding = message.getValueS32("padding"); - -			setSizeInternal(); -			 -			mTextureParamsReceived = true; -		} -		else if(message_name == "updated") -		{			 -			if(message.hasValue("left")) -			{ -				LLRect newDirtyRect; -				newDirtyRect.mLeft = message.getValueS32("left"); -				newDirtyRect.mTop = message.getValueS32("top"); -				newDirtyRect.mRight = message.getValueS32("right"); -				newDirtyRect.mBottom = message.getValueS32("bottom"); -							 -				// The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion. -				// If they're backwards, swap them. -				if(newDirtyRect.mTop < newDirtyRect.mBottom) -				{ -					S32 temp = newDirtyRect.mTop; -					newDirtyRect.mTop = newDirtyRect.mBottom; -					newDirtyRect.mBottom = temp; -				} -				 -				if(mDirtyRect.isEmpty()) -				{ -					mDirtyRect = newDirtyRect; -				} -				else -				{ -					mDirtyRect.unionWith(newDirtyRect); -				} - -				LL_DEBUGS("Plugin") << "adjusted incoming rect is: ("  -					<< newDirtyRect.mLeft << ", " -					<< newDirtyRect.mTop << ", " -					<< newDirtyRect.mRight << ", " -					<< newDirtyRect.mBottom << "), new dirty rect is: (" -					<< mDirtyRect.mLeft << ", " -					<< mDirtyRect.mTop << ", " -					<< mDirtyRect.mRight << ", " -					<< mDirtyRect.mBottom << ")" -					<< LL_ENDL; -				 -				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED); -			}			 -			 - -			bool time_duration_updated = false; -			int previous_percent = mProgressPercent; - -			if(message.hasValue("current_time")) -			{ -				mCurrentTime = message.getValueReal("current_time"); -				time_duration_updated = true; -			} -			if(message.hasValue("duration")) -			{ -				mDuration = message.getValueReal("duration"); -				time_duration_updated = true; -			} - -			if(message.hasValue("current_rate")) -			{ -				mCurrentRate = message.getValueReal("current_rate"); -			} -			 -			if(message.hasValue("loaded_duration")) -			{ -				mLoadedDuration = message.getValueReal("loaded_duration"); -				time_duration_updated = true; -			} -			else -			{ -				// If the message doesn't contain a loaded_duration param, assume it's equal to duration -				mLoadedDuration = mDuration; -			} -			 -			// Calculate a percentage based on the loaded duration and total duration. -			if(mDuration != 0.0f)	// Don't divide by zero. -			{ -				mProgressPercent = (int)((mLoadedDuration * 100.0f)/mDuration); -			} - -			if(time_duration_updated) -			{ -				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED); -			} -			 -			if(previous_percent != mProgressPercent) -			{ -				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED); -			} -		} -		else if(message_name == "media_status") -		{ -			std::string status = message.getValue("status"); -			 -			LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL; -			 -			if(status == "loading") -			{ -				mStatus = LLPluginClassMediaOwner::MEDIA_LOADING; -			} -			else if(status == "loaded") -			{ -				mStatus = LLPluginClassMediaOwner::MEDIA_LOADED; -			} -			else if(status == "error") -			{ -				mStatus = LLPluginClassMediaOwner::MEDIA_ERROR; -			} -			else if(status == "playing") -			{ -				mStatus = LLPluginClassMediaOwner::MEDIA_PLAYING; -			} -			else if(status == "paused") -			{ -				mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED; -			} -			else if(status == "done") -			{ -				mStatus = LLPluginClassMediaOwner::MEDIA_DONE; -			} -			else -			{ -				// empty string or any unknown string -				mStatus = LLPluginClassMediaOwner::MEDIA_NONE; -			} -		} -		else if(message_name == "size_change_request") -		{ -			S32 width = message.getValueS32("width"); -			S32 height = message.getValueS32("height"); -			std::string name = message.getValue("name"); - -			// TODO: check that name matches? -			mNaturalMediaWidth = width; -			mNaturalMediaHeight = height; -			 -			setSizeInternal(); -		} -		else if(message_name == "size_change_response") -		{ -			std::string name = message.getValue("name"); -			 -			// TODO: check that name matches? -			 -			mTextureWidth = message.getValueS32("texture_width"); -			mTextureHeight = message.getValueS32("texture_height"); -			mMediaWidth = message.getValueS32("width"); -			mMediaHeight = message.getValueS32("height"); -			 -			// This invalidates any existing dirty rect. -			resetDirty(); -			 -			// TODO: should we verify that the plugin sent back the right values?   -			// Two size changes in a row may cause them to not match, due to queueing, etc. - -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED); -		} -		else if(message_name == "cursor_changed") -		{ -			mCursorName = message.getValue("name"); - -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CURSOR_CHANGED); -		} -		else if(message_name == "edit_state") -		{ -			if(message.hasValue("cut")) -			{ -				mCanCut = message.getValueBoolean("cut"); -			} -			if(message.hasValue("copy")) -			{ -				mCanCopy = message.getValueBoolean("copy"); -			} -			if(message.hasValue("paste")) -			{ -				mCanPaste = message.getValueBoolean("paste"); -			} -		} -		else if(message_name == "name_text") -		{ -			mMediaName = message.getValue("name"); -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED); -		} -		else if(message_name == "pick_file") -		{ -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST); -		} -		else if(message_name == "auth_request") -		{ -			mAuthURL = message.getValue("url"); -			mAuthRealm = message.getValue("realm"); -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST); -		} -		else -		{ -			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; -		} -	} -	else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) -	{ -		std::string message_name = message.getName(); -		if(message_name == "navigate_begin") -		{ -			mNavigateURI = message.getValue("uri"); -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_BEGIN); -		} -		else if(message_name == "navigate_complete") -		{ -			mNavigateURI = message.getValue("uri"); -			mNavigateResultCode = message.getValueS32("result_code"); -			mNavigateResultString = message.getValue("result_string"); -			mHistoryBackAvailable = message.getValueBoolean("history_back_available"); -			mHistoryForwardAvailable = message.getValueBoolean("history_forward_available"); -			 -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE); -		} -		else if(message_name == "progress") -		{ -			mProgressPercent = message.getValueS32("percent"); -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED); -		} -		else if(message_name == "status_text") -		{ -			mStatusText = message.getValue("status"); -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_STATUS_TEXT_CHANGED); -		} -		else if(message_name == "location_changed") -		{ -			mLocation = message.getValue("uri"); -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LOCATION_CHANGED); -		} -		else if(message_name == "click_href") -		{ -			mClickURL = message.getValue("uri"); -			mClickTarget = message.getValue("target"); -			mClickUUID = message.getValue("uuid"); -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF); -		} -		else if(message_name == "click_nofollow") -		{ -			mClickURL = message.getValue("uri"); -			mClickNavType = message.getValue("nav_type"); -			mClickTarget.clear(); -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW); -		} -		else if(message_name == "navigate_error_page") -		{ -			mStatusCode = message.getValueS32("status_code"); -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_ERROR_PAGE); -		} -		else if(message_name == "cookie_set") -		{ -			if(mOwner) -			{ -				mOwner->handleCookieSet(this, message.getValue("cookie")); -			} -		} -		else if(message_name == "close_request") -		{ -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLOSE_REQUEST); -		} -		else if(message_name == "geometry_change") -		{ -			mClickUUID = message.getValue("uuid"); -			mGeometryX = message.getValueS32("x"); -			mGeometryY = message.getValueS32("y"); -			mGeometryWidth = message.getValueS32("width"); -			mGeometryHeight = message.getValueS32("height"); -				 -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE); -		} -		else if(message_name == "link_hovered") -		{ -			// text is not currently used -- the tooltip hover text is taken from the "title". -			mHoverLink = message.getValue("link"); -			mHoverText = message.getValue("title"); -			// message.getValue("text"); -				 -			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED); -		} -		else -		{ -			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; -		} -	} -	else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) -	{ -		std::string message_name = message.getName(); - -		// This class hasn't defined any incoming messages yet. -//		if(message_name == "message_name") -//		{ -//		} -//		else  -		{ -			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; -		} -	} - -} - -/* virtual */  -void LLPluginClassMedia::pluginLaunchFailed() -{ -	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH); -} - -/* virtual */  -void LLPluginClassMedia::pluginDied() -{ -	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED); -} - -void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event) -{ -	if(mOwner) -	{ -		mOwner->handleMediaEvent(this, event); -	} -} - -void LLPluginClassMedia::sendMessage(const LLPluginMessage &message) -{ -	if(mPlugin && mPlugin->isRunning()) -	{ -		mPlugin->sendMessage(message); -	} -	else -	{ -		// The plugin isn't set up yet -- queue this message to be sent after initialization. -		mSendQueue.push(message); -	} -} - -//////////////////////////////////////////////////////////// -// MARK: media_browser class functions -bool LLPluginClassMedia::pluginSupportsMediaBrowser(void) -{ -	std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER); -	return !version.empty(); -} - -void LLPluginClassMedia::focus(bool focused) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus"); - -	message.setValueBoolean("focused", focused); -	 -	sendMessage(message); -} - -void LLPluginClassMedia::clear_cache() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache"); -	sendMessage(message); -} - -void LLPluginClassMedia::clear_cookies() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cookies"); -	sendMessage(message); -} - -void LLPluginClassMedia::set_cookies(const std::string &cookies) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies"); -	message.setValue("cookies", cookies);	 -	sendMessage(message); -} - -void LLPluginClassMedia::enable_cookies(bool enable) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies"); -	message.setValueBoolean("enable", enable); -	sendMessage(message); -} - -void LLPluginClassMedia::proxy_setup(bool enable, const std::string &host, int port) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup"); - -	message.setValueBoolean("enable", enable); -	message.setValue("host", host); -	message.setValueS32("port", port); - -	sendMessage(message); -} - -void LLPluginClassMedia::browse_stop() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_stop"); -	sendMessage(message); -} - -void LLPluginClassMedia::browse_reload(bool ignore_cache) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload"); - -	message.setValueBoolean("ignore_cache", ignore_cache); -	 -	sendMessage(message); -} - -void LLPluginClassMedia::browse_forward() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_forward"); -	sendMessage(message); -} - -void LLPluginClassMedia::browse_back() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_back"); -	sendMessage(message); -} - -void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent"); - -	message.setValue("user_agent", user_agent); - -	sendMessage(message); -} - -void LLPluginClassMedia::proxyWindowOpened(const std::string &target, const std::string &uuid) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_opened"); - -	message.setValue("target", target); -	message.setValue("uuid", uuid); - -	sendMessage(message); -} - -void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_closed"); - -	message.setValue("uuid", uuid); - -	sendMessage(message); -} - -void LLPluginClassMedia::ignore_ssl_cert_errors(bool ignore) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors"); -	message.setValueBoolean("ignore", ignore); -	sendMessage(message); -} - -void LLPluginClassMedia::addCertificateFilePath(const std::string& path) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "add_certificate_file_path"); -	message.setValue("path", path); -	sendMessage(message); -} - -void LLPluginClassMedia::crashPlugin() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash"); - -	sendMessage(message); -} - -void LLPluginClassMedia::hangPlugin() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hang"); - -	sendMessage(message); -} - - -//////////////////////////////////////////////////////////// -// MARK: media_time class functions -bool LLPluginClassMedia::pluginSupportsMediaTime(void) -{ -	std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME); -	return !version.empty(); -} - -void LLPluginClassMedia::stop() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "stop"); -	sendMessage(message); -} - -void LLPluginClassMedia::start(float rate) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "start"); - -	message.setValueReal("rate", rate); - -	sendMessage(message); -} - -void LLPluginClassMedia::pause() -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "pause"); -	sendMessage(message); -} - -void LLPluginClassMedia::seek(float time) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek"); - -	message.setValueReal("time", time); -	 -	sendMessage(message); -} - -void LLPluginClassMedia::setLoop(bool loop) -{ -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_loop"); - -	message.setValueBoolean("loop", loop); - -	sendMessage(message); -} - -void LLPluginClassMedia::setVolume(float volume) -{ -	if(volume != mRequestedVolume) -	{ -		mRequestedVolume = volume; -		 -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume"); - -		message.setValueReal("volume", volume); -		 -		sendMessage(message); -	} -} - -float LLPluginClassMedia::getVolume() -{ -	return mRequestedVolume; -} - -void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history) -{ -	// Send URL history to plugin -	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "init_history"); -	message.setValueLLSD("history", url_history); -	sendMessage(message); - -	LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL; -} - +/** 
 + * @file llpluginclassmedia.cpp
 + * @brief LLPluginClassMedia handles a plugin which knows about the "media" message class.
 + *
 + * @cond
 + * $LicenseInfo:firstyear=2008&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$
 + * @endcond
 + */
 +
 +#include "linden_common.h"
 +#include "indra_constants.h"
 +
 +#include "llpluginclassmedia.h"
 +#include "llpluginmessageclasses.h"
 +
 +#include "llqtwebkit.h"
 +
 +static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256;
 +
 +static int nextPowerOf2( int value )
 +{
 +	int next_power_of_2 = 1;
 +	while ( next_power_of_2 < value )
 +	{
 +		next_power_of_2 <<= 1;
 +	}
 +	
 +	return next_power_of_2;
 +}
 +
 +LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner)
 +{
 +	mOwner = owner;
 +	mPlugin = NULL;
 +	reset();
 +
 +	//debug use
 +	mDeleteOK = true ;
 +}
 +
 +
 +LLPluginClassMedia::~LLPluginClassMedia()
 +{
 +	llassert_always(mDeleteOK) ;
 +	reset();
 +}
 +
 +bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug)
 +{	
 +	LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL;
 +	LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL;
 +	LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL;
 +	
 +	mPlugin = new LLPluginProcessParent(this);
 +	mPlugin->setSleepTime(mSleepTime);
 +	
 +	// Queue up the media init message -- it will be sent after all the currently queued messages.
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init");
 +	message.setValue("target", mTarget);
 +	sendMessage(message);
 +	
 +	mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug);
 +
 +	return true;
 +}
 +
 +
 +void LLPluginClassMedia::reset()
 +{
 +	if(mPlugin != NULL)
 +	{
 +		delete mPlugin;
 +		mPlugin = NULL;
 +	}
 +
 +	mTextureParamsReceived = false;
 +	mRequestedTextureDepth = 0;
 +	mRequestedTextureInternalFormat = 0;
 +	mRequestedTextureFormat = 0;
 +	mRequestedTextureType = 0;
 +	mRequestedTextureSwapBytes = false;
 +	mRequestedTextureCoordsOpenGL = false;
 +	mTextureSharedMemorySize = 0;
 +	mTextureSharedMemoryName.clear();
 +	mDefaultMediaWidth = 0;
 +	mDefaultMediaHeight = 0;
 +	mNaturalMediaWidth = 0;
 +	mNaturalMediaHeight = 0;
 +	mSetMediaWidth = -1;
 +	mSetMediaHeight = -1;
 +	mRequestedMediaWidth = 0;
 +	mRequestedMediaHeight = 0;
 +	mRequestedTextureWidth = 0;
 +	mRequestedTextureHeight = 0;
 +	mFullMediaWidth = 0;
 +	mFullMediaHeight = 0;
 +	mTextureWidth = 0;
 +	mTextureHeight = 0;
 +	mMediaWidth = 0;
 +	mMediaHeight = 0;
 +	mDirtyRect = LLRect::null;	
 +	mAutoScaleMedia = false;
 +	mRequestedVolume = 1.0f;
 +	mPriority = PRIORITY_NORMAL;
 +	mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT;
 +	mAllowDownsample = false;
 +	mPadding = 0;
 +	mLastMouseX = 0;
 +	mLastMouseY = 0;
 +	mStatus = LLPluginClassMediaOwner::MEDIA_NONE;
 +	mSleepTime = 1.0f / 100.0f;
 +	mCanCut = false;
 +	mCanCopy = false;
 +	mCanPaste = false;
 +	mMediaName.clear();
 +	mMediaDescription.clear();
 +	mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f);
 +	
 +	// media_browser class
 +	mNavigateURI.clear();
 +	mNavigateResultCode = -1;
 +	mNavigateResultString.clear();
 +	mHistoryBackAvailable = false;
 +	mHistoryForwardAvailable = false;
 +	mStatusText.clear();
 +	mProgressPercent = 0;	
 +	mClickURL.clear();
 +	mClickNavType.clear();
 +	mClickTarget.clear();
 +	mClickUUID.clear();
 +	mStatusCode = 0;
 +	
 +	// media_time class
 +	mCurrentTime = 0.0f;
 +	mDuration = 0.0f;
 +	mCurrentRate = 0.0f;
 +	mLoadedDuration = 0.0f;
 +}
 +
 +void LLPluginClassMedia::idle(void)
 +{
 +	if(mPlugin)
 +	{
 +		mPlugin->idle();
 +	}
 +	
 +	if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL))
 +	{
 +		// Can't process a size change at this time
 +	}
 +	else if((mRequestedMediaWidth != mMediaWidth) || (mRequestedMediaHeight != mMediaHeight))
 +	{
 +		// Calculate the correct size for the media texture
 +		mRequestedTextureHeight = mRequestedMediaHeight;
 +		if(mPadding < 0)
 +		{
 +			// negative values indicate the plugin wants a power of 2
 +			mRequestedTextureWidth = nextPowerOf2(mRequestedMediaWidth);
 +		}
 +		else
 +		{
 +			mRequestedTextureWidth = mRequestedMediaWidth;
 +			
 +			if(mPadding > 1)
 +			{
 +				// Pad up to a multiple of the specified number of bytes per row
 +				int rowbytes = mRequestedTextureWidth * mRequestedTextureDepth;
 +				int pad = rowbytes % mPadding;
 +				if(pad != 0)
 +				{
 +					rowbytes += mPadding - pad;
 +				}
 +				
 +				if(rowbytes % mRequestedTextureDepth == 0)
 +				{
 +					mRequestedTextureWidth = rowbytes / mRequestedTextureDepth;
 +				}
 +				else
 +				{
 +					LL_WARNS("Plugin") << "Unable to pad texture width, padding size " << mPadding << "is not a multiple of pixel size " << mRequestedTextureDepth << LL_ENDL;
 +				}
 +			}
 +		}
 +
 +		
 +		// Size change has been requested but not initiated yet.
 +		size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth;
 +
 +		// Add an extra line for padding, just in case.
 +		newsize += mRequestedTextureWidth * mRequestedTextureDepth;
 +
 +		if(newsize != mTextureSharedMemorySize)
 +		{
 +			if(!mTextureSharedMemoryName.empty())
 +			{
 +				// Tell the plugin to remove the old memory segment
 +				mPlugin->removeSharedMemory(mTextureSharedMemoryName);
 +				mTextureSharedMemoryName.clear();
 +			}
 +			
 +			mTextureSharedMemorySize = newsize;
 +			mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize);
 +			if(!mTextureSharedMemoryName.empty())
 +			{
 +				void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
 +				
 +				// clear texture memory to avoid random screen visual fuzz from uninitialized texture data
 +				memset( addr, 0x00, newsize );
 +				
 +				// We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin,
 +				// so it may not be worthwhile.
 +				// mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight);
 +			}
 +		}
 +		
 +		// This is our local indicator that a change is in progress.
 +		mTextureWidth = -1;
 +		mTextureHeight = -1;
 +		mMediaWidth = -1;
 +		mMediaHeight = -1;
 +
 +		// This invalidates any existing dirty rect.
 +		resetDirty();
 +		
 +		// Send a size change message to the plugin
 +		{
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change");
 +			message.setValue("name", mTextureSharedMemoryName);
 +			message.setValueS32("width", mRequestedMediaWidth);
 +			message.setValueS32("height", mRequestedMediaHeight);
 +			message.setValueS32("texture_width", mRequestedTextureWidth);
 +			message.setValueS32("texture_height", mRequestedTextureHeight);
 +			message.setValueReal("background_r", mBackgroundColor.mV[VX]);
 +			message.setValueReal("background_g", mBackgroundColor.mV[VY]);
 +			message.setValueReal("background_b", mBackgroundColor.mV[VZ]);
 +			message.setValueReal("background_a", mBackgroundColor.mV[VW]);
 +			mPlugin->sendMessage(message);	// DO NOT just use sendMessage() here -- we want this to jump ahead of the queue.
 +			
 +			LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL;
 +		}
 +	}
 +	
 +	if(mPlugin && mPlugin->isRunning())
 +	{
 +		// Send queued messages
 +		while(!mSendQueue.empty())
 +		{
 +			LLPluginMessage message = mSendQueue.front();
 +			mSendQueue.pop();
 +			mPlugin->sendMessage(message);
 +		}
 +	}
 +}
 +
 +int LLPluginClassMedia::getTextureWidth() const
 +{
 +	return nextPowerOf2(mTextureWidth);
 +}
 +
 +int LLPluginClassMedia::getTextureHeight() const
 +{
 +	return nextPowerOf2(mTextureHeight);
 +}
 +
 +unsigned char* LLPluginClassMedia::getBitsData()
 +{
 +	unsigned char *result = NULL;
 +	if((mPlugin != NULL) && !mTextureSharedMemoryName.empty())
 +	{
 +		result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
 +	}
 +	return result;
 +}
 +
 +void LLPluginClassMedia::setSize(int width, int height)
 +{
 +	if((width > 0) && (height > 0))
 +	{
 +		mSetMediaWidth = width;
 +		mSetMediaHeight = height;
 +	}
 +	else
 +	{
 +		mSetMediaWidth = -1;
 +		mSetMediaHeight = -1;
 +	}
 +
 +	setSizeInternal();
 +}
 +
 +void LLPluginClassMedia::setSizeInternal(void)
 +{
 +	if((mSetMediaWidth > 0) && (mSetMediaHeight > 0))
 +	{
 +		mRequestedMediaWidth = mSetMediaWidth;
 +		mRequestedMediaHeight = mSetMediaHeight;
 +	}
 +	else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0))
 +	{
 +		mRequestedMediaWidth = mNaturalMediaWidth;
 +		mRequestedMediaHeight = mNaturalMediaHeight;
 +	}
 +	else
 +	{
 +		mRequestedMediaWidth = mDefaultMediaWidth;
 +		mRequestedMediaHeight = mDefaultMediaHeight;
 +	}
 +	
 +	// Save these for size/interest calculations
 +	mFullMediaWidth = mRequestedMediaWidth;
 +	mFullMediaHeight = mRequestedMediaHeight;
 +	
 +	if(mAllowDownsample)
 +	{
 +		switch(mPriority)
 +		{
 +			case PRIORITY_SLIDESHOW:
 +			case PRIORITY_LOW:
 +				// Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit
 +				while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit))
 +				{
 +					mRequestedMediaWidth /= 2;
 +					mRequestedMediaHeight /= 2;
 +				}
 +			break;
 +			
 +			default:
 +				// Don't adjust texture size
 +			break;
 +		}
 +	}
 +	
 +	if(mAutoScaleMedia)
 +	{
 +		mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth);
 +		mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight);
 +	}
 +	
 +	if(mRequestedMediaWidth > 2048)
 +		mRequestedMediaWidth = 2048;
 +
 +	if(mRequestedMediaHeight > 2048)
 +		mRequestedMediaHeight = 2048;
 +}
 +
 +void LLPluginClassMedia::setAutoScale(bool auto_scale)
 +{
 +	if(auto_scale != mAutoScaleMedia)
 +	{
 +		mAutoScaleMedia = auto_scale;
 +		setSizeInternal();
 +	}
 +}
 +
 +bool LLPluginClassMedia::textureValid(void)
 +{
 +	if(
 +		!mTextureParamsReceived ||
 +		mTextureWidth <= 0 ||
 +		mTextureHeight <= 0 ||
 +		mMediaWidth <= 0 ||
 +		mMediaHeight <= 0 ||
 +		mRequestedMediaWidth != mMediaWidth ||
 +		mRequestedMediaHeight != mMediaHeight ||
 +		getBitsData() == NULL
 +	)	
 +		return false;
 +	
 +	return true;
 +}
 +
 +bool LLPluginClassMedia::getDirty(LLRect *dirty_rect)
 +{
 +	bool result = !mDirtyRect.isEmpty();
 +
 +	if(dirty_rect != NULL)
 +	{
 +		*dirty_rect = mDirtyRect;
 +	}
 +
 +	return result;
 +}
 +
 +void LLPluginClassMedia::resetDirty(void)
 +{
 +	mDirtyRect = LLRect::null;
 +}
 +
 +std::string LLPluginClassMedia::translateModifiers(MASK modifiers)
 +{
 +	std::string result;
 +	
 +	
 +	if(modifiers & MASK_CONTROL)
 +	{
 +		result += "control|";
 +	}
 +
 +	if(modifiers & MASK_ALT)
 +	{
 +		result += "alt|";
 +	}
 +
 +	if(modifiers & MASK_SHIFT)
 +	{
 +		result += "shift|";
 +	}
 +
 +	// TODO: should I deal with platform differences here or in callers?
 +	// TODO: how do we deal with the Mac "command" key?
 +/*
 +	if(modifiers & MASK_SOMETHING)
 +	{
 +		result += "meta|";
 +	}
 +*/	
 +	return result;
 +}
 +
 +void LLPluginClassMedia::jsEnableObject( bool enable )
 +{
 +	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 +	{
 +		return;
 +	}
 +
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_enable_object");
 +	message.setValueBoolean( "enable", enable );
 +	sendMessage( message );
 +}
 +
 +void LLPluginClassMedia::jsAgentLocationEvent( double x, double y, double z )
 +{
 +	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 +	{
 +		return;
 +	}
 +
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_location");
 +	message.setValueReal( "x", x );
 +	message.setValueReal( "y", y );
 +	message.setValueReal( "z", z );
 +	sendMessage( message );
 +}
 +
 +void LLPluginClassMedia::jsAgentGlobalLocationEvent( double x, double y, double z )
 +{
 +	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 +	{
 +		return;
 +	}
 +
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_global_location");
 +	message.setValueReal( "x", x );
 +	message.setValueReal( "y", y );
 +	message.setValueReal( "z", z );
 +	sendMessage( message );
 +}
 +
 +void LLPluginClassMedia::jsAgentOrientationEvent( double angle )
 +{
 +	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 +	{
 +		return;
 +	}
 +
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_orientation");
 +	message.setValueReal( "angle", angle );
 +
 +	sendMessage( message );
 +}
 +
 +void LLPluginClassMedia::jsAgentLanguageEvent( const std::string& language )
 +{
 +	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 +	{
 +		return;
 +	}
 +
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_language");
 +	message.setValue( "language", language );
 +	sendMessage( message );
 +}
 +
 +void LLPluginClassMedia::jsAgentRegionEvent( const std::string& region )
 +{
 +	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 +	{
 +		return;
 +	}
 +
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_region");
 +	message.setValue( "region", region );
 +	sendMessage( message );
 +}
 +
 +void LLPluginClassMedia::jsAgentMaturityEvent( const std::string& maturity )
 +{
 +	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
 +	{
 +		return;
 +	}
 +
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_maturity");
 +	message.setValue( "maturity", maturity );
 +	sendMessage( message );
 +}
 +
 +void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers)
 +{
 +	if(type == MOUSE_EVENT_MOVE)
 +	{
 +		if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked())
 +		{
 +			// Don't queue up mouse move events that can't be delivered.
 +			return;
 +		}
 +
 +		if((x == mLastMouseX) && (y == mLastMouseY))
 +		{
 +			// Don't spam unnecessary mouse move events.
 +			return;
 +		}
 +		
 +		mLastMouseX = x;
 +		mLastMouseY = y;
 +	}
 +	
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event");
 +	std::string temp;
 +	switch(type)
 +	{
 +		case MOUSE_EVENT_DOWN:			temp = "down";			break;
 +		case MOUSE_EVENT_UP:			temp = "up";			break;
 +		case MOUSE_EVENT_MOVE:			temp = "move";			break;
 +		case MOUSE_EVENT_DOUBLE_CLICK:	temp = "double_click";	break;
 +	}
 +	message.setValue("event", temp);
 +
 +	message.setValueS32("button", button);
 +
 +	message.setValueS32("x", x);
 +	
 +	// Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it.
 +	if(!mRequestedTextureCoordsOpenGL)
 +	{
 +		// TODO: Should I use mMediaHeight or mRequestedMediaHeight here?
 +		y = mMediaHeight - y;
 +	}
 +	message.setValueS32("y", y);
 +
 +	message.setValue("modifiers", translateModifiers(modifiers));
 +	
 +	sendMessage(message);
 +}
 +
 +bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data)
 +{
 +	bool result = true;
 +	
 +	// FIXME:
 +	// HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode.
 +	// For now, return false for the ones the webkit plugin won't handle properly.
 +	
 +	switch(key_code)
 +	{
 +		case KEY_BACKSPACE:		
 +		case KEY_TAB:			
 +		case KEY_RETURN:		
 +		case KEY_PAD_RETURN:	
 +		case KEY_SHIFT:			
 +		case KEY_CONTROL:		
 +		case KEY_ALT:			
 +		case KEY_CAPSLOCK:		
 +		case KEY_ESCAPE:		
 +		case KEY_PAGE_UP:		
 +		case KEY_PAGE_DOWN:		
 +		case KEY_END:			
 +		case KEY_HOME:			
 +		case KEY_LEFT:			
 +		case KEY_UP:			
 +		case KEY_RIGHT:			
 +		case KEY_DOWN:			
 +		case KEY_INSERT:		
 +		case KEY_DELETE:
 +			// These will be handled		
 +		break;
 +		
 +		default:
 +			// regular ASCII characters will also be handled
 +			if(key_code >= KEY_SPECIAL)
 +			{
 +				// Other "special" codes will not work properly.
 +				result = false;
 +			}
 +		break;
 +	}
 +
 +#if LL_DARWIN	
 +	if(modifiers & MASK_ALT)
 +	{
 +		// Option-key modified characters should be handled by the unicode input path instead of this one.
 +		result = false;
 +	}
 +#endif
 +
 +	if(result)
 +	{
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event");
 +		std::string temp;
 +		switch(type)
 +		{
 +			case KEY_EVENT_DOWN:			temp = "down";			break;
 +			case KEY_EVENT_UP:				temp = "up";			break;
 +			case KEY_EVENT_REPEAT:			temp = "repeat";		break;
 +		}
 +		message.setValue("event", temp);
 +		
 +		message.setValueS32("key", key_code);
 +
 +		message.setValue("modifiers", translateModifiers(modifiers));
 +		message.setValueLLSD("native_key_data", native_key_data);
 +		
 +		sendMessage(message);
 +	}
 +		
 +	return result;
 +}
 +
 +void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event");
 +
 +	message.setValueS32("x", x);
 +	message.setValueS32("y", y);
 +	message.setValue("modifiers", translateModifiers(modifiers));
 +	
 +	sendMessage(message);
 +}
 +	
 +bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event");
 +
 +	message.setValue("text", text);
 +	message.setValue("modifiers", translateModifiers(modifiers));
 +	message.setValueLLSD("native_key_data", native_key_data);
 +	
 +	sendMessage(message);
 +	
 +	return true;
 +}
 +
 +void LLPluginClassMedia::loadURI(const std::string &uri)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri");
 +
 +	message.setValue("uri", uri);
 +	
 +	sendMessage(message);
 +}
 +
 +const char* LLPluginClassMedia::priorityToString(EPriority priority)
 +{
 +	const char* result = "UNKNOWN";
 +	switch(priority)
 +	{
 +		case PRIORITY_UNLOADED:		result = "unloaded";	break;
 +		case PRIORITY_STOPPED:		result = "stopped";		break;
 +		case PRIORITY_HIDDEN:		result = "hidden";		break;
 +		case PRIORITY_SLIDESHOW:	result = "slideshow";	break;
 +		case PRIORITY_LOW:			result = "low";			break;
 +		case PRIORITY_NORMAL:		result = "normal";		break;
 +		case PRIORITY_HIGH:			result = "high";		break;
 +	}
 +	
 +	return result;
 +}
 +
 +void LLPluginClassMedia::setPriority(EPriority priority)
 +{
 +	if(mPriority != priority)
 +	{
 +		mPriority = priority;
 +
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority");
 +		
 +		std::string priority_string = priorityToString(priority);
 +		switch(priority)
 +		{
 +			case PRIORITY_UNLOADED:	
 +				mSleepTime = 1.0f;
 +			break;
 +			case PRIORITY_STOPPED:	
 +				mSleepTime = 1.0f;
 +			break;
 +			case PRIORITY_HIDDEN:	
 +				mSleepTime = 1.0f;
 +			break;
 +			case PRIORITY_SLIDESHOW:
 +				mSleepTime = 1.0f;
 +			break;
 +			case PRIORITY_LOW:		
 +				mSleepTime = 1.0f / 25.0f;
 +			break;
 +			case PRIORITY_NORMAL:	
 +				mSleepTime = 1.0f / 50.0f;
 +			break;
 +			case PRIORITY_HIGH:		
 +				mSleepTime = 1.0f / 100.0f;
 +			break;
 +		}
 +		
 +		message.setValue("priority", priority_string);
 +
 +		sendMessage(message);
 +		
 +		if(mPlugin)
 +		{
 +			mPlugin->setSleepTime(mSleepTime);
 +		}
 +		
 +		LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL;
 +		
 +		// This may affect the calculated size, so recalculate it here.
 +		setSizeInternal();
 +	}
 +}
 +
 +void LLPluginClassMedia::setLowPrioritySizeLimit(int size)
 +{
 +	int power = nextPowerOf2(size);
 +	if(mLowPrioritySizeLimit != power)
 +	{
 +		mLowPrioritySizeLimit = power;
 +
 +		// This may affect the calculated size, so recalculate it here.
 +		setSizeInternal();
 +	}
 +}
 +
 +F64 LLPluginClassMedia::getCPUUsage()
 +{
 +	F64 result = 0.0f;
 +	
 +	if(mPlugin)
 +	{
 +		result = mPlugin->getCPUUsage();
 +	}
 +	
 +	return result;
 +}
 +
 +void LLPluginClassMedia::sendPickFileResponse(const std::string &file)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response");
 +	message.setValue("file", file);
 +	if(mPlugin && mPlugin->isBlocked())
 +	{
 +		// If the plugin sent a blocking pick-file request, the response should unblock it.
 +		message.setValueBoolean("blocking_response", true);
 +	}
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, const std::string &password)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response");
 +	message.setValueBoolean("ok", ok);
 +	message.setValue("username", username);
 +	message.setValue("password", password);
 +	if(mPlugin && mPlugin->isBlocked())
 +	{
 +		// If the plugin sent a blocking pick-file request, the response should unblock it.
 +		message.setValueBoolean("blocking_response", true);
 +	}
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::cut()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::copy()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_copy");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::paste()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_paste");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path");
 +	message.setValue("path", user_data_path);
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::setLanguageCode(const std::string &language_code)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_language_code");
 +	message.setValue("language", language_code);
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::setPluginsEnabled(const bool enabled)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled");
 +	message.setValueBoolean("enable", enabled);
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::setJavascriptEnabled(const bool enabled)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled");
 +	message.setValueBoolean("enable", enabled);
 +	sendMessage(message);
 +}
 +
 +
 +void LLPluginClassMedia::enableMediaPluginDebugging( bool enable )
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "enable_media_plugin_debugging");
 +	message.setValueBoolean( "enable", enable );
 +	sendMessage( message );
 +}
 +
 +void LLPluginClassMedia::setTarget(const std::string &target)
 +{
 +	mTarget = target;
 +}
 +
 +/* virtual */ 
 +void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
 +{
 +	std::string message_class = message.getClass();
 +	
 +	if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
 +	{
 +		std::string message_name = message.getName();
 +		if(message_name == "texture_params")
 +		{
 +			mRequestedTextureDepth = message.getValueS32("depth");
 +			mRequestedTextureInternalFormat = message.getValueU32("internalformat");
 +			mRequestedTextureFormat = message.getValueU32("format");
 +			mRequestedTextureType = message.getValueU32("type");
 +			mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes");
 +			mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl");			
 +			
 +			// These two are optional, and will default to 0 if they're not specified.
 +			mDefaultMediaWidth = message.getValueS32("default_width");
 +			mDefaultMediaHeight = message.getValueS32("default_height");
 +			
 +			mAllowDownsample = message.getValueBoolean("allow_downsample");
 +			mPadding = message.getValueS32("padding");
 +
 +			setSizeInternal();
 +			
 +			mTextureParamsReceived = true;
 +		}
 +		else if(message_name == "updated")
 +		{			
 +			if(message.hasValue("left"))
 +			{
 +				LLRect newDirtyRect;
 +				newDirtyRect.mLeft = message.getValueS32("left");
 +				newDirtyRect.mTop = message.getValueS32("top");
 +				newDirtyRect.mRight = message.getValueS32("right");
 +				newDirtyRect.mBottom = message.getValueS32("bottom");
 +							
 +				// The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion.
 +				// If they're backwards, swap them.
 +				if(newDirtyRect.mTop < newDirtyRect.mBottom)
 +				{
 +					S32 temp = newDirtyRect.mTop;
 +					newDirtyRect.mTop = newDirtyRect.mBottom;
 +					newDirtyRect.mBottom = temp;
 +				}
 +				
 +				if(mDirtyRect.isEmpty())
 +				{
 +					mDirtyRect = newDirtyRect;
 +				}
 +				else
 +				{
 +					mDirtyRect.unionWith(newDirtyRect);
 +				}
 +
 +				LL_DEBUGS("Plugin") << "adjusted incoming rect is: (" 
 +					<< newDirtyRect.mLeft << ", "
 +					<< newDirtyRect.mTop << ", "
 +					<< newDirtyRect.mRight << ", "
 +					<< newDirtyRect.mBottom << "), new dirty rect is: ("
 +					<< mDirtyRect.mLeft << ", "
 +					<< mDirtyRect.mTop << ", "
 +					<< mDirtyRect.mRight << ", "
 +					<< mDirtyRect.mBottom << ")"
 +					<< LL_ENDL;
 +				
 +				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED);
 +			}			
 +			
 +
 +			bool time_duration_updated = false;
 +			int previous_percent = mProgressPercent;
 +
 +			if(message.hasValue("current_time"))
 +			{
 +				mCurrentTime = message.getValueReal("current_time");
 +				time_duration_updated = true;
 +			}
 +			if(message.hasValue("duration"))
 +			{
 +				mDuration = message.getValueReal("duration");
 +				time_duration_updated = true;
 +			}
 +
 +			if(message.hasValue("current_rate"))
 +			{
 +				mCurrentRate = message.getValueReal("current_rate");
 +			}
 +			
 +			if(message.hasValue("loaded_duration"))
 +			{
 +				mLoadedDuration = message.getValueReal("loaded_duration");
 +				time_duration_updated = true;
 +			}
 +			else
 +			{
 +				// If the message doesn't contain a loaded_duration param, assume it's equal to duration
 +				mLoadedDuration = mDuration;
 +			}
 +			
 +			// Calculate a percentage based on the loaded duration and total duration.
 +			if(mDuration != 0.0f)	// Don't divide by zero.
 +			{
 +				mProgressPercent = (int)((mLoadedDuration * 100.0f)/mDuration);
 +			}
 +
 +			if(time_duration_updated)
 +			{
 +				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED);
 +			}
 +			
 +			if(previous_percent != mProgressPercent)
 +			{
 +				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
 +			}
 +		}
 +		else if(message_name == "media_status")
 +		{
 +			std::string status = message.getValue("status");
 +			
 +			LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL;
 +			
 +			if(status == "loading")
 +			{
 +				mStatus = LLPluginClassMediaOwner::MEDIA_LOADING;
 +			}
 +			else if(status == "loaded")
 +			{
 +				mStatus = LLPluginClassMediaOwner::MEDIA_LOADED;
 +			}
 +			else if(status == "error")
 +			{
 +				mStatus = LLPluginClassMediaOwner::MEDIA_ERROR;
 +			}
 +			else if(status == "playing")
 +			{
 +				mStatus = LLPluginClassMediaOwner::MEDIA_PLAYING;
 +			}
 +			else if(status == "paused")
 +			{
 +				mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED;
 +			}
 +			else if(status == "done")
 +			{
 +				mStatus = LLPluginClassMediaOwner::MEDIA_DONE;
 +			}
 +			else
 +			{
 +				// empty string or any unknown string
 +				mStatus = LLPluginClassMediaOwner::MEDIA_NONE;
 +			}
 +		}
 +		else if(message_name == "size_change_request")
 +		{
 +			S32 width = message.getValueS32("width");
 +			S32 height = message.getValueS32("height");
 +			std::string name = message.getValue("name");
 +
 +			// TODO: check that name matches?
 +			mNaturalMediaWidth = width;
 +			mNaturalMediaHeight = height;
 +			
 +			setSizeInternal();
 +		}
 +		else if(message_name == "size_change_response")
 +		{
 +			std::string name = message.getValue("name");
 +			
 +			// TODO: check that name matches?
 +			
 +			mTextureWidth = message.getValueS32("texture_width");
 +			mTextureHeight = message.getValueS32("texture_height");
 +			mMediaWidth = message.getValueS32("width");
 +			mMediaHeight = message.getValueS32("height");
 +			
 +			// This invalidates any existing dirty rect.
 +			resetDirty();
 +			
 +			// TODO: should we verify that the plugin sent back the right values?  
 +			// Two size changes in a row may cause them to not match, due to queueing, etc.
 +
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED);
 +		}
 +		else if(message_name == "cursor_changed")
 +		{
 +			mCursorName = message.getValue("name");
 +
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CURSOR_CHANGED);
 +		}
 +		else if(message_name == "edit_state")
 +		{
 +			if(message.hasValue("cut"))
 +			{
 +				mCanCut = message.getValueBoolean("cut");
 +			}
 +			if(message.hasValue("copy"))
 +			{
 +				mCanCopy = message.getValueBoolean("copy");
 +			}
 +			if(message.hasValue("paste"))
 +			{
 +				mCanPaste = message.getValueBoolean("paste");
 +			}
 +		}
 +		else if(message_name == "name_text")
 +		{
 +			mMediaName = message.getValue("name");
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED);
 +		}
 +		else if(message_name == "pick_file")
 +		{
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST);
 +		}
 +		else if(message_name == "auth_request")
 +		{
 +			mAuthURL = message.getValue("url");
 +			mAuthRealm = message.getValue("realm");
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST);
 +		}		
 +		else if(message_name == "debug_message")
 +		{
 +			mDebugMessageText = message.getValue("message_text");
 +			mDebugMessageLevel = message.getValue("message_level");
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_DEBUG_MESSAGE);
 +		}
 +		else
 +		{
 +			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
 +		}
 +	}
 +	else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
 +	{
 +		std::string message_name = message.getName();
 +		if(message_name == "navigate_begin")
 +		{
 +			mNavigateURI = message.getValue("uri");
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_BEGIN);
 +		}
 +		else if(message_name == "navigate_complete")
 +		{
 +			mNavigateURI = message.getValue("uri");
 +			mNavigateResultCode = message.getValueS32("result_code");
 +			mNavigateResultString = message.getValue("result_string");
 +			mHistoryBackAvailable = message.getValueBoolean("history_back_available");
 +			mHistoryForwardAvailable = message.getValueBoolean("history_forward_available");
 +			
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE);
 +		}
 +		else if(message_name == "progress")
 +		{
 +			mProgressPercent = message.getValueS32("percent");
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
 +		}
 +		else if(message_name == "status_text")
 +		{
 +			mStatusText = message.getValue("status");
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_STATUS_TEXT_CHANGED);
 +		}
 +		else if(message_name == "location_changed")
 +		{
 +			mLocation = message.getValue("uri");
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LOCATION_CHANGED);
 +		}
 +		else if(message_name == "click_href")
 +		{
 +			mClickURL = message.getValue("uri");
 +			mClickTarget = message.getValue("target");
 +			mClickUUID = message.getValue("uuid");
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF);
 +		}
 +		else if(message_name == "click_nofollow")
 +		{
 +			mClickURL = message.getValue("uri");
 +			mClickNavType = message.getValue("nav_type");
 +			mClickTarget.clear();
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW);
 +		}
 +		else if(message_name == "navigate_error_page")
 +		{
 +			mStatusCode = message.getValueS32("status_code");
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_ERROR_PAGE);
 +		}
 +		else if(message_name == "cookie_set")
 +		{
 +			if(mOwner)
 +			{
 +				mOwner->handleCookieSet(this, message.getValue("cookie"));
 +			}
 +		}
 +		else if(message_name == "close_request")
 +		{
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLOSE_REQUEST);
 +		}
 +		else if(message_name == "geometry_change")
 +		{
 +			mClickUUID = message.getValue("uuid");
 +			mGeometryX = message.getValueS32("x");
 +			mGeometryY = message.getValueS32("y");
 +			mGeometryWidth = message.getValueS32("width");
 +			mGeometryHeight = message.getValueS32("height");
 +				
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE);
 +		}
 +		else if(message_name == "link_hovered")
 +		{
 +			// text is not currently used -- the tooltip hover text is taken from the "title".
 +			mHoverLink = message.getValue("link");
 +			mHoverText = message.getValue("title");
 +			// message.getValue("text");
 +				
 +			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED);
 +		}
 +		else
 +		{
 +			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
 +		}
 +	}
 +	else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
 +	{
 +		std::string message_name = message.getName();
 +
 +		// This class hasn't defined any incoming messages yet.
 +//		if(message_name == "message_name")
 +//		{
 +//		}
 +//		else 
 +		{
 +			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
 +		}
 +	}
 +
 +}
 +
 +/* virtual */ 
 +void LLPluginClassMedia::pluginLaunchFailed()
 +{
 +	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH);
 +}
 +
 +/* virtual */ 
 +void LLPluginClassMedia::pluginDied()
 +{
 +	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED);
 +}
 +
 +void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event)
 +{
 +	if(mOwner)
 +	{
 +		mOwner->handleMediaEvent(this, event);
 +	}
 +}
 +
 +void LLPluginClassMedia::sendMessage(const LLPluginMessage &message)
 +{
 +	if(mPlugin && mPlugin->isRunning())
 +	{
 +		mPlugin->sendMessage(message);
 +	}
 +	else
 +	{
 +		// The plugin isn't set up yet -- queue this message to be sent after initialization.
 +		mSendQueue.push(message);
 +	}
 +}
 +
 +////////////////////////////////////////////////////////////
 +// MARK: media_browser class functions
 +bool LLPluginClassMedia::pluginSupportsMediaBrowser(void)
 +{
 +	std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER);
 +	return !version.empty();
 +}
 +
 +void LLPluginClassMedia::focus(bool focused)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus");
 +
 +	message.setValueBoolean("focused", focused);
 +	
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::clear_cache()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::clear_cookies()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cookies");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::set_cookies(const std::string &cookies)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies");
 +	message.setValue("cookies", cookies);	
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::enable_cookies(bool enable)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies");
 +	message.setValueBoolean("enable", enable);
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::proxy_setup(bool enable, const std::string &host, int port)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup");
 +
 +	message.setValueBoolean("enable", enable);
 +	message.setValue("host", host);
 +	message.setValueS32("port", port);
 +
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::browse_stop()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_stop");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::browse_reload(bool ignore_cache)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload");
 +
 +	message.setValueBoolean("ignore_cache", ignore_cache);
 +	
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::browse_forward()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_forward");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::browse_back()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_back");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent");
 +
 +	message.setValue("user_agent", user_agent);
 +
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::showWebInspector( bool show )
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "show_web_inspector");
 +	message.setValueBoolean("show", true);	// only open for now - closed manually by user
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::proxyWindowOpened(const std::string &target, const std::string &uuid)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_opened");
 +
 +	message.setValue("target", target);
 +	message.setValue("uuid", uuid);
 +
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_closed");
 +
 +	message.setValue("uuid", uuid);
 +
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::ignore_ssl_cert_errors(bool ignore)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors");
 +	message.setValueBoolean("ignore", ignore);
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::addCertificateFilePath(const std::string& path)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "add_certificate_file_path");
 +	message.setValue("path", path);
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::crashPlugin()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash");
 +
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::hangPlugin()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hang");
 +
 +	sendMessage(message);
 +}
 +
 +
 +////////////////////////////////////////////////////////////
 +// MARK: media_time class functions
 +bool LLPluginClassMedia::pluginSupportsMediaTime(void)
 +{
 +	std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME);
 +	return !version.empty();
 +}
 +
 +void LLPluginClassMedia::stop()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "stop");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::start(float rate)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "start");
 +
 +	message.setValueReal("rate", rate);
 +
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::pause()
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "pause");
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::seek(float time)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek");
 +
 +	message.setValueReal("time", time);
 +	
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::setLoop(bool loop)
 +{
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_loop");
 +
 +	message.setValueBoolean("loop", loop);
 +
 +	sendMessage(message);
 +}
 +
 +void LLPluginClassMedia::setVolume(float volume)
 +{
 +	if(volume != mRequestedVolume)
 +	{
 +		mRequestedVolume = volume;
 +		
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume");
 +
 +		message.setValueReal("volume", volume);
 +		
 +		sendMessage(message);
 +	}
 +}
 +
 +float LLPluginClassMedia::getVolume()
 +{
 +	return mRequestedVolume;
 +}
 +
 +void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history)
 +{
 +	// Send URL history to plugin
 +	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "init_history");
 +	message.setValueLLSD("history", url_history);
 +	sendMessage(message);
 +
 +	LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL;
 +}
 +
 diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index d32cb0afe9..1f548f8cc0 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -118,6 +118,9 @@ public:  	void scrollEvent(int x, int y, MASK modifiers); +	// enable/disable media plugin debugging messages and info spam +	void enableMediaPluginDebugging( bool enable ); +  	// Javascript <-> viewer events  	void jsEnableObject( bool enable );  	void jsAgentLocationEvent( double x, double y, double z ); @@ -209,6 +212,7 @@ public:  	void browse_forward();  	void browse_back();  	void setBrowserUserAgent(const std::string& user_agent); +	void showWebInspector( bool show );  	void proxyWindowOpened(const std::string &target, const std::string &uuid);  	void proxyWindowClosed(const std::string &uuid);  	void ignore_ssl_cert_errors(bool ignore); @@ -244,6 +248,10 @@ public:  	// This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE  	std::string getClickUUID() const { return mClickUUID; }; +	// These are valid during MEDIA_EVENT_DEBUG_MESSAGE +	std::string getDebugMessageText() const { return mDebugMessageText; }; +	std::string getDebugMessageLevel() const { return mDebugMessageLevel; }; +  	// This is valid after MEDIA_EVENT_NAVIGATE_ERROR_PAGE  	S32 getStatusCode() const { return mStatusCode; }; @@ -395,6 +403,8 @@ protected:  	std::string		mClickNavType;  	std::string		mClickTarget;  	std::string		mClickUUID; +	std::string		mDebugMessageText; +	std::string		mDebugMessageLevel;  	S32				mGeometryX;  	S32				mGeometryY;  	S32				mGeometryWidth; diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h index 5a4fb1ce90..2f3edba7f3 100644 --- a/indra/llplugin/llpluginclassmediaowner.h +++ b/indra/llplugin/llpluginclassmediaowner.h @@ -64,6 +64,8 @@ public:  		MEDIA_EVENT_AUTH_REQUEST,			// The plugin wants to display an auth dialog +		MEDIA_EVENT_DEBUG_MESSAGE,			// plugin sending back debug information for host to process +  		MEDIA_EVENT_LINK_HOVERED			// Got a "link hovered" event from the plugin  	} EMediaEvent; diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index cddda03faf..89d8842393 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -525,15 +525,12 @@ void LLComboBox::createLineEditor(const LLComboBox::Params& p)  	else  	{  		mButton->setRect(rect); -		mButton->setTabStop(TRUE); -		mButton->setHAlign(LLFontGL::LEFT);  		mButton->setLabel(mLabel.getString());  		if (mTextEntry)  		{  			mTextEntry->setVisible(FALSE);  		} -		mButton->setFollowsAll();  	}  } diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index 96f642f2a0..430ae9d4dc 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -1,1394 +1,1447 @@ -/**  - * @file media_plugin_webkit.cpp - * @brief Webkit plugin for LLMedia API plugin system - * - * @cond - * $LicenseInfo:firstyear=2008&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$ - * @endcond - */ - -#include "llqtwebkit.h" - -#include "linden_common.h" -#include "indra_constants.h" // for indra keyboard codes - -#include "llgl.h" - -#include "llplugininstance.h" -#include "llpluginmessage.h" -#include "llpluginmessageclasses.h" -#include "media_plugin_base.h" - -// set to 1 if you're using the version of llqtwebkit that's QPixmap-ified -#if LL_LINUX -# define LL_QTWEBKIT_USES_PIXMAPS 0 -extern "C" { -# include <glib.h> -# include <glib-object.h> -} -#else -# define LL_QTWEBKIT_USES_PIXMAPS 0 -#endif // LL_LINUX - -# include "volume_catcher.h" - -#if LL_WINDOWS -# include <direct.h> -#else -# include <unistd.h> -# include <stdlib.h> -#endif - -#if LL_WINDOWS -	// *NOTE:Mani - This captures the module handle for the dll. This is used below -	// to get the path to this dll for webkit initialization. -	// I don't know how/if this can be done with apr... -	namespace {	HMODULE gModuleHandle;}; -	BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -	{ -		gModuleHandle = (HMODULE) hinstDLL; -		return TRUE; -	} -#endif - -//////////////////////////////////////////////////////////////////////////////// -// -class MediaPluginWebKit :  -		public MediaPluginBase, -		public LLEmbeddedBrowserWindowObserver -{ -public: -	MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); -	~MediaPluginWebKit(); - -	/*virtual*/ void receiveMessage(const char *message_string); - -private: - -	std::string mProfileDir; -	std::string mHostLanguage; -	std::string mUserAgent; -	bool mCookiesEnabled; -	bool mJavascriptEnabled; -	bool mPluginsEnabled; - -	enum -	{ -		INIT_STATE_UNINITIALIZED,		// LLQtWebkit hasn't been set up yet -		INIT_STATE_INITIALIZED,			// LLQtWebkit has been set up, but no browser window has been created yet. -		INIT_STATE_NAVIGATING,			// Browser instance has been set up and initial navigate to about:blank has been issued -		INIT_STATE_NAVIGATE_COMPLETE,	// initial navigate to about:blank has completed -		INIT_STATE_WAIT_REDRAW,			// First real navigate begin has been received, waiting for page changed event to start handling redraws -		INIT_STATE_WAIT_COMPLETE,		// Waiting for first real navigate complete event -		INIT_STATE_RUNNING				// All initialization gymnastics are complete. -	}; -	int mBrowserWindowId; -	int mInitState; -	std::string mInitialNavigateURL; -	bool mNeedsUpdate; - -	bool	mCanCut; -	bool	mCanCopy; -	bool	mCanPaste; -	int mLastMouseX; -	int mLastMouseY; -	bool mFirstFocus; -	F32 mBackgroundR; -	F32 mBackgroundG; -	F32 mBackgroundB; -	std::string mTarget; -	 -	VolumeCatcher mVolumeCatcher; - -	void setInitState(int state) -	{ -//		std::cerr << "changing init state to " << state << std::endl; -		mInitState = state; -	} -	 -	//////////////////////////////////////////////////////////////////////////////// -	// -	void update(int milliseconds) -	{ -#if LL_QTLINUX_DOESNT_HAVE_GLIB -		// pump glib generously, as Linux browser plugins are on the -		// glib main loop, even if the browser itself isn't - ugh -		// This is NOT NEEDED if Qt itself was built with glib -		// mainloop integration. -		GMainContext *mainc = g_main_context_default(); -		while(g_main_context_iteration(mainc, FALSE)); -#endif // LL_QTLINUX_DOESNT_HAVE_GLIB - -		// pump qt -		LLQtWebKit::getInstance()->pump( milliseconds ); -		 -		mVolumeCatcher.pump(); - -		checkEditState(); -		 -		if(mInitState == INIT_STATE_NAVIGATE_COMPLETE) -		{ -			if(!mInitialNavigateURL.empty()) -			{ -				// We already have the initial navigate URL -- kick off the navigate. -				LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, mInitialNavigateURL ); -				mInitialNavigateURL.clear(); -			} -		} -		 -		if ( (mInitState > INIT_STATE_WAIT_REDRAW) && mNeedsUpdate ) -		{ -			const unsigned char* browser_pixels = LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId ); - -			unsigned int rowspan = LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId ); -			unsigned int height = LLQtWebKit::getInstance()->getBrowserHeight( mBrowserWindowId ); -#if !LL_QTWEBKIT_USES_PIXMAPS -			unsigned int buffer_size = rowspan * height; -#endif // !LL_QTWEBKIT_USES_PIXMAPS -			 -//			std::cerr << "webkit plugin: updating" << std::endl; -			 -			// TODO: should get rid of this memcpy if possible -			if ( mPixels && browser_pixels ) -			{ -//				std::cerr << "    memcopy of " << buffer_size << " bytes" << std::endl; - -#if LL_QTWEBKIT_USES_PIXMAPS -				// copy the pixel data upside-down because of the co-ord system -				for (int y=0; y<height; ++y) -				{ -					memcpy( &mPixels[(height-y-1)*rowspan], &browser_pixels[y*rowspan], rowspan ); -				} -#else -				memcpy( mPixels, browser_pixels, buffer_size ); -#endif // LL_QTWEBKIT_USES_PIXMAPS -			} - -			if ( mWidth > 0 && mHeight > 0 ) -			{ -//				std::cerr << "Setting dirty, " << mWidth << " x " << mHeight << std::endl; -				setDirty( 0, 0, mWidth, mHeight ); -			} - -			mNeedsUpdate = false; -		}; -	}; - -	//////////////////////////////////////////////////////////////////////////////// -	// -	bool initBrowser() -	{ -		// already initialized -		if ( mInitState > INIT_STATE_UNINITIALIZED ) -			return true; - -		// set up directories -		char cwd[ FILENAME_MAX ];	// I *think* this is defined on all platforms we use -		if (NULL == getcwd( cwd, FILENAME_MAX - 1 )) -		{ -			llwarns << "Couldn't get cwd - probably too long - failing to init." << llendl; -			return false; -		} -		std::string application_dir = std::string( cwd ); - -#if LL_LINUX -		// take care to initialize glib properly, because some -		// versions of Qt don't, and we indirectly need it for (some -		// versions of) Flash to not crash the browser. -		if (!g_thread_supported ()) g_thread_init (NULL); -		g_type_init(); -#endif - -#if LL_DARWIN -		// When running under the Xcode debugger, there's a setting called "Break on Debugger()/DebugStr()" which defaults to being turned on. -		// This causes the environment variable USERBREAK to be set to 1, which causes these legacy calls to break into the debugger. -		// This wouldn't cause any problems except for the fact that the current release version of the Flash plugin has a call to Debugger() in it -		// which gets hit when the plugin is probed by webkit. -		// Unsetting the environment variable here works around this issue. -		unsetenv("USERBREAK"); -#endif - -#if LL_WINDOWS -		//*NOTE:Mani - On windows, at least, the component path is the -		// location of this dll's image file.  -		std::string component_dir; -		char dll_path[_MAX_PATH]; -		DWORD len = GetModuleFileNameA(gModuleHandle, (LPCH)&dll_path, _MAX_PATH); -		while(len && dll_path[ len ] != ('\\') ) -		{ -			len--; -		} -		if(len >= 0) -		{ -			dll_path[len] = 0; -			component_dir = dll_path; -		} -		else -		{ -			// *NOTE:Mani - This case should be an rare exception.  -			// GetModuleFileNameA should always give you a full path, no? -			component_dir = application_dir; -		} -#else -		std::string component_dir = application_dir; -#endif - -		// window handle - needed on Windows and must be app window. -#if LL_WINDOWS -		char window_title[ MAX_PATH ]; -		GetConsoleTitleA( window_title, MAX_PATH ); -		void* native_window_handle = (void*)FindWindowA( NULL, window_title ); -#else -		void* native_window_handle = 0; -#endif - -		// main browser initialization -		bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, mProfileDir, native_window_handle ); -		if ( result ) -		{ -			mInitState = INIT_STATE_INITIALIZED; -			 -			return true; -		}; - -		return false; -	}; - -	//////////////////////////////////////////////////////////////////////////////// -	// -	bool initBrowserWindow() -	{ -		// already initialized -		if ( mInitState > INIT_STATE_INITIALIZED ) -			return true; - -		// not enough information to initialize the browser yet. -		if ( mWidth < 0 || mHeight < 0 || mDepth < 0 ||  -				mTextureWidth < 0 || mTextureHeight < 0 ) -		{ -			return false; -		}; -		 -		// Set up host language before creating browser window -		if(!mHostLanguage.empty()) -		{ -			LLQtWebKit::getInstance()->setHostLanguage(mHostLanguage); -		} - -		// turn on/off cookies based on what host app tells us -		LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled ); - -		// turn on/off plugins based on what host app tells us -		LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled ); - -		// turn on/off Javascript based on what host app tells us -		LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled ); -		 -		// create single browser window -		mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight, mTarget); - -		// tell LLQtWebKit about the size of the browser window -		LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); - -		// observer events that LLQtWebKit emits -		LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this ); - -		// append details to agent string -		LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent ); -		 -#if !LL_QTWEBKIT_USES_PIXMAPS -		// don't flip bitmap -		LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true ); -#endif // !LL_QTWEBKIT_USES_PIXMAPS - -		// set background color -		// convert background color channels from [0.0, 1.0] to [0, 255]; -		LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, int(mBackgroundR * 255.0f), int(mBackgroundG * 255.0f), int(mBackgroundB * 255.0f) ); - -		// Set state _before_ starting the navigate, since onNavigateBegin might get called before this call returns. -		setInitState(INIT_STATE_NAVIGATING); - -		// Don't do this here -- it causes the dreaded "white flash" when loading a browser instance. -		// FIXME: Re-added this because navigating to a "page" initializes things correctly - especially -		// for the HTTP AUTH dialog issues (DEV-41731). Will fix at a later date. -		// Build a data URL like this: "data:text/html,%3Chtml%3E%3Cbody bgcolor=%22#RRGGBB%22%3E%3C/body%3E%3C/html%3E" -		// where RRGGBB is the background color in HTML style -		std::stringstream url; -		 -		url << "data:text/html,%3Chtml%3E%3Cbody%20bgcolor=%22#"; -		// convert background color channels from [0.0, 1.0] to [0, 255]; -		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundR * 255.0f); -		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundG * 255.0f); -		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundB * 255.0f); -		url << "%22%3E%3C/body%3E%3C/html%3E"; -		 -		//lldebugs << "data url is: " << url.str() << llendl; -					 -		LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, url.str() ); -//		LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" ); - -		return true;	 -	} - -	void setVolume(F32 vol); - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onCursorChanged(const EventType& event) -	{ -		LLQtWebKit::ECursor llqt_cursor = (LLQtWebKit::ECursor)event.getIntValue(); -		std::string name; - -		switch(llqt_cursor) -		{ -			case LLQtWebKit::C_ARROW: -				name = "arrow"; -			break; -			case LLQtWebKit::C_IBEAM: -				name = "ibeam"; -			break; -			case LLQtWebKit::C_SPLITV: -				name = "splitv"; -			break; -			case LLQtWebKit::C_SPLITH: -				name = "splith"; -			break; -			case LLQtWebKit::C_POINTINGHAND: -				name = "hand"; -			break; -			 -			default: -				llwarns << "Unknown cursor ID: " << (int)llqt_cursor << llendl; -			break; -		} -		 -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed"); -		message.setValue("name", name); -		sendMessage(message); -	} - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onPageChanged( const EventType& event ) -	{ -		if(mInitState == INIT_STATE_WAIT_REDRAW) -		{ -			setInitState(INIT_STATE_WAIT_COMPLETE); -		} -		 -		// flag that an update is required -		mNeedsUpdate = true; -	}; - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onNavigateBegin(const EventType& event) -	{ -		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) -		{ -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin"); -			message.setValue("uri", event.getEventUri()); -			message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK)); -			message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD)); -			sendMessage(message); -		 -			setStatus(STATUS_LOADING); -		} - -		if(mInitState == INIT_STATE_NAVIGATE_COMPLETE) -		{ -			// Skip the WAIT_REDRAW state now -- with the right background color set, it should no longer be necessary. -//			setInitState(INIT_STATE_WAIT_REDRAW); -			setInitState(INIT_STATE_WAIT_COMPLETE); -		} -		 -	} - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onNavigateComplete(const EventType& event) -	{ -		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) -		{ -			if(mInitState < INIT_STATE_RUNNING) -			{ -				setInitState(INIT_STATE_RUNNING); -				 -				// Clear the history, so the "back" button doesn't take you back to "about:blank". -				LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId); -			} -			 -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete"); -			message.setValue("uri", event.getEventUri()); -			message.setValueS32("result_code", event.getIntValue()); -			message.setValue("result_string", event.getStringValue()); -			message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK)); -			message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD)); -			sendMessage(message); -			 -			setStatus(STATUS_LOADED); -		} -		else if(mInitState == INIT_STATE_NAVIGATING) -		{ -			setInitState(INIT_STATE_NAVIGATE_COMPLETE); -		} - -	} - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onUpdateProgress(const EventType& event) -	{ -		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) -		{ -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "progress"); -			message.setValueS32("percent", event.getIntValue()); -			sendMessage(message); -		} -	} -	 -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onStatusTextChange(const EventType& event) -	{ -		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) -		{ -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text"); -			message.setValue("status", event.getStringValue()); -			sendMessage(message); -		} -	} - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onTitleChange(const EventType& event) -	{ -		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) -		{ -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text"); -			message.setValue("name", event.getStringValue()); -			sendMessage(message); -		} -	} - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onNavigateErrorPage(const EventType& event) -	{ -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_error_page"); -		message.setValueS32("status_code", event.getIntValue()); -		sendMessage(message); -	} -	 -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onLocationChange(const EventType& event) -	{ -		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) -		{ -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed"); -			message.setValue("uri", event.getEventUri()); -			sendMessage(message); -		} -	} -	 -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onClickLinkHref(const EventType& event) -	{ -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href"); -		message.setValue("uri", event.getEventUri()); -		message.setValue("target", event.getStringValue()); -		message.setValue("uuid", event.getStringValue2()); -		sendMessage(message); -	} -	 -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onClickLinkNoFollow(const EventType& event) -	{ -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow"); -		message.setValue("uri", event.getEventUri()); -#if LLQTWEBKIT_API_VERSION >= 7 -		message.setValue("nav_type", event.getNavigationType()); -#else -		message.setValue("nav_type", "clicked"); -#endif -		sendMessage(message); -	} -	 - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onCookieChanged(const EventType& event) -	{ -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "cookie_set"); -		message.setValue("cookie", event.getStringValue()); -		// These could be passed through as well, but aren't really needed. -//		message.setValue("uri", event.getEventUri()); -//		message.setValueBoolean("dead", (event.getIntValue() != 0)) -		sendMessage(message); -	} - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onWindowCloseRequested(const EventType& event) -	{ -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "close_request"); -		message.setValue("uuid", event.getStringValue()); -		sendMessage(message); -	} - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onWindowGeometryChangeRequested(const EventType& event) -	{ -		int x, y, width, height; -		event.getRectValue(x, y, width, height); - -		// This sometimes gets called with a zero-size request.  Don't pass these along. -		if(width > 0 && height > 0) -		{ -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "geometry_change"); -			message.setValue("uuid", event.getStringValue()); -			message.setValueS32("x", x); -			message.setValueS32("y", y); -			message.setValueS32("width", width); -			message.setValueS32("height", height); -			sendMessage(message); -		} -	} - -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	std::string onRequestFilePicker( const EventType& eventIn ) -	{ -		return blockingPickFile(); -	} -	 -	std::string mAuthUsername; -	std::string mAuthPassword; -	bool mAuthOK; -	 -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	bool onAuthRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password) -	{ -		mAuthOK = false; - -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_request"); -		message.setValue("url", in_url); -		message.setValue("realm", in_realm); -		message.setValueBoolean("blocking_request", true); -				 -		// The "blocking_request" key in the message means this sendMessage call will block until a response is received. -		sendMessage(message); -		 -		if(mAuthOK) -		{ -			out_username = mAuthUsername; -			out_password = mAuthPassword; -		} -		 -		return mAuthOK; -	} -	 -	void authResponse(LLPluginMessage &message) -	{ -		mAuthOK = message.getValueBoolean("ok"); -		if(mAuthOK) -		{ -			mAuthUsername = message.getValue("username"); -			mAuthPassword = message.getValue("password"); -		} -	} -	 -	//////////////////////////////////////////////////////////////////////////////// -	// virtual -	void onLinkHovered(const EventType& event) -	{ -		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) -		{ -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "link_hovered"); -			message.setValue("link", event.getEventUri()); -			message.setValue("title", event.getStringValue()); -			message.setValue("text", event.getStringValue2()); -			sendMessage(message); -		} -	} -	 -	LLQtWebKit::EKeyboardModifier decodeModifiers(std::string &modifiers) -	{ -		int result = 0; -		 -		if(modifiers.find("shift") != std::string::npos) -			result |= LLQtWebKit::KM_MODIFIER_SHIFT; - -		if(modifiers.find("alt") != std::string::npos) -			result |= LLQtWebKit::KM_MODIFIER_ALT; -		 -		if(modifiers.find("control") != std::string::npos) -			result |= LLQtWebKit::KM_MODIFIER_CONTROL; -		 -		if(modifiers.find("meta") != std::string::npos) -			result |= LLQtWebKit::KM_MODIFIER_META; -		 -		return (LLQtWebKit::EKeyboardModifier)result; -	} -	 -	//////////////////////////////////////////////////////////////////////////////// -	// -	void deserializeKeyboardData( LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers ) -	{ -		native_scan_code = 0; -		native_virtual_key = 0; -		native_modifiers = 0; -		 -		if( native_key_data.isMap() ) -		{ -#if LL_DARWIN -			native_scan_code = (uint32_t)(native_key_data["char_code"].asInteger()); -			native_virtual_key = (uint32_t)(native_key_data["key_code"].asInteger()); -			native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger()); -#elif LL_WINDOWS -			native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger()); -			native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger()); -			// TODO: I don't think we need to do anything with native modifiers here -- please verify -#elif LL_LINUX -			native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger()); -			native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger()); -			native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger()); -#else -			// Add other platforms here as needed -#endif -		}; -	}; - -	//////////////////////////////////////////////////////////////////////////////// -	// -	void keyEvent(LLQtWebKit::EKeyEvent key_event, int key, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap()) -	{ -		// The incoming values for 'key' will be the ones from indra_constants.h -		std::string utf8_text; -		 -		if(key < KEY_SPECIAL) -		{ -			// Low-ascii characters need to get passed through. -			utf8_text = (char)key; -		} -		 -		// Any special-case handling we want to do for particular keys... -		switch((KEY)key) -		{ -			// ASCII codes for some standard keys -			case LLQtWebKit::KEY_BACKSPACE:		utf8_text = (char)8;		break; -			case LLQtWebKit::KEY_TAB:			utf8_text = (char)9;		break; -			case LLQtWebKit::KEY_RETURN:		utf8_text = (char)13;		break; -			case LLQtWebKit::KEY_PAD_RETURN:	utf8_text = (char)13;		break; -			case LLQtWebKit::KEY_ESCAPE:		utf8_text = (char)27;		break; -			 -			default:   -			break; -		} -		 -//		std::cerr << "key event " << (int)key_event << ", native_key_data = " << native_key_data << std::endl; -		 -		uint32_t native_scan_code = 0; -		uint32_t native_virtual_key = 0; -		uint32_t native_modifiers = 0; -		deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers ); -		 -		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, key_event, (uint32_t)key, utf8_text.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); - -		checkEditState(); -	}; - -	//////////////////////////////////////////////////////////////////////////////// -	// -	void unicodeInput( const std::string &utf8str, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap()) -	{		 -		uint32_t key = LLQtWebKit::KEY_NONE; -		 -//		std::cerr << "unicode input, native_key_data = " << native_key_data << std::endl; -		 -		if(utf8str.size() == 1) -		{ -			// The only way a utf8 string can be one byte long is if it's actually a single 7-bit ascii character. -			// In this case, use it as the key value. -			key = utf8str[0]; -		} - -		uint32_t native_scan_code = 0; -		uint32_t native_virtual_key = 0; -		uint32_t native_modifiers = 0; -		deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers ); -		 -		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_DOWN, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); -		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_UP, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers); - -		checkEditState(); -	}; -	 -	void checkEditState(void) -	{ -		bool can_cut = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT); -		bool can_copy = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY); -		bool can_paste = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE); -					 -		if((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste)) -		{ -			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state"); -			 -			if(can_cut != mCanCut) -			{ -				mCanCut = can_cut; -				message.setValueBoolean("cut", can_cut); -			} - -			if(can_copy != mCanCopy) -			{ -				mCanCopy = can_copy; -				message.setValueBoolean("copy", can_copy); -			} - -			if(can_paste != mCanPaste) -			{ -				mCanPaste = can_paste; -				message.setValueBoolean("paste", can_paste); -			} -			 -			sendMessage(message); -			 -		} -	} -	 -	std::string mPickedFile; -	 -	std::string blockingPickFile(void) -	{ -		mPickedFile.clear(); -		 -		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file"); -		message.setValueBoolean("blocking_request", true); -		 -		// The "blocking_request" key in the message means this sendMessage call will block until a response is received. -		sendMessage(message); -		 -		return mPickedFile; -	} - -	void onPickFileResponse(const std::string &file) -	{ -		mPickedFile = file; -	} - -}; - -MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) : -	MediaPluginBase(host_send_func, host_user_data) -{ -//	std::cerr << "MediaPluginWebKit constructor" << std::endl; - -	mBrowserWindowId = 0; -	mInitState = INIT_STATE_UNINITIALIZED; -	mNeedsUpdate = true; -	mCanCut = false; -	mCanCopy = false; -	mCanPaste = false; -	mLastMouseX = 0; -	mLastMouseY = 0; -	mFirstFocus = true; -	mBackgroundR = 0.0f; -	mBackgroundG = 0.0f; -	mBackgroundB = 0.0f; - -	mHostLanguage = "en";		// default to english -	mJavascriptEnabled = true;	// default to on -	mPluginsEnabled = true;		// default to on -	mUserAgent = "LLPluginMedia Web Browser"; -} - -MediaPluginWebKit::~MediaPluginWebKit() -{ -	// unhook observer -	LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this ); - -	// clean up -	LLQtWebKit::getInstance()->reset(); - -//	std::cerr << "MediaPluginWebKit destructor" << std::endl; -} - -void MediaPluginWebKit::receiveMessage(const char *message_string) -{ -//	std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl; -	LLPluginMessage message_in; -	 -	if(message_in.parse(message_string) >= 0) -	{ -		std::string message_class = message_in.getClass(); -		std::string message_name = message_in.getName(); -		if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) -		{ -			if(message_name == "init") -			{ -				LLPluginMessage message("base", "init_response"); -				LLSD versions = LLSD::emptyMap(); -				versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; -				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; -				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; -				message.setValueLLSD("versions", versions); - -				std::string plugin_version = "Webkit media plugin, Webkit version "; -				plugin_version += LLQtWebKit::getInstance()->getVersion(); -				message.setValue("plugin_version", plugin_version); -				sendMessage(message); -			} -			else if(message_name == "idle") -			{ -				// no response is necessary here. -				F64 time = message_in.getValueReal("time"); -				 -				// Convert time to milliseconds for update() -				update((int)(time * 1000.0f)); -			} -			else if(message_name == "cleanup") -			{ -				// DTOR most likely won't be called but the recent change to the way this process -				// is (not) killed means we see this message and can do what we need to here. -				// Note: this cleanup is ultimately what writes cookies to the disk -				LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this ); -				LLQtWebKit::getInstance()->reset(); -			} -			else if(message_name == "shm_added") -			{ -				SharedSegmentInfo info; -				info.mAddress = message_in.getValuePointer("address"); -				info.mSize = (size_t)message_in.getValueS32("size"); -				std::string name = message_in.getValue("name"); -				 -//				std::cerr << "MediaPluginWebKit::receiveMessage: shared memory added, name: " << name  -//					<< ", size: " << info.mSize  -//					<< ", address: " << info.mAddress  -//					<< std::endl; - -				mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); -			 -			} -			else if(message_name == "shm_remove") -			{ -				std::string name = message_in.getValue("name"); -				 -//				std::cerr << "MediaPluginWebKit::receiveMessage: shared memory remove, name = " << name << std::endl; - -				SharedSegmentMap::iterator iter = mSharedSegments.find(name); -				if(iter != mSharedSegments.end()) -				{ -					if(mPixels == iter->second.mAddress) -					{ -						// This is the currently active pixel buffer.  Make sure we stop drawing to it. -						mPixels = NULL; -						mTextureSegmentName.clear(); -					} -					mSharedSegments.erase(iter); -				} -				else -				{ -//					std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl; -				} - -				// Send the response so it can be cleaned up. -				LLPluginMessage message("base", "shm_remove_response"); -				message.setValue("name", name); -				sendMessage(message); -			} -			else -			{ -//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl; -			} -		} -		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) -		{ -			if(message_name == "set_volume") -			{ -				F32 volume = message_in.getValueReal("volume"); -				setVolume(volume); -			} -		} -		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) -		{ -			if(message_name == "init") -			{ -				mTarget = message_in.getValue("target"); -				 -				// This is the media init message -- all necessary data for initialization should have been received. -				if(initBrowser()) -				{ -					 -					// Plugin gets to decide the texture parameters to use. -					mDepth = 4; - -					LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); -					message.setValueS32("default_width", 1024); -					message.setValueS32("default_height", 1024); -					message.setValueS32("depth", mDepth); -					message.setValueU32("internalformat", GL_RGBA); -	#if LL_QTWEBKIT_USES_PIXMAPS -					message.setValueU32("format", GL_BGRA_EXT); // I hope this isn't system-dependant... is it?  If so, we'll have to check the root window's pixel layout or something... yuck. -	#else -					message.setValueU32("format", GL_RGBA); -	#endif // LL_QTWEBKIT_USES_PIXMAPS -					message.setValueU32("type", GL_UNSIGNED_BYTE); -					message.setValueBoolean("coords_opengl", true); -					sendMessage(message); -				} -				else -				{ -					// if initialization failed, we're done. -					mDeleteMe = true; -				} - -			} -			else if(message_name == "set_user_data_path") -			{ -				std::string user_data_path = message_in.getValue("path"); // n.b. always has trailing platform-specific dir-delimiter -				mProfileDir = user_data_path + "browser_profile"; - -				// FIXME: Should we do anything with this if it comes in after the browser has been initialized? -			} -			else if(message_name == "set_language_code") -			{ -				mHostLanguage = message_in.getValue("language"); - -				// FIXME: Should we do anything with this if it comes in after the browser has been initialized? -			} -			else if(message_name == "plugins_enabled") -			{ -				mPluginsEnabled = message_in.getValueBoolean("enable"); -			} -			else if(message_name == "javascript_enabled") -			{ -				mJavascriptEnabled = message_in.getValueBoolean("enable"); -			} -			else if(message_name == "size_change") -			{ -				std::string name = message_in.getValue("name"); -				S32 width = message_in.getValueS32("width"); -				S32 height = message_in.getValueS32("height"); -				S32 texture_width = message_in.getValueS32("texture_width"); -				S32 texture_height = message_in.getValueS32("texture_height"); -				mBackgroundR = message_in.getValueReal("background_r"); -				mBackgroundG = message_in.getValueReal("background_g"); -				mBackgroundB = message_in.getValueReal("background_b"); -//				mBackgroundA = message_in.setValueReal("background_a");		// Ignore any alpha -								 -				if(!name.empty()) -				{ -					// Find the shared memory region with this name -					SharedSegmentMap::iterator iter = mSharedSegments.find(name); -					if(iter != mSharedSegments.end()) -					{ -						mPixels = (unsigned char*)iter->second.mAddress; -						mWidth = width; -						mHeight = height; - -						if(initBrowserWindow()) -						{ - -							// size changed so tell the browser -							LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); -							 -	//						std::cerr << "webkit plugin: set size to " << mWidth << " x " << mHeight  -	//								<< ", rowspan is " << LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) << std::endl; -									 -							S32 real_width = LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) / LLQtWebKit::getInstance()->getBrowserDepth(mBrowserWindowId);  -							 -							// The actual width the browser will be drawing to is probably smaller... let the host know by modifying texture_width in the response. -							if(real_width <= texture_width) -							{ -								texture_width = real_width; -							} -							else -							{ -								// This won't work -- it'll be bigger than the allocated memory.  This is a fatal error. -	//							std::cerr << "Fatal error: browser rowbytes greater than texture width" << std::endl; -								mDeleteMe = true; -								return; -							} -						} -						else -						{ -							// Setting up the browser window failed.  This is a fatal error. -							mDeleteMe = true; -						} - -						 -						mTextureWidth = texture_width; -						mTextureHeight = texture_height; -						 -					}; -				}; - -				LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); -				message.setValue("name", name); -				message.setValueS32("width", width); -				message.setValueS32("height", height); -				message.setValueS32("texture_width", texture_width); -				message.setValueS32("texture_height", texture_height); -				sendMessage(message); - -			} -			else if(message_name == "load_uri") -			{ -				std::string uri = message_in.getValue("uri"); - -//				std::cout << "loading URI: " << uri << std::endl; -				 -				if(!uri.empty()) -				{ -					if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) -					{ -						LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, uri ); -					} -					else -					{ -						mInitialNavigateURL = uri; -					} -				} -			} -			else if(message_name == "mouse_event") -			{ -				std::string event = message_in.getValue("event"); -				S32 button = message_in.getValueS32("button"); -				mLastMouseX = message_in.getValueS32("x"); -				mLastMouseY = message_in.getValueS32("y"); -				std::string modifiers = message_in.getValue("modifiers"); -				 -				// Treat unknown mouse events as mouse-moves. -				LLQtWebKit::EMouseEvent mouse_event = LLQtWebKit::ME_MOUSE_MOVE; -				if(event == "down") -				{ -					mouse_event = LLQtWebKit::ME_MOUSE_DOWN; -				} -				else if(event == "up") -				{ -					mouse_event = LLQtWebKit::ME_MOUSE_UP; -				} -				else if(event == "double_click") -				{ -					mouse_event = LLQtWebKit::ME_MOUSE_DOUBLE_CLICK; -				} -				 -				LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, mouse_event, button, mLastMouseX, mLastMouseY, decodeModifiers(modifiers)); -				checkEditState(); -			} -			else if(message_name == "scroll_event") -			{ -				S32 x = message_in.getValueS32("x"); -				S32 y = message_in.getValueS32("y"); -				std::string modifiers = message_in.getValue("modifiers"); -				 -				// Incoming scroll events are adjusted so that 1 detent is approximately 1 unit. -				// Qt expects 1 detent to be 120 units. -				// It also seems that our y scroll direction is inverted vs. what Qt expects. -				 -				x *= 120; -				y *= -120; -				 -				LLQtWebKit::getInstance()->scrollWheelEvent(mBrowserWindowId, mLastMouseX, mLastMouseY, x, y, decodeModifiers(modifiers)); -			} -			else if(message_name == "key_event") -			{ -				std::string event = message_in.getValue("event"); -				S32 key = message_in.getValueS32("key"); -				std::string modifiers = message_in.getValue("modifiers"); -				LLSD native_key_data = message_in.getValueLLSD("native_key_data"); -				 -				// Treat unknown events as key-up for safety. -				LLQtWebKit::EKeyEvent key_event = LLQtWebKit::KE_KEY_UP; -				if(event == "down") -				{ -					key_event = LLQtWebKit::KE_KEY_DOWN; -				} -				else if(event == "repeat") -				{ -					key_event = LLQtWebKit::KE_KEY_REPEAT; -				} -				 -				keyEvent(key_event, key, decodeModifiers(modifiers), native_key_data); -			} -			else if(message_name == "text_event") -			{ -				std::string text = message_in.getValue("text"); -				std::string modifiers = message_in.getValue("modifiers"); -				LLSD native_key_data = message_in.getValueLLSD("native_key_data"); -				 -				unicodeInput(text, decodeModifiers(modifiers), native_key_data); -			} -			if(message_name == "edit_cut") -			{ -				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT ); -				checkEditState(); -			} -			if(message_name == "edit_copy") -			{ -				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY ); -				checkEditState(); -			} -			if(message_name == "edit_paste") -			{ -				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE ); -				checkEditState(); -			} -			if(message_name == "pick_file_response") -			{ -				onPickFileResponse(message_in.getValue("file")); -			} -			if(message_name == "auth_response") -			{ -				authResponse(message_in); -			} -			else -			if(message_name == "js_enable_object") -			{ -#if LLQTWEBKIT_API_VERSION >= 9 -				bool enable = message_in.getValueBoolean( "enable" ); -				LLQtWebKit::getInstance()->setSLObjectEnabled( enable ); -#endif -			} -			else -			if(message_name == "js_agent_location") -			{ -#if LLQTWEBKIT_API_VERSION >= 9 -				F32 x = message_in.getValueReal("x"); -				F32 y = message_in.getValueReal("y"); -				F32 z = message_in.getValueReal("z"); -				LLQtWebKit::getInstance()->setAgentLocation( x, y, z ); -				LLQtWebKit::getInstance()->emitLocation(); -#endif -			} -			else -			if(message_name == "js_agent_global_location") -			{ -#if LLQTWEBKIT_API_VERSION >= 9 -				F32 x = message_in.getValueReal("x"); -				F32 y = message_in.getValueReal("y"); -				F32 z = message_in.getValueReal("z"); -				LLQtWebKit::getInstance()->setAgentGlobalLocation( x, y, z ); -				LLQtWebKit::getInstance()->emitLocation(); -#endif -			} -			else			 -			if(message_name == "js_agent_orientation") -			{ -#if LLQTWEBKIT_API_VERSION >= 9 -				F32 angle = message_in.getValueReal("angle"); -				LLQtWebKit::getInstance()->setAgentOrientation( angle ); -				LLQtWebKit::getInstance()->emitLocation(); -#endif -			} -			else -			if(message_name == "js_agent_region") -			{ -#if LLQTWEBKIT_API_VERSION >= 9 -				const std::string& region = message_in.getValue("region"); -				LLQtWebKit::getInstance()->setAgentRegion( region ); -				LLQtWebKit::getInstance()->emitLocation(); -#endif -			} -			else -				if(message_name == "js_agent_maturity") -				{ -#if LLQTWEBKIT_API_VERSION >= 9 -					const std::string& maturity = message_in.getValue("maturity"); -					LLQtWebKit::getInstance()->setAgentMaturity( maturity ); -					LLQtWebKit::getInstance()->emitMaturity(); -#endif -				} -			else -			if(message_name == "js_agent_language") -			{ -#if LLQTWEBKIT_API_VERSION >= 9 -				const std::string& language = message_in.getValue("language"); -				LLQtWebKit::getInstance()->setAgentLanguage( language ); -				LLQtWebKit::getInstance()->emitLanguage(); -#endif -			} -			else -			{ -//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl; -			} -		} -		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) -		{ -			if(message_name == "focus") -			{ -				bool val = message_in.getValueBoolean("focused"); -				LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, val ); -				 -				if(mFirstFocus && val) -				{ -					// On the first focus, post a tab key event.  This fixes a problem with initial focus. -					std::string empty; -					keyEvent(LLQtWebKit::KE_KEY_DOWN, KEY_TAB, decodeModifiers(empty)); -					keyEvent(LLQtWebKit::KE_KEY_UP, KEY_TAB, decodeModifiers(empty)); -					mFirstFocus = false; -				} -			} -			else if(message_name == "clear_cache") -			{ -				LLQtWebKit::getInstance()->clearCache(); -			} -			else if(message_name == "clear_cookies") -			{ -				LLQtWebKit::getInstance()->clearAllCookies(); -			} -			else if(message_name == "enable_cookies") -			{ -				mCookiesEnabled = message_in.getValueBoolean("enable"); -				LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled ); -			} -			else if(message_name == "enable_plugins") -			{ -				mPluginsEnabled = message_in.getValueBoolean("enable"); -				LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled ); -			} -			else if(message_name == "enable_javascript") -			{ -				mJavascriptEnabled = message_in.getValueBoolean("enable"); -				//LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled ); -			} -			else if(message_name == "set_cookies") -			{ -				LLQtWebKit::getInstance()->setCookies(message_in.getValue("cookies")); -			} -			else if(message_name == "proxy_setup") -			{ -				bool val = message_in.getValueBoolean("enable"); -				std::string host = message_in.getValue("host"); -				int port = message_in.getValueS32("port"); -				LLQtWebKit::getInstance()->enableProxy( val, host, port ); -			} -			else if(message_name == "browse_stop") -			{ -				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_STOP ); -			} -			else if(message_name == "browse_reload") -			{ -				// foo = message_in.getValueBoolean("ignore_cache"); -				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD ); -			} -			else if(message_name == "browse_forward") -			{ -				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD ); -			} -			else if(message_name == "browse_back") -			{ -				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK ); -			} -			else if(message_name == "set_status_redirect") -			{ -				int code = message_in.getValueS32("code"); -				std::string url = message_in.getValue("url"); -				if ( 404 == code )	// browser lib only supports 404 right now -				{ -#if LLQTWEBKIT_API_VERSION < 8 -				 	LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url ); -#endif -				}; -			} -			else if(message_name == "set_user_agent") -			{ -				mUserAgent = message_in.getValue("user_agent"); -				LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent ); -			} -			else if(message_name == "ignore_ssl_cert_errors") -			{ -#if LLQTWEBKIT_API_VERSION >= 3 -				LLQtWebKit::getInstance()->setIgnoreSSLCertErrors( message_in.getValueBoolean("ignore") ); -#else -				llwarns << "Ignoring ignore_ssl_cert_errors message (llqtwebkit version is too old)." << llendl; -#endif -			} -			else if(message_name == "add_certificate_file_path") -			{ -#if LLQTWEBKIT_API_VERSION >= 6 -				LLQtWebKit::getInstance()->setCAFile( message_in.getValue("path") ); -#else -				llwarns << "Ignoring add_certificate_file_path message (llqtwebkit version is too old)." << llendl; -#endif -			} -			else if(message_name == "init_history") -			{ -				// Initialize browser history -				LLSD history = message_in.getValueLLSD("history"); -				// First, clear the URL history -				LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId); -				// Then, add the history items in order -				LLSD::array_iterator iter_history = history.beginArray(); -				LLSD::array_iterator end_history = history.endArray(); -				for(; iter_history != end_history; ++iter_history) -				{ -					std::string url = (*iter_history).asString(); -					if(! url.empty()) { -						LLQtWebKit::getInstance()->prependHistoryUrl(mBrowserWindowId, url); -					} -				} -			} -			else if(message_name == "proxy_window_opened") -			{ -				std::string target = message_in.getValue("target"); -				std::string uuid = message_in.getValue("uuid"); -				LLQtWebKit::getInstance()->proxyWindowOpened(mBrowserWindowId, target, uuid); -			} -			else if(message_name == "proxy_window_closed") -			{ -				std::string uuid = message_in.getValue("uuid"); -				LLQtWebKit::getInstance()->proxyWindowClosed(mBrowserWindowId, uuid); -			} -			else -			{ -//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl; -			}; -		} -		else -		{ -//			std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl; -		}; -	} -} - -void MediaPluginWebKit::setVolume(F32 volume) -{ -	mVolumeCatcher.setVolume(volume); -} - -int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) -{ -	MediaPluginWebKit *self = new MediaPluginWebKit(host_send_func, host_user_data); -	*plugin_send_func = MediaPluginWebKit::staticReceiveMessage; -	*plugin_user_data = (void*)self; - -	return 0; -} - - +/** 
 + * @file media_plugin_webkit.cpp
 + * @brief Webkit plugin for LLMedia API plugin system
 + *
 + * @cond
 + * $LicenseInfo:firstyear=2008&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$
 + * @endcond
 + */
 +
 +#include "llqtwebkit.h"
 +
 +#include "linden_common.h"
 +#include "indra_constants.h" // for indra keyboard codes
 +
 +#include "llgl.h"
 +
 +#include "llplugininstance.h"
 +#include "llpluginmessage.h"
 +#include "llpluginmessageclasses.h"
 +#include "media_plugin_base.h"
 +
 +// set to 1 if you're using the version of llqtwebkit that's QPixmap-ified
 +#if LL_LINUX
 +# define LL_QTWEBKIT_USES_PIXMAPS 0
 +extern "C" {
 +# include <glib.h>
 +# include <glib-object.h>
 +}
 +#else
 +# define LL_QTWEBKIT_USES_PIXMAPS 0
 +#endif // LL_LINUX
 +
 +# include "volume_catcher.h"
 +
 +#if LL_WINDOWS
 +# include <direct.h>
 +#else
 +# include <unistd.h>
 +# include <stdlib.h>
 +#endif
 +
 +#if LL_WINDOWS
 +	// *NOTE:Mani - This captures the module handle for the dll. This is used below
 +	// to get the path to this dll for webkit initialization.
 +	// I don't know how/if this can be done with apr...
 +	namespace {	HMODULE gModuleHandle;};
 +	BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 +	{
 +		gModuleHandle = (HMODULE) hinstDLL;
 +		return TRUE;
 +	}
 +#endif
 +
 +////////////////////////////////////////////////////////////////////////////////
 +//
 +class MediaPluginWebKit : 
 +		public MediaPluginBase,
 +		public LLEmbeddedBrowserWindowObserver
 +{
 +public:
 +	MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
 +	~MediaPluginWebKit();
 +
 +	/*virtual*/ void receiveMessage(const char *message_string);
 +
 +private:
 +
 +	std::string mProfileDir;
 +	std::string mHostLanguage;
 +	std::string mUserAgent;
 +	bool mCookiesEnabled;
 +	bool mJavascriptEnabled;
 +	bool mPluginsEnabled;
 +	bool mEnableMediaPluginDebugging;
 +
 +	enum
 +	{
 +		INIT_STATE_UNINITIALIZED,		// LLQtWebkit hasn't been set up yet
 +		INIT_STATE_INITIALIZED,			// LLQtWebkit has been set up, but no browser window has been created yet.
 +		INIT_STATE_NAVIGATING,			// Browser instance has been set up and initial navigate to about:blank has been issued
 +		INIT_STATE_NAVIGATE_COMPLETE,	// initial navigate to about:blank has completed
 +		INIT_STATE_WAIT_REDRAW,			// First real navigate begin has been received, waiting for page changed event to start handling redraws
 +		INIT_STATE_WAIT_COMPLETE,		// Waiting for first real navigate complete event
 +		INIT_STATE_RUNNING				// All initialization gymnastics are complete.
 +	};
 +	int mBrowserWindowId;
 +	int mInitState;
 +	std::string mInitialNavigateURL;
 +	bool mNeedsUpdate;
 +
 +	bool	mCanCut;
 +	bool	mCanCopy;
 +	bool	mCanPaste;
 +	int mLastMouseX;
 +	int mLastMouseY;
 +	bool mFirstFocus;
 +	F32 mBackgroundR;
 +	F32 mBackgroundG;
 +	F32 mBackgroundB;
 +	std::string mTarget;
 +	
 +	VolumeCatcher mVolumeCatcher;
 +
 +	void postDebugMessage( const std::string& msg )
 +	{
 +		if ( mEnableMediaPluginDebugging )
 +		{
 +			LLPluginMessage debug_message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "debug_message");
 +			debug_message.setValue("message_text", "Media> " + msg);
 +			debug_message.setValue("message_level", "info");
 +			sendMessage(debug_message);
 +		}
 +	}
 +	
 +	void setInitState(int state)
 +	{
 +//		std::cerr << "changing init state to " << state << std::endl;
 +		mInitState = state;
 +	}
 +	
 +	////////////////////////////////////////////////////////////////////////////////
 +	//
 +	void update(int milliseconds)
 +	{
 +#if LL_QTLINUX_DOESNT_HAVE_GLIB
 +		// pump glib generously, as Linux browser plugins are on the
 +		// glib main loop, even if the browser itself isn't - ugh
 +		// This is NOT NEEDED if Qt itself was built with glib
 +		// mainloop integration.
 +		GMainContext *mainc = g_main_context_default();
 +		while(g_main_context_iteration(mainc, FALSE));
 +#endif // LL_QTLINUX_DOESNT_HAVE_GLIB
 +
 +		// pump qt
 +		LLQtWebKit::getInstance()->pump( milliseconds );
 +		
 +		mVolumeCatcher.pump();
 +
 +		checkEditState();
 +		
 +		if(mInitState == INIT_STATE_NAVIGATE_COMPLETE)
 +		{
 +			if(!mInitialNavigateURL.empty())
 +			{
 +				// We already have the initial navigate URL -- kick off the navigate.
 +				LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, mInitialNavigateURL );
 +				mInitialNavigateURL.clear();
 +			}
 +		}
 +		
 +		if ( (mInitState > INIT_STATE_WAIT_REDRAW) && mNeedsUpdate )
 +		{
 +			const unsigned char* browser_pixels = LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId );
 +
 +			unsigned int rowspan = LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId );
 +			unsigned int height = LLQtWebKit::getInstance()->getBrowserHeight( mBrowserWindowId );
 +#if !LL_QTWEBKIT_USES_PIXMAPS
 +			unsigned int buffer_size = rowspan * height;
 +#endif // !LL_QTWEBKIT_USES_PIXMAPS
 +			
 +//			std::cerr << "webkit plugin: updating" << std::endl;
 +			
 +			// TODO: should get rid of this memcpy if possible
 +			if ( mPixels && browser_pixels )
 +			{
 +//				std::cerr << "    memcopy of " << buffer_size << " bytes" << std::endl;
 +
 +#if LL_QTWEBKIT_USES_PIXMAPS
 +				// copy the pixel data upside-down because of the co-ord system
 +				for (int y=0; y<height; ++y)
 +				{
 +					memcpy( &mPixels[(height-y-1)*rowspan], &browser_pixels[y*rowspan], rowspan );
 +				}
 +#else
 +				memcpy( mPixels, browser_pixels, buffer_size );
 +#endif // LL_QTWEBKIT_USES_PIXMAPS
 +			}
 +
 +			if ( mWidth > 0 && mHeight > 0 )
 +			{
 +//				std::cerr << "Setting dirty, " << mWidth << " x " << mHeight << std::endl;
 +				setDirty( 0, 0, mWidth, mHeight );
 +			}
 +
 +			mNeedsUpdate = false;
 +		};
 +	};
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	//
 +	bool initBrowser()
 +	{
 +		// already initialized
 +		if ( mInitState > INIT_STATE_UNINITIALIZED )
 +			return true;
 +
 +		// set up directories
 +		char cwd[ FILENAME_MAX ];	// I *think* this is defined on all platforms we use
 +		if (NULL == getcwd( cwd, FILENAME_MAX - 1 ))
 +		{
 +			llwarns << "Couldn't get cwd - probably too long - failing to init." << llendl;
 +			return false;
 +		}
 +		std::string application_dir = std::string( cwd );
 +
 +#if LL_LINUX
 +		// take care to initialize glib properly, because some
 +		// versions of Qt don't, and we indirectly need it for (some
 +		// versions of) Flash to not crash the browser.
 +		if (!g_thread_supported ()) g_thread_init (NULL);
 +		g_type_init();
 +#endif
 +
 +#if LL_DARWIN
 +		// When running under the Xcode debugger, there's a setting called "Break on Debugger()/DebugStr()" which defaults to being turned on.
 +		// This causes the environment variable USERBREAK to be set to 1, which causes these legacy calls to break into the debugger.
 +		// This wouldn't cause any problems except for the fact that the current release version of the Flash plugin has a call to Debugger() in it
 +		// which gets hit when the plugin is probed by webkit.
 +		// Unsetting the environment variable here works around this issue.
 +		unsetenv("USERBREAK");
 +#endif
 +
 +#if LL_WINDOWS
 +		//*NOTE:Mani - On windows, at least, the component path is the
 +		// location of this dll's image file. 
 +		std::string component_dir;
 +		char dll_path[_MAX_PATH];
 +		DWORD len = GetModuleFileNameA(gModuleHandle, (LPCH)&dll_path, _MAX_PATH);
 +		while(len && dll_path[ len ] != ('\\') )
 +		{
 +			len--;
 +		}
 +		if(len >= 0)
 +		{
 +			dll_path[len] = 0;
 +			component_dir = dll_path;
 +		}
 +		else
 +		{
 +			// *NOTE:Mani - This case should be an rare exception. 
 +			// GetModuleFileNameA should always give you a full path, no?
 +			component_dir = application_dir;
 +		}
 +#else
 +		std::string component_dir = application_dir;
 +#endif
 +
 +		// debug spam sent to viewer and displayed in the log as usual
 +		postDebugMessage( "Component dir set to: " + component_dir );
 +
 +		// window handle - needed on Windows and must be app window.
 +#if LL_WINDOWS
 +		char window_title[ MAX_PATH ];
 +		GetConsoleTitleA( window_title, MAX_PATH );
 +		void* native_window_handle = (void*)FindWindowA( NULL, window_title );
 +#else
 +		void* native_window_handle = 0;
 +#endif
 +
 +		// main browser initialization
 +		bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, mProfileDir, native_window_handle );
 +		if ( result )
 +		{
 +			mInitState = INIT_STATE_INITIALIZED;
 +
 +			// debug spam sent to viewer and displayed in the log as usual
 +			postDebugMessage( "browser initialized okay" );
 +
 +			return true;
 +		};
 +
 +		// debug spam sent to viewer and displayed in the log as usual
 +		postDebugMessage( "browser nOT initialized." );
 +
 +		return false;
 +	};
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	//
 +	bool initBrowserWindow()
 +	{
 +		// already initialized
 +		if ( mInitState > INIT_STATE_INITIALIZED )
 +			return true;
 +
 +		// not enough information to initialize the browser yet.
 +		if ( mWidth < 0 || mHeight < 0 || mDepth < 0 || 
 +				mTextureWidth < 0 || mTextureHeight < 0 )
 +		{
 +			return false;
 +		};
 +		
 +		// Set up host language before creating browser window
 +		if(!mHostLanguage.empty())
 +		{
 +			LLQtWebKit::getInstance()->setHostLanguage(mHostLanguage);
 +			postDebugMessage( "Setting language to " + mHostLanguage );
 +		}
 +
 +		// turn on/off cookies based on what host app tells us
 +		LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled );
 +		
 +		// turn on/off plugins based on what host app tells us
 +		LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled );
 +
 +		// turn on/off Javascript based on what host app tells us
 +		LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled );
 +
 +		std::stringstream str;
 +		str << "Cookies enabled = " << mCookiesEnabled << ", plugins enabled = " << mPluginsEnabled << ", Javascript enabled = " << mJavascriptEnabled;
 +		postDebugMessage( str.str() );
 +
 +		// create single browser window
 +		mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight, mTarget);
 +
 +		str.str("");
 +		str.clear();
 +		str << "Setting browser window size to " << mWidth << " x " << mHeight;
 +		postDebugMessage( str.str() );
 +
 +		// tell LLQtWebKit about the size of the browser window
 +		LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight );
 +
 +		// observer events that LLQtWebKit emits
 +		LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this );
 +
 +		// append details to agent string
 +		LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent );
 +		postDebugMessage( "Updating user agent with " + mUserAgent );
 +		
 +#if !LL_QTWEBKIT_USES_PIXMAPS
 +		// don't flip bitmap
 +		LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true );
 +#endif // !LL_QTWEBKIT_USES_PIXMAPS
 +
 +		// set background color
 +		// convert background color channels from [0.0, 1.0] to [0, 255];
 +		LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, int(mBackgroundR * 255.0f), int(mBackgroundG * 255.0f), int(mBackgroundB * 255.0f) );
 +
 +		// Set state _before_ starting the navigate, since onNavigateBegin might get called before this call returns.
 +		setInitState(INIT_STATE_NAVIGATING);
 +
 +		// Don't do this here -- it causes the dreaded "white flash" when loading a browser instance.
 +		// FIXME: Re-added this because navigating to a "page" initializes things correctly - especially
 +		// for the HTTP AUTH dialog issues (DEV-41731). Will fix at a later date.
 +		// Build a data URL like this: "data:text/html,%3Chtml%3E%3Cbody bgcolor=%22#RRGGBB%22%3E%3C/body%3E%3C/html%3E"
 +		// where RRGGBB is the background color in HTML style
 +		std::stringstream url;
 +		
 +		url << "data:text/html,%3Chtml%3E%3Cbody%20bgcolor=%22#";
 +		// convert background color channels from [0.0, 1.0] to [0, 255];
 +		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundR * 255.0f);
 +		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundG * 255.0f);
 +		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundB * 255.0f);
 +		url << "%22%3E%3C/body%3E%3C/html%3E";
 +		
 +		//lldebugs << "data url is: " << url.str() << llendl;
 +					
 +		LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, url.str() );
 +//		LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" );
 +
 +		return true;	
 +	}
 +
 +	void setVolume(F32 vol);
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onCursorChanged(const EventType& event)
 +	{
 +		LLQtWebKit::ECursor llqt_cursor = (LLQtWebKit::ECursor)event.getIntValue();
 +		std::string name;
 +
 +		switch(llqt_cursor)
 +		{
 +			case LLQtWebKit::C_ARROW:
 +				name = "arrow";
 +			break;
 +			case LLQtWebKit::C_IBEAM:
 +				name = "ibeam";
 +			break;
 +			case LLQtWebKit::C_SPLITV:
 +				name = "splitv";
 +			break;
 +			case LLQtWebKit::C_SPLITH:
 +				name = "splith";
 +			break;
 +			case LLQtWebKit::C_POINTINGHAND:
 +				name = "hand";
 +			break;
 +			
 +			default:
 +				llwarns << "Unknown cursor ID: " << (int)llqt_cursor << llendl;
 +			break;
 +		}
 +		
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed");
 +		message.setValue("name", name);
 +		sendMessage(message);
 +	}
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onPageChanged( const EventType& event )
 +	{
 +		if(mInitState == INIT_STATE_WAIT_REDRAW)
 +		{
 +			setInitState(INIT_STATE_WAIT_COMPLETE);
 +		}
 +		
 +		// flag that an update is required
 +		mNeedsUpdate = true;
 +	};
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onNavigateBegin(const EventType& event)
 +	{
 +		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
 +		{
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
 +			message.setValue("uri", event.getEventUri());
 +			message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK));
 +			message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD));
 +			sendMessage(message);
 +
 +			// debug spam sent to viewer and displayed in the log as usual
 +			postDebugMessage( "Navigate begin event at: " + event.getEventUri() );
 +
 +			setStatus(STATUS_LOADING);
 +		}
 +
 +		if(mInitState == INIT_STATE_NAVIGATE_COMPLETE)
 +		{
 +			// Skip the WAIT_REDRAW state now -- with the right background color set, it should no longer be necessary.
 +//			setInitState(INIT_STATE_WAIT_REDRAW);
 +			setInitState(INIT_STATE_WAIT_COMPLETE);
 +		}
 +		
 +	}
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onNavigateComplete(const EventType& event)
 +	{
 +		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
 +		{
 +			if(mInitState < INIT_STATE_RUNNING)
 +			{
 +				setInitState(INIT_STATE_RUNNING);
 +				
 +				// Clear the history, so the "back" button doesn't take you back to "about:blank".
 +				LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId);
 +			}
 +			
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete");
 +			message.setValue("uri", event.getEventUri());
 +			message.setValueS32("result_code", event.getIntValue());
 +			message.setValue("result_string", event.getStringValue());
 +			message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK));
 +			message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD));
 +			sendMessage(message);
 +			
 +			setStatus(STATUS_LOADED);
 +		}
 +		else if(mInitState == INIT_STATE_NAVIGATING)
 +		{
 +			setInitState(INIT_STATE_NAVIGATE_COMPLETE);
 +		}
 +
 +		// debug spam sent to viewer and displayed in the log as usual
 +		postDebugMessage( "Navigate complete event at: " + event.getEventUri() );
 +	}
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onUpdateProgress(const EventType& event)
 +	{
 +		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
 +		{
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "progress");
 +			message.setValueS32("percent", event.getIntValue());
 +			sendMessage(message);
 +		}
 +	}
 +	
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onStatusTextChange(const EventType& event)
 +	{
 +		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
 +		{
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text");
 +			message.setValue("status", event.getStringValue());
 +			sendMessage(message);
 +		}
 +	}
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onTitleChange(const EventType& event)
 +	{
 +		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
 +		{
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
 +			message.setValue("name", event.getStringValue());
 +			sendMessage(message);
 +		}
 +	}
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onNavigateErrorPage(const EventType& event)
 +	{
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_error_page");
 +		message.setValueS32("status_code", event.getIntValue());
 +		sendMessage(message);
 +	}
 +	
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onLocationChange(const EventType& event)
 +	{
 +		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
 +		{
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed");
 +			message.setValue("uri", event.getEventUri());
 +			sendMessage(message);
 +		}
 +	}
 +	
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onClickLinkHref(const EventType& event)
 +	{
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href");
 +		message.setValue("uri", event.getEventUri());
 +		message.setValue("target", event.getStringValue());
 +		message.setValue("uuid", event.getStringValue2());
 +		sendMessage(message);
 +	}
 +	
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onClickLinkNoFollow(const EventType& event)
 +	{
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
 +		message.setValue("uri", event.getEventUri());
 +#if LLQTWEBKIT_API_VERSION >= 7
 +		message.setValue("nav_type", event.getNavigationType());
 +#else
 +		message.setValue("nav_type", "clicked");
 +#endif
 +		sendMessage(message);
 +	}
 +	
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onCookieChanged(const EventType& event)
 +	{
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "cookie_set");
 +		message.setValue("cookie", event.getStringValue());
 +		// These could be passed through as well, but aren't really needed.
 +//		message.setValue("uri", event.getEventUri());
 +//		message.setValueBoolean("dead", (event.getIntValue() != 0))
 +		sendMessage(message);
 +	}
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onWindowCloseRequested(const EventType& event)
 +	{
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "close_request");
 +		message.setValue("uuid", event.getStringValue());
 +		sendMessage(message);
 +	}
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onWindowGeometryChangeRequested(const EventType& event)
 +	{
 +		int x, y, width, height;
 +		event.getRectValue(x, y, width, height);
 +
 +		// This sometimes gets called with a zero-size request.  Don't pass these along.
 +		if(width > 0 && height > 0)
 +		{
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "geometry_change");
 +			message.setValue("uuid", event.getStringValue());
 +			message.setValueS32("x", x);
 +			message.setValueS32("y", y);
 +			message.setValueS32("width", width);
 +			message.setValueS32("height", height);
 +			sendMessage(message);
 +		}
 +	}
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	std::string onRequestFilePicker( const EventType& eventIn )
 +	{
 +		return blockingPickFile();
 +	}
 +	
 +	std::string mAuthUsername;
 +	std::string mAuthPassword;
 +	bool mAuthOK;
 +	
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	bool onAuthRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password)
 +	{
 +		mAuthOK = false;
 +
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_request");
 +		message.setValue("url", in_url);
 +		message.setValue("realm", in_realm);
 +		message.setValueBoolean("blocking_request", true);
 +				
 +		// The "blocking_request" key in the message means this sendMessage call will block until a response is received.
 +		sendMessage(message);
 +		
 +		if(mAuthOK)
 +		{
 +			out_username = mAuthUsername;
 +			out_password = mAuthPassword;
 +		}
 +		
 +		return mAuthOK;
 +	}
 +	
 +	void authResponse(LLPluginMessage &message)
 +	{
 +		mAuthOK = message.getValueBoolean("ok");
 +		if(mAuthOK)
 +		{
 +			mAuthUsername = message.getValue("username");
 +			mAuthPassword = message.getValue("password");
 +		}
 +	}
 +	
 +	////////////////////////////////////////////////////////////////////////////////
 +	// virtual
 +	void onLinkHovered(const EventType& event)
 +	{
 +		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
 +		{
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "link_hovered");
 +			message.setValue("link", event.getEventUri());
 +			message.setValue("title", event.getStringValue());
 +			message.setValue("text", event.getStringValue2());
 +			sendMessage(message);
 +		}
 +	}
 +	
 +	LLQtWebKit::EKeyboardModifier decodeModifiers(std::string &modifiers)
 +	{
 +		int result = 0;
 +		
 +		if(modifiers.find("shift") != std::string::npos)
 +			result |= LLQtWebKit::KM_MODIFIER_SHIFT;
 +
 +		if(modifiers.find("alt") != std::string::npos)
 +			result |= LLQtWebKit::KM_MODIFIER_ALT;
 +		
 +		if(modifiers.find("control") != std::string::npos)
 +			result |= LLQtWebKit::KM_MODIFIER_CONTROL;
 +		
 +		if(modifiers.find("meta") != std::string::npos)
 +			result |= LLQtWebKit::KM_MODIFIER_META;
 +		
 +		return (LLQtWebKit::EKeyboardModifier)result;
 +	}
 +	
 +	////////////////////////////////////////////////////////////////////////////////
 +	//
 +	void deserializeKeyboardData( LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers )
 +	{
 +		native_scan_code = 0;
 +		native_virtual_key = 0;
 +		native_modifiers = 0;
 +		
 +		if( native_key_data.isMap() )
 +		{
 +#if LL_DARWIN
 +			native_scan_code = (uint32_t)(native_key_data["char_code"].asInteger());
 +			native_virtual_key = (uint32_t)(native_key_data["key_code"].asInteger());
 +			native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger());
 +#elif LL_WINDOWS
 +			native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger());
 +			native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());
 +			// TODO: I don't think we need to do anything with native modifiers here -- please verify
 +#elif LL_LINUX
 +			native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger());
 +			native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());
 +			native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger());
 +#else
 +			// Add other platforms here as needed
 +#endif
 +		};
 +	};
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	//
 +	void keyEvent(LLQtWebKit::EKeyEvent key_event, int key, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
 +	{
 +		// The incoming values for 'key' will be the ones from indra_constants.h
 +		std::string utf8_text;
 +		
 +		if(key < KEY_SPECIAL)
 +		{
 +			// Low-ascii characters need to get passed through.
 +			utf8_text = (char)key;
 +		}
 +		
 +		// Any special-case handling we want to do for particular keys...
 +		switch((KEY)key)
 +		{
 +			// ASCII codes for some standard keys
 +			case LLQtWebKit::KEY_BACKSPACE:		utf8_text = (char)8;		break;
 +			case LLQtWebKit::KEY_TAB:			utf8_text = (char)9;		break;
 +			case LLQtWebKit::KEY_RETURN:		utf8_text = (char)13;		break;
 +			case LLQtWebKit::KEY_PAD_RETURN:	utf8_text = (char)13;		break;
 +			case LLQtWebKit::KEY_ESCAPE:		utf8_text = (char)27;		break;
 +			
 +			default:  
 +			break;
 +		}
 +		
 +//		std::cerr << "key event " << (int)key_event << ", native_key_data = " << native_key_data << std::endl;
 +		
 +		uint32_t native_scan_code = 0;
 +		uint32_t native_virtual_key = 0;
 +		uint32_t native_modifiers = 0;
 +		deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers );
 +		
 +		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, key_event, (uint32_t)key, utf8_text.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
 +
 +		checkEditState();
 +	};
 +
 +	////////////////////////////////////////////////////////////////////////////////
 +	//
 +	void unicodeInput( const std::string &utf8str, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
 +	{		
 +		uint32_t key = LLQtWebKit::KEY_NONE;
 +		
 +//		std::cerr << "unicode input, native_key_data = " << native_key_data << std::endl;
 +		
 +		if(utf8str.size() == 1)
 +		{
 +			// The only way a utf8 string can be one byte long is if it's actually a single 7-bit ascii character.
 +			// In this case, use it as the key value.
 +			key = utf8str[0];
 +		}
 +
 +		uint32_t native_scan_code = 0;
 +		uint32_t native_virtual_key = 0;
 +		uint32_t native_modifiers = 0;
 +		deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers );
 +		
 +		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_DOWN, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
 +		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_UP, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
 +
 +		checkEditState();
 +	};
 +	
 +	void checkEditState(void)
 +	{
 +		bool can_cut = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT);
 +		bool can_copy = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY);
 +		bool can_paste = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE);
 +					
 +		if((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste))
 +		{
 +			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state");
 +			
 +			if(can_cut != mCanCut)
 +			{
 +				mCanCut = can_cut;
 +				message.setValueBoolean("cut", can_cut);
 +			}
 +
 +			if(can_copy != mCanCopy)
 +			{
 +				mCanCopy = can_copy;
 +				message.setValueBoolean("copy", can_copy);
 +			}
 +
 +			if(can_paste != mCanPaste)
 +			{
 +				mCanPaste = can_paste;
 +				message.setValueBoolean("paste", can_paste);
 +			}
 +			
 +			sendMessage(message);
 +			
 +		}
 +	}
 +	
 +	std::string mPickedFile;
 +	
 +	std::string blockingPickFile(void)
 +	{
 +		mPickedFile.clear();
 +		
 +		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file");
 +		message.setValueBoolean("blocking_request", true);
 +		
 +		// The "blocking_request" key in the message means this sendMessage call will block until a response is received.
 +		sendMessage(message);
 +		
 +		return mPickedFile;
 +	}
 +
 +	void onPickFileResponse(const std::string &file)
 +	{
 +		mPickedFile = file;
 +	}
 +
 +};
 +
 +MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) :
 +	MediaPluginBase(host_send_func, host_user_data)
 +{
 +//	std::cerr << "MediaPluginWebKit constructor" << std::endl;
 +
 +	mBrowserWindowId = 0;
 +	mInitState = INIT_STATE_UNINITIALIZED;
 +	mNeedsUpdate = true;
 +	mCanCut = false;
 +	mCanCopy = false;
 +	mCanPaste = false;
 +	mLastMouseX = 0;
 +	mLastMouseY = 0;
 +	mFirstFocus = true;
 +	mBackgroundR = 0.0f;
 +	mBackgroundG = 0.0f;
 +	mBackgroundB = 0.0f;
 +
 +	mHostLanguage = "en";		// default to english
 +	mJavascriptEnabled = true;	// default to on
 +	mPluginsEnabled = true;		// default to on
 +	mEnableMediaPluginDebugging = false;
 +	mUserAgent = "LLPluginMedia Web Browser";
 +}
 +
 +MediaPluginWebKit::~MediaPluginWebKit()
 +{
 +	// unhook observer
 +	LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this );
 +
 +	// clean up
 +	LLQtWebKit::getInstance()->reset();
 +
 +//	std::cerr << "MediaPluginWebKit destructor" << std::endl;
 +}
 +
 +void MediaPluginWebKit::receiveMessage(const char *message_string)
 +{
 +//	std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
 +	LLPluginMessage message_in;
 +	
 +	if(message_in.parse(message_string) >= 0)
 +	{
 +		std::string message_class = message_in.getClass();
 +		std::string message_name = message_in.getName();
 +		if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
 +		{
 +			if(message_name == "init")
 +			{
 +				LLPluginMessage message("base", "init_response");
 +				LLSD versions = LLSD::emptyMap();
 +				versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
 +				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
 +				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
 +				message.setValueLLSD("versions", versions);
 +
 +				std::string plugin_version = "Webkit media plugin, Webkit version ";
 +				plugin_version += LLQtWebKit::getInstance()->getVersion();
 +				message.setValue("plugin_version", plugin_version);
 +				sendMessage(message);
 +			}
 +			else if(message_name == "idle")
 +			{
 +				// no response is necessary here.
 +				F64 time = message_in.getValueReal("time");
 +				
 +				// Convert time to milliseconds for update()
 +				update((int)(time * 1000.0f));
 +			}
 +			else if(message_name == "cleanup")
 +			{
 +				// DTOR most likely won't be called but the recent change to the way this process
 +				// is (not) killed means we see this message and can do what we need to here.
 +				// Note: this cleanup is ultimately what writes cookies to the disk
 +				LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this );
 +				LLQtWebKit::getInstance()->reset();
 +			}
 +			else if(message_name == "shm_added")
 +			{
 +				SharedSegmentInfo info;
 +				info.mAddress = message_in.getValuePointer("address");
 +				info.mSize = (size_t)message_in.getValueS32("size");
 +				std::string name = message_in.getValue("name");
 +				
 +//				std::cerr << "MediaPluginWebKit::receiveMessage: shared memory added, name: " << name 
 +//					<< ", size: " << info.mSize 
 +//					<< ", address: " << info.mAddress 
 +//					<< std::endl;
 +
 +				mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
 +			
 +			}
 +			else if(message_name == "shm_remove")
 +			{
 +				std::string name = message_in.getValue("name");
 +				
 +//				std::cerr << "MediaPluginWebKit::receiveMessage: shared memory remove, name = " << name << std::endl;
 +
 +				SharedSegmentMap::iterator iter = mSharedSegments.find(name);
 +				if(iter != mSharedSegments.end())
 +				{
 +					if(mPixels == iter->second.mAddress)
 +					{
 +						// This is the currently active pixel buffer.  Make sure we stop drawing to it.
 +						mPixels = NULL;
 +						mTextureSegmentName.clear();
 +					}
 +					mSharedSegments.erase(iter);
 +				}
 +				else
 +				{
 +//					std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl;
 +				}
 +
 +				// Send the response so it can be cleaned up.
 +				LLPluginMessage message("base", "shm_remove_response");
 +				message.setValue("name", name);
 +				sendMessage(message);
 +			}
 +			else
 +			{
 +//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl;
 +			}
 +		}
 +		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
 +		{
 +			if(message_name == "set_volume")
 +			{
 +				F32 volume = message_in.getValueReal("volume");
 +				setVolume(volume);
 +			}
 +		}
 +		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
 +		{
 +			if(message_name == "init")
 +			{
 +				mTarget = message_in.getValue("target");
 +				
 +				// This is the media init message -- all necessary data for initialization should have been received.
 +				if(initBrowser())
 +				{
 +					
 +					// Plugin gets to decide the texture parameters to use.
 +					mDepth = 4;
 +
 +					LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
 +					message.setValueS32("default_width", 1024);
 +					message.setValueS32("default_height", 1024);
 +					message.setValueS32("depth", mDepth);
 +					message.setValueU32("internalformat", GL_RGBA);
 +	#if LL_QTWEBKIT_USES_PIXMAPS
 +					message.setValueU32("format", GL_BGRA_EXT); // I hope this isn't system-dependant... is it?  If so, we'll have to check the root window's pixel layout or something... yuck.
 +	#else
 +					message.setValueU32("format", GL_RGBA);
 +	#endif // LL_QTWEBKIT_USES_PIXMAPS
 +					message.setValueU32("type", GL_UNSIGNED_BYTE);
 +					message.setValueBoolean("coords_opengl", true);
 +					sendMessage(message);
 +				}
 +				else
 +				{
 +					// if initialization failed, we're done.
 +					mDeleteMe = true;
 +				}
 +
 +			}
 +			else if(message_name == "set_user_data_path")
 +			{
 +				std::string user_data_path = message_in.getValue("path"); // n.b. always has trailing platform-specific dir-delimiter
 +				mProfileDir = user_data_path + "browser_profile";
 +
 +				// FIXME: Should we do anything with this if it comes in after the browser has been initialized?
 +			}
 +			else if(message_name == "set_language_code")
 +			{
 +				mHostLanguage = message_in.getValue("language");
 +
 +				// FIXME: Should we do anything with this if it comes in after the browser has been initialized?
 +			}
 +			else if(message_name == "plugins_enabled")
 +			{
 +				mPluginsEnabled = message_in.getValueBoolean("enable");
 +			}
 +			else if(message_name == "javascript_enabled")
 +			{
 +				mJavascriptEnabled = message_in.getValueBoolean("enable");
 +			}
 +			else if(message_name == "size_change")
 +			{
 +				std::string name = message_in.getValue("name");
 +				S32 width = message_in.getValueS32("width");
 +				S32 height = message_in.getValueS32("height");
 +				S32 texture_width = message_in.getValueS32("texture_width");
 +				S32 texture_height = message_in.getValueS32("texture_height");
 +				mBackgroundR = message_in.getValueReal("background_r");
 +				mBackgroundG = message_in.getValueReal("background_g");
 +				mBackgroundB = message_in.getValueReal("background_b");
 +//				mBackgroundA = message_in.setValueReal("background_a");		// Ignore any alpha
 +								
 +				if(!name.empty())
 +				{
 +					// Find the shared memory region with this name
 +					SharedSegmentMap::iterator iter = mSharedSegments.find(name);
 +					if(iter != mSharedSegments.end())
 +					{
 +						mPixels = (unsigned char*)iter->second.mAddress;
 +						mWidth = width;
 +						mHeight = height;
 +
 +						if(initBrowserWindow())
 +						{
 +
 +							// size changed so tell the browser
 +							LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight );
 +							
 +	//						std::cerr << "webkit plugin: set size to " << mWidth << " x " << mHeight 
 +	//								<< ", rowspan is " << LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) << std::endl;
 +									
 +							S32 real_width = LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) / LLQtWebKit::getInstance()->getBrowserDepth(mBrowserWindowId); 
 +							
 +							// The actual width the browser will be drawing to is probably smaller... let the host know by modifying texture_width in the response.
 +							if(real_width <= texture_width)
 +							{
 +								texture_width = real_width;
 +							}
 +							else
 +							{
 +								// This won't work -- it'll be bigger than the allocated memory.  This is a fatal error.
 +	//							std::cerr << "Fatal error: browser rowbytes greater than texture width" << std::endl;
 +								mDeleteMe = true;
 +								return;
 +							}
 +						}
 +						else
 +						{
 +							// Setting up the browser window failed.  This is a fatal error.
 +							mDeleteMe = true;
 +						}
 +
 +						
 +						mTextureWidth = texture_width;
 +						mTextureHeight = texture_height;
 +						
 +					};
 +				};
 +
 +				LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
 +				message.setValue("name", name);
 +				message.setValueS32("width", width);
 +				message.setValueS32("height", height);
 +				message.setValueS32("texture_width", texture_width);
 +				message.setValueS32("texture_height", texture_height);
 +				sendMessage(message);
 +
 +			}
 +			else if(message_name == "load_uri")
 +			{
 +				std::string uri = message_in.getValue("uri");
 +
 +//				std::cout << "loading URI: " << uri << std::endl;
 +				
 +				if(!uri.empty())
 +				{
 +					if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
 +					{
 +						LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, uri );
 +					}
 +					else
 +					{
 +						mInitialNavigateURL = uri;
 +					}
 +				}
 +			}
 +			else if(message_name == "mouse_event")
 +			{
 +				std::string event = message_in.getValue("event");
 +				S32 button = message_in.getValueS32("button");
 +				mLastMouseX = message_in.getValueS32("x");
 +				mLastMouseY = message_in.getValueS32("y");
 +				std::string modifiers = message_in.getValue("modifiers");
 +				
 +				// Treat unknown mouse events as mouse-moves.
 +				LLQtWebKit::EMouseEvent mouse_event = LLQtWebKit::ME_MOUSE_MOVE;
 +				if(event == "down")
 +				{
 +					mouse_event = LLQtWebKit::ME_MOUSE_DOWN;
 +				}
 +				else if(event == "up")
 +				{
 +					mouse_event = LLQtWebKit::ME_MOUSE_UP;
 +				}
 +				else if(event == "double_click")
 +				{
 +					mouse_event = LLQtWebKit::ME_MOUSE_DOUBLE_CLICK;
 +				}
 +				
 +				LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, mouse_event, button, mLastMouseX, mLastMouseY, decodeModifiers(modifiers));
 +				checkEditState();
 +			}
 +			else if(message_name == "scroll_event")
 +			{
 +				S32 x = message_in.getValueS32("x");
 +				S32 y = message_in.getValueS32("y");
 +				std::string modifiers = message_in.getValue("modifiers");
 +				
 +				// Incoming scroll events are adjusted so that 1 detent is approximately 1 unit.
 +				// Qt expects 1 detent to be 120 units.
 +				// It also seems that our y scroll direction is inverted vs. what Qt expects.
 +				
 +				x *= 120;
 +				y *= -120;
 +				
 +				LLQtWebKit::getInstance()->scrollWheelEvent(mBrowserWindowId, mLastMouseX, mLastMouseY, x, y, decodeModifiers(modifiers));
 +			}
 +			else if(message_name == "key_event")
 +			{
 +				std::string event = message_in.getValue("event");
 +				S32 key = message_in.getValueS32("key");
 +				std::string modifiers = message_in.getValue("modifiers");
 +				LLSD native_key_data = message_in.getValueLLSD("native_key_data");
 +				
 +				// Treat unknown events as key-up for safety.
 +				LLQtWebKit::EKeyEvent key_event = LLQtWebKit::KE_KEY_UP;
 +				if(event == "down")
 +				{
 +					key_event = LLQtWebKit::KE_KEY_DOWN;
 +				}
 +				else if(event == "repeat")
 +				{
 +					key_event = LLQtWebKit::KE_KEY_REPEAT;
 +				}
 +				
 +				keyEvent(key_event, key, decodeModifiers(modifiers), native_key_data);
 +			}
 +			else if(message_name == "text_event")
 +			{
 +				std::string text = message_in.getValue("text");
 +				std::string modifiers = message_in.getValue("modifiers");
 +				LLSD native_key_data = message_in.getValueLLSD("native_key_data");
 +				
 +				unicodeInput(text, decodeModifiers(modifiers), native_key_data);
 +			}
 +			if(message_name == "edit_cut")
 +			{
 +				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT );
 +				checkEditState();
 +			}
 +			if(message_name == "edit_copy")
 +			{
 +				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY );
 +				checkEditState();
 +			}
 +			if(message_name == "edit_paste")
 +			{
 +				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE );
 +				checkEditState();
 +			}
 +			if(message_name == "pick_file_response")
 +			{
 +				onPickFileResponse(message_in.getValue("file"));
 +			}
 +			if(message_name == "auth_response")
 +			{
 +				authResponse(message_in);
 +			}
 +			else
 +			if(message_name == "enable_media_plugin_debugging")
 +			{
 +				mEnableMediaPluginDebugging = message_in.getValueBoolean( "enable" );
 +			}
 +
 +			else
 +			if(message_name == "js_enable_object")
 +			{
 +#if LLQTWEBKIT_API_VERSION >= 9
 +				bool enable = message_in.getValueBoolean( "enable" );
 +				LLQtWebKit::getInstance()->setSLObjectEnabled( enable );
 +#endif
 +			}
 +			else
 +			if(message_name == "js_agent_location")
 +			{
 +#if LLQTWEBKIT_API_VERSION >= 9
 +				F32 x = message_in.getValueReal("x");
 +				F32 y = message_in.getValueReal("y");
 +				F32 z = message_in.getValueReal("z");
 +				LLQtWebKit::getInstance()->setAgentLocation( x, y, z );
 +				LLQtWebKit::getInstance()->emitLocation();
 +#endif
 +			}
 +			else
 +			if(message_name == "js_agent_global_location")
 +			{
 +#if LLQTWEBKIT_API_VERSION >= 9
 +				F32 x = message_in.getValueReal("x");
 +				F32 y = message_in.getValueReal("y");
 +				F32 z = message_in.getValueReal("z");
 +				LLQtWebKit::getInstance()->setAgentGlobalLocation( x, y, z );
 +				LLQtWebKit::getInstance()->emitLocation();
 +#endif
 +			}
 +			else			
 +			if(message_name == "js_agent_orientation")
 +			{
 +#if LLQTWEBKIT_API_VERSION >= 9
 +				F32 angle = message_in.getValueReal("angle");
 +				LLQtWebKit::getInstance()->setAgentOrientation( angle );
 +				LLQtWebKit::getInstance()->emitLocation();
 +#endif
 +			}
 +			else
 +			if(message_name == "js_agent_region")
 +			{
 +#if LLQTWEBKIT_API_VERSION >= 9
 +				const std::string& region = message_in.getValue("region");
 +				LLQtWebKit::getInstance()->setAgentRegion( region );
 +				LLQtWebKit::getInstance()->emitLocation();
 +#endif
 +			}
 +			else
 +				if(message_name == "js_agent_maturity")
 +				{
 +#if LLQTWEBKIT_API_VERSION >= 9
 +					const std::string& maturity = message_in.getValue("maturity");
 +					LLQtWebKit::getInstance()->setAgentMaturity( maturity );
 +					LLQtWebKit::getInstance()->emitMaturity();
 +#endif
 +				}
 +			else
 +			if(message_name == "js_agent_language")
 +			{
 +#if LLQTWEBKIT_API_VERSION >= 9
 +				const std::string& language = message_in.getValue("language");
 +				LLQtWebKit::getInstance()->setAgentLanguage( language );
 +				LLQtWebKit::getInstance()->emitLanguage();
 +#endif
 +			}
 +			else
 +			{
 +//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl;
 +			}
 +		}
 +		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
 +		{
 +			if(message_name == "focus")
 +			{
 +				bool val = message_in.getValueBoolean("focused");
 +				LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, val );
 +				
 +				if(mFirstFocus && val)
 +				{
 +					// On the first focus, post a tab key event.  This fixes a problem with initial focus.
 +					std::string empty;
 +					keyEvent(LLQtWebKit::KE_KEY_DOWN, KEY_TAB, decodeModifiers(empty));
 +					keyEvent(LLQtWebKit::KE_KEY_UP, KEY_TAB, decodeModifiers(empty));
 +					mFirstFocus = false;
 +				}
 +			}
 +			else if(message_name == "clear_cache")
 +			{
 +				LLQtWebKit::getInstance()->clearCache();
 +			}
 +			else if(message_name == "clear_cookies")
 +			{
 +				LLQtWebKit::getInstance()->clearAllCookies();
 +			}
 +			else if(message_name == "enable_cookies")
 +			{
 +				mCookiesEnabled = message_in.getValueBoolean("enable");
 +				LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled );
 +			}
 +			else if(message_name == "enable_plugins")
 +			{
 +				mPluginsEnabled = message_in.getValueBoolean("enable");
 +				LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled );
 +			}
 +			else if(message_name == "enable_javascript")
 +			{
 +				mJavascriptEnabled = message_in.getValueBoolean("enable");
 +				//LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled );
 +			}
 +			else if(message_name == "set_cookies")
 +			{
 +				LLQtWebKit::getInstance()->setCookies(message_in.getValue("cookies"));
 +			}
 +			else if(message_name == "proxy_setup")
 +			{
 +				bool val = message_in.getValueBoolean("enable");
 +				std::string host = message_in.getValue("host");
 +				int port = message_in.getValueS32("port");
 +				LLQtWebKit::getInstance()->enableProxy( val, host, port );
 +			}
 +			else if(message_name == "browse_stop")
 +			{
 +				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_STOP );
 +			}
 +			else if(message_name == "browse_reload")
 +			{
 +				// foo = message_in.getValueBoolean("ignore_cache");
 +				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD );
 +			}
 +			else if(message_name == "browse_forward")
 +			{
 +				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD );
 +			}
 +			else if(message_name == "browse_back")
 +			{
 +				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK );
 +			}
 +			else if(message_name == "set_status_redirect")
 +			{
 +				int code = message_in.getValueS32("code");
 +				std::string url = message_in.getValue("url");
 +				if ( 404 == code )	// browser lib only supports 404 right now
 +				{
 +#if LLQTWEBKIT_API_VERSION < 8
 +				 	LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url );
 +#endif
 +				};
 +			}
 +			else if(message_name == "set_user_agent")
 +			{
 +				mUserAgent = message_in.getValue("user_agent");
 +				LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent );
 +			}
 +			else if(message_name == "show_web_inspector")
 +			{
 +#if LLQTWEBKIT_API_VERSION >= 10
 +				bool val = message_in.getValueBoolean("show");
 +				LLQtWebKit::getInstance()->showWebInspector( val );
 +#else
 +				llwarns << "Ignoring showWebInspector message (llqtwebkit version is too old)." << llendl;
 +#endif
 +			}
 +			else if(message_name == "ignore_ssl_cert_errors")
 +			{
 +#if LLQTWEBKIT_API_VERSION >= 3
 +				LLQtWebKit::getInstance()->setIgnoreSSLCertErrors( message_in.getValueBoolean("ignore") );
 +#else
 +				llwarns << "Ignoring ignore_ssl_cert_errors message (llqtwebkit version is too old)." << llendl;
 +#endif
 +			}
 +			else if(message_name == "add_certificate_file_path")
 +			{
 +#if LLQTWEBKIT_API_VERSION >= 6
 +				LLQtWebKit::getInstance()->setCAFile( message_in.getValue("path") );
 +#else
 +				llwarns << "Ignoring add_certificate_file_path message (llqtwebkit version is too old)." << llendl;
 +#endif
 +			}
 +			else if(message_name == "init_history")
 +			{
 +				// Initialize browser history
 +				LLSD history = message_in.getValueLLSD("history");
 +				// First, clear the URL history
 +				LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId);
 +				// Then, add the history items in order
 +				LLSD::array_iterator iter_history = history.beginArray();
 +				LLSD::array_iterator end_history = history.endArray();
 +				for(; iter_history != end_history; ++iter_history)
 +				{
 +					std::string url = (*iter_history).asString();
 +					if(! url.empty()) {
 +						LLQtWebKit::getInstance()->prependHistoryUrl(mBrowserWindowId, url);
 +					}
 +				}
 +			}
 +			else if(message_name == "proxy_window_opened")
 +			{
 +				std::string target = message_in.getValue("target");
 +				std::string uuid = message_in.getValue("uuid");
 +				LLQtWebKit::getInstance()->proxyWindowOpened(mBrowserWindowId, target, uuid);
 +			}
 +			else if(message_name == "proxy_window_closed")
 +			{
 +				std::string uuid = message_in.getValue("uuid");
 +				LLQtWebKit::getInstance()->proxyWindowClosed(mBrowserWindowId, uuid);
 +			}
 +			else
 +			{
 +//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl;
 +			};
 +		}
 +		else
 +		{
 +//			std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl;
 +		};
 +	}
 +}
 +
 +void MediaPluginWebKit::setVolume(F32 volume)
 +{
 +	mVolumeCatcher.setVolume(volume);
 +}
 +
 +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
 +{
 +	MediaPluginWebKit *self = new MediaPluginWebKit(host_send_func, host_user_data);
 +	*plugin_send_func = MediaPluginWebKit::staticReceiveMessage;
 +	*plugin_user_data = (void*)self;
 +
 +	return 0;
 +}
 +
 +
 diff --git a/indra/newview/app_settings/CA.pem b/indra/newview/app_settings/CA.pem index 6140842a7f..a16b4225e5 100644 --- a/indra/newview/app_settings/CA.pem +++ b/indra/newview/app_settings/CA.pem @@ -4587,38 +4587,6 @@ zo9uoV1/A3U05K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATy  wy39FCqQmbkHzJ8=  -----END CERTIFICATE-----  -----BEGIN CERTIFICATE----- -MIIFijCCA3KgAwIBAgIQDHbanJEMTiye/hXQWJM8TDANBgkqhkiG9w0BAQUFADBf -MQswCQYDVQQGEwJOTDESMBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdp -Tm90YXIgUm9vdCBDQTEgMB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmww -HhcNMDcwNTE2MTcxOTM2WhcNMjUwMzMxMTgxOTIxWjBfMQswCQYDVQQGEwJOTDES -MBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdpTm90YXIgUm9vdCBDQTEg -MB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmwwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCssFjBAL3YIQgLK5r+blYwBZ8bd5AQQVzDDYcRd46B -8cp86Yxq7Th0Nbva3/m7wAk3tJZzgX0zGpg595NvlX89ubF1h7pRSOiLcD6VBMXY -tsMW2YiwsYcdcNqGtA8Ui3rPENF0NqISe3eGSnnme98CEWilToauNFibJBN4ViIl -HgGLS1Fx+4LMWZZpiFpoU8W5DQI3y0u8ZkqQfioLBQftFl9VkHXYRskbg+IIvvEj -zJkd1ioPgyAVWCeCLvriIsJJsbkBgWqdbZ1Ad2h2TiEqbYRAhU52mXyC8/O3AlnU -JgEbjt+tUwbRrhjd4rI6y9eIOI6sWym5GdOY+RgDz0iChmYLG2kPyes4iHomGgVM -ktck1JbyrFIto0fVUvY//s6EBnCmqj6i8rZWNBhXouSBbefK8GrTx5FrAoNBfBXv -a5pkXuPQPOWx63tdhvvL5ndJzaNl3Pe5nLjkC1+Tz8wwGjIczhxjlaX56uF0i57p -K6kwe6AYHw4YC+VbqdPRbB4HZ4+RS6mKvNJmqpMBiLKR+jFc1abBUggJzQpjotMi -puih2TkGl/VujQKQjBR7P4DNG5y6xFhyI6+2Vp/GekIzKQc/gsnmHwUNzUwoNovT -yD4cxojvXu6JZOkd69qJfjKmadHdzIif0dDJZiHcBmfFlHqabWJMfczgZICynkeO -owIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV -HQ4EFgQUiGi/4I41xDs4a2L3KDuEgcgM100wDQYJKoZIhvcNAQEFBQADggIBADsC -jcs8MOhuoK3yc7NfniUTBAXT9uOLuwt5zlPe5JbF0a9zvNXD0EBVfEB/zRtfCdXy -fJ9oHbtdzno5wozWmHvFg1Wo1X1AyuAe94leY12hE8JdiraKfADzI8PthV9xdvBo -Y6pFITlIYXg23PFDk9Qlx/KAZeFTAnVR/Ho67zerhChXDNjU1JlWbOOi/lmEtDHo -M/hklJRRl6s5xUvt2t2AC298KQ3EjopyDedTFLJgQT2EkTFoPSdE2+Xe9PpjRchM -Ppj1P0G6Tss3DbpmmPHdy59c91Q2gmssvBNhl0L4eLvMyKKfyvBovWsdst+Nbwed -2o5nx0ceyrm/KkKRt2NTZvFCo+H0Wk1Ya7XkpDOtXHAd3ODy63MUkZoDweoAZbwH -/M8SESIsrqC9OuCiKthZ6SnTGDWkrBFfGbW1G/8iSlzGeuQX7yCpp/Q/rYqnmgQl -nQ7KN+ZQ/YxCKQSa7LnPS3K94gg2ryMvYuXKAdNw23yCIywWMQzGNgeQerEfZ1jE -O1hZibCMjFCz2IbLaKPECudpSyDOwR5WS5WpI2jYMNjD67BVUc3l/Su49bsRn1NU -9jQZjHkJNsphFyUXC4KYcwx3dMPVDceoEkzHp1RxRy4sGn3J4ys7SN4nhKdjNrN9 -j6BkOSQNPXuHr2ZcdBtLc7LljPCGmbjlxd+Ewbfr ------END CERTIFICATE----- ------BEGIN CERTIFICATE-----  MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO  TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh  dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index baa083d96c..16bc88e237 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -5503,6 +5503,17 @@        <key>Value</key>        <real>60.0</real>      </map> +  <key>MediaPluginDebugging</key> +  <map> +    <key>Comment</key> +    <string>Turn on debugging messages that may help diagnosing media issues (WARNING: May reduce performance).</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>Boolean</string> +    <key>Value</key> +    <integer>0</integer> +  </map>    <key>MediaControlFadeTime</key>    <map>      <key>Comment</key> diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 1388d9aee0..a0af94ba77 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -2285,7 +2285,9 @@ void LLAppearanceMgr::autopopulateOutfits()  void LLAppearanceMgr::onFirstFullyVisible()  {  	gAgentAvatarp->debugAvatarVisible(); -	autopopulateOutfits(); +	// The auto-populate is failing at the point of generating outfits
 +	// folders, so don't do the library copy until that is resolved.
 +	// autopopulateOutfits();  }  bool LLAppearanceMgr::updateBaseOutfit() diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index ec162e00eb..e4bd2049fa 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -181,6 +181,7 @@ LLFolderView::Params::Params()  // Default constructor  LLFolderView::LLFolderView(const Params& p)  :	LLFolderViewFolder(p), +	mRunningHeight(0),  	mScrollContainer( NULL ),  	mPopupMenuHandle(),  	mAllowMultiSelect(p.allow_multiselect), @@ -479,6 +480,7 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_gen  		target_height = running_height;  	} +	mRunningHeight = running_height;  	LLRect scroll_rect = mScrollContainer->getContentWindowRect();  	reshape( llmax(scroll_rect.getWidth(), total_width), running_height ); @@ -524,10 +526,11 @@ void LLFolderView::reshape(S32 width, S32 height, BOOL called_from_parent)  	LLRect scroll_rect;  	if (mScrollContainer)  	{ +		LLView::reshape(width, height, called_from_parent);  		scroll_rect = mScrollContainer->getContentWindowRect();  	}  	width = llmax(mMinWidth, scroll_rect.getWidth()); -	height = llmax(height, scroll_rect.getHeight()); +	height = llmax(mRunningHeight, scroll_rect.getHeight());  	// restrict width with scroll container's width  	if (mUseEllipses) @@ -1915,9 +1918,9 @@ BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,  	if (!handled)  	{  		if (getListener()->getUUID().notNull()) -		{ -			LLFolderViewFolder::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); -		} +	{ +		LLFolderViewFolder::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); +	}  		else  		{  			if (!mFolders.empty()) diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index 705a76a7b4..8af01e9102 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -314,6 +314,7 @@ protected:  	signal_t						mReshapeSignal;  	S32								mSignalSelectCallback;  	S32								mMinWidth; +	S32								mRunningHeight;  	std::map<LLUUID, LLFolderViewItem*> mItemMap;  	BOOL							mDragAndDropThisFrame; diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 1eb786f433..5bbef78dd4 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -319,6 +319,11 @@ BOOL LLMediaCtrl::handleRightMouseDown( S32 x, S32 y, MASK mask )  	if (mContextMenu)  	{ +		// hide/show debugging options +		bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging"); +		mContextMenu->setItemVisible("open_webinspector", media_plugin_debugging_enabled ); +		mContextMenu->setItemVisible("debug_separator", media_plugin_debugging_enabled ); +  		mContextMenu->show(x, y);  		LLMenuGL::showPopup(this, mContextMenu, x, y);  	} @@ -385,12 +390,22 @@ void LLMediaCtrl::onFocusLost()  //  BOOL LLMediaCtrl::postBuild ()  { +	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar; +	registar.add("Open.WebInspector", boost::bind(&LLMediaCtrl::onOpenWebInspector, this)); +  	mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(  		"menu_media_ctrl.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());  	setVisibleCallback(boost::bind(&LLMediaCtrl::onVisibilityChange, this, _2)); +  	return TRUE;  } +void LLMediaCtrl::onOpenWebInspector() +{ +	if (mMediaSource && mMediaSource->hasMedia()) +		mMediaSource->getMediaPlugin()->showWebInspector( true ); +} +  ////////////////////////////////////////////////////////////////////////////////  //  BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask ) @@ -1065,6 +1080,12 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)  			mHoverTextChanged = true;  		};  		break; + +		case MEDIA_EVENT_DEBUG_MESSAGE: +		{ +			LL_INFOS("media") << self->getDebugMessageText() << LL_ENDL;  +		}; +		break;  	};  	// chain all events to any potential observers of this object. diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 0e4a5b1d65..3c0436e27a 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -166,6 +166,9 @@ public:  		// Incoming media event dispatcher  		virtual void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); +		// right click debugging item +		void onOpenWebInspector(); +  		LLUUID getTextureID() {return mMediaTextureID;}  	protected: diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index bef809f3a7..db7d836799 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -154,6 +154,10 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,  	}  	updateLocationCombo(false); +	LLUICtrl& mode_combo = getChildRef<LLUICtrl>("mode_combo"); +	mode_combo.setValue(gSavedSettings.getString("SessionSettingsFile")); +	mode_combo.setCommitCallback(boost::bind(&LLPanelLogin::onModeChange, this, getChild<LLUICtrl>("mode_combo")->getValue(), _2)); +  	LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo");  	server_choice_combo->setCommitCallback(onSelectServer, NULL);  	server_choice_combo->setFocusLostCallback(boost::bind(onServerComboLostFocus, _1)); @@ -1021,6 +1025,32 @@ void LLPanelLogin::updateLoginPanelLinks()  	sInstance->getChildView("forgot_password_text")->setVisible( system_grid);  } +void LLPanelLogin::onModeChange(const LLSD& original_value, const LLSD& new_value) +{ +	if (original_value.asString() != new_value.asString()) +	{ +		LLNotificationsUtil::add("ModeChange", LLSD(), LLSD(), boost::bind(&LLPanelLogin::onModeChangeConfirm, this, original_value, new_value, _1, _2)); +	} +} + +void LLPanelLogin::onModeChangeConfirm(const LLSD& original_value, const LLSD& new_value, const LLSD& notification, const LLSD& response) +{ +	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); +	switch (option) +	{ +	case 0: +		gSavedSettings.getControl("SessionSettingsFile")->set(new_value); +		LLAppViewer::instance()->requestQuit(); +		break; +	case 1: +		// revert to original value +		getChild<LLUICtrl>("mode_combo")->setValue(original_value); +		break; +	default: +		break; +	} +} +  std::string canonicalize_username(const std::string& name)  {  	std::string cname = name; diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index 4078eedc77..be9de884d1 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -87,6 +87,8 @@ private:  	void reshapeBrowser();  	void addFavoritesToStartLocation();  	void addUsersWithFavoritesToUsername(); +	void onModeChange(const LLSD& original_value, const LLSD& new_value); +	void onModeChangeConfirm(const LLSD& original_value, const LLSD& new_value, const LLSD& notification, const LLSD& response);  	static void onClickConnect(void*);  	static void onClickNewAccount(void*);  	static void onClickVersion(void*); @@ -97,7 +99,6 @@ private:  	static void onServerComboLostFocus(LLFocusableElement*);  	static void updateServerCombo();  	static void updateStartSLURL(); -	  	static void updateLoginPanelLinks();  private: diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp index 4cf1df1655..a853726dea 100644 --- a/indra/newview/llslurl.cpp +++ b/indra/newview/llslurl.cpp @@ -273,11 +273,11 @@ LLSLURL::LLSLURL(const std::string& slurl)  			mRegion = LLURI::unescape(path_array[0].asString());  			path_array.erase(0); -			// parse the x, y, z -			if(path_array.size() >= 3) +			// parse the x, y, and optionally z +			if(path_array.size() >= 2)  			{	 -			  mPosition = LLVector3(path_array); +			  mPosition = LLVector3(path_array); // this construction handles LLSD without all components (values default to 0.f)  			  if((F32(mPosition[VX]) < 0.f) ||                                (mPosition[VX] > REGION_WIDTH_METERS) ||  			     (F32(mPosition[VY]) < 0.f) ||  diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index 1b8be7a5b2..0a00885843 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -162,6 +162,8 @@ BOOL LLStatusBar::handleRightMouseDown(S32 x, S32 y, MASK mask)  BOOL LLStatusBar::postBuild()  { +	LLControlVariablePtr mode_control = gSavedSettings.getControl("SessionSettingsFile"); +  	gMenuBarView->setRightMouseDownCallback(boost::bind(&show_navbar_context_menu, _1, _2, _3));  	mTextTime = getChild<LLTextBox>("TimeText" ); @@ -233,9 +235,40 @@ BOOL LLStatusBar::postBuild()  	mScriptOut = getChildView("scriptout"); +	LLUICtrl& mode_combo = getChildRef<LLUICtrl>("mode_combo"); +	mode_combo.setValue(gSavedSettings.getString("SessionSettingsFile")); +	mode_combo.setCommitCallback(boost::bind(&LLStatusBar::onModeChange, this, getChild<LLUICtrl>("mode_combo")->getValue(), _2)); + +  	return TRUE;  } +void LLStatusBar::onModeChange(const LLSD& original_value, const LLSD& new_value) +{ +	if (original_value.asString() != new_value.asString()) +	{ +		LLNotificationsUtil::add("ModeChange", LLSD(), LLSD(), boost::bind(&LLStatusBar::onModeChangeConfirm, this, original_value, new_value, _1, _2)); +	} +} + +void LLStatusBar::onModeChangeConfirm(const LLSD& original_value, const LLSD& new_value, const LLSD& notification, const LLSD& response) +{ +	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); +	switch (option) +	{ +	case 0: +		gSavedSettings.getControl("SessionSettingsFile")->set(new_value); +		LLAppViewer::instance()->requestQuit(); +		break; +	case 1: +		// revert to original value +		getChild<LLUICtrl>("mode_combo")->setValue(original_value); +		break; +	default: +		break; +	} +} +  // Per-frame updates of visibility  void LLStatusBar::refresh()  { diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index 4ea3183d18..e1e1f5459b 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -92,6 +92,8 @@ private:  	void onMouseEnterVolume();  	void onMouseEnterNearbyMedia();  	void onClickScreen(S32 x, S32 y); +	void onModeChange(const LLSD& original_value, const LLSD& new_value);
 +	void onModeChangeConfirm(const LLSD& original_value, const LLSD& new_value, const LLSD& notification, const LLSD& response);
  	static void onClickMediaToggle(void* data);  	static void onClickBalance(void* data); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 384f7cd61d..31b22119cb 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1776,6 +1776,7 @@ void LLViewerMediaImpl::createMediaSource()  			LL_WARNS("Media") << "Failed to initialize media for mime type " << mMimeType << LL_ENDL;  		}  	} +  }  ////////////////////////////////////////////////////////////////////////////////////////// @@ -1880,7 +1881,10 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_  			// collect 'javascript enabled' setting from prefs and send to embedded browser  			bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" );  			media_source->setJavascriptEnabled( javascript_enabled ); -			 +		 +			bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging"); +			media_source->enableMediaPluginDebugging( media_plugin_debugging_enabled ); +  			media_source->setTarget(target);  			const std::string plugin_dir = gDirUtilp->getLLPluginDir(); diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index dfa35edef4..90fbc41daa 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -485,6 +485,12 @@ void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent  {  	switch(event)  	{ +		case MEDIA_EVENT_DEBUG_MESSAGE: +		{ +			// LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_DEBUG_MESSAGE " << LL_ENDL; +		}; +		break; +  		case MEDIA_EVENT_CONTENT_UPDATED:  		{  			// LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_CONTENT_UPDATED " << LL_ENDL; diff --git a/indra/newview/skins/default/xui/en/menu_media_ctrl.xml b/indra/newview/skins/default/xui/en/menu_media_ctrl.xml index c39c26f25f..960da4bd7a 100644 --- a/indra/newview/skins/default/xui/en/menu_media_ctrl.xml +++ b/indra/newview/skins/default/xui/en/menu_media_ctrl.xml @@ -28,4 +28,16 @@      <menu_item_call.on_enable       function="Edit.EnablePaste" />    </menu_item_call> +  <menu_item_separator +   layout="topleft" +   name="debug_separator" +   visible="false" /> +  <menu_item_call +   label="Open Web Inspector" +   layout="topleft" +   name="open_webinspector" +   visible="false"> +    <menu_item_call.on_click +     function="Open.WebInspector" /> +  </menu_item_call>  </context_menu> diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index 83f1bff91f..983f93cb03 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -117,17 +117,33 @@ label="Remember password"    name="connect_btn"    top="35"    width="90" /> -  <!-- Utf code in label is a filled up-pointing triangle --> -  <menu_button -  left_pad="5" -  top="35" -  width="80" +  <text +  follows="left|bottom" +  font="SansSerifSmall" +  height="15" +  left_pad="10" +  name="mode_selection_text" +  top="20" +  width="130"> +    Mode: +  </text> +  <combo_box +    follows="left|bottom"    height="23" -  label="Mode ▲" -  name="mode_menu"   +    max_chars="128"    tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features." -  menu_filename="menu_mode_change.xml" -    /> +    top_pad="0" +    name="mode_combo" +    width="110"> +    <combo_box.item +      label="Basic" +      name="Basic" +      value="settings_minimal.xml" /> +    <combo_box.item +      label="Advanced" +      name="Advanced" +      value="" /> +  </combo_box>    <text    follows="left|bottom"    font="SansSerifSmall" diff --git a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml index 8a7bd53054..9749b6fdd4 100644 --- a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml @@ -97,7 +97,7 @@  	     mouse_opaque="false"  	     name="location_combo"  	     top_delta="0" -	     width="266"> +	     width="226">           <combo_list           mouse_wheel_opaque="true"/>  	     <!-- *TODO: Delete.  Let the location_input use the correct art sizes. @@ -137,7 +137,7 @@  	     name="search_combo_box"  	     tool_tip="Search"  	     top_delta="0" -	     width="200" > +	     width="244" >           <combo_editor            label="Search [SECOND_LIFE]"            name="search_combo_editor"/> diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml index f25a73da38..c780cf2696 100644 --- a/indra/newview/skins/default/xui/en/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml @@ -35,7 +35,7 @@      </panel.string>    <panel      height="18" -    left="-315" +    left="-355"      width="95"      top="1"      follows="right|top"  @@ -77,20 +77,28 @@       top="0"       width="55" />    </panel> -  <!-- UTF 9660 code in label below is a down-pointing filled-in triangle --> -  <menu_button -     follows="right|top"     -    image_color="0 0 0 0" -    hover_glow_amount="0" +  <combo_box +    follows="right|top"    +    drop_down_button.pad_left="10"       left_pad="5" -    top="2" -    width="55" -    height="18" -    label="Mode ▼" +    top="0" +    width="120" +    height="20" +    pad_left="5" +    name="mode_combo"      tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features." -    menu_filename="menu_mode_change.xml" -    /> +    > +    <combo_box.item +      label="Basic Mode" +      name="Basic" +      value="settings_minimal.xml" /> +    <combo_box.item +      label="Advanced Mode" +      name="Advanced" +      value="" /> +  </combo_box>      <text +      left_pad="5"       type="string"       font="SansSerifSmall"       text_readonly_color="TimeTextColor" @@ -99,10 +107,9 @@       height="16"       top="5"       layout="topleft" -     left_pad="5"       name="TimeText"       tool_tip="Current time (Pacific)" -     width="90"> +     width="75">          24:00 AM PST      </text>      <button diff --git a/indra/newview/skins/default/xui/en/widgets/combo_box.xml b/indra/newview/skins/default/xui/en/widgets/combo_box.xml index d1f68a9ef9..82d620d1e6 100644 --- a/indra/newview/skins/default/xui/en/widgets/combo_box.xml +++ b/indra/newview/skins/default/xui/en/widgets/combo_box.xml @@ -16,6 +16,9 @@                                font="SansSerifSmall"                                scale_image="true"                                pad_right="24" +                              halign="left" +                              tab_stop="true" +                              follows="all"                                image_unselected="DropDown_Off"                                image_selected="DropDown_On"                                image_pressed="DropDown_Press"  diff --git a/indra/newview/skins/minimal/xui/en/main_view.xml b/indra/newview/skins/minimal/xui/en/main_view.xml index ec2683880a..0ce6cbc984 100644 --- a/indra/newview/skins/minimal/xui/en/main_view.xml +++ b/indra/newview/skins/minimal/xui/en/main_view.xml @@ -187,9 +187,9 @@         name="status_bar_container"         tab_stop="false"         height="30" -       left="-120" +       left="-160"         top="0" -       width="120" +       width="160"         visible="false"/>    <panel follows="top|bottom"           height="500" diff --git a/indra/newview/skins/minimal/xui/en/panel_login.xml b/indra/newview/skins/minimal/xui/en/panel_login.xml index d89a0c6be1..40d2df78e1 100644 --- a/indra/newview/skins/minimal/xui/en/panel_login.xml +++ b/indra/newview/skins/minimal/xui/en/panel_login.xml @@ -118,16 +118,33 @@ label="Remember password"    name="connect_btn"    top="35"    width="90" /> -  <menu_button -left_pad="10" -top="35" -width="80" -height="23" -label="Mode ▲" -name="mode_menu" -tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features." -menu_filename="menu_mode_change.xml" -    /> +  <text +  follows="left|bottom" +  font="SansSerifSmall" +  height="15" +  left_pad="10" +  name="mode_selection_text" +  top="20" +  width="130"> +    Mode: +  </text> +  <combo_box +  follows="left|bottom" +  height="23" +  max_chars="128" +  tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features." +  top_pad="0" +  name="mode_combo" +  width="110"> +    <combo_box.item +      label="Basic" +      name="Basic" +      value="settings_minimal.xml" /> +    <combo_box.item +      label="Advanced" +      name="Advanced" +      value="" /> +  </combo_box>  </layout_panel>  <layout_panel  tab_stop="false" diff --git a/indra/newview/skins/minimal/xui/en/panel_navigation_bar.xml b/indra/newview/skins/minimal/xui/en/panel_navigation_bar.xml index e50911b8d2..73a8564274 100644 --- a/indra/newview/skins/minimal/xui/en/panel_navigation_bar.xml +++ b/indra/newview/skins/minimal/xui/en/panel_navigation_bar.xml @@ -63,7 +63,7 @@ width="31" />       mouse_opaque="false"       name="location_combo"       top_delta="0" -     width="390"> +     width="325">      </location_input>      <icon follows="right"            height="20" diff --git a/indra/newview/skins/minimal/xui/en/panel_status_bar.xml b/indra/newview/skins/minimal/xui/en/panel_status_bar.xml index 42e6f30d48..fdd6b5d6ec 100644 --- a/indra/newview/skins/minimal/xui/en/panel_status_bar.xml +++ b/indra/newview/skins/minimal/xui/en/panel_status_bar.xml @@ -12,7 +12,7 @@   name="status"   top="19"   tab_stop="false" - width="120"> + width="185">      <panel.string       name="packet_loss_tooltip">          Packet Loss @@ -33,18 +33,27 @@       name="buycurrencylabel">          L$ [AMT]      </panel.string> -  <menu_button -     follows="right|top"     -    image_color="0 0 0 0" -    hover_glow_amount="0" -    left="5" -    top="7" -    width="55"   -    height="18" -    label="Mode ▼" -    tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features." -    menu_filename="menu_mode_change.xml" -    /> +  <combo_box +   follows="right|top" +   left_pad="5" +   drop_down_button.pad_left="10" +   left="0" +   top="5" +   pad_left="5" +   width="120" +   height="23" +   name="mode_combo" +   tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features." +    > +    <combo_box.item +      label="Basic Mode" +      name="Basic" +      value="settings_minimal.xml" /> +    <combo_box.item +      label="Advanced Mode" +      name="Advanced" +      value="" /> +  </combo_box>       <button       follows="right|top"       height="16" @@ -53,7 +62,7 @@       image_pressed="Pause_Press"       image_pressed_selected="Play_Press"       is_toggle="true" -     left="65" +     left_pad="5"       top="7"       name="media_toggle_btn"       tool_tip="Start/Stop All Media (Music, Video, Web pages)" | 
