diff options
| author | Dave SIMmONs <simon@lindenlab.com> | 2011-05-16 16:16:11 -0700 | 
|---|---|---|
| committer | Dave SIMmONs <simon@lindenlab.com> | 2011-05-16 16:16:11 -0700 | 
| commit | eaf293f62f06e37f914efaf1cd33ab63648699d4 (patch) | |
| tree | 1110079e0deff4b48e9eb841b3b6883f0c6e4b0d | |
| parent | 8a6965a3f94c0e56e0c2b17af329a6ac2c235735 (diff) | |
| parent | 113f532ee57eeeca4dc7eb6ca05f923f1f3543d3 (diff) | |
Merge latest from lindenlab/viewer-development
30 files changed, 346 insertions, 99 deletions
@@ -109,3 +109,6 @@ d7fcefabdf32bb61a9ea6d6037c1bb26190a85bc 2.6.3-beta1  bb1075286b3b147b1dae2e3d6b2d56f04ff03f35 DRTVWR-52_2.6.6-beta1  bb1075286b3b147b1dae2e3d6b2d56f04ff03f35 2.6.6-beta1  5e349dbe9cc84ea5795af8aeb6d473a0af9d4953 2.6.8-start +11d5d8080e67c3955914caf98f2eb116af30e55a 2.6.9-start +11d5d8080e67c3955914caf98f2eb116af30e55a 2.6.9-start +e67da2c6e3125966dd49eef98b36317afac1fcfe 2.6.9-start diff --git a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp index 60ddf63b21..976aae08bb 100644 --- a/indra/integration_tests/llimage_libtest/llimage_libtest.cpp +++ b/indra/integration_tests/llimage_libtest/llimage_libtest.cpp @@ -70,6 +70,10 @@ static const char USAGE[] = "\n"  "        be used. Blocks must be smaller than precincts. Like precincts, this option adds\n"  "        PLT, tile markers and uses RPCL.\n"  "        Only valid for output j2c images. Default is 64.\n" +" -l, --levels <n>\n" +"        Number of decomposition levels (aka discard levels) in the output image.\n" +"        The maximum number of levels authorized is 32.\n" +"        Only valid for output j2c images. Default is 5.\n"  " -rev, --reversible\n"  "        Set the compression to be lossless (reversible in j2c parlance).\n"  "        Only valid for output j2c images.\n" @@ -147,7 +151,7 @@ LLPointer<LLImageRaw> load_image(const std::string &src_filename, int discard_le  }  // Save a raw image instance into a file -bool save_image(const std::string &dest_filename, LLPointer<LLImageRaw> raw_image, int blocks_size, int precincts_size, bool reversible, bool output_stats) +bool save_image(const std::string &dest_filename, LLPointer<LLImageRaw> raw_image, int blocks_size, int precincts_size, int levels, bool reversible, bool output_stats)  {  	LLPointer<LLImageFormatted> image = create_image(dest_filename); @@ -156,9 +160,9 @@ bool save_image(const std::string &dest_filename, LLPointer<LLImageRaw> raw_imag  	{  		// That method doesn't exist (and likely, doesn't make sense) for any other image file format  		// hence the required cryptic cast. -		if ((blocks_size != -1) || (precincts_size != -1)) +		if ((blocks_size != -1) || (precincts_size != -1) || (levels != 0))  		{ -			((LLImageJ2C*)(image.get()))->initEncode(*raw_image, blocks_size, precincts_size); +			((LLImageJ2C*)(image.get()))->initEncode(*raw_image, blocks_size, precincts_size, levels);  		}  		((LLImageJ2C*)(image.get()))->setReversible(reversible);  	} @@ -306,6 +310,7 @@ int main(int argc, char** argv)  	int discard_level = -1;  	int precincts_size = -1;  	int blocks_size = -1; +	int levels = 0;  	bool reversible = false;  	// Init whatever is necessary @@ -403,7 +408,6 @@ int main(int argc, char** argv)  			else  			{  				precincts_size = atoi(value_str.c_str()); -				// *TODO: make sure precincts_size is a power of 2  			}  		}  		else if (!strcmp(argv[arg], "--blocks") || !strcmp(argv[arg], "-b")) @@ -420,7 +424,22 @@ int main(int argc, char** argv)  			else  			{  				blocks_size = atoi(value_str.c_str()); -				// *TODO: make sure blocks_size is a power of 2 +			} +		} +		else if (!strcmp(argv[arg], "--levels") || !strcmp(argv[arg], "-l")) +		{ +			std::string value_str; +			if ((arg + 1) < argc) +			{ +				value_str = argv[arg+1]; +			} +			if (((arg + 1) >= argc) || (value_str[0] == '-')) +			{ +				std::cout << "No valid --levels argument given, default (5) will be used" << std::endl; +			} +			else +			{ +				levels = atoi(value_str.c_str());  			}  		}  		else if (!strcmp(argv[arg], "--reversible") || !strcmp(argv[arg], "-rev")) @@ -499,7 +518,7 @@ int main(int argc, char** argv)  		// Save file  		if (out_file != out_end)  		{ -			if (!save_image(*out_file, raw_image, blocks_size, precincts_size, reversible, image_stats)) +			if (!save_image(*out_file, raw_image, blocks_size, precincts_size, levels, reversible, image_stats))  			{  				std::cout << "Error: Image " << *out_file << " could not be saved" << std::endl;  			} diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 18444f3934..c464c3b2b6 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -35,8 +35,21 @@  const S32 MIN_IMAGE_MIP =  2; // 4x4, only used for expand/contract power of 2  const S32 MAX_IMAGE_MIP = 11; // 2048x2048 + +// *TODO : Use MAX_IMAGE_MIP as max discard level and modify j2c management so that the number  +// of levels is read from the header's file, not inferred from its size.  const S32 MAX_DISCARD_LEVEL = 5; +// JPEG2000 size constraints +// Those are declared here as they are germane to other image constraints used in the viewer +// and declared right here. Some come from the JPEG2000 spec, some conventions specific to SL. +const S32 MAX_DECOMPOSITION_LEVELS = 32;	// Number of decomposition levels cannot exceed 32 according to jpeg2000 spec +const S32 MIN_DECOMPOSITION_LEVELS = 5;		// the SL viewer will *crash* trying to decode images with fewer than 5 decomposition levels (unless image is small that is) +const S32 MAX_PRECINCT_SIZE = 2048;			// No reason to be bigger than MAX_IMAGE_SIZE  +const S32 MIN_PRECINCT_SIZE = 4;			// Can't be smaller than MIN_BLOCK_SIZE +const S32 MAX_BLOCK_SIZE = 64;				// Max total block size is 4096, hence 64x64 when using square blocks +const S32 MIN_BLOCK_SIZE = 4;				// Min block dim is 4 according to jpeg2000 spec +  const S32 MIN_IMAGE_SIZE = (1<<MIN_IMAGE_MIP); // 4, only used for expand/contract power of 2  const S32 MAX_IMAGE_SIZE = (1<<MAX_IMAGE_MIP); // 2048  const S32 MIN_IMAGE_AREA = MIN_IMAGE_SIZE * MIN_IMAGE_SIZE; diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index a90df0f1c1..44e6b89dd3 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -144,9 +144,9 @@ BOOL LLImageJ2C::initDecode(LLImageRaw &raw_image, int discard_level, int* regio  	return mImpl->initDecode(*this,raw_image,discard_level,region);  } -BOOL LLImageJ2C::initEncode(LLImageRaw &raw_image, int blocks_size, int precincts_size) +BOOL LLImageJ2C::initEncode(LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)  { -	return mImpl->initEncode(*this,raw_image,blocks_size,precincts_size); +	return mImpl->initEncode(*this,raw_image,blocks_size,precincts_size,levels);  }  BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time) diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h index 6bba81aab5..914174fc57 100644 --- a/indra/llimage/llimagej2c.h +++ b/indra/llimage/llimagej2c.h @@ -57,7 +57,7 @@ public:  	/*virtual*/ void setLastError(const std::string& message, const std::string& filename = std::string());  	BOOL initDecode(LLImageRaw &raw_image, int discard_level, int* region); -	BOOL initEncode(LLImageRaw &raw_image, int blocks_size, int precincts_size); +	BOOL initEncode(LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels);  	// Encode with comment text   	BOOL encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time=0.0); @@ -120,7 +120,7 @@ protected:  	virtual BOOL encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,  							BOOL reversible=FALSE) = 0;  	virtual BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL) = 0; -	virtual BOOL initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1) = 0; +	virtual BOOL initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1, int levels = 0) = 0;  	friend class LLImageJ2C;  }; diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp index 8288fa1f5c..d15824ce5a 100644 --- a/indra/llimagej2coj/llimagej2coj.cpp +++ b/indra/llimagej2coj/llimagej2coj.cpp @@ -113,7 +113,7 @@ BOOL LLImageJ2COJ::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int disca  	return FALSE;  } -BOOL LLImageJ2COJ::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size) +BOOL LLImageJ2COJ::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)  {  	// No specific implementation for this method in the OpenJpeg case  	return FALSE; diff --git a/indra/llimagej2coj/llimagej2coj.h b/indra/llimagej2coj/llimagej2coj.h index 9c7cc09fcb..40ad4edb00 100644 --- a/indra/llimagej2coj/llimagej2coj.h +++ b/indra/llimagej2coj/llimagej2coj.h @@ -40,7 +40,7 @@ protected:  	/*virtual*/ BOOL encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,  								BOOL reversible = FALSE);  	/*virtual*/ BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL); -	/*virtual*/ BOOL initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1); +	/*virtual*/ BOOL initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1, int levels = 0);  };  #endif diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index ae456a48be..39ae09650e 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -29,6 +29,7 @@  #include "lltimer.h"  #include "llpointer.h" +#include "llmath.h"  #include "llkdumem.h" @@ -192,7 +193,8 @@ mTileIndicesp(NULL),  mRawImagep(NULL),  mDecodeState(NULL),  mBlocksSize(-1), -mPrecinctsSize(-1) +mPrecinctsSize(-1), +mLevels(0)  {  } @@ -328,10 +330,29 @@ BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int disc  	return initDecode(base,raw_image,0.0f,MODE_FAST,0,4,discard_level,region);  } -BOOL LLImageJ2CKDU::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size) +BOOL LLImageJ2CKDU::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)  { -	mBlocksSize = blocks_size;  	mPrecinctsSize = precincts_size; +	if (mPrecinctsSize != -1) +	{ +		mPrecinctsSize = get_lower_power_two(mPrecinctsSize,MAX_PRECINCT_SIZE); +		mPrecinctsSize = llmax(mPrecinctsSize,MIN_PRECINCT_SIZE); +	} +	mBlocksSize = blocks_size; +	if (mBlocksSize != -1) +	{ +		mBlocksSize = get_lower_power_two(mBlocksSize,MAX_BLOCK_SIZE); +		mBlocksSize = llmax(mBlocksSize,MIN_BLOCK_SIZE); +		if (mPrecinctsSize != -1) +		{ +			mBlocksSize = llmin(mBlocksSize,mPrecinctsSize);	// blocks *must* be smaller than precincts +		} +	} +	mLevels = levels; +	if (mLevels != 0) +	{ +		mLevels = llclamp(mLevels,MIN_DECOMPOSITION_LEVELS,MIN_DECOMPOSITION_LEVELS);		 +	}  	return TRUE;  } @@ -373,10 +394,12 @@ BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco  		// Resize raw_image according to the image to be decoded  		kdu_dims dims; mCodeStreamp->get_dims(0,dims); +		// *TODO: Use the real number of levels read from the file throughout the code instead of relying on an infered value from dimensions +		//S32 levels = mCodeStreamp->get_min_dwt_levels();  		S32 channels = base.getComponents() - first_channel;  		channels = llmin(channels,max_channel_count);  		raw_image.resize(dims.size.x, dims.size.y, channels); -		//	llinfos << "Resizing raw_image to " << dims.size.x << ":" << dims.size.y << llendl; +		//llinfos << "j2c image dimension: width = " << dims.size.x << ", height = " << dims.size.y << ", channels = " << channels << ", levels = " << levels << llendl;  		if (!mTileIndicesp)  		{ @@ -653,6 +676,11 @@ BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co  			std::string Parts_string = llformat("ORGtparts=R");  			codestream.access_siz()->parse_string(Parts_string.c_str());  		} +		if (mLevels != 0) +		{ +			std::string levels_string = llformat("Clevels=%d",mLevels); +			codestream.access_siz()->parse_string(levels_string.c_str()); +		}  		codestream.access_siz()->finalize_all();  		codestream.change_appearance(transpose,vflip,hflip); diff --git a/indra/llkdu/llimagej2ckdu.h b/indra/llkdu/llimagej2ckdu.h index 9fce58b762..1489dbf704 100644 --- a/indra/llkdu/llimagej2ckdu.h +++ b/indra/llkdu/llimagej2ckdu.h @@ -59,7 +59,7 @@ protected:  	/*virtual*/ BOOL encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,  								BOOL reversible=FALSE);  	/*virtual*/ BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL); -	/*virtual*/ BOOL initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1); +	/*virtual*/ BOOL initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1, int levels = 0);  private:  	BOOL initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count, int discard_level = -1, int* region = NULL); @@ -73,6 +73,7 @@ private:  	kdu_dims *mTileIndicesp;  	int mBlocksSize;  	int mPrecinctsSize; +	int mLevels;  	// Temporary variables for in-progress decodes...  	LLImageRaw *mRawImagep; diff --git a/indra/llkdu/tests/llimagej2ckdu_test.cpp b/indra/llkdu/tests/llimagej2ckdu_test.cpp index 7ac24a969a..ab60ab6d50 100644 --- a/indra/llkdu/tests/llimagej2ckdu_test.cpp +++ b/indra/llkdu/tests/llimagej2ckdu_test.cpp @@ -134,6 +134,7 @@ kdu_params* kdu_params::access_cluster(const char*) { return NULL; }  void kdu_codestream::set_fast() { }  void kdu_codestream::set_fussy() { }  void kdu_codestream::get_dims(int, kdu_dims&, bool ) { } +int kdu_codestream::get_min_dwt_levels() { return 5; }  void kdu_codestream::change_appearance(bool, bool, bool) { }  void kdu_codestream::get_tile_dims(kdu_coords, int, kdu_dims&, bool ) { }  void kdu_codestream::destroy() { } diff --git a/indra/llmessage/tests/commtest.h b/indra/llmessage/tests/commtest.h index 32035783e2..0fef596df2 100644 --- a/indra/llmessage/tests/commtest.h +++ b/indra/llmessage/tests/commtest.h @@ -35,6 +35,13 @@  #include "llhost.h"  #include "stringize.h"  #include <string> +#include <stdexcept> +#include <boost/lexical_cast.hpp> + +struct CommtestError: public std::runtime_error +{ +    CommtestError(const std::string& what): std::runtime_error(what) {} +};  /**   * This struct is shared by a couple of standalone comm tests (ADD_COMM_BUILD_TEST). @@ -55,13 +62,24 @@ struct commtest_data          replyPump("reply"),          errorPump("error"),          success(false), -        host("127.0.0.1", 8000), +        host("127.0.0.1", getport("PORT")),          server(STRINGIZE("http://" << host.getString() << "/"))      {          replyPump.listen("self", boost::bind(&commtest_data::outcome, this, _1, true));          errorPump.listen("self", boost::bind(&commtest_data::outcome, this, _1, false));      } +    static int getport(const std::string& var) +    { +        const char* port = getenv(var.c_str()); +        if (! port) +        { +            throw CommtestError("missing $PORT environment variable"); +        } +        // This will throw, too, if the value of PORT isn't numeric. +        return boost::lexical_cast<int>(port); +    } +      bool outcome(const LLSD& _result, bool _success)      {  //      std::cout << "commtest_data::outcome(" << _result << ", " << _success << ")\n"; diff --git a/indra/llmessage/tests/test_llsdmessage_peer.py b/indra/llmessage/tests/test_llsdmessage_peer.py index 580ee7f8b4..cea5032111 100644 --- a/indra/llmessage/tests/test_llsdmessage_peer.py +++ b/indra/llmessage/tests/test_llsdmessage_peer.py @@ -38,7 +38,7 @@ mydir = os.path.dirname(__file__)       # expected to be .../indra/llmessage/tes  sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "lib", "python"))  from indra.util.fastest_elementtree import parse as xml_parse  from indra.base import llsd -from testrunner import run, debug +from testrunner import freeport, run, debug  class TestHTTPRequestHandler(BaseHTTPRequestHandler):      """This subclass of BaseHTTPRequestHandler is to receive and echo @@ -97,6 +97,10 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):              self.wfile.write(response)          else:                           # fail requested              status = data.get("status", 500) +            # self.responses maps an int status to a (short, long) pair of +            # strings. We want the longer string. That's why we pass a string +            # pair to get(): the [1] will select the second string, whether it +            # came from self.responses or from our default pair.              reason = data.get("reason",                                 self.responses.get(status,                                                    ("fail requested", @@ -113,11 +117,17 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):          # Suppress error output as well          pass -class TestHTTPServer(Thread): -    def run(self): -        httpd = HTTPServer(('127.0.0.1', 8000), TestHTTPRequestHandler) -        debug("Starting HTTP server...\n") -        httpd.serve_forever() -  if __name__ == "__main__": -    sys.exit(run(server=TestHTTPServer(name="httpd"), *sys.argv[1:])) +    # Instantiate an HTTPServer(TestHTTPRequestHandler) on the first free port +    # in the specified port range. Doing this inline is better than in a +    # daemon thread: if it blows up here, we'll get a traceback. If it blew up +    # in some other thread, the traceback would get eaten and we'd run the +    # subject test program anyway. +    httpd, port = freeport(xrange(8000, 8020), +                           lambda port: HTTPServer(('127.0.0.1', port), TestHTTPRequestHandler)) +    # Pass the selected port number to the subject test program via the +    # environment. We don't want to impose requirements on the test program's +    # command-line parsing -- and anyway, for C++ integration tests, that's +    # performed in TUT code rather than our own. +    os.environ["PORT"] = str(port) +    sys.exit(run(server=Thread(name="httpd", target=httpd.serve_forever), *sys.argv[1:])) diff --git a/indra/llmessage/tests/testrunner.py b/indra/llmessage/tests/testrunner.py index b70ce91ee7..8ff13e0426 100644 --- a/indra/llmessage/tests/testrunner.py +++ b/indra/llmessage/tests/testrunner.py @@ -29,6 +29,8 @@ $/LicenseInfo$  import os  import sys +import errno +import socket  def debug(*args):      sys.stdout.writelines(args) @@ -36,6 +38,85 @@ def debug(*args):  # comment out the line below to enable debug output  debug = lambda *args: None +def freeport(portlist, expr): +    """ +    Find a free server port to use. Specifically, evaluate 'expr' (a +    callable(port)) until it stops raising EADDRINUSE exception. + +    Pass: + +    portlist: an iterable (e.g. xrange()) of ports to try. If you exhaust the +    range, freeport() lets the socket.error exception propagate. If you want +    unbounded, you could pass itertools.count(baseport), though of course in +    practice the ceiling is 2^16-1 anyway. But it seems prudent to constrain +    the range much more sharply: if we're iterating an absurd number of times, +    probably something else is wrong. + +    expr: a callable accepting a port number, specifically one of the items +    from portlist. If calling that callable raises socket.error with +    EADDRINUSE, freeport() retrieves the next item from portlist and retries. + +    Returns: (expr(port), port) + +    port: the value from portlist for which expr(port) succeeded + +    Raises: + +    Any exception raised by expr(port) other than EADDRINUSE. + +    socket.error if, for every item from portlist, expr(port) raises +    socket.error. The exception you see is the one from the last item in +    portlist. + +    StopIteration if portlist is completely empty. + +    Example: + +    server, port = freeport(xrange(8000, 8010), +                            lambda port: HTTPServer(("localhost", port), +                                                    MyRequestHandler)) +    # pass 'port' to client code +    # call server.serve_forever() +    """ +    # If portlist is completely empty, let StopIteration propagate: that's an +    # error because we can't return meaningful values. We have no 'port', +    # therefore no 'expr(port)'. +    portiter = iter(portlist) +    port = portiter.next() + +    while True: +        try: +            # If this value of port works, return as promised. +            return expr(port), port + +        except socket.error, err: +            # Anything other than 'Address already in use', propagate +            if err.args[0] != errno.EADDRINUSE: +                raise + +            # Here we want the next port from portiter. But on StopIteration, +            # we want to raise the original exception rather than +            # StopIteration. So save the original exc_info(). +            type, value, tb = sys.exc_info() +            try: +                try: +                    port = portiter.next() +                except StopIteration: +                    raise type, value, tb +            finally: +                # Clean up local traceback, see docs for sys.exc_info() +                del tb + +        # Recap of the control flow above: +        # If expr(port) doesn't raise, return as promised. +        # If expr(port) raises anything but EADDRINUSE, propagate that +        # exception. +        # If portiter.next() raises StopIteration -- that is, if the port +        # value we just passed to expr(port) was the last available -- reraise +        # the EADDRINUSE exception. +        # If we've actually arrived at this point, portiter.next() delivered a +        # new port value. Loop back to pass that to expr(port). +  def run(*args, **kwds):      """All positional arguments collectively form a command line, executed as      a synchronous child process. diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index ac52cff49a..33c5e533be 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -4284,6 +4284,39 @@        <key>Value</key>          <real>0.25</real>        </map> +	<key>Jpeg2000AdvancedCompression</key> +	  <map> +      <key>Comment</key> +        <string>Use advanced Jpeg2000 compression options (precincts, blocks, ordering, markers)</string> +      <key>Persist</key> +        <integer>1</integer> +      <key>Type</key> +        <string>Boolean</string> +      <key>Value</key> +        <integer>0</integer> +	  </map> +	<key>Jpeg2000PrecinctsSize</key> +	  <map> +      <key>Comment</key> +        <string>Size of image precincts. Assumed square and same for all levels. Must be power of 2.</string> +      <key>Persist</key> +        <integer>1</integer> +      <key>Type</key> +        <string>S32</string> +      <key>Value</key> +        <integer>256</integer> +	  </map> +	<key>Jpeg2000BlocksSize</key> +	  <map> +      <key>Comment</key> +        <string>Size of encoding blocks. Assumed square and same for all levels. Must be power of 2. Max 64, Min 4.</string> +      <key>Persist</key> +        <integer>1</integer> +      <key>Type</key> +        <string>S32</string> +      <key>Value</key> +        <integer>64</integer> +	  </map>      <key>KeepAspectForSnapshot</key>      <map>        <key>Comment</key> diff --git a/indra/newview/app_settings/settings_minimal.xml b/indra/newview/app_settings/settings_minimal.xml index d3f0ec5dad..70a75cb4ca 100644 --- a/indra/newview/app_settings/settings_minimal.xml +++ b/indra/newview/app_settings/settings_minimal.xml @@ -45,15 +45,6 @@          <key>Value</key>              <integer>0</integer>          </map> -    <key>EnableVoiceChat</key> -        <map> -        <key>Comment</key> -            <string>Enable talking to other residents with a microphone</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <integer>1</integer> -        </map>      <key>HelpURLFormat</key>          <map>          <key>Comment</key> diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml index 8efec1cff0..ff24efaf2c 100644 --- a/indra/newview/app_settings/settings_per_account.xml +++ b/indra/newview/app_settings/settings_per_account.xml @@ -44,6 +44,17 @@          <key>Value</key>              <integer>0</integer>          </map> +    <key>LastPostcardRecipient</key> +      <map> +        <key>Comment</key> +          <string>Last recipient of postcard</string> +        <key>Persist</key> +          <integer>1</integer> +        <key>Type</key> +          <string>String</string> +        <key>Value</key> +          <string /> +      </map>      <key>LogNearbyChat</key>          <map>          <key>Comment</key> diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp index c72cdfd1dc..f51552aae5 100644 --- a/indra/newview/llbottomtray.cpp +++ b/indra/newview/llbottomtray.cpp @@ -559,7 +559,7 @@ BOOL LLBottomTray::postBuild()  	else  	{  		LLTransientFloaterMgr::getInstance()->addControlView(getChild<LLButton>("speak_btn")); -		LLTransientFloaterMgr::getInstance()->addControlView(getChild<LLButton>("speak_flyout_btn")); +		LLTransientFloaterMgr::getInstance()->addControlView(getChild<LLButton>("flyout_btn"));  	} @@ -1591,7 +1591,7 @@ void LLBottomTray::initResizeStateContainers()  // because it resets chatbar's width according to resize logic.  void LLBottomTray::initButtonsVisibility()  { -	setVisibleAndFitWidths(RS_BUTTON_SPEAK, gSavedSettings.getBOOL("EnableVoiceChat")); +	setVisibleAndFitWidths(RS_BUTTON_SPEAK, gSavedSettings.getBOOL("EnableVoiceChat") || !mSpeakBtn );  	setVisibleAndFitWidths(RS_BUTTON_GESTURES, gSavedSettings.getBOOL("ShowGestureButton"));  	setVisibleAndFitWidths(RS_BUTTON_MOVEMENT, gSavedSettings.getBOOL("ShowMoveButton"));  	setVisibleAndFitWidths(RS_BUTTON_CAMERA, gSavedSettings.getBOOL("ShowCameraButton")); @@ -1605,7 +1605,12 @@ void LLBottomTray::initButtonsVisibility()  void LLBottomTray::setButtonsControlsAndListeners()  { -	gSavedSettings.getControl("EnableVoiceChat")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_SPEAK, _2)); +	// always show the speak panel if using the basic skin +	if (mSpeakBtn) +	{ +		gSavedSettings.getControl("EnableVoiceChat")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_SPEAK, _2)); +	}	 +  	gSavedSettings.getControl("ShowGestureButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_GESTURES, _2));  	gSavedSettings.getControl("ShowMoveButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_MOVEMENT, _2));  	gSavedSettings.getControl("ShowCameraButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_CAMERA, _2)); diff --git a/indra/newview/llfloatersounddevices.cpp b/indra/newview/llfloatersounddevices.cpp index 3903b9b015..9fe7c7f9dd 100644 --- a/indra/newview/llfloatersounddevices.cpp +++ b/indra/newview/llfloatersounddevices.cpp @@ -56,7 +56,7 @@ BOOL LLFloaterSoundDevices::postBuild()  {  	LLTransientDockableFloater::postBuild(); -	LLView *anchor_panel = LLBottomTray::getInstance()->getChild<LLView>("speak_flyout_btn"); +	LLView *anchor_panel = LLBottomTray::getInstance()->getChild<LLView>("flyout_btn");  	setDockControl(new LLDockControl(anchor_panel, this, getDockTongue(), LLDockControl::TOP));  	setIsChrome(TRUE); diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 4ac3a248d3..27f341b4f6 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -769,7 +769,10 @@ void LLPanelLogin::loadLoginPage()  	gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid());  	LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html"); -	web_browser->navigateTo( oStr.str(), "text/html" ); +	if (web_browser->getCurrentNavUrl() != oStr.str()) +	{ +		web_browser->navigateTo( oStr.str(), "text/html" ); +	}  }  void LLPanelLogin::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent event) diff --git a/indra/newview/llpanelvoicedevicesettings.cpp b/indra/newview/llpanelvoicedevicesettings.cpp index 71bb4a5584..dc87bd0077 100644 --- a/indra/newview/llpanelvoicedevicesettings.cpp +++ b/indra/newview/llpanelvoicedevicesettings.cpp @@ -221,23 +221,7 @@ void LLPanelVoiceDeviceSettings::refresh()  				iter != LLVoiceClient::getInstance()->getCaptureDevices().end();  				iter++)  			{ -				// Lets try to localize some system device names. EXT-8375 -				std::string device_name = *iter; -				LLStringUtil::toLower(device_name); //compare in low case -				if ("default system device" == device_name) -				{ -					device_name = getString(device_name); -				} -				else if ("no device" == device_name) -				{ -					device_name = getString(device_name); -				} -				else -				{ -					// restore original value -					device_name = *iter; -				} -				mCtrlInputDevices->add(device_name, ADD_BOTTOM ); +				mCtrlInputDevices->add( *iter, ADD_BOTTOM );  			}  			if(!mCtrlInputDevices->setSimple(mInputDevice)) @@ -254,23 +238,7 @@ void LLPanelVoiceDeviceSettings::refresh()  			for(iter= LLVoiceClient::getInstance()->getRenderDevices().begin();   				iter !=  LLVoiceClient::getInstance()->getRenderDevices().end(); iter++)  			{ -				// Lets try to localize some system device names. EXT-8375 -				std::string device_name = *iter; -				LLStringUtil::toLower(device_name); //compare in low case -				if ("default system device" == device_name) -				{ -					device_name = getString(device_name); -				} -				else if ("no device" == device_name) -				{ -					device_name = getString(device_name); -				} -				else -				{ -					// restore original value -					device_name = *iter; -				} -				mCtrlOutputDevices->add(device_name, ADD_BOTTOM ); +				mCtrlOutputDevices->add( *iter, ADD_BOTTOM );  			}  			if(!mCtrlOutputDevices->setSimple(mOutputDevice)) diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index fea5345f9c..298e789f65 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -5373,6 +5373,12 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem)  	{  		// notification was specified using the new mechanism, so we can just handle it here  		std::string notificationID; +		msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID);
 +		if (!LLNotifications::getInstance()->templateExists(notificationID))
 +		{
 +			return false;
 +		} +  		std::string llsdRaw;  		LLSD llsdBlock;  		msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID); diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index d331779e1f..33e7328cd7 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -946,16 +946,19 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename,  	LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);  	if (image.isNull())  	{ +		image->setLastError("Couldn't open the image to be uploaded.");  		return FALSE;  	}	  	if (!image->load(filename))  	{ +		image->setLastError("Couldn't load the image to be uploaded.");  		return FALSE;  	}  	// Decompress or expand it in a raw image structure  	LLPointer<LLImageRaw> raw_image = new LLImageRaw;  	if (!image->decode(raw_image, 0.0f))  	{ +		image->setLastError("Couldn't decode the image to be uploaded.");  		return FALSE;  	}  	// Check the image constraints @@ -966,8 +969,15 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename,  	}  	// Convert to j2c (JPEG2000) and save the file locally  	LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image);	 +	if (compressedImage.isNull()) +	{ +		image->setLastError("Couldn't convert the image to jpeg2000."); +		llinfos << "Couldn't convert to j2c, file : " << filename << llendl; +		return FALSE; +	}  	if (!compressedImage->save(out_filename))  	{ +		image->setLastError("Couldn't create the jpeg2000 image for upload.");  		llinfos << "Couldn't create output file : " << out_filename << llendl;  		return FALSE;  	} @@ -975,6 +985,7 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename,  	LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C;  	if (!integrity_test->loadAndValidate( out_filename ))  	{ +		image->setLastError("The created jpeg2000 image is corrupt.");  		llinfos << "Image file : " << out_filename << " is corrupt" << llendl;  		return FALSE;  	} @@ -992,7 +1003,25 @@ LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImage  		(raw_image->getWidth() * raw_image->getHeight() <= LL_IMAGE_REZ_LOSSLESS_CUTOFF * LL_IMAGE_REZ_LOSSLESS_CUTOFF))  		compressedImage->setReversible(TRUE); -	compressedImage->encode(raw_image, 0.0f); + +	if (gSavedSettings.getBOOL("Jpeg2000AdvancedCompression")) +	{ +		// This test option will create jpeg2000 images with precincts for each level, RPCL ordering +		// and PLT markers. The block size is also optionally modifiable. +		// Note: the images hence created are compatible with older versions of the viewer. +		// Read the blocks and precincts size settings +		S32 block_size = gSavedSettings.getS32("Jpeg2000BlocksSize"); +		S32 precinct_size = gSavedSettings.getS32("Jpeg2000PrecinctsSize"); +		llinfos << "Advanced JPEG2000 Compression: precinct = " << precinct_size << ", block = " << block_size << llendl; +		compressedImage->initEncode(*raw_image, block_size, precinct_size, 0); +	} +	 +	if (!compressedImage->encode(raw_image, 0.0f)) +	{ +		llinfos << "convertToUploadFile : encode returns with error!!" << llendl; +		// Clear up the pointer so we don't leak that one +		compressedImage = NULL; +	}  	return compressedImage;  } diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index a71539266d..bd12328a6b 100644 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -412,6 +412,7 @@ void LLVoiceChannel::doSetState(const EState& new_state)  {  	EState old_state = mState;  	mState = new_state; +  	if (!mStateChangedCallback.empty())  		mStateChangedCallback(old_state, mState, mCallDirection, mCallEndedByAgent);  } @@ -846,8 +847,13 @@ void LLVoiceChannelP2P::activate()  		// otherwise answering the call  		else  		{ -			LLVoiceClient::getInstance()->answerInvite(mSessionHandle); -			 +			if (!LLVoiceClient::getInstance()->answerInvite(mSessionHandle)) +			{ +				mCallEndedByAgent = false; +				mSessionHandle.clear(); +				handleError(ERROR_UNKNOWN); +				return; +			}  			// using the session handle invalidates it.  Clear it out here so we can't reuse it by accident.  			mSessionHandle.clear();  		} diff --git a/indra/newview/skins/default/xui/en/floater_postcard.xml b/indra/newview/skins/default/xui/en/floater_postcard.xml index b4ecedd981..8da35e9d7f 100644 --- a/indra/newview/skins/default/xui/en/floater_postcard.xml +++ b/indra/newview/skins/default/xui/en/floater_postcard.xml @@ -36,6 +36,7 @@          Recipient's Email:      </text>      <line_editor +     control_name="LastPostcardRecipient"       follows="left|top"       height="20"       layout="topleft" diff --git a/indra/newview/skins/default/xui/en/floater_script_debug_panel.xml b/indra/newview/skins/default/xui/en/floater_script_debug_panel.xml index d1db5c17ba..ce96ea232e 100644 --- a/indra/newview/skins/default/xui/en/floater_script_debug_panel.xml +++ b/indra/newview/skins/default/xui/en/floater_script_debug_panel.xml @@ -20,5 +20,6 @@       parse_highlights="true"        read_only="true"       width="420" +     track_bottom="true"        word_wrap="true" />  </floater> diff --git a/indra/newview/skins/default/xui/en/floater_sound_devices.xml b/indra/newview/skins/default/xui/en/floater_sound_devices.xml index c7c7a05af2..304987c3d5 100644 --- a/indra/newview/skins/default/xui/en/floater_sound_devices.xml +++ b/indra/newview/skins/default/xui/en/floater_sound_devices.xml @@ -11,7 +11,7 @@   save_rect="true"   single_instance="true"   bevel_style="in" - height="140" + height="164"   layout="topleft"   name="floater_sound_devices"   title="Sound Devices" @@ -25,4 +25,23 @@      left="2"      top="26"      class="panel_voice_device_settings"/> +  <text +    name="voice_label" +    top="136" +    left="12" +    height="14" +    width="80" +    layout="topleft" +    >Voice Chat</text> +  <check_box +    layout="topleft" +    control_name="EnableVoiceChat" +    follows="bottom|left" +    top="138" +    left="80" +    name="enable_voice" +    width="100" +    height="14" +    label="Enabled" +    />  </floater> diff --git a/indra/newview/skins/default/xui/en/panel_sound_devices.xml b/indra/newview/skins/default/xui/en/panel_sound_devices.xml index 9812281323..ccae7c5350 100644 --- a/indra/newview/skins/default/xui/en/panel_sound_devices.xml +++ b/indra/newview/skins/default/xui/en/panel_sound_devices.xml @@ -11,14 +11,6 @@  	  name="default_text">  		Default  	</panel.string> -	<panel.string -	  name="default system device"> -		Default system device -	</panel.string> -	<panel.string -	  name="no device"> -		No device -	</panel.string>  	<icon  		   height="18"  		   image_name="Microphone_On" diff --git a/indra/newview/skins/minimal/xui/en/panel_bottomtray.xml b/indra/newview/skins/minimal/xui/en/panel_bottomtray.xml index 237af61717..d722c54081 100644 --- a/indra/newview/skins/minimal/xui/en/panel_bottomtray.xml +++ b/indra/newview/skins/minimal/xui/en/panel_bottomtray.xml @@ -115,7 +115,7 @@          top="5"       left="0"       height="23" -     name="speak_flyout_btn" +     name="flyout_btn"       label=""       tab_stop="false"       tool_tip="Change your sound preferences" diff --git a/indra/newview/tests/llxmlrpclistener_test.cpp b/indra/newview/tests/llxmlrpclistener_test.cpp index 4d5df1043e..711c2a3d51 100644 --- a/indra/newview/tests/llxmlrpclistener_test.cpp +++ b/indra/newview/tests/llxmlrpclistener_test.cpp @@ -40,8 +40,10 @@  #include "llevents.h"  #include "lleventfilter.h"  #include "llsd.h" +#include "llhost.h"  #include "llcontrol.h"  #include "tests/wrapllerrs.h" +#include "tests/commtest.h"  LLControlGroup gSavedSettings("Global"); @@ -54,7 +56,8 @@ namespace tut      {          data():              pumps(LLEventPumps::instance()), -            uri("http://127.0.0.1:8000") +            uri(std::string("http://") + +                LLHost("127.0.0.1", commtest_data::getport("PORT")).getString())          {              // These variables are required by machinery used by              // LLXMLRPCTransaction. The values reflect reality for this test @@ -145,7 +148,7 @@ namespace tut          pumps.obtain("LLXMLRPCTransaction").post(request);          // Set the timer          F32 timeout(10); -        watchdog.eventAfter(timeout, LLSD().insert("timeout", 0)); +        watchdog.eventAfter(timeout, LLSD().with("timeout", 0));          // and pump "mainloop" until we get something, whether from          // LLXMLRPCListener or from the watchdog filter.          LLTimer timer; @@ -182,7 +185,7 @@ namespace tut          pumps.obtain("LLXMLRPCTransaction").post(request);          // Set the timer          F32 timeout(10); -        watchdog.eventAfter(timeout, LLSD().insert("timeout", 0)); +        watchdog.eventAfter(timeout, LLSD().with("timeout", 0));          // and pump "mainloop" until we get something, whether from          // LLXMLRPCListener or from the watchdog filter.          LLTimer timer; @@ -218,7 +221,7 @@ namespace tut          pumps.obtain("LLXMLRPCTransaction").post(request);          // Set the timer          F32 timeout(10); -        watchdog.eventAfter(timeout, LLSD().insert("timeout", 0)); +        watchdog.eventAfter(timeout, LLSD().with("timeout", 0));          // and pump "mainloop" until we get something, whether from          // LLXMLRPCListener or from the watchdog filter.          LLTimer timer; diff --git a/indra/newview/tests/test_llxmlrpc_peer.py b/indra/newview/tests/test_llxmlrpc_peer.py index 1c7204a6b6..281b72a058 100644 --- a/indra/newview/tests/test_llxmlrpc_peer.py +++ b/indra/newview/tests/test_llxmlrpc_peer.py @@ -37,7 +37,7 @@ from SimpleXMLRPCServer import SimpleXMLRPCServer  mydir = os.path.dirname(__file__)       # expected to be .../indra/newview/tests/  sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "lib", "python"))  sys.path.insert(1, os.path.join(mydir, os.pardir, os.pardir, "llmessage", "tests")) -from testrunner import run, debug +from testrunner import freeport, run, debug  class TestServer(SimpleXMLRPCServer):      def _dispatch(self, method, params): @@ -66,11 +66,16 @@ class TestServer(SimpleXMLRPCServer):          # Suppress error output as well          pass -class ServerRunner(Thread): -    def run(self): -        server = TestServer(('127.0.0.1', 8000)) -        debug("Starting XMLRPC server...\n") -        server.serve_forever() -  if __name__ == "__main__": -    sys.exit(run(server=ServerRunner(name="xmlrpc"), *sys.argv[1:])) +    # Instantiate a TestServer on the first free port in the specified port +    # range. Doing this inline is better than in a daemon thread: if it blows +    # up here, we'll get a traceback. If it blew up in some other thread, the +    # traceback would get eaten and we'd run the subject test program anyway. +    xmlrpcd, port = freeport(xrange(8000, 8020), +                             lambda port: TestServer(('127.0.0.1', port))) +    # Pass the selected port number to the subject test program via the +    # environment. We don't want to impose requirements on the test program's +    # command-line parsing -- and anyway, for C++ integration tests, that's +    # performed in TUT code rather than our own. +    os.environ["PORT"] = str(port) +    sys.exit(run(server=Thread(name="xmlrpc", target=xmlrpcd.serve_forever), *sys.argv[1:]))  | 
