merge changes for 4.1.1-release

master
Oz Linden 2016-10-18 15:38:33 -04:00
commit 8e30a2f06d
265 changed files with 10660 additions and 3937 deletions

View File

@ -517,3 +517,6 @@ e9d350764dfbf5a46229e627547ef5c1b1eeef00 4.0.2-release
0a5de9ec2cb868f367501024d8d6958c20869053 4.0.4-release
450de775fff66a011be1a001acd117cc623c445d 4.0.5-release
4070611edd95eb3a683d1cd97c4c07fe67793812 4.0.6-release
33981d8130f031597b4c7f4c981b18359afb61a0 4.0.7-release
45eaee56883df7a439ed3300c44d3126f7e3a41e 4.0.8-release
b280a1c797a3891e68dbc237e73de9cf19f426e9 4.1.1-release

View File

@ -90,4 +90,3 @@ EDU_viewer_channel_suffix = "edu"
# environment variable 'email' to a space-separated list of email addresses

View File

@ -1454,9 +1454,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>faa1e5b7cf70c143caabe190fa5588ce</string>
<string>fddd634dec5ec03924d62cc774f7f8ea</string>
<key>url</key>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/llappearance_viewer-update-llappearance-utility/rev/304432/arch/Linux/installer/llappearance_utility-0.0.1-linux-304432.tar.bz2</string>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/p64_viewer-llappearance-utility/rev/317266/arch/Linux/installer/llappearance_utility-0.0.1-linux-317266.tar.bz2</string>
</map>
<key>name</key>
<string>linux</string>
@ -1512,11 +1512,11 @@
<key>archive</key>
<map>
<key>hash</key>
<string>29a1f64df46094eda0d681821a98d17e</string>
<string>db992d58c46c80df7d4d31f8a4784b98</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llceflib_3p-llceflib/rev/311349/arch/Darwin/installer/llceflib-1.5.3.311349-darwin-311349.tar.bz2</string>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llceflib_3p-llceflib/rev/317959/arch/Darwin/installer/llceflib-1.5.3.317959-darwin-317959.tar.bz2</string>
</map>
<key>name</key>
<string>darwin</string>
@ -1526,18 +1526,18 @@
<key>archive</key>
<map>
<key>hash</key>
<string>827b7c339a2cd401d9d23f9ee02cb83f</string>
<string>bb3818628131a99cd789febfad9dc2c2</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llceflib_3p-llceflib/rev/311349/arch/CYGWIN/installer/llceflib-1.5.3.311349-windows-311349.tar.bz2</string>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llceflib_3p-llceflib/rev/317959/arch/CYGWIN/installer/llceflib-1.5.3.317959-windows-317959.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
</map>
</map>
<key>version</key>
<string>1.5.3.311349</string>
<string>1.5.3.317959</string>
</map>
<key>llphysicsextensions_source</key>
<map>
@ -2163,6 +2163,46 @@
<key>version</key>
<string>0.8.0.1</string>
</map>
<key>vlc-bin</key>
<map>
<key>copyright</key>
<string>Copyright (C) 1998-2016 VLC authors and VideoLAN</string>
<key>license</key>
<string>GPL2</string>
<key>license_file</key>
<string>LICENSES/vlc.txt</string>
<key>name</key>
<string>vlc-bin</string>
<key>platforms</key>
<map>
<key>linux</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>2f410640df3f9812d1abff02a414cfa8</string>
<key>url</key>
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-vlc-bin/rev/315283/arch/Linux/vlc_bin-2.2.3-linux-201606011750-r10.tar.bz2</string>
</map>
<key>name</key>
<string>linux</string>
</map>
<key>windows</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>04cff37070a5f65f3652b4ddcec7183f</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-vlc-bin/rev/317935/arch/CYGWIN/installer/vlc_bin-2.2.4.317935-windows-317935.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
</map>
</map>
<key>version</key>
<string>2.2.4.317935</string>
</map>
<key>xmlrpc-epi</key>
<map>
<key>copyright</key>

View File

@ -190,6 +190,9 @@ Ansariel Hiller
STORM-2094
MAINT-5756
MAINT-4677
MAINT-6432
STORM-2133
MAINT-6511
Aralara Rajal
Arare Chantilly
CHUIBUG-191

View File

@ -24,7 +24,6 @@ set(cmake_SOURCE_FILES
DirectX.cmake
DragDrop.cmake
EXPAT.cmake
## ExamplePlugin.cmake
FindAPR.cmake
FindAutobuild.cmake
FindBerkeleyDB.cmake
@ -100,6 +99,7 @@ set(cmake_SOURCE_FILES
Variables.cmake
ViewerMiscLibs.cmake
VisualLeakDetector.cmake
LibVLCPlugin.cmake
XmlRpcEpi.cmake
ZLIB.cmake
)

View File

@ -18,7 +18,7 @@ else (USESYSTEMLIBS)
use_prebuilt_binary(SDL)
set (SDL_FOUND TRUE)
set (SDL_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/i686-linux)
set (SDL_LIBRARY SDL directfb fusion direct)
set (SDL_LIBRARY SDL directfb fusion direct X11)
endif (LINUX)
endif (USESYSTEMLIBS)

View File

@ -0,0 +1,27 @@
# -*- cmake -*-
include(Linking)
include(Prebuilt)
if (USESYSTEMLIBS)
set(LIBVLCPLUGIN OFF CACHE BOOL
"LIBVLCPLUGIN support for the llplugin/llmedia test apps.")
else (USESYSTEMLIBS)
use_prebuilt_binary(vlc-bin)
set(LIBVLCPLUGIN ON CACHE BOOL
"LIBVLCPLUGIN support for the llplugin/llmedia test apps.")
set(VLC_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/vlc)
endif (USESYSTEMLIBS)
if (WINDOWS)
set(VLC_PLUGIN_LIBRARIES
libvlc.lib
libvlccore.lib
)
elseif (DARWIN)
elseif (LINUX)
# Specify a full path to make sure we get a static link
set(VLC_PLUGIN_LIBRARIES
${LIBS_PREBUILT_DIR}/lib/libvlc.a
${LIBS_PREBUILT_DIR}/lib/libvlccore.a
)
endif (WINDOWS)

View File

@ -1,3 +1,4 @@
2014-02-25 10:34

View File

@ -51,7 +51,7 @@ int main(int argc, char **argv)
return 1;
}
app.mainLoop();
app.frame();
app.cleanup();
LL_INFOS() << "Crash reporter finished normally." << LL_ENDL;
return 0;

View File

@ -114,7 +114,7 @@ void LLCrashLoggerLinux::gatherPlatformSpecificFiles()
{
}
bool LLCrashLoggerLinux::mainLoop()
bool LLCrashLoggerLinux::frame()
{
bool send_logs = true;
if(CRASH_BEHAVIOR_ASK == getCrashBehavior())

View File

@ -36,7 +36,7 @@ class LLCrashLoggerLinux : public LLCrashLogger
public:
LLCrashLoggerLinux(void);
~LLCrashLoggerLinux(void);
virtual bool mainLoop();
virtual bool frame();
virtual void updateApplication(const std::string& = LLStringUtil::null);
virtual void gatherPlatformSpecificFiles();
virtual bool cleanup();

View File

@ -58,6 +58,7 @@ set(llcommon_SOURCE_FILES
lleventfilter.cpp
llevents.cpp
lleventtimer.cpp
llexception.cpp
llfasttimer.cpp
llfile.cpp
llfindlocale.cpp
@ -157,6 +158,7 @@ set(llcommon_HEADER_FILES
lleventfilter.h
llevents.h
lleventemitter.h
llexception.h
llfasttimer.h
llfile.h
llfindlocale.h
@ -315,7 +317,7 @@ if (LL_TESTS)
LL_ADD_INTEGRATION_TEST(llprocinfo "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llrand "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llsdserialize "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llsingleton "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llsingleton "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llstring "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(lltrace "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(lltreeiterators "" "${test_libs}")
@ -328,6 +330,11 @@ if (LL_TESTS)
LL_ADD_INTEGRATION_TEST(llleap "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llstreamqueue "" "${test_libs}")
## llexception_test.cpp isn't a regression test, and doesn't need to be run
## every build. It's to help a developer make implementation choices about
## throwing and catching exceptions.
##LL_ADD_INTEGRATION_TEST(llexception "" "${test_libs}")
# *TODO - reenable these once tcmalloc libs no longer break the build.
#ADD_BUILD_TEST(llallocator llcommon)
#ADD_BUILD_TEST(llallocator_heap_profile llcommon)

View File

@ -60,6 +60,10 @@ const LLUUID IMG_SMOKE_POOF ("1e63e323-5fe0-452e-92f8-b98bd0f764e3"); // On d
const LLUUID IMG_BIG_EXPLOSION_1 ("5e47a0dc-97bf-44e0-8b40-de06718cee9d"); // On dataserver
const LLUUID IMG_BIG_EXPLOSION_2 ("9c8eca51-53d5-42a7-bb58-cef070395db8"); // On dataserver
const LLUUID IMG_ALPHA_GRAD ("e97cf410-8e61-7005-ec06-629eba4cd1fb"); // VIEWER
const LLUUID IMG_ALPHA_GRAD_2D ("38b86f85-2575-52a9-a531-23108d8da837"); // VIEWER
const LLUUID IMG_TRANSPARENT ("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"); // VIEWER
const LLUUID IMG_BLOOM1 ("3c59f7fe-9dc8-47f9-8aaf-a9dd1fbc3bef"); // VIEWER
const LLUUID TERRAIN_DIRT_DETAIL ("0bc58228-74a0-7e83-89bc-5c23464bcec5"); // VIEWER
const LLUUID TERRAIN_GRASS_DETAIL ("63338ede-0037-c4fd-855b-015d77112fc8"); // VIEWER

View File

@ -197,6 +197,10 @@ LL_COMMON_API extern const LLUUID IMG_SMOKE_POOF;
LL_COMMON_API extern const LLUUID IMG_BIG_EXPLOSION_1;
LL_COMMON_API extern const LLUUID IMG_BIG_EXPLOSION_2;
LL_COMMON_API extern const LLUUID IMG_ALPHA_GRAD;
LL_COMMON_API extern const LLUUID IMG_ALPHA_GRAD_2D;
LL_COMMON_API extern const LLUUID IMG_TRANSPARENT;
LL_COMMON_API extern const LLUUID IMG_BLOOM1;
LL_COMMON_API extern const LLUUID TERRAIN_DIRT_DETAIL;
LL_COMMON_API extern const LLUUID TERRAIN_GRASS_DETAIL;

View File

@ -172,12 +172,12 @@ public:
virtual bool cleanup() = 0; // Override to do application cleanup
//
// mainLoop()
// frame()
//
// Runs the application main loop. It's assumed that when you exit
// this method, the application is in one of the cleanup states, either QUITTING or ERROR
// Pass control to the application for a single frame. Returns 'done'
// flag: if frame() returns false, it expects to be called again.
//
virtual bool mainLoop() = 0; // Override for the application main loop. Needs to at least gracefully notice the QUITTING state and exit.
virtual bool frame() = 0; // Override for application body logic
//
// Crash logging

View File

@ -38,6 +38,7 @@
#include "llevents.h"
#include "llerror.h"
#include "stringize.h"
#include "llexception.h"
// do nothing, when we need nothing done
void LLCoros::no_cleanup(CoroData*) {}
@ -131,9 +132,9 @@ bool LLCoros::cleanup(const LLSD&)
if ((previousCount < 5) || !(previousCount % 50))
{
if (previousCount < 5)
LL_INFOS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << LL_ENDL;
LL_DEBUGS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << LL_ENDL;
else
LL_INFOS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << "("<< previousCount << ")" << LL_ENDL;
LL_DEBUGS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << "("<< previousCount << ")" << LL_ENDL;
}
// The erase() call will invalidate its passed iterator value --
@ -185,9 +186,9 @@ std::string LLCoros::generateDistinctName(const std::string& prefix) const
if ((previousCount < 5) || !(previousCount % 50))
{
if (previousCount < 5)
LL_INFOS("LLCoros") << "LLCoros: launching coroutine " << name << LL_ENDL;
LL_DEBUGS("LLCoros") << "LLCoros: launching coroutine " << name << LL_ENDL;
else
LL_INFOS("LLCoros") << "LLCoros: launching coroutine " << name << "(" << previousCount << ")" << LL_ENDL;
LL_DEBUGS("LLCoros") << "LLCoros: launching coroutine " << name << "(" << previousCount << ")" << LL_ENDL;
}
@ -223,7 +224,7 @@ std::string LLCoros::getName() const
void LLCoros::setStackSize(S32 stacksize)
{
LL_INFOS("LLCoros") << "Setting coroutine stack size to " << stacksize << LL_ENDL;
LL_DEBUGS("LLCoros") << "Setting coroutine stack size to " << stacksize << LL_ENDL;
mStackSize = stacksize;
}
@ -235,7 +236,23 @@ void LLCoros::toplevel(coro::self& self, CoroData* data, const callable_t& calla
// capture the 'self' param in CoroData
data->mSelf = &self;
// run the code the caller actually wants in the coroutine
callable();
try
{
callable();
}
catch (const LLContinueError&)
{
// Any uncaught exception derived from LLContinueError will be caught
// here and logged. This coroutine will terminate but the rest of the
// viewer will carry on.
LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << data->mName));
}
catch (...)
{
// Any OTHER kind of uncaught exception will cause the viewer to
// crash, hopefully informatively.
CRASH_ON_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << data->mName));
}
// This cleanup isn't perfectly symmetrical with the way we initially set
// data->mPrev, but this is our last chance to reset mCurrentCoro.
sCurrentCoro.reset(data->mPrev);

View File

@ -40,6 +40,7 @@
#include <boost/graph/topological_sort.hpp>
#include <boost/graph/exception.hpp>
// other Linden headers
#include "llexception.h"
LLDependenciesBase::VertexList LLDependenciesBase::topo_sort(int vertices, const EdgeList& edges) const
{
@ -76,7 +77,7 @@ LLDependenciesBase::VertexList LLDependenciesBase::topo_sort(int vertices, const
// Omit independent nodes: display only those that might contribute to
// the cycle.
describe(out, false);
throw Cycle(out.str());
LLTHROW(Cycle(out.str()));
}
// A peculiarity of boost::topological_sort() is that it emits results in
// REVERSE topological order: to get the result you want, you must

View File

@ -34,13 +34,13 @@
#include <vector>
#include <set>
#include <map>
#include <stdexcept>
#include <iosfwd>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/iterator/indirect_iterator.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include "llexception.h"
/*****************************************************************************
* Utilities
@ -106,9 +106,9 @@ public:
/**
* Exception thrown by sort() if there's a cycle
*/
struct Cycle: public std::runtime_error
struct Cycle: public LLException
{
Cycle(const std::string& what): std::runtime_error(what) {}
Cycle(const std::string& what): LLException(what) {}
};
/**

View File

@ -174,7 +174,8 @@ namespace LLError
// not really a level
// used to indicate that no messages should be logged
};
// If you change ELevel, please update llvlog() macro below.
/* Macro support
The classes CallSite and Log are used by the logging macros below.
They are not intended for general use.
@ -305,24 +306,38 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
/////////////////////////////////
// Error Logging Macros
// See top of file for common usage.
// See top of file for common usage.
/////////////////////////////////
// this macro uses a one-shot do statement to avoid parsing errors when writing control flow statements
// without braces:
// if (condition) LL_INFOS() << "True" << LL_ENDL; else LL_INFOS()() << "False" << LL_ENDL
// Instead of using LL_DEBUGS(), LL_INFOS() et al., it may be tempting to
// directly code the lllog() macro so you can pass in the LLError::ELevel as a
// variable. DON'T DO IT! The reason is that the first time control passes
// through lllog(), it initializes a local static LLError::CallSite with that
// *first* ELevel value. All subsequent visits will decide whether or not to
// emit output based on the *first* ELevel value bound into that static
// CallSite instance. Use LL_VLOGS() instead. lllog() assumes its ELevel
// argument never varies.
#define lllog(level, once, ...) \
do { \
const char* tags[] = {"", ##__VA_ARGS__}; \
::size_t tag_count = LL_ARRAY_SIZE(tags) - 1; \
static LLError::CallSite _site( \
level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__, once, &tags[1], tag_count);\
if (LL_UNLIKELY(_site.shouldLog())) \
{ \
std::ostringstream* _out = LLError::Log::out(); \
// this macro uses a one-shot do statement to avoid parsing errors when
// writing control flow statements without braces:
// if (condition) LL_INFOS() << "True" << LL_ENDL; else LL_INFOS()() << "False" << LL_ENDL;
#define lllog(level, once, ...) \
do { \
const char* tags[] = {"", ##__VA_ARGS__}; \
static LLError::CallSite _site(lllog_site_args_(level, once, tags)); \
lllog_test_()
#define lllog_test_() \
if (LL_UNLIKELY(_site.shouldLog())) \
{ \
std::ostringstream* _out = LLError::Log::out(); \
(*_out)
#define lllog_site_args_(level, once, tags) \
level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), \
__FUNCTION__, once, &tags[1], LL_ARRAY_SIZE(tags)-1
//Use this construct if you need to do computation in the middle of a
//message:
//
@ -363,4 +378,46 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
#define LL_INFOS_ONCE(...) lllog(LLError::LEVEL_INFO, true, ##__VA_ARGS__)
#define LL_WARNS_ONCE(...) lllog(LLError::LEVEL_WARN, true, ##__VA_ARGS__)
// Use this if you need to pass LLError::ELevel as a variable.
#define LL_VLOGS(level, ...) llvlog(level, false, ##__VA_ARGS__)
#define LL_VLOGS_ONCE(level, ...) llvlog(level, true, ##__VA_ARGS__)
// The problem with using lllog() with a variable level is that the first time
// through, it initializes a static CallSite instance with whatever level you
// pass. That first level is bound into the CallSite; the level parameter is
// never again examined. One approach to variable level would be to
// dynamically construct a CallSite instance every call -- which could get
// expensive, depending on context. So instead, initialize a static CallSite
// for each level value we support, then dynamically select the CallSite
// instance for the passed level value.
// Compare implementation to lllog() above.
#define llvlog(level, once, ...) \
do { \
const char* tags[] = {"", ##__VA_ARGS__}; \
/* Need a static CallSite instance per expected ELevel value. */ \
/* Since we intend to index this array with the ELevel, */ \
/* _sites[0] should be ELevel(0), and so on -- avoid using */ \
/* ELevel symbolic names when initializing -- except for */ \
/* the last entry, which handles anything beyond the end. */ \
/* (Commented ELevel value names are from 2016-09-01.) */ \
/* Passing an ELevel past the end of this array is itself */ \
/* a fatal error, so ensure the last is LEVEL_ERROR. */ \
static LLError::CallSite _sites[] = \
{ \
/* LEVEL_DEBUG */ \
LLError::CallSite(lllog_site_args_(LLError::ELevel(0), once, tags)), \
/* LEVEL_INFO */ \
LLError::CallSite(lllog_site_args_(LLError::ELevel(1), once, tags)), \
/* LEVEL_WARN */ \
LLError::CallSite(lllog_site_args_(LLError::ELevel(2), once, tags)), \
/* LEVEL_ERROR */ \
LLError::CallSite(lllog_site_args_(LLError::LEVEL_ERROR, once, tags)) \
}; \
/* Clamp the passed 'level' to at most last entry */ \
std::size_t which((std::size_t(level) >= LL_ARRAY_SIZE(_sites)) ? \
(LL_ARRAY_SIZE(_sites) - 1) : std::size_t(level)); \
/* selected CallSite *must* be named _site for LL_ENDL */ \
LLError::CallSite& _site(_sites[which]); \
lllog_test_()
#endif // LL_LLERROR_H

View File

@ -39,6 +39,7 @@
#include "llerror.h"
#include "llcoros.h"
#include "llmake.h"
#include "llexception.h"
#include "lleventfilter.h"
@ -351,7 +352,7 @@ LLSD errorException(const LLEventWithID& result, const std::string& desc)
// returning it, deliver it via exception.
if (result.second)
{
throw LLErrorEvent(desc, result.first);
LLTHROW(LLErrorEvent(desc, result.first));
}
// That way, our caller knows a simple return must be from the reply
// pump (pump 0).

View File

@ -31,10 +31,10 @@
#include <boost/optional.hpp>
#include <string>
#include <stdexcept>
#include <utility> // std::pair
#include "llevents.h"
#include "llerror.h"
#include "llexception.h"
/**
* Like LLListenerOrPumpName, this is a class intended for parameter lists:
@ -234,11 +234,11 @@ LLSD errorException(const LLEventWithID& result, const std::string& desc);
* because it's not an error in event processing: rather, this exception
* announces an event that bears error information (for some other API).
*/
class LL_COMMON_API LLErrorEvent: public std::runtime_error
class LL_COMMON_API LLErrorEvent: public LLException
{
public:
LLErrorEvent(const std::string& what, const LLSD& data):
std::runtime_error(what),
LLException(what),
mData(data)
{}
virtual ~LLErrorEvent() throw() {}

View File

@ -57,6 +57,7 @@
#include "stringize.h"
#include "llerror.h"
#include "llsdutil.h"
#include "llexception.h"
#if LL_MSVC
#pragma warning (disable : 4702)
#endif
@ -174,7 +175,7 @@ std::string LLEventPumps::registerNew(const LLEventPump& pump, const std::string
// Unless we're permitted to tweak it, that's Bad.
if (! tweak)
{
throw LLEventPump::DupPumpName(std::string("Duplicate LLEventPump name '") + name + "'");
LLTHROW(LLEventPump::DupPumpName("Duplicate LLEventPump name '" + name + "'"));
}
// The passed name isn't unique, but we're permitted to tweak it. Find the
// first decimal-integer suffix not already taken. The insert() attempt
@ -326,8 +327,8 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL
// is only when the existing connection object is still connected.
if (found != mConnections.end() && found->second.connected())
{
throw DupListenerName(std::string("Attempt to register duplicate listener name '") + name +
"' on " + typeid(*this).name() + " '" + getName() + "'");
LLTHROW(DupListenerName("Attempt to register duplicate listener name '" + name +
"' on " + typeid(*this).name() + " '" + getName() + "'"));
}
// Okay, name is unique, try to reconcile its dependencies. Specify a new
// "node" value that we never use for an mSignal placement; we'll fix it
@ -353,8 +354,8 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL
// unsortable. If we leave the new node in mDeps, it will continue
// to screw up all future attempts to sort()! Pull it out.
mDeps.remove(name);
throw Cycle(std::string("New listener '") + name + "' on " + typeid(*this).name() +
" '" + getName() + "' would cause cycle: " + e.what());
LLTHROW(Cycle("New listener '" + name + "' on " + typeid(*this).name() +
" '" + getName() + "' would cause cycle: " + e.what()));
}
// Walk the list to verify that we haven't changed the order.
float previous = 0.0, myprev = 0.0;
@ -418,7 +419,7 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL
// NOW remove the offending listener node.
mDeps.remove(name);
// Having constructed a description of the order change, inform caller.
throw OrderChange(out.str());
LLTHROW(OrderChange(out.str()));
}
// This node becomes the previous one.
previous = dmi->second;
@ -608,7 +609,7 @@ bool LLListenerOrPumpName::operator()(const LLSD& event) const
{
if (! mListener)
{
throw Empty("attempting to call uninitialized");
LLTHROW(Empty("attempting to call uninitialized"));
}
return (*mListener)(event);
}

View File

@ -37,7 +37,6 @@
#include <set>
#include <vector>
#include <deque>
#include <stdexcept>
#if LL_WINDOWS
#pragma warning (push)
#pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch
@ -62,6 +61,7 @@
#include "llsingleton.h"
#include "lldependencies.h"
#include "llstl.h"
#include "llexception.h"
/*==========================================================================*|
// override this to allow binding free functions with more parameters
@ -95,12 +95,32 @@ struct LLStopWhenHandled
result_type operator()(InputIterator first, InputIterator last) const
{
for (InputIterator si = first; si != last; ++si)
{
if (*si)
{
return true;
}
}
{
try
{
if (*si)
{
return true;
}
}
catch (const LLContinueError&)
{
// We catch LLContinueError here because an LLContinueError-
// based exception means the viewer as a whole should carry on
// to the best of our ability. Therefore subsequent listeners
// on the same LLEventPump should still receive this event.
// The iterator passed to a boost::signals2 Combiner is very
// clever, but provides no contextual information. We would
// very much like to be able to log the name of the LLEventPump
// plus the name of this particular listener, but alas.
LOG_UNHANDLED_EXCEPTION("LLEventPump");
}
// We do NOT catch (...) here because we might as well let it
// propagate out to the generic handler. If we were able to log
// context information here, that would be great, but we can't, so
// there's no point.
}
return false;
}
};
@ -188,10 +208,10 @@ public:
bool operator()(const LLSD& event) const;
/// exception if you try to call when empty
struct Empty: public std::runtime_error
struct Empty: public LLException
{
Empty(const std::string& what):
std::runtime_error(std::string("LLListenerOrPumpName::Empty: ") + what) {}
LLException(std::string("LLListenerOrPumpName::Empty: ") + what) {}
};
private:
@ -371,10 +391,10 @@ public:
* you didn't pass <tt>tweak=true</tt> to permit it to generate a unique
* variant.
*/
struct DupPumpName: public std::runtime_error
struct DupPumpName: public LLException
{
DupPumpName(const std::string& what):
std::runtime_error(std::string("DupPumpName: ") + what) {}
LLException(std::string("DupPumpName: ") + what) {}
};
/**
@ -399,9 +419,9 @@ public:
/// group exceptions thrown by listen(). We use exceptions because these
/// particular errors are likely to be coding errors, found and fixed by
/// the developer even before preliminary checkin.
struct ListenError: public std::runtime_error
struct ListenError: public LLException
{
ListenError(const std::string& what): std::runtime_error(what) {}
ListenError(const std::string& what): LLException(what) {}
};
/**
* exception thrown by listen(). You are attempting to register a

View File

@ -0,0 +1,55 @@
/**
* @file llexception.cpp
* @author Nat Goodspeed
* @date 2016-08-12
* @brief Implementation for llexception.
*
* $LicenseInfo:firstyear=2016&license=viewerlgpl$
* Copyright (c) 2016, Linden Research, Inc.
* $/LicenseInfo$
*/
// Precompiled header
#include "linden_common.h"
// associated header
#include "llexception.h"
// STL headers
// std headers
#include <typeinfo>
// external library headers
#include <boost/exception/diagnostic_information.hpp>
// other Linden headers
#include "llerror.h"
#include "llerrorcontrol.h"
namespace {
// used by crash_on_unhandled_exception_() and log_unhandled_exception_()
void log_unhandled_exception_(LLError::ELevel level,
const char* file, int line, const char* pretty_function,
const std::string& context)
{
// log same message but allow caller-specified severity level
LL_VLOGS(level, "LLException") << LLError::abbreviateFile(file)
<< "(" << line << "): Unhandled exception caught in " << pretty_function;
if (! context.empty())
{
LL_CONT << ": " << context;
}
LL_CONT << ":\n" << boost::current_exception_diagnostic_information() << LL_ENDL;
}
}
void crash_on_unhandled_exception_(const char* file, int line, const char* pretty_function,
const std::string& context)
{
// LL_ERRS() terminates and propagates message into crash dump.
log_unhandled_exception_(LLError::LEVEL_ERROR, file, line, pretty_function, context);
}
void log_unhandled_exception_(const char* file, int line, const char* pretty_function,
const std::string& context)
{
// Use LL_WARNS() because we seriously do not expect this to happen
// routinely, but we DO expect to return from this function.
log_unhandled_exception_(LLError::LEVEL_WARN, file, line, pretty_function, context);
}

View File

@ -0,0 +1,85 @@
/**
* @file llexception.h
* @author Nat Goodspeed
* @date 2016-06-29
* @brief Types needed for generic exception handling
*
* $LicenseInfo:firstyear=2016&license=viewerlgpl$
* Copyright (c) 2016, Linden Research, Inc.
* $/LicenseInfo$
*/
#if ! defined(LL_LLEXCEPTION_H)
#define LL_LLEXCEPTION_H
#include <stdexcept>
#include <boost/exception/exception.hpp>
#include <boost/throw_exception.hpp>
#include <boost/current_function.hpp>
// "Found someone who can comfort me
// But there are always exceptions..."
// - Empty Pages, Traffic, from John Barleycorn (1970)
// https://www.youtube.com/watch?v=dRH0CGVK7ic
/**
* LLException is intended as the common base class from which all
* viewer-specific exceptions are derived. Rationale for why it's derived from
* both std::exception and boost::exception is explained in
* tests/llexception_test.cpp.
*
* boost::current_exception_diagnostic_information() is quite wonderful: if
* all we need to do with an exception is log it, in most places we should
* catch (...) and log boost::current_exception_diagnostic_information().
* See CRASH_ON_UNHANDLED_EXCEPTION() and LOG_UNHANDLED_EXCEPTION() below.
*
* There may be circumstances in which it would be valuable to distinguish an
* exception explicitly thrown by viewer code from an exception thrown by
* (say) a third-party library. Catching (const LLException&) supports such
* usage. However, most of the value of this base class is in the
* diagnostic_information() available via Boost.Exception.
*/
struct LLException:
public std::runtime_error,
public boost::exception
{
LLException(const std::string& what):
std::runtime_error(what)
{}
};
/**
* The point of LLContinueError is to distinguish exceptions that need not
* terminate the whole viewer session. In general, an uncaught exception will
* be logged and will crash the viewer. However, though an uncaught exception
* derived from LLContinueError will still be logged, the viewer will attempt
* to continue processing.
*/
struct LLContinueError: public LLException
{
LLContinueError(const std::string& what):
LLException(what)
{}
};
/**
* Please use LLTHROW() to throw viewer exceptions whenever possible. This
* enriches the exception's diagnostic_information() with the source file,
* line and containing function of the LLTHROW() macro.
*/
// Currently we implement that using BOOST_THROW_EXCEPTION(). Wrap it in
// LLTHROW() in case we ever want to revisit that implementation decision.
#define LLTHROW(x) BOOST_THROW_EXCEPTION(x)
/// Call this macro from a catch (...) clause
#define CRASH_ON_UNHANDLED_EXCEPTION(CONTEXT) \
crash_on_unhandled_exception_(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, CONTEXT)
void crash_on_unhandled_exception_(const char*, int, const char*, const std::string&);
/// Call this from a catch (const LLContinueError&) clause, or from a catch
/// (...) clause in which you do NOT want the viewer to crash.
#define LOG_UNHANDLED_EXCEPTION(CONTEXT) \
log_unhandled_exception_(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, CONTEXT)
void log_unhandled_exception_(const char*, int, const char*, const std::string&);
#endif /* ! defined(LL_LLEXCEPTION_H) */

View File

@ -296,7 +296,16 @@ LL_FORCE_INLINE BlockTimer::BlockTimer(BlockTimerStatHandle& timer)
{
#if LL_FAST_TIMER_ON
BlockTimerStackRecord* cur_timer_data = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance();
if (!cur_timer_data) return;
if (!cur_timer_data)
{
// How likely is it that
// LLThreadLocalSingletonPointer<T>::getInstance() will return NULL?
// Even without researching, what we can say is that if we exit
// without setting mStartTime at all, gcc 4.7 produces (fatal)
// warnings about a possibly-uninitialized data member.
mStartTime = 0;
return;
}
TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator();
accumulator.mActiveCount++;
// keep current parent as long as it is active when we are

View File

@ -28,8 +28,11 @@
#define LLHANDLE_H
#include "llpointer.h"
#include "llexception.h"
#include <stdexcept>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/throw_exception.hpp>
/**
* Helper object for LLHandle. Don't instantiate these directly, used
@ -213,4 +216,82 @@ private:
mutable LLRootHandle<T> mHandle;
};
class LLCheckedHandleBase
{
public:
class Stale : public LLException
{
public:
Stale() :
LLException("Attempt to access stale handle.")
{}
};
protected:
LLCheckedHandleBase() { }
};
/**
* This is a simple wrapper for Handles, allowing direct calls to the underlying
* pointer. The checked handle will throw a Stale if an attempt
* is made to access the object referenced by the handle and that object has
* been destroyed.
**/
template <typename T>
class LLCheckedHandle: public LLCheckedHandleBase
{
public:
LLCheckedHandle(LLHandle<T> handle):
mHandle(handle)
{ }
/**
* Test the underlying handle. If it is no longer valid, throw a Stale exception.
*/
void check() const
{
T* ptr = mHandle.get();
if (!ptr)
BOOST_THROW_EXCEPTION(Stale());
}
/**
* Cast back to an appropriate handle
*/
operator LLHandle<T>() const
{
return mHandle;
}
/**
* Converts the LLCheckedHandle to a bool. Allows for if (chkdHandle) {}
* Does not throw.
*/
/*explicit*/ operator bool() const // explicit conversion operator not available with Linux compiler
{
return (mHandle.get() != NULL);
}
/**
* Attempt to call a method or access a member in the structure referenced
* by the handle. If the handle no longer points to a valid structure
* throw a Stale.
*/
T* operator ->() const
{
T* ptr = mHandle.get();
if (!ptr)
BOOST_THROW_EXCEPTION(Stale());
return ptr;
}
private:
LLHandle<T> mHandle;
};
#endif

View File

@ -33,6 +33,7 @@
#include "lltimer.h"
#include "lluuid.h"
#include "llleaplistener.h"
#include "llexception.h"
#if LL_MSVC
#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
@ -69,7 +70,7 @@ public:
// Rule out empty vector
if (plugin.empty())
{
throw Error("no plugin command");
LLTHROW(Error("no plugin command"));
}
// Don't leave desc empty either, but in this case, if we weren't
@ -112,7 +113,7 @@ public:
// If that didn't work, no point in keeping this LLLeap object.
if (! mChild)
{
throw Error(STRINGIZE("failed to run " << mDesc));
LLTHROW(Error(STRINGIZE("failed to run " << mDesc)));
}
// Okay, launch apparently worked. Change our mDonePump listener.

View File

@ -13,9 +13,9 @@
#define LL_LLLEAP_H
#include "llinstancetracker.h"
#include "llexception.h"
#include <string>
#include <vector>
#include <stdexcept>
/**
* LLSD Event API Plugin class. Because instances are managed by
@ -67,9 +67,9 @@ public:
* string(s) passed to create() might come from an external source. This
* way the caller can catch LLLeap::Error and try to recover.
*/
struct Error: public std::runtime_error
struct Error: public LLException
{
Error(const std::string& what): std::runtime_error(what) {}
Error(const std::string& what): LLException(what) {}
};
virtual ~LLLeap();

View File

@ -110,11 +110,15 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
#if defined(LL_WINDOWS)
return _aligned_malloc(size, align);
#else
char* aligned = NULL;
void* mem = malloc( size + (align - 1) + sizeof(void*) );
char* aligned = ((char*)mem) + sizeof(void*);
aligned += align - ((uintptr_t)aligned & (align - 1));
if (mem)
{
aligned = ((char*)mem) + sizeof(void*);
aligned += align - ((uintptr_t)aligned & (align - 1));
((void**)aligned)[-1] = mem;
((void**)aligned)[-1] = mem;
}
return aligned;
#endif
}

View File

@ -34,6 +34,7 @@
#include "llapr.h"
#include "apr_signal.h"
#include "llevents.h"
#include "llexception.h"
#include <boost/foreach.hpp>
#include <boost/bind.hpp>
@ -472,9 +473,9 @@ private:
*****************************************************************************/
/// Need an exception to avoid constructing an invalid LLProcess object, but
/// internal use only
struct LLProcessError: public std::runtime_error
struct LLProcessError: public LLException
{
LLProcessError(const std::string& msg): std::runtime_error(msg) {}
LLProcessError(const std::string& msg): LLException(msg) {}
};
LLProcessPtr LLProcess::create(const LLSDOrParams& params)
@ -530,8 +531,8 @@ LLProcess::LLProcess(const LLSDOrParams& params):
if (! params.validateBlock(true))
{
throw LLProcessError(STRINGIZE("not launched: failed parameter validation\n"
<< LLSDNotationStreamer(params)));
LLTHROW(LLProcessError(STRINGIZE("not launched: failed parameter validation\n"
<< LLSDNotationStreamer(params))));
}
mPostend = params.postend;
@ -596,10 +597,10 @@ LLProcess::LLProcess(const LLSDOrParams& params):
}
else
{
throw LLProcessError(STRINGIZE("For " << params.executable()
<< ": unsupported FileParam for " << which
<< ": type='" << fparam.type()
<< "', name='" << fparam.name() << "'"));
LLTHROW(LLProcessError(STRINGIZE("For " << params.executable()
<< ": unsupported FileParam for " << which
<< ": type='" << fparam.type()
<< "', name='" << fparam.name() << "'")));
}
}
// By default, pass APR_NO_PIPE for unspecified slots.
@ -678,7 +679,7 @@ LLProcess::LLProcess(const LLSDOrParams& params):
if (ll_apr_warn_status(apr_proc_create(&mProcess, argv[0], &argv[0], NULL, procattr,
gAPRPoolp)))
{
throw LLProcessError(STRINGIZE(params << " failed"));
LLTHROW(LLProcessError(STRINGIZE(params << " failed")));
}
// arrange to call status_callback()
@ -1063,7 +1064,7 @@ PIPETYPE& LLProcess::getPipe(FILESLOT slot)
PIPETYPE* wp = getPipePtr<PIPETYPE>(error, slot);
if (! wp)
{
throw NoPipe(error);
LLTHROW(NoPipe(error));
}
return *wp;
}

View File

@ -30,13 +30,13 @@
#include "llinitparam.h"
#include "llsdparam.h"
#include "llwin32headerslean.h"
#include "llexception.h"
#include "apr_thread_proc.h"
#include <boost/shared_ptr.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/optional.hpp>
#include <boost/noncopyable.hpp>
#include <iosfwd> // std::ostream
#include <stdexcept>
#if LL_WINDOWS
#include "llwin32headerslean.h" // for HANDLE
@ -479,9 +479,9 @@ public:
/// Exception thrown by getWritePipe(), getReadPipe() if you didn't ask to
/// create a pipe at the corresponding FILESLOT.
struct NoPipe: public std::runtime_error
struct NoPipe: public LLException
{
NoPipe(const std::string& what): std::runtime_error(what) {}
NoPipe(const std::string& what): LLException(what) {}
};
/**

View File

@ -576,6 +576,33 @@ std::string utf8str_truncate(const std::string& utf8str, const S32 max_len)
}
}
std::string utf8str_symbol_truncate(const std::string& utf8str, const S32 symbol_len)
{
if (0 == symbol_len)
{
return std::string();
}
if ((S32)utf8str.length() <= symbol_len)
{
return utf8str;
}
else
{
int len = 0, byteIndex = 0;
const char* aStr = utf8str.c_str();
size_t origSize = utf8str.size();
for (byteIndex = 0; len < symbol_len && byteIndex < origSize; byteIndex++)
{
if ((aStr[byteIndex] & 0xc0) != 0x80)
{
len += 1;
}
}
return utf8str.substr(0, byteIndex);
}
}
std::string utf8str_substChar(
const std::string& utf8str,
const llwchar target_char,

View File

@ -563,6 +563,17 @@ LL_COMMON_API S32 utf8str_compare_insensitive(
const std::string& lhs,
const std::string& rhs);
/**
* @brief Properly truncate a utf8 string to a maximum character count.
*
* If symbol_len is longer than the string passed in, the return
* value == utf8str.
* @param utf8str A valid utf8 string to truncate.
* @param symbol_len The maximum number of symbols in the return value.
* @return Returns a valid utf8 string with symbol count <= max_len.
*/
LL_COMMON_API std::string utf8str_symbol_truncate(const std::string& utf8str, const S32 symbol_len);
/**
* @brief Replace all occurences of target_char with replace_char
*

View File

@ -27,6 +27,7 @@
#include <apr_pools.h>
#include <apr_queue.h>
#include "llthreadsafequeue.h"
#include "llexception.h"
@ -41,13 +42,13 @@ LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(apr_pool_t * po
{
if(mOwnsPool) {
apr_status_t status = apr_pool_create(&mPool, 0);
if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate pool");
if(status != APR_SUCCESS) LLTHROW(LLThreadSafeQueueError("failed to allocate pool"));
} else {
; // No op.
}
apr_status_t status = apr_queue_create(&mQueue, capacity, mPool);
if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate queue");
if(status != APR_SUCCESS) LLTHROW(LLThreadSafeQueueError("failed to allocate queue"));
}
@ -68,9 +69,9 @@ void LLThreadSafeQueueImplementation::pushFront(void * element)
apr_status_t status = apr_queue_push(mQueue, element);
if(status == APR_EINTR) {
throw LLThreadSafeQueueInterrupt();
LLTHROW(LLThreadSafeQueueInterrupt());
} else if(status != APR_SUCCESS) {
throw LLThreadSafeQueueError("push failed");
LLTHROW(LLThreadSafeQueueError("push failed"));
} else {
; // Success.
}
@ -88,9 +89,9 @@ void * LLThreadSafeQueueImplementation::popBack(void)
apr_status_t status = apr_queue_pop(mQueue, &element);
if(status == APR_EINTR) {
throw LLThreadSafeQueueInterrupt();
LLTHROW(LLThreadSafeQueueInterrupt());
} else if(status != APR_SUCCESS) {
throw LLThreadSafeQueueError("pop failed");
LLTHROW(LLThreadSafeQueueError("pop failed"));
} else {
return element;
}

View File

@ -27,9 +27,8 @@
#ifndef LL_LLTHREADSAFEQUEUE_H
#define LL_LLTHREADSAFEQUEUE_H
#include "llexception.h"
#include <string>
#include <stdexcept>
struct apr_pool_t; // From apr_pools.h
@ -40,11 +39,11 @@ class LLThreadSafeQueueImplementation; // See below.
// A general queue exception.
//
class LL_COMMON_API LLThreadSafeQueueError:
public std::runtime_error
public LLException
{
public:
LLThreadSafeQueueError(std::string const & message):
std::runtime_error(message)
LLException(message)
{
; // No op.
}

View File

@ -83,7 +83,7 @@ unsigned int decode( char const * fiveChars ) throw( bad_input_data )
unsigned int ret = 0;
for( int ix = 0; ix < 5; ++ix ) {
char * s = strchr( encodeTable, fiveChars[ ix ] );
if( s == 0 ) throw bad_input_data();
if( s == 0 ) LLTHROW(bad_input_data());
ret = ret * 85 + (s-encodeTable);
}
return ret;

View File

@ -237,8 +237,21 @@ namespace tut
void ErrorTestObject::test<4>()
// file abbreviation
{
std::string thisFile = __FILE__;
std::string abbreviateFile = LLError::abbreviateFile(thisFile);
std::string prev, abbreviateFile = __FILE__;
do
{
prev = abbreviateFile;
abbreviateFile = LLError::abbreviateFile(abbreviateFile);
// __FILE__ is assumed to end with
// indra/llcommon/tests/llerror_test.cpp. This test used to call
// abbreviateFile() exactly once, then check below whether it
// still contained the string 'indra'. That fails if the FIRST
// part of the pathname also contains indra! Certain developer
// machine images put local directory trees under
// /ngi-persist/indra, which is where we observe the problem. So
// now, keep calling abbreviateFile() until it returns its
// argument unchanged, THEN check.
} while (abbreviateFile != prev);
ensure_ends_with("file name abbreviation",
abbreviateFile,

View File

@ -0,0 +1,308 @@
/**
* @file llexception_test.cpp
* @author Nat Goodspeed
* @date 2016-08-12
* @brief Tests for throwing exceptions.
*
* This isn't a regression test: it doesn't need to be run every build, which
* is why the corresponding line in llcommon/CMakeLists.txt is commented out.
* Rather it's a head-to-head test of what kind of exception information we
* can collect from various combinations of exception base classes, type of
* throw verb and sequences of catch clauses.
*
* This "test" makes no ensure() calls: its output goes to stdout for human
* examination.
*
* As of 2016-08-12 with Boost 1.57, we come to the following conclusions.
* These should probably be re-examined from time to time as we update Boost.
*
* - It is indisputably beneficial to use BOOST_THROW_EXCEPTION() rather than
* plain throw. The macro annotates the exception object with the filename,
* line number and function name from which the exception was thrown.
*
* - That being the case, deriving only from boost::exception isn't an option.
* Every exception object passed to BOOST_THROW_EXCEPTION() must be derived
* directly or indirectly from std::exception. The only question is whether
* to also derive from boost::exception. We decided to derive LLException
* from both, as it makes message output slightly cleaner, but this is a
* trivial reason: if a strong reason emerges to prefer single inheritance,
* dropping the boost::exception base class shouldn't be a problem.
*
* - (As you will have guessed, ridiculous things like a char* or int or a
* class derived from neither boost::exception nor std::exception can only
* be caught by that specific type or (...), and
* boost::current_exception_diagnostic_information() simply throws up its
* hands and confesses utter ignorance. Stay away from such nonsense.)
*
* - But if you derive from std::exception, to nat's surprise,
* boost::current_exception_diagnostic_information() gives as much
* information about exceptions in a catch (...) clause as you can get from
* a specific catch (const std::exception&) clause, notably the concrete
* exception class and the what() string. So instead of a sequence like
*
* try { ... }
* catch (const boost::exception& e) { ... boost-flavored logging ... }
* catch (const std::exception& e) { ... std::exception logging ... }
* catch (...) { ... generic logging ... }
*
* we should be able to get away with only a catch (...) clause that logs
* boost::current_exception_diagnostic_information().
*
* - Going further: boost::current_exception_diagnostic_information() provides
* just as much information even within a std::set_terminate() handler. So
* it might not even be strictly necessary to include a catch (...) clause
* since the viewer does use std::set_terminate().
*
* - (We might consider adding a catch (int) clause because Kakadu internally
* throws ints, and who knows if one of those might leak out. If it does,
* boost::current_exception_diagnostic_information() can do nothing with it.
* A catch (int) clause could at least log the value and rethrow.)
*
* $LicenseInfo:firstyear=2016&license=viewerlgpl$
* Copyright (c) 2016, Linden Research, Inc.
* $/LicenseInfo$
*/
// Precompiled header
#include "linden_common.h"
// associated header
#include "llexception.h"
// STL headers
// std headers
#include <typeinfo>
// external library headers
#include <boost/throw_exception.hpp>
// other Linden headers
#include "../test/lltut.h"
// helper for display output
// usage: std::cout << center(some string value, fill char, width) << std::endl;
// (assumes it's the only thing on that particular line)
struct center
{
center(const std::string& label, char fill, std::size_t width):
mLabel(label),
mFill(fill),
mWidth(width)
{}
// Use friend declaration not because we need to grant access, but because
// it lets us declare a free operator like a member function.
friend std::ostream& operator<<(std::ostream& out, const center& ctr)
{
std::size_t padded = ctr.mLabel.length() + 2;
std::size_t left = (ctr.mWidth - padded) / 2;
std::size_t right = ctr.mWidth - left - padded;
return out << std::string(left, ctr.mFill) << ' ' << ctr.mLabel << ' '
<< std::string(right, ctr.mFill);
}
std::string mLabel;
char mFill;
std::size_t mWidth;
};
/*****************************************************************************
* Four kinds of exceptions: derived from boost::exception, from
* std::exception, from both, from neither
*****************************************************************************/
// Interestingly, we can't use this variant with BOOST_THROW_EXCEPTION()
// (which we want) -- we reach a failure topped by this comment:
// //All boost exceptions are required to derive from std::exception,
// //to ensure compatibility with BOOST_NO_EXCEPTIONS.
struct FromBoost: public boost::exception
{
FromBoost(const std::string& what): mWhat(what) {}
~FromBoost() throw() {}
std::string what() const { return mWhat; }
std::string mWhat;
};
struct FromStd: public std::runtime_error
{
FromStd(const std::string& what): std::runtime_error(what) {}
};
struct FromBoth: public boost::exception, public std::runtime_error
{
FromBoth(const std::string& what): std::runtime_error(what) {}
};
// Same deal with FromNeither: can't use with BOOST_THROW_EXCEPTION().
struct FromNeither
{
FromNeither(const std::string& what): mWhat(what) {}
std::string what() const { return mWhat; }
std::string mWhat;
};
/*****************************************************************************
* Two kinds of throws: plain throw and BOOST_THROW_EXCEPTION()
*****************************************************************************/
template <typename EXC>
void plain_throw(const std::string& what)
{
throw EXC(what);
}
template <typename EXC>
void boost_throw(const std::string& what)
{
BOOST_THROW_EXCEPTION(EXC(what));
}
// Okay, for completeness, functions that throw non-class values. We wouldn't
// even deign to consider these if we hadn't found examples in our own source
// code! (Note that Kakadu's internal exception support is still based on
// throwing ints.)
void throw_char_ptr(const std::string& what)
{
throw what.c_str(); // umm...
}
void throw_int(const std::string& what)
{
throw int(what.length());
}
/*****************************************************************************
* Three sequences of catch clauses:
* boost::exception then ...,
* std::exception then ...,
* or just ...
*****************************************************************************/
void catch_boost_dotdotdot(void (*thrower)(const std::string&), const std::string& what)
{
try
{
thrower(what);
}
catch (const boost::exception& e)
{
std::cout << "catch (const boost::exception& e)" << std::endl;
std::cout << "e is " << typeid(e).name() << std::endl;
std::cout << "boost::diagnostic_information(e):\n'"
<< boost::diagnostic_information(e) << "'" << std::endl;
// no way to report e.what()
}
catch (...)
{
std::cout << "catch (...)" << std::endl;
std::cout << "boost::current_exception_diagnostic_information():\n'"
<< boost::current_exception_diagnostic_information() << "'"
<< std::endl;
}
}
void catch_std_dotdotdot(void (*thrower)(const std::string&), const std::string& what)
{
try
{
thrower(what);
}
catch (const std::exception& e)
{
std::cout << "catch (const std::exception& e)" << std::endl;
std::cout << "e is " << typeid(e).name() << std::endl;
std::cout << "boost::diagnostic_information(e):\n'"
<< boost::diagnostic_information(e) << "'" << std::endl;
std::cout << "e.what: '"
<< e.what() << "'" << std::endl;
}
catch (...)
{
std::cout << "catch (...)" << std::endl;
std::cout << "boost::current_exception_diagnostic_information():\n'"
<< boost::current_exception_diagnostic_information() << "'"
<< std::endl;
}
}
void catch_dotdotdot(void (*thrower)(const std::string&), const std::string& what)
{
try
{
thrower(what);
}
catch (...)
{
std::cout << "catch (...)" << std::endl;
std::cout << "boost::current_exception_diagnostic_information():\n'"
<< boost::current_exception_diagnostic_information() << "'"
<< std::endl;
}
}
/*****************************************************************************
* Try a particular kind of throw against each of three catch sequences
*****************************************************************************/
void catch_several(void (*thrower)(const std::string&), const std::string& what)
{
std::cout << std::string(20, '-') << "catch_boost_dotdotdot(" << what << ")" << std::endl;
catch_boost_dotdotdot(thrower, "catch_boost_dotdotdot(" + what + ")");
std::cout << std::string(20, '-') << "catch_std_dotdotdot(" << what << ")" << std::endl;
catch_std_dotdotdot(thrower, "catch_std_dotdotdot(" + what + ")");
std::cout << std::string(20, '-') << "catch_dotdotdot(" << what << ")" << std::endl;
catch_dotdotdot(thrower, "catch_dotdotdot(" + what + ")");
}
/*****************************************************************************
* For a particular kind of exception, try both kinds of throw against all
* three catch sequences
*****************************************************************************/
template <typename EXC>
void catch_both_several(const std::string& what)
{
std::cout << std::string(20, '*') << "plain_throw<" << what << ">" << std::endl;
catch_several(plain_throw<EXC>, "plain_throw<" + what + ">");
std::cout << std::string(20, '*') << "boost_throw<" << what << ">" << std::endl;
catch_several(boost_throw<EXC>, "boost_throw<" + what + ">");
}
/*****************************************************************************
* TUT
*****************************************************************************/
namespace tut
{
struct llexception_data
{
};
typedef test_group<llexception_data> llexception_group;
typedef llexception_group::object object;
llexception_group llexceptiongrp("llexception");
template<> template<>
void object::test<1>()
{
set_test_name("throwing exceptions");
// For each kind of exception, try both kinds of throw against all
// three catch sequences
std::size_t margin = 72;
std::cout << center("FromStd", '=', margin) << std::endl;
catch_both_several<FromStd>("FromStd");
std::cout << center("FromBoth", '=', margin) << std::endl;
catch_both_several<FromBoth>("FromBoth");
std::cout << center("FromBoost", '=', margin) << std::endl;
// can't throw with BOOST_THROW_EXCEPTION(), just use catch_several()
catch_several(plain_throw<FromBoost>, "plain_throw<FromBoost>");
std::cout << center("FromNeither", '=', margin) << std::endl;
// can't throw this with BOOST_THROW_EXCEPTION() either
catch_several(plain_throw<FromNeither>, "plain_throw<FromNeither>");
std::cout << center("const char*", '=', margin) << std::endl;
// We don't expect BOOST_THROW_EXCEPTION() to throw anything so daft
// as a const char* or an int, so don't bother with
// catch_both_several() -- just catch_several().
catch_several(throw_char_ptr, "throw_char_ptr");
std::cout << center("int", '=', margin) << std::endl;
catch_several(throw_int, "throw_int");
}
} // namespace tut

View File

@ -35,13 +35,13 @@
#include <tut/tut.hpp>
#include "llerrorcontrol.h"
#include "llexception.h"
#include "stringize.h"
#include <boost/bind.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <list>
#include <string>
#include <stdexcept>
// statically reference the function in test.cpp... it's short, we could
// replicate, but better to reuse
@ -67,9 +67,9 @@ struct WrapLLErrs
LLError::restoreSettings(mPriorErrorSettings);
}
struct FatalException: public std::runtime_error
struct FatalException: public LLException
{
FatalException(const std::string& what): std::runtime_error(what) {}
FatalException(const std::string& what): LLException(what) {}
};
void operator()(const std::string& message)
@ -78,7 +78,7 @@ struct WrapLLErrs
error = message;
// Also throw an appropriate exception since calling code is likely to
// assume that control won't continue beyond LL_ERRS.
throw FatalException(message);
LLTHROW(FatalException(message));
}
std::string error;

View File

@ -57,7 +57,7 @@ public:
LLSD constructPostData();
virtual void updateApplication(const std::string& message = LLStringUtil::null);
virtual bool init();
virtual bool mainLoop() = 0;
virtual bool frame() = 0;
virtual bool cleanup() = 0;
void commonCleanup();
void setUserText(const std::string& text) { mCrashInfo["UserNotes"] = text; }

View File

@ -773,7 +773,8 @@ const U8* LLImageBase::getData() const
{
if(mBadBufferAllocation)
{
LL_ERRS() << "Bad memory allocation for the image buffer!" << LL_ENDL ;
LL_WARNS() << "Bad memory allocation for the image buffer!" << LL_ENDL ;
return NULL;
}
return mData;
@ -783,7 +784,8 @@ U8* LLImageBase::getData()
{
if(mBadBufferAllocation)
{
LL_ERRS() << "Bad memory allocation for the image buffer!" << LL_ENDL ;
LL_WARNS() << "Bad memory allocation for the image buffer!" << LL_ENDL;
return NULL;
}
return mData;
@ -895,30 +897,30 @@ void LLImageRaw::setDataAndSize(U8 *data, S32 width, S32 height, S8 components)
sGlobalRawMemory += getDataSize();
}
BOOL LLImageRaw::resize(U16 width, U16 height, S8 components)
bool LLImageRaw::resize(U16 width, U16 height, S8 components)
{
if ((getWidth() == width) && (getHeight() == height) && (getComponents() == components))
{
return TRUE;
return true;
}
// Reallocate the data buffer.
deleteData();
allocateDataSize(width,height,components);
return TRUE;
return true;
}
BOOL LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,
const U8 *data, U32 stride, BOOL reverse_y)
bool LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,
const U8 *data, U32 stride, bool reverse_y)
{
if (!getData())
{
return FALSE;
return false;
}
if (!data)
{
return FALSE;
return false;
}
// Should do some simple bounds checking
@ -933,13 +935,19 @@ BOOL LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,
data + from_offset, getComponents()*width);
}
return TRUE;
return true;
}
void LLImageRaw::clear(U8 r, U8 g, U8 b, U8 a)
{
llassert( getComponents() <= 4 );
// This is fairly bogus, but it'll do for now.
if (isBufferInvalid())
{
LL_WARNS() << "Invalid image buffer" << LL_ENDL;
return;
}
U8 *pos = getData();
U32 x, y;
for (x = 0; x < getWidth(); x++)
@ -988,7 +996,7 @@ void LLImageRaw::verticalFlip()
}
void LLImageRaw::expandToPowerOfTwo(S32 max_dim, BOOL scale_image)
void LLImageRaw::expandToPowerOfTwo(S32 max_dim, bool scale_image)
{
// Find new sizes
S32 new_width = expandDimToPowerOfTwo(getWidth(), max_dim);
@ -997,7 +1005,7 @@ void LLImageRaw::expandToPowerOfTwo(S32 max_dim, BOOL scale_image)
scale( new_width, new_height, scale_image );
}
void LLImageRaw::contractToPowerOfTwo(S32 max_dim, BOOL scale_image)
void LLImageRaw::contractToPowerOfTwo(S32 max_dim, bool scale_image)
{
// Find new sizes
S32 new_width = contractDimToPowerOfTwo(getWidth(), MIN_IMAGE_SIZE);
@ -1067,6 +1075,11 @@ void LLImageRaw::composite( LLImageRaw* src )
{
LLImageRaw* dst = this; // Just for clarity.
if (!validateSrcAndDst("LLImageRaw::composite", src, dst))
{
return;
}
llassert(3 == src->getComponents());
llassert(3 == dst->getComponents());
@ -1134,7 +1147,6 @@ void LLImageRaw::compositeUnscaled4onto3( LLImageRaw* src )
llassert( (3 == src->getComponents()) || (4 == src->getComponents()) );
llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) );
U8* src_data = src->getData();
U8* dst_data = dst->getData();
S32 pixels = getWidth() * getHeight();
@ -1169,6 +1181,11 @@ void LLImageRaw::copyUnscaledAlphaMask( LLImageRaw* src, const LLColor4U& fill)
{
LLImageRaw* dst = this; // Just for clarity.
if (!validateSrcAndDst("LLImageRaw::copyUnscaledAlphaMask", src, dst))
{
return;
}
llassert( 1 == src->getComponents() );
llassert( 4 == dst->getComponents() );
llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) );
@ -1191,6 +1208,12 @@ void LLImageRaw::copyUnscaledAlphaMask( LLImageRaw* src, const LLColor4U& fill)
// Fill the buffer with a constant color
void LLImageRaw::fill( const LLColor4U& color )
{
if (isBufferInvalid())
{
LL_WARNS() << "Invalid image buffer" << LL_ENDL;
return;
}
S32 pixels = getWidth() * getHeight();
if( 4 == getComponents() )
{
@ -1229,14 +1252,13 @@ LLPointer<LLImageRaw> LLImageRaw::duplicate()
// Src and dst can be any size. Src and dst can each have 3 or 4 components.
void LLImageRaw::copy(LLImageRaw* src)
{
if (!src)
LLImageRaw* dst = this; // Just for clarity.
if (!validateSrcAndDst("LLImageRaw::copy", src, dst))
{
LL_WARNS() << "LLImageRaw::copy called with a null src pointer" << LL_ENDL;
return;
}
LLImageRaw* dst = this; // Just for clarity.
if( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) )
{
// No scaling needed
@ -1363,6 +1385,11 @@ void LLImageRaw::copyScaled( LLImageRaw* src )
{
LLImageRaw* dst = this; // Just for clarity.
if (!validateSrcAndDst("LLImageRaw::copyScaled", src, dst))
{
return;
}
llassert_always( (1 == src->getComponents()) || (3 == src->getComponents()) || (4 == src->getComponents()) );
llassert_always( src->getComponents() == dst->getComponents() );
@ -1397,86 +1424,83 @@ void LLImageRaw::copyScaled( LLImageRaw* src )
}
BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )
bool LLImageRaw::scale( S32 new_width, S32 new_height, bool scale_image_data )
{
llassert((1 == getComponents()) || (3 == getComponents()) || (4 == getComponents()) );
S32 components = getComponents();
if (! ((1 == components) || (3 == components) || (4 == components) ))
{
LL_WARNS() << "Invalid getComponents value (" << components << ")" << LL_ENDL;
return false;
}
if (isBufferInvalid())
{
LL_WARNS() << "Invalid image buffer" << LL_ENDL;
return false;
}
S32 old_width = getWidth();
S32 old_height = getHeight();
if( (old_width == new_width) && (old_height == new_height) )
{
return TRUE; // Nothing to do.
return true; // Nothing to do.
}
// Reallocate the data buffer.
if (scale_image_data)
{
/*
S32 temp_data_size = old_width * new_height * getComponents();
llassert_always(temp_data_size > 0);
std::vector<U8> temp_buffer(temp_data_size);
S32 new_data_size = new_width * new_height * components;
// Vertical
for( S32 col = 0; col < old_width; col++ )
{
copyLineScaled( getData() + (getComponents() * col), &temp_buffer[0] + (getComponents() * col), old_height, new_height, old_width, old_width );
if (new_data_size > 0)
{
U8 *new_data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), new_data_size);
if(NULL == new_data)
{
return false;
}
bilinear_scale(getData(), old_width, old_height, components, old_width*components, new_data, new_width, new_height, components, new_width*components);
setDataAndSize(new_data, new_width, new_height, components);
}
deleteData();
U8* new_buffer = allocateDataSize(new_width, new_height, getComponents());
// Horizontal
for( S32 row = 0; row < new_height; row++ )
{
copyLineScaled( &temp_buffer[0] + (getComponents() * old_width * row), new_buffer + (getComponents() * new_width * row), old_width, new_width, 1, 1 );
}
*/
S32 new_data_size = new_width * new_height * getComponents();
llassert_always(new_data_size > 0);
U8 *new_data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), new_data_size);
if(NULL == new_data)
{
return FALSE;
}
bilinear_scale(getData(), old_width, old_height, getComponents(), old_width*getComponents(), new_data, new_width, new_height, getComponents(), new_width*getComponents());
setDataAndSize(new_data, new_width, new_height, getComponents());
}
else
{
// copy out existing image data
S32 temp_data_size = old_width * old_height * getComponents();
S32 temp_data_size = old_width * old_height * components;
std::vector<U8> temp_buffer(temp_data_size);
memcpy(&temp_buffer[0], getData(), temp_data_size);
// allocate new image data, will delete old data
U8* new_buffer = allocateDataSize(new_width, new_height, getComponents());
U8* new_buffer = allocateDataSize(new_width, new_height, components);
for( S32 row = 0; row < new_height; row++ )
{
if (row < old_height)
{
memcpy(new_buffer + (new_width * row * getComponents()), &temp_buffer[0] + (old_width * row * getComponents()), getComponents() * llmin(old_width, new_width));
if (old_width < new_width)
{
// pad out rest of row with black
memset(new_buffer + (getComponents() * ((new_width * row) + old_width)), 0, getComponents() * (new_width - old_width));
}
}
else
{
// pad remaining rows with black
memset(new_buffer + (new_width * row * getComponents()), 0, new_width * getComponents());
}
}
if (!new_buffer)
{
LL_WARNS() << "Failed to allocate new image data buffer" << LL_ENDL;
return false;
}
for( S32 row = 0; row < new_height; row++ )
{
if (row < old_height)
{
memcpy(new_buffer + (new_width * row * components), &temp_buffer[0] + (old_width * row * components), components * llmin(old_width, new_width));
if (old_width < new_width)
{
// pad out rest of row with black
memset(new_buffer + (components * ((new_width * row) + old_width)), 0, components * (new_width - old_width));
}
}
else
{
// pad remaining rows with black
memset(new_buffer + (new_width * row * components), 0, new_width * components);
}
}
}
return TRUE ;
return true ;
}
void LLImageRaw::copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step )
@ -1690,6 +1714,25 @@ void LLImageRaw::compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S3
}
}
bool LLImageRaw::validateSrcAndDst(std::string func, LLImageRaw* src, LLImageRaw* dst)
{
if (!src || !dst || src->isBufferInvalid() || dst->isBufferInvalid())
{
LL_WARNS() << func << ": Source: ";
if (!src) LL_CONT << "Null pointer";
else if (src->isBufferInvalid()) LL_CONT << "Invalid buffer";
else LL_CONT << "OK";
LL_CONT << "; Destination: ";
if (!dst) LL_CONT << "Null pointer";
else if (dst->isBufferInvalid()) LL_CONT << "Invalid buffer";
else LL_CONT << "OK";
LL_CONT << "." << LL_ENDL;
return false;
}
return true;
}
//----------------------------------------------------------------------------
@ -1795,7 +1838,7 @@ bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip
ifs.read ((char*)buffer, length);
ifs.close();
BOOL success;
bool success;
success = image->updateData();
if (success)
@ -1971,7 +2014,7 @@ S32 LLImageFormatted::calcDiscardLevelBytes(S32 bytes)
//----------------------------------------------------------------------------
// Subclasses that can handle more than 4 channels should override this function.
BOOL LLImageFormatted::decodeChannels(LLImageRaw* raw_image,F32 decode_time, S32 first_channel, S32 max_channel)
bool LLImageFormatted::decodeChannels(LLImageRaw* raw_image,F32 decode_time, S32 first_channel, S32 max_channel)
{
llassert( (first_channel == 0) && (max_channel == 4) );
return decode( raw_image, decode_time ); // Loads first 4 channels by default.
@ -2022,7 +2065,7 @@ void LLImageFormatted::sanityCheck()
//----------------------------------------------------------------------------
BOOL LLImageFormatted::copyData(U8 *data, S32 size)
bool LLImageFormatted::copyData(U8 *data, S32 size)
{
if ( data && ((data != getData()) || (size != getDataSize())) )
{
@ -2030,7 +2073,7 @@ BOOL LLImageFormatted::copyData(U8 *data, S32 size)
allocateData(size);
memcpy(getData(), data, size); /* Flawfinder: ignore */
}
return TRUE;
return true;
}
// LLImageFormatted becomes the owner of data
@ -2066,7 +2109,7 @@ void LLImageFormatted::appendData(U8 *data, S32 size)
//----------------------------------------------------------------------------
BOOL LLImageFormatted::load(const std::string &filename, int load_size)
bool LLImageFormatted::load(const std::string &filename, int load_size)
{
resetLastError();
@ -2077,12 +2120,12 @@ BOOL LLImageFormatted::load(const std::string &filename, int load_size)
if (!apr_file)
{
setLastError("Unable to open file for reading", filename);
return FALSE;
return false;
}
if (file_size == 0)
{
setLastError("File is empty",filename);
return FALSE;
return false;
}
// Constrain the load size to acceptable values
@ -2090,7 +2133,7 @@ BOOL LLImageFormatted::load(const std::string &filename, int load_size)
{
load_size = file_size;
}
BOOL res;
bool res;
U8 *data = allocateData(load_size);
apr_size_t bytes_read = load_size;
apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read
@ -2098,7 +2141,7 @@ BOOL LLImageFormatted::load(const std::string &filename, int load_size)
{
deleteData();
setLastError("Unable to read file",filename);
res = FALSE;
res = false;
}
else
{
@ -2108,7 +2151,7 @@ BOOL LLImageFormatted::load(const std::string &filename, int load_size)
return res;
}
BOOL LLImageFormatted::save(const std::string &filename)
bool LLImageFormatted::save(const std::string &filename)
{
resetLastError();
@ -2117,15 +2160,15 @@ BOOL LLImageFormatted::save(const std::string &filename)
if (!outfile.getFileHandle())
{
setLastError("Unable to open file for writing", filename);
return FALSE;
return false;
}
outfile.write(getData(), getDataSize());
outfile.close() ;
return TRUE;
return true;
}
// BOOL LLImageFormatted::save(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type)
// bool LLImageFormatted::save(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type)
// Depricated to remove VFS dependency.
// Use:
// LLVFile::writeFile(image->getData(), image->getDataSize(), vfs, uuid, type);

View File

@ -199,11 +199,11 @@ public:
/*virtual*/ U8* allocateData(S32 size = -1);
/*virtual*/ U8* reallocateData(S32 size);
BOOL resize(U16 width, U16 height, S8 components);
bool resize(U16 width, U16 height, S8 components);
//U8 * getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const;
BOOL setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,
const U8 *data, U32 stride = 0, BOOL reverse_y = FALSE);
bool setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,
const U8 *data, U32 stride = 0, bool reverse_y = false);
void clear(U8 r=0, U8 g=0, U8 b=0, U8 a=255);
@ -212,10 +212,10 @@ public:
static S32 biasedDimToPowerOfTwo(S32 curr_dim, S32 max_dim = MAX_IMAGE_SIZE);
static S32 expandDimToPowerOfTwo(S32 curr_dim, S32 max_dim = MAX_IMAGE_SIZE);
static S32 contractDimToPowerOfTwo(S32 curr_dim, S32 min_dim = MIN_IMAGE_SIZE);
void expandToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE);
void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE);
void expandToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, bool scale_image = true);
void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, bool scale_image = true);
void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE);
BOOL scale( S32 new_width, S32 new_height, BOOL scale_image = TRUE );
bool scale( S32 new_width, S32 new_height, bool scale_image = true );
// Fill the buffer with a constant color
void fill( const LLColor4U& color );
@ -277,6 +277,9 @@ protected:
public:
static S32 sGlobalRawMemory;
static S32 sRawImageCount;
private:
bool validateSrcAndDst(std::string func, LLImageRaw* src, LLImageRaw* dst);
};
// Compressed representation of image.
@ -314,23 +317,23 @@ public:
// getRawDiscardLevel() by default returns mDiscardLevel, but may be overridden (LLImageJ2C)
virtual S8 getRawDiscardLevel() { return mDiscardLevel; }
BOOL load(const std::string& filename, int load_size = 0);
BOOL save(const std::string& filename);
bool load(const std::string& filename, int load_size = 0);
bool save(const std::string& filename);
virtual BOOL updateData() = 0; // pure virtual
virtual bool updateData() = 0; // pure virtual
void setData(U8 *data, S32 size);
void appendData(U8 *data, S32 size);
// Loads first 4 channels.
virtual BOOL decode(LLImageRaw* raw_image, F32 decode_time) = 0;
virtual bool decode(LLImageRaw* raw_image, F32 decode_time) = 0;
// Subclasses that can handle more than 4 channels should override this function.
virtual BOOL decodeChannels(LLImageRaw* raw_image, F32 decode_time, S32 first_channel, S32 max_channel);
virtual bool decodeChannels(LLImageRaw* raw_image, F32 decode_time, S32 first_channel, S32 max_channel);
virtual BOOL encode(const LLImageRaw* raw_image, F32 encode_time) = 0;
virtual bool encode(const LLImageRaw* raw_image, F32 encode_time) = 0;
S8 getCodec() const;
BOOL isDecoding() const { return mDecoding ? TRUE : FALSE; }
BOOL isDecoded() const { return mDecoded ? TRUE : FALSE; }
bool isDecoding() const { return mDecoding; }
bool isDecoded() const { return mDecoded; }
void setDiscardLevel(S8 discard_level) { mDiscardLevel = discard_level; }
S8 getDiscardLevel() const { return mDiscardLevel; }
S8 getLevels() const { return mLevels; }
@ -341,7 +344,7 @@ public:
virtual void setLastError(const std::string& message, const std::string& filename = std::string());
protected:
BOOL copyData(U8 *data, S32 size); // calls updateData()
bool copyData(U8 *data, S32 size); // calls updateData()
protected:
S8 mCodec;

View File

@ -78,7 +78,7 @@ LLImageBMP::LLImageBMP()
mColorPalette( NULL ),
mBitmapOffset( 0 ),
mBitsPerPixel( 0 ),
mOriginAtTop( FALSE )
mOriginAtTop( false )
{
mBitfieldMask[0] = 0;
mBitfieldMask[1] = 0;
@ -92,7 +92,7 @@ LLImageBMP::~LLImageBMP()
}
BOOL LLImageBMP::updateData()
bool LLImageBMP::updateData()
{
resetLastError();
@ -101,7 +101,7 @@ BOOL LLImageBMP::updateData()
if (!mdata || (0 == getDataSize()))
{
setLastError("Uninitialized instance of LLImageBMP");
return FALSE;
return false;
}
// Read the bitmap headers in order to get all the useful info
@ -120,12 +120,12 @@ BOOL LLImageBMP::updateData()
if ((mdata[0] != 'B') || (mdata[1] != 'A'))
{
setLastError("OS/2 bitmap array BMP files are not supported");
return FALSE;
return false;
}
else
{
setLastError("Does not appear to be a bitmap file");
return FALSE;
return false;
}
}
@ -160,12 +160,12 @@ BOOL LLImageBMP::updateData()
llendianswizzleone(header.mNumColors);
llendianswizzleone(header.mNumColorsImportant);
BOOL windows_nt_version = FALSE;
BOOL windows_95_version = FALSE;
bool windows_nt_version = false;
bool windows_95_version = false;
if( 12 == header.mSize )
{
setLastError("Windows 2.x and OS/2 1.x BMP files are not supported");
return FALSE;
return false;
}
else
if( 40 == header.mSize )
@ -173,7 +173,7 @@ BOOL LLImageBMP::updateData()
if( 3 == header.mCompression )
{
// Windows NT
windows_nt_version = TRUE;
windows_nt_version = true;
}
else
{
@ -184,32 +184,32 @@ BOOL LLImageBMP::updateData()
if( 12 <= header.mSize && 64 <= header.mSize )
{
setLastError("OS/2 2.x BMP files are not supported");
return FALSE;
return false;
}
else
if( 108 == header.mSize )
{
// BITMAPV4HEADER
windows_95_version = TRUE;
windows_95_version = true;
}
else
if( 108 < header.mSize )
{
// BITMAPV5HEADER or greater
// Should work as long at Microsoft maintained backwards compatibility (which they did in V4 and V5)
windows_95_version = TRUE;
windows_95_version = true;
}
S32 width = header.mWidth;
S32 height = header.mHeight;
if (height < 0)
{
mOriginAtTop = TRUE;
mOriginAtTop = true;
height = -height;
}
else
{
mOriginAtTop = FALSE;
mOriginAtTop = false;
}
mBitsPerPixel = header.mBitsPerPixel;
@ -228,10 +228,10 @@ BOOL LLImageBMP::updateData()
case 16: // Started work on 16, but doesn't work yet
// These are legal, but we don't support them yet.
setLastError("Unsupported bit depth");
return FALSE;
return false;
default:
setLastError("Unrecognized bit depth");
return FALSE;
return false;
}
setSize(width, height, components);
@ -244,11 +244,11 @@ BOOL LLImageBMP::updateData()
case 1:
setLastError("8 bit RLE compression not supported.");
return FALSE;
return false;
case 2:
setLastError("4 bit RLE compression not supported.");
return FALSE;
return false;
case 3:
// Windows NT or Windows 95
@ -256,7 +256,7 @@ BOOL LLImageBMP::updateData()
default:
setLastError("Unsupported compression format.");
return FALSE;
return false;
}
////////////////////////////////////////////////////////////////////
@ -267,13 +267,13 @@ BOOL LLImageBMP::updateData()
if( (16 != header.mBitsPerPixel) && (32 != header.mBitsPerPixel) )
{
setLastError("Bitfield encoding requires 16 or 32 bits per pixel.");
return FALSE;
return false;
}
if( 0 != header.mNumColors )
{
setLastError("Bitfield encoding is not compatible with a color table.");
return FALSE;
return false;
}
@ -322,15 +322,15 @@ BOOL LLImageBMP::updateData()
if (!mColorPalette)
{
LL_ERRS() << "Out of memory in LLImageBMP::updateData()" << LL_ENDL;
return FALSE;
return false;
}
memcpy( mColorPalette, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE + extension_size, color_palette_size ); /* Flawfinder: ignore */
}
return TRUE;
return true;
}
BOOL LLImageBMP::decode(LLImageRaw* raw_image, F32 decode_time)
bool LLImageBMP::decode(LLImageRaw* raw_image, F32 decode_time)
{
llassert_always(raw_image);
@ -341,7 +341,7 @@ BOOL LLImageBMP::decode(LLImageRaw* raw_image, F32 decode_time)
if (!mdata || (0 == getDataSize()))
{
setLastError("llimagebmp trying to decode an image with no data!");
return FALSE;
return false;
}
raw_image->resize(getWidth(), getHeight(), 3);
@ -349,7 +349,7 @@ BOOL LLImageBMP::decode(LLImageRaw* raw_image, F32 decode_time)
U8* src = mdata + mBitmapOffset;
U8* dst = raw_image->getData();
BOOL success = FALSE;
bool success = false;
switch( mBitsPerPixel )
{
@ -393,7 +393,7 @@ U32 LLImageBMP::countTrailingZeros( U32 m )
}
BOOL LLImageBMP::decodeColorMask16( U8* dst, U8* src )
bool LLImageBMP::decodeColorMask16( U8* dst, U8* src )
{
llassert( 16 == mBitsPerPixel );
@ -426,10 +426,10 @@ BOOL LLImageBMP::decodeColorMask16( U8* dst, U8* src )
src += alignment_bytes;
}
return TRUE;
return true;
}
BOOL LLImageBMP::decodeColorMask32( U8* dst, U8* src )
bool LLImageBMP::decodeColorMask32( U8* dst, U8* src )
{
// Note: alpha is not supported
@ -445,7 +445,7 @@ BOOL LLImageBMP::decodeColorMask32( U8* dst, U8* src )
if (getWidth() * getHeight() * 4 > getDataSize() - mBitmapOffset)
{ //here we have situation when data size in src less than actually needed
return FALSE;
return false;
}
S32 src_row_span = getWidth() * 4;
@ -469,11 +469,11 @@ BOOL LLImageBMP::decodeColorMask32( U8* dst, U8* src )
src += alignment_bytes;
}
return TRUE;
return true;
}
BOOL LLImageBMP::decodeColorTable8( U8* dst, U8* src )
bool LLImageBMP::decodeColorTable8( U8* dst, U8* src )
{
llassert( (8 == mBitsPerPixel) && (mColorPaletteColors >= 256) );
@ -482,7 +482,7 @@ BOOL LLImageBMP::decodeColorTable8( U8* dst, U8* src )
if ((getWidth() * getHeight()) + getHeight() * alignment_bytes > getDataSize() - mBitmapOffset)
{ //here we have situation when data size in src less than actually needed
return FALSE;
return false;
}
for( S32 row = 0; row < getHeight(); row++ )
@ -499,11 +499,11 @@ BOOL LLImageBMP::decodeColorTable8( U8* dst, U8* src )
src += alignment_bytes;
}
return TRUE;
return true;
}
BOOL LLImageBMP::decodeTruecolor24( U8* dst, U8* src )
bool LLImageBMP::decodeTruecolor24( U8* dst, U8* src )
{
llassert( 24 == mBitsPerPixel );
llassert( 3 == getComponents() );
@ -512,7 +512,7 @@ BOOL LLImageBMP::decodeTruecolor24( U8* dst, U8* src )
if ((getWidth() * getHeight() * 3) + getHeight() * alignment_bytes > getDataSize() - mBitmapOffset)
{ //here we have situation when data size in src less than actually needed
return FALSE;
return false;
}
for( S32 row = 0; row < getHeight(); row++ )
@ -528,10 +528,10 @@ BOOL LLImageBMP::decodeTruecolor24( U8* dst, U8* src )
src += alignment_bytes;
}
return TRUE;
return true;
}
BOOL LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time)
bool LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time)
{
llassert_always(raw_image);
@ -563,7 +563,7 @@ BOOL LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time)
// Allocate the new buffer for the data.
if(!allocateData(file_bytes)) //memory allocation failed
{
return FALSE ;
return false ;
}
magic[0] = 'B'; magic[1] = 'M';
@ -663,5 +663,5 @@ BOOL LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time)
}
}
return TRUE;
return true;
}

View File

@ -40,15 +40,15 @@ public:
LLImageBMP();
/*virtual*/ std::string getExtension() { return std::string("bmp"); }
/*virtual*/ BOOL updateData();
/*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 decode_time);
/*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 encode_time);
/*virtual*/ bool updateData();
/*virtual*/ bool decode(LLImageRaw* raw_image, F32 decode_time);
/*virtual*/ bool encode(const LLImageRaw* raw_image, F32 encode_time);
protected:
BOOL decodeColorTable8( U8* dst, U8* src );
BOOL decodeColorMask16( U8* dst, U8* src );
BOOL decodeTruecolor24( U8* dst, U8* src );
BOOL decodeColorMask32( U8* dst, U8* src );
bool decodeColorTable8( U8* dst, U8* src );
bool decodeColorMask16( U8* dst, U8* src );
bool decodeTruecolor24( U8* dst, U8* src );
bool decodeColorMask32( U8* dst, U8* src );
U32 countTrailingZeros( U32 m );
@ -58,7 +58,7 @@ protected:
S32 mBitmapOffset;
S32 mBitsPerPixel;
U32 mBitfieldMask[4]; // rgba
BOOL mOriginAtTop;
bool mOriginAtTop;
};
#endif

View File

@ -201,7 +201,7 @@ bool LLImageDimensionsInfo::getImageDimensionsJpeg()
cinfo.out_color_space = JCS_RGB;
jpeg_start_decompress (&cinfo);
mHeight = cinfo.output_width;
mWidth = cinfo.output_width;
mHeight = cinfo.output_height;
jpeg_destroy_decompress(&cinfo);

View File

@ -172,7 +172,7 @@ LLImageDXT::~LLImageDXT()
}
// virtual
BOOL LLImageDXT::updateData()
bool LLImageDXT::updateData()
{
resetLastError();
@ -182,7 +182,7 @@ BOOL LLImageDXT::updateData()
if (!data || !data_size)
{
setLastError("LLImageDXT uninitialized");
return FALSE;
return false;
}
S32 width, height, miplevelmax;
@ -216,7 +216,7 @@ BOOL LLImageDXT::updateData()
discard = llmin(discard, miplevelmax);
setDiscardLevel(discard);
return TRUE;
return true;
}
// discard: 0 = largest (last) mip
@ -257,7 +257,7 @@ void LLImageDXT::setFormat()
}
// virtual
BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time)
bool LLImageDXT::decode(LLImageRaw* raw_image, F32 time)
{
// *TODO: Test! This has been tweaked since its intial inception,
// but we don't use it any more!
@ -266,7 +266,7 @@ BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time)
if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXR5)
{
LL_WARNS() << "Attempt to decode compressed LLImageDXT to Raw (unsupported)" << LL_ENDL;
return FALSE;
return false;
}
S32 width = getWidth(), height = getHeight();
@ -286,16 +286,16 @@ BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time)
if ((!getData()) || (data + image_size > getData() + getDataSize()))
{
setLastError("LLImageDXT trying to decode an image with not enough data!");
return FALSE;
return false;
}
raw_image->resize(width, height, ncomponents);
memcpy(raw_image->getData(), data, image_size); /* Flawfinder: ignore */
return TRUE;
return true;
}
BOOL LLImageDXT::getMipData(LLPointer<LLImageRaw>& raw, S32 discard)
bool LLImageDXT::getMipData(LLPointer<LLImageRaw>& raw, S32 discard)
{
if (discard < 0)
{
@ -310,10 +310,10 @@ BOOL LLImageDXT::getMipData(LLPointer<LLImageRaw>& raw, S32 discard)
S32 height = 0;
calcDiscardWidthHeight(discard, mFileFormat, width, height);
raw = new LLImageRaw(data, width, height, getComponents());
return TRUE;
return true;
}
BOOL LLImageDXT::encodeDXT(const LLImageRaw* raw_image, F32 time, bool explicit_mips)
bool LLImageDXT::encodeDXT(const LLImageRaw* raw_image, F32 time, bool explicit_mips)
{
llassert_always(raw_image);
@ -395,11 +395,11 @@ BOOL LLImageDXT::encodeDXT(const LLImageRaw* raw_image, F32 time, bool explicit_
prev_mipdata = mipdata;
}
return TRUE;
return true;
}
// virtual
BOOL LLImageDXT::encode(const LLImageRaw* raw_image, F32 time)
bool LLImageDXT::encode(const LLImageRaw* raw_image, F32 time)
{
return encodeDXT(raw_image, time, false);
}

View File

@ -93,21 +93,21 @@ protected:
/*virtual*/ ~LLImageDXT();
private:
BOOL encodeDXT(const LLImageRaw* raw_image, F32 decode_time, bool explicit_mips);
bool encodeDXT(const LLImageRaw* raw_image, F32 decode_time, bool explicit_mips);
public:
LLImageDXT();
/*virtual*/ std::string getExtension() { return std::string("dxt"); }
/*virtual*/ BOOL updateData();
/*virtual*/ bool updateData();
/*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 decode_time);
/*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 encode_time);
/*virtual*/ bool decode(LLImageRaw* raw_image, F32 decode_time);
/*virtual*/ bool encode(const LLImageRaw* raw_image, F32 encode_time);
/*virtual*/ S32 calcHeaderSize();
/*virtual*/ S32 calcDataSize(S32 discard_level = 0);
BOOL getMipData(LLPointer<LLImageRaw>& raw, S32 discard=-1);
bool getMipData(LLPointer<LLImageRaw>& raw, S32 discard=-1);
void setFormat();
S32 getMipOffset(S32 discard);

View File

@ -31,18 +31,13 @@
#include "llmath.h"
#include "llmemory.h"
#include "llsd.h"
#include <boost/scoped_ptr.hpp>
typedef LLImageJ2CImpl* (*CreateLLImageJ2CFunction)();
typedef void (*DestroyLLImageJ2CFunction)(LLImageJ2CImpl*);
typedef const char* (*EngineInfoLLImageJ2CFunction)();
// Declare the prototype for theses functions here. Their functionality
// will be implemented in other files which define a derived LLImageJ2CImpl
// but only ONE static library which has the implementation for these
// functions should ever be included.
// Declare the prototype for this factory function here. It is implemented in
// other files which define a LLImageJ2CImpl subclass, but only ONE static
// library which has the implementation for this function should ever be
// linked.
LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl();
void fallbackDestroyLLImageJ2CImpl(LLImageJ2CImpl* impl);
const char* fallbackEngineInfoLLImageJ2CImpl();
// Test data gathering handle
LLImageCompressionTester* LLImageJ2C::sTesterp = NULL ;
@ -51,17 +46,20 @@ const std::string sTesterName("ImageCompressionTester");
//static
std::string LLImageJ2C::getEngineInfo()
{
return fallbackEngineInfoLLImageJ2CImpl();
// All known LLImageJ2CImpl implementation subclasses are cheap to
// construct.
boost::scoped_ptr<LLImageJ2CImpl> impl(fallbackCreateLLImageJ2CImpl());
return impl->getEngineInfo();
}
LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C),
mMaxBytes(0),
mRawDiscardLevel(-1),
mRate(DEFAULT_COMPRESSION_RATE),
mReversible(FALSE),
mReversible(false),
mAreaUsedForDataSizeCalcs(0)
{
mImpl = fallbackCreateLLImageJ2CImpl();
mImpl.reset(fallbackCreateLLImageJ2CImpl());
claimMem(mImpl);
// Clear data size table
@ -83,13 +81,7 @@ LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C),
}
// virtual
LLImageJ2C::~LLImageJ2C()
{
if ( mImpl )
{
fallbackDestroyLLImageJ2CImpl(mImpl);
}
}
LLImageJ2C::~LLImageJ2C() {}
// virtual
void LLImageJ2C::resetLastError()
@ -111,16 +103,16 @@ S8 LLImageJ2C::getRawDiscardLevel()
return mRawDiscardLevel;
}
BOOL LLImageJ2C::updateData()
bool LLImageJ2C::updateData()
{
BOOL res = TRUE;
bool res = true;
resetLastError();
// Check to make sure that this instance has been initialized with data
if (!getData() || (getDataSize() < 16))
{
setLastError("LLImageJ2C uninitialized");
res = FALSE;
res = false;
}
else
{
@ -142,29 +134,29 @@ BOOL LLImageJ2C::updateData()
return res;
}
BOOL LLImageJ2C::initDecode(LLImageRaw &raw_image, int discard_level, int* region)
bool LLImageJ2C::initDecode(LLImageRaw &raw_image, int discard_level, int* region)
{
setDiscardLevel(discard_level != -1 ? discard_level : 0);
return mImpl->initDecode(*this,raw_image,discard_level,region);
}
BOOL LLImageJ2C::initEncode(LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)
bool LLImageJ2C::initEncode(LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)
{
return mImpl->initEncode(*this,raw_image,blocks_size,precincts_size,levels);
}
BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time)
bool LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time)
{
return decodeChannels(raw_imagep, decode_time, 0, 4);
}
// Returns TRUE to mean done, whether successful or not.
BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count )
// Returns true to mean done, whether successful or not.
bool LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count )
{
LLTimer elapsed;
BOOL res = TRUE;
bool res = true;
resetLastError();
@ -172,13 +164,13 @@ BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir
if (!getData() || (getDataSize() < 16))
{
setLastError("LLImageJ2C uninitialized");
res = TRUE; // done
res = true; // done
}
else
{
// Update the raw discard level
updateRawDiscardLevel();
mDecoding = TRUE;
mDecoding = true;
res = mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count);
}
@ -191,7 +183,7 @@ BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir
}
else
{
mDecoding = FALSE;
mDecoding = false;
}
}
@ -210,7 +202,7 @@ BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir
tester->updateDecompressionStats(elapsed.getElapsedTimeF32()) ;
if (res)
{
// The whole data stream is finally decompressed when res is returned as TRUE
// The whole data stream is finally decompressed when res is returned as true
tester->updateDecompressionStats(this->getDataSize(), raw_imagep->getDataSize()) ;
}
}
@ -219,17 +211,17 @@ BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir
}
BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, F32 encode_time)
bool LLImageJ2C::encode(const LLImageRaw *raw_imagep, F32 encode_time)
{
return encode(raw_imagep, NULL, encode_time);
}
BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time)
bool LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time)
{
LLTimer elapsed;
resetLastError();
BOOL res = mImpl->encodeImpl(*this, *raw_imagep, comment_text, encode_time, mReversible);
bool res = mImpl->encodeImpl(*this, *raw_imagep, comment_text, encode_time, mReversible);
if (!mLastError.empty())
{
LLImage::setLastError(mLastError);
@ -245,7 +237,7 @@ BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text,
tester->updateCompressionStats(elapsed.getElapsedTimeF32()) ;
if (res)
{
// The whole data stream is finally compressed when res is returned as TRUE
// The whole data stream is finally compressed when res is returned as true
tester->updateCompressionStats(this->getDataSize(), raw_imagep->getDataSize()) ;
}
}
@ -348,15 +340,15 @@ void LLImageJ2C::setMaxBytes(S32 max_bytes)
mMaxBytes = max_bytes;
}
void LLImageJ2C::setReversible(const BOOL reversible)
void LLImageJ2C::setReversible(const bool reversible)
{
mReversible = reversible;
}
BOOL LLImageJ2C::loadAndValidate(const std::string &filename)
bool LLImageJ2C::loadAndValidate(const std::string &filename)
{
BOOL res = TRUE;
bool res = true;
resetLastError();
@ -367,12 +359,12 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename)
if (!apr_file)
{
setLastError("Unable to open file for reading", filename);
res = FALSE;
res = false;
}
else if (file_size == 0)
{
setLastError("File is empty",filename);
res = FALSE;
res = false;
}
else
{
@ -385,7 +377,7 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename)
{
FREE_MEM(LLImageBase::getPrivatePool(), data);
setLastError("Unable to read entire file");
res = FALSE;
res = false;
}
else
{
@ -402,21 +394,21 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename)
}
BOOL LLImageJ2C::validate(U8 *data, U32 file_size)
bool LLImageJ2C::validate(U8 *data, U32 file_size)
{
resetLastError();
setData(data, file_size);
BOOL res = updateData();
bool res = updateData();
if ( res )
{
// Check to make sure that this instance has been initialized with data
if (!getData() || (0 == getDataSize()))
{
setLastError("LLImageJ2C uninitialized");
res = FALSE;
res = false;
}
else
{
@ -433,7 +425,7 @@ BOOL LLImageJ2C::validate(U8 *data, U32 file_size)
void LLImageJ2C::decodeFailed()
{
mDecoding = FALSE;
mDecoding = false;
}
void LLImageJ2C::updateRawDiscardLevel()

View File

@ -30,6 +30,7 @@
#include "llimage.h"
#include "llassettype.h"
#include "llmetricperformancetester.h"
#include <boost/scoped_ptr.hpp>
// JPEG2000 : compression rate used in j2c conversion.
const F32 DEFAULT_COMPRESSION_RATE = 1.f/8.f;
@ -47,10 +48,10 @@ public:
// Base class overrides
/*virtual*/ std::string getExtension() { return std::string("j2c"); }
/*virtual*/ BOOL updateData();
/*virtual*/ BOOL decode(LLImageRaw *raw_imagep, F32 decode_time);
/*virtual*/ BOOL decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count);
/*virtual*/ BOOL encode(const LLImageRaw *raw_imagep, F32 encode_time);
/*virtual*/ bool updateData();
/*virtual*/ bool decode(LLImageRaw *raw_imagep, F32 decode_time);
/*virtual*/ bool decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count);
/*virtual*/ bool encode(const LLImageRaw *raw_imagep, F32 encode_time);
/*virtual*/ S32 calcHeaderSize();
/*virtual*/ S32 calcDataSize(S32 discard_level = 0);
/*virtual*/ S32 calcDiscardLevelBytes(S32 bytes);
@ -59,17 +60,17 @@ public:
/*virtual*/ void resetLastError();
/*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, int levels);
bool initDecode(LLImageRaw &raw_image, int discard_level, int* region);
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);
bool encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time=0.0);
BOOL validate(U8 *data, U32 file_size);
BOOL loadAndValidate(const std::string &filename);
bool validate(U8 *data, U32 file_size);
bool loadAndValidate(const std::string &filename);
// Encode accessors
void setReversible(const BOOL reversible); // Use non-lossy?
void setReversible(const bool reversible); // Use non-lossy?
void setMaxBytes(S32 max_bytes);
S32 getMaxBytes() const { return mMaxBytes; }
@ -93,8 +94,8 @@ protected:
S8 mRawDiscardLevel;
F32 mRate;
BOOL mReversible;
LLImageJ2CImpl *mImpl;
bool mReversible;
boost::scoped_ptr<LLImageJ2CImpl> mImpl;
std::string mLastError;
// Image compression/decompression tester
@ -111,23 +112,25 @@ protected:
// Return value:
// true: image size and number of channels was determined
// false: error on decode
virtual BOOL getMetadata(LLImageJ2C &base) = 0;
virtual bool getMetadata(LLImageJ2C &base) = 0;
// Decode the raw image optionally aborting (to continue later) after
// decode_time seconds. Decode at most max_channel_count and start
// decoding channel first_channel.
// Return value:
// true: decoding complete (even if it failed)
// false: time expired while decoding
virtual BOOL decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) = 0;
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, int levels = 0) = 0;
virtual bool decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) = 0;
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, int levels = 0) = 0;
virtual std::string getEngineInfo() const = 0;
friend class LLImageJ2C;
};
#define LINDEN_J2C_COMMENT_PREFIX "LL_"
#define LINDEN_J2C_COMMENT_PREFIX "LL_" // Used by LLAppearanceUtility
//
// This class is used for performance data gathering only.

View File

@ -45,7 +45,7 @@ LLImageJPEG::~LLImageJPEG()
delete[] mOutputBuffer;
}
BOOL LLImageJPEG::updateData()
bool LLImageJPEG::updateData()
{
resetLastError();
@ -53,7 +53,7 @@ BOOL LLImageJPEG::updateData()
if (!getData() || (0 == getDataSize()))
{
setLastError("Uninitialized instance of LLImageJPEG");
return FALSE;
return false;
}
////////////////////////////////////////
@ -79,7 +79,7 @@ BOOL LLImageJPEG::updateData()
if(setjmp(sSetjmpBuffer))
{
jpeg_destroy_decompress(&cinfo);
return FALSE;
return false;
}
try
{
@ -106,7 +106,7 @@ BOOL LLImageJPEG::updateData()
////////////////////////////////////////
// Step 3: read file parameters with jpeg_read_header()
jpeg_read_header( &cinfo, TRUE );
jpeg_read_header( &cinfo, true );
// Data set by jpeg_read_header
setSize(cinfo.image_width, cinfo.image_height, 3); // Force to 3 components (RGB)
@ -115,13 +115,13 @@ BOOL LLImageJPEG::updateData()
// More data set by jpeg_read_header
cinfo.num_components;
cinfo.jpeg_color_space; // Colorspace of image
cinfo.saw_JFIF_marker; // TRUE if a JFIF APP0 marker was seen
cinfo.saw_JFIF_marker; // true if a JFIF APP0 marker was seen
cinfo.JFIF_major_version; // Version information from JFIF marker
cinfo.JFIF_minor_version; //
cinfo.density_unit; // Resolution data from JFIF marker
cinfo.X_density;
cinfo.Y_density;
cinfo.saw_Adobe_marker; // TRUE if an Adobe APP14 marker was seen
cinfo.saw_Adobe_marker; // true if an Adobe APP14 marker was seen
cinfo.Adobe_transform; // Color transform code from Adobe marker
*/
}
@ -129,13 +129,13 @@ BOOL LLImageJPEG::updateData()
{
jpeg_destroy_decompress(&cinfo);
return FALSE;
return false;
}
////////////////////////////////////////
// Step 4: Release JPEG decompression object
jpeg_destroy_decompress(&cinfo);
return TRUE;
return true;
}
// Initialize source --- called by jpeg_read_header
@ -154,7 +154,7 @@ boolean LLImageJPEG::decodeFillInputBuffer( j_decompress_ptr cinfo )
// Should never get here, since we provide the entire buffer up front.
ERREXIT(cinfo, JERR_INPUT_EMPTY);
return TRUE;
return true;
}
// Skip data --- used to skip over a potentially large amount of
@ -182,7 +182,7 @@ void LLImageJPEG::decodeTermSource (j_decompress_ptr cinfo)
// Returns true when done, whether or not decode was successful.
BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
bool LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
{
llassert_always(raw_image);
@ -192,7 +192,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
if (!getData() || (0 == getDataSize()))
{
setLastError("LLImageJPEG trying to decode an image with no data!");
return TRUE; // done
return true; // done
}
S32 row_stride = 0;
@ -220,7 +220,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
if(setjmp(sSetjmpBuffer))
{
jpeg_destroy_decompress(&cinfo);
return TRUE; // done
return true; // done
}
try
{
@ -247,11 +247,11 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
////////////////////////////////////////
// Step 3: read file parameters with jpeg_read_header()
jpeg_read_header(&cinfo, TRUE);
jpeg_read_header(&cinfo, true);
// We can ignore the return value from jpeg_read_header since
// (a) suspension is not possible with our data source, and
// (b) we passed TRUE to reject a tables-only JPEG file as an error.
// (b) we passed true to reject a tables-only JPEG file as an error.
// See libjpeg.doc for more info.
setSize(cinfo.image_width, cinfo.image_height, 3); // Force to 3 components (RGB)
@ -314,7 +314,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
catch (int)
{
jpeg_destroy_decompress(&cinfo);
return TRUE; // done
return true; // done
}
// Check to see whether any corrupt-data warnings occurred
@ -322,10 +322,10 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
{
// TODO: extract the warning to find out what went wrong.
setLastError( "Unable to decode JPEG image.");
return TRUE; // done
return true; // done
}
return TRUE;
return true;
}
@ -344,11 +344,11 @@ void LLImageJPEG::encodeInitDestination ( j_compress_ptr cinfo )
//
// In typical applications, this should write the entire output buffer
// (ignoring the current state of next_output_byte & free_in_buffer),
// reset the pointer & count to the start of the buffer, and return TRUE
// reset the pointer & count to the start of the buffer, and return true
// indicating that the buffer has been dumped.
//
// In applications that need to be able to suspend compression due to output
// overrun, a FALSE return indicates that the buffer cannot be emptied now.
// overrun, a false return indicates that the buffer cannot be emptied now.
// In this situation, the compressor will return to its caller (possibly with
// an indication that it has not accepted all the supplied scanlines). The
// application should resume compression after it has made more room in the
@ -357,7 +357,7 @@ void LLImageJPEG::encodeInitDestination ( j_compress_ptr cinfo )
//
// When suspending, the compressor will back up to a convenient restart point
// (typically the start of the current MCU). next_output_byte & free_in_buffer
// indicate where the restart point will be if the current call returns FALSE.
// indicate where the restart point will be if the current call returns false.
// Data beyond this point will be regenerated after resumption, so do not
// write it out when emptying the buffer externally.
@ -374,7 +374,7 @@ boolean LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )
if (!new_buffer)
{
LL_ERRS() << "Out of memory in LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )" << LL_ENDL;
return FALSE;
return false;
}
memcpy( new_buffer, self->mOutputBuffer, self->mOutputBufferSize ); /* Flawfinder: ignore */
delete[] self->mOutputBuffer;
@ -386,7 +386,7 @@ boolean LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )
self->mOutputBufferSize = new_buffer_size;
self->claimMem(new_buffer_size);
return TRUE;
return true;
}
// Terminate destination --- called by jpeg_finish_compress
@ -465,11 +465,11 @@ void LLImageJPEG::errorOutputMessage( j_common_ptr cinfo )
std::string error = buffer ;
LLImage::setLastError(error);
BOOL is_decode = (cinfo->is_decompressor != 0);
bool is_decode = (cinfo->is_decompressor != 0);
LL_WARNS() << "LLImageJPEG " << (is_decode ? "decode " : "encode ") << " failed: " << buffer << LL_ENDL;
}
BOOL LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
{
llassert_always(raw_image);
@ -482,7 +482,7 @@ BOOL LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
break;
default:
setLastError("Unable to encode a JPEG image that doesn't have 1 or 3 components.");
return FALSE;
return false;
}
setSize(raw_image->getWidth(), raw_image->getHeight(), raw_image->getComponents());
@ -531,7 +531,7 @@ BOOL LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
mOutputBuffer = NULL;
disclaimMem(mOutputBufferSize);
mOutputBufferSize = 0;
return FALSE;
return false;
}
try
@ -576,7 +576,7 @@ BOOL LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
break;
default:
setLastError("Unable to encode a JPEG image that doesn't have 1 or 3 components.");
return FALSE;
return false;
}
// Now use the library's routine to set default compression parameters.
@ -585,15 +585,15 @@ BOOL LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
jpeg_set_defaults(&cinfo);
// Now you can set any non-default parameters you wish to.
jpeg_set_quality(&cinfo, mEncodeQuality, TRUE ); // limit to baseline-JPEG values
jpeg_set_quality(&cinfo, mEncodeQuality, true ); // limit to baseline-JPEG values
////////////////////////////////////////
// Step 4: Start compressor
//
// TRUE ensures that we will write a complete interchange-JPEG file.
// Pass TRUE unless you are very sure of what you're doing.
// true ensures that we will write a complete interchange-JPEG file.
// Pass true unless you are very sure of what you're doing.
jpeg_start_compress(&cinfo, TRUE);
jpeg_start_compress(&cinfo, true);
////////////////////////////////////////
// Step 5: while (scan lines remain to be written)
@ -647,8 +647,8 @@ BOOL LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
mOutputBuffer = NULL;
disclaimMem(mOutputBufferSize);
mOutputBufferSize = 0;
return FALSE;
return false;
}
return TRUE;
return true;
}

View File

@ -51,9 +51,9 @@ public:
LLImageJPEG(S32 quality = 75);
/*virtual*/ std::string getExtension() { return std::string("jpg"); }
/*virtual*/ BOOL updateData();
/*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 decode_time);
/*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 encode_time);
/*virtual*/ bool updateData();
/*virtual*/ bool decode(LLImageRaw* raw_image, F32 decode_time);
/*virtual*/ bool encode(const LLImageRaw* raw_image, F32 encode_time);
void setEncodeQuality( S32 q ) { mEncodeQuality = q; } // on a scale from 1 to 100
S32 getEncodeQuality() { return mEncodeQuality; }
@ -73,7 +73,7 @@ public:
static void errorEmitMessage(j_common_ptr cinfo, int msg_level);
static void errorOutputMessage(j_common_ptr cinfo);
static BOOL decompress(LLImageJPEG* imagep);
static bool decompress(LLImageJPEG* imagep);
protected:
U8* mOutputBuffer; // temp buffer used during encoding

View File

@ -47,7 +47,7 @@ LLImagePNG::~LLImagePNG()
// Virtual
// Parse PNG image information and set the appropriate
// width, height and component (channel) information.
BOOL LLImagePNG::updateData()
bool LLImagePNG::updateData()
{
resetLastError();
@ -55,7 +55,7 @@ BOOL LLImagePNG::updateData()
if (!getData() || (0 == getDataSize()))
{
setLastError("Uninitialized instance of LLImagePNG");
return FALSE;
return false;
}
// Decode the PNG data and extract sizing information
@ -63,25 +63,25 @@ BOOL LLImagePNG::updateData()
if (!pngWrapper.isValidPng(getData()))
{
setLastError("LLImagePNG data does not have a valid PNG header!");
return FALSE;
return false;
}
LLPngWrapper::ImageInfo infop;
if (! pngWrapper.readPng(getData(), getDataSize(), NULL, &infop))
{
setLastError(pngWrapper.getErrorMessage());
return FALSE;
return false;
}
setSize(infop.mWidth, infop.mHeight, infop.mComponents);
return TRUE;
return true;
}
// Virtual
// Decode an in-memory PNG image into the raw RGB or RGBA format
// used within SecondLife.
BOOL LLImagePNG::decode(LLImageRaw* raw_image, F32 decode_time)
bool LLImagePNG::decode(LLImageRaw* raw_image, F32 decode_time)
{
llassert_always(raw_image);
@ -91,7 +91,7 @@ BOOL LLImagePNG::decode(LLImageRaw* raw_image, F32 decode_time)
if (!getData() || (0 == getDataSize()))
{
setLastError("LLImagePNG trying to decode an image with no data!");
return FALSE;
return false;
}
// Decode the PNG data into the raw image
@ -99,21 +99,21 @@ BOOL LLImagePNG::decode(LLImageRaw* raw_image, F32 decode_time)
if (!pngWrapper.isValidPng(getData()))
{
setLastError("LLImagePNG data does not have a valid PNG header!");
return FALSE;
return false;
}
if (! pngWrapper.readPng(getData(), getDataSize(), raw_image))
{
setLastError(pngWrapper.getErrorMessage());
return FALSE;
return false;
}
return TRUE;
return true;
}
// Virtual
// Encode the in memory RGB image into PNG format.
BOOL LLImagePNG::encode(const LLImageRaw* raw_image, F32 encode_time)
bool LLImagePNG::encode(const LLImageRaw* raw_image, F32 encode_time)
{
llassert_always(raw_image);
@ -133,7 +133,7 @@ BOOL LLImagePNG::encode(const LLImageRaw* raw_image, F32 encode_time)
{
setLastError(pngWrapper.getErrorMessage());
delete[] tmpWriteBuffer;
return FALSE;
return false;
}
// Resize internal buffer and copy from temp
@ -143,6 +143,6 @@ BOOL LLImagePNG::encode(const LLImageRaw* raw_image, F32 encode_time)
delete[] tmpWriteBuffer;
return TRUE;
return true;
}

View File

@ -38,9 +38,9 @@ public:
LLImagePNG();
/*virtual*/ std::string getExtension() { return std::string("png"); }
/*virtual*/ BOOL updateData();
/*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 decode_time);
/*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 encode_time);
/*virtual*/ bool updateData();
/*virtual*/ bool decode(LLImageRaw* raw_image, F32 decode_time);
/*virtual*/ bool encode(const LLImageRaw* raw_image, F32 encode_time);
};
#endif

View File

@ -61,7 +61,7 @@ LLImageTGA::LLImageTGA()
mColorMapStart( 0 ),
mColorMapLength( 0 ),
mColorMapBytesPerEntry( 0 ),
mIs15Bit( FALSE ),
mIs15Bit( false ),
mAttributeBits(0),
mColorMapDepth(0),
@ -94,7 +94,7 @@ LLImageTGA::LLImageTGA(const std::string& file_name)
mColorMapStart( 0 ),
mColorMapLength( 0 ),
mColorMapBytesPerEntry( 0 ),
mIs15Bit( FALSE )
mIs15Bit( false )
{
loadFile(file_name);
}
@ -104,7 +104,7 @@ LLImageTGA::~LLImageTGA()
delete [] mColorMap;
}
BOOL LLImageTGA::updateData()
bool LLImageTGA::updateData()
{
resetLastError();
@ -112,7 +112,7 @@ BOOL LLImageTGA::updateData()
if (!getData() || (0 == getDataSize()))
{
setLastError("LLImageTGA uninitialized");
return FALSE;
return false;
}
// Pull image information from the header...
@ -185,13 +185,13 @@ BOOL LLImageTGA::updateData()
case 0:
// No image data included in file
setLastError("Unable to load file. TGA file contains no image data.");
return FALSE;
return false;
case 1:
// Colormapped uncompressed
if( 8 != mPixelSize )
{
setLastError("Unable to load file. Colormapped images must have 8 bits per pixel.");
return FALSE;
return false;
}
break;
case 2:
@ -202,7 +202,7 @@ BOOL LLImageTGA::updateData()
if( 8 != mPixelSize )
{
setLastError("Unable to load file. Monochrome images must have 8 bits per pixel.");
return FALSE;
return false;
}
break;
case 9:
@ -216,12 +216,12 @@ BOOL LLImageTGA::updateData()
if( 8 != mPixelSize )
{
setLastError("Unable to load file. Monochrome images must have 8 bits per pixel.");
return FALSE;
return false;
}
break;
default:
setLastError("Unable to load file. Unrecoginzed TGA image type.");
return FALSE;
return false;
}
// discard the ID field, if any
@ -266,8 +266,8 @@ BOOL LLImageTGA::updateData()
mColorMap = new U8[ color_map_bytes ];
if (!mColorMap)
{
LL_ERRS() << "Out of Memory in BOOL LLImageTGA::updateData()" << LL_ENDL;
return FALSE;
LL_ERRS() << "Out of Memory in bool LLImageTGA::updateData()" << LL_ENDL;
return false;
}
memcpy( mColorMap, getData() + mDataOffset, color_map_bytes ); /* Flawfinder: ignore */
}
@ -302,28 +302,28 @@ BOOL LLImageTGA::updateData()
// if( mAttributeBits != 8 )
// {
// setLastError("Unable to load file. 32 bit TGA image does not have 8 bits of alpha.");
// return FALSE;
// return false;
// }
mAttributeBits = 8;
break;
case 15:
case 16:
components = 3;
mIs15Bit = TRUE; // 16th bit is used for Targa hardware interupts and is ignored.
mIs15Bit = true; // 16th bit is used for Targa hardware interupts and is ignored.
break;
case 8:
components = 1;
break;
default:
setLastError("Unable to load file. Unknown pixel size.");
return FALSE;
return false;
}
setSize(width, height, components);
return TRUE;
return true;
}
BOOL LLImageTGA::decode(LLImageRaw* raw_image, F32 decode_time)
bool LLImageTGA::decode(LLImageRaw* raw_image, F32 decode_time)
{
llassert_always(raw_image);
@ -331,7 +331,7 @@ BOOL LLImageTGA::decode(LLImageRaw* raw_image, F32 decode_time)
if (!getData() || (0 == getDataSize()))
{
setLastError("LLImageTGA trying to decode an image with no data!");
return FALSE;
return false;
}
// Copy everything after the header.
@ -343,18 +343,18 @@ BOOL LLImageTGA::decode(LLImageRaw* raw_image, F32 decode_time)
(getComponents() != 4) )
{
setLastError("TGA images with a number of components other than 1, 3, and 4 are not supported.");
return FALSE;
return false;
}
if( mOriginRightBit )
{
setLastError("TGA images with origin on right side are not supported.");
return FALSE;
return false;
}
BOOL flipped = (mOriginTopBit != 0);
BOOL rle_compressed = ((mImageType & 0x08) != 0);
bool flipped = (mOriginTopBit != 0);
bool rle_compressed = ((mImageType & 0x08) != 0);
if( mColorMap )
{
@ -366,10 +366,10 @@ BOOL LLImageTGA::decode(LLImageRaw* raw_image, F32 decode_time)
}
}
BOOL LLImageTGA::decodeTruecolor( LLImageRaw* raw_image, BOOL rle, BOOL flipped )
bool LLImageTGA::decodeTruecolor( LLImageRaw* raw_image, bool rle, bool flipped )
{
BOOL success = FALSE;
BOOL alpha_opaque = FALSE;
bool success = false;
bool alpha_opaque = false;
if( rle )
{
@ -404,7 +404,7 @@ BOOL LLImageTGA::decodeTruecolor( LLImageRaw* raw_image, BOOL rle, BOOL flipped
}
else
{
BOOL alpha_opaque;
bool alpha_opaque;
success = decodeTruecolorNonRle( raw_image, alpha_opaque );
if (alpha_opaque && raw_image->getComponents() == 4)
{
@ -430,9 +430,9 @@ BOOL LLImageTGA::decodeTruecolor( LLImageRaw* raw_image, BOOL rle, BOOL flipped
}
BOOL LLImageTGA::decodeTruecolorNonRle( LLImageRaw* raw_image, BOOL &alpha_opaque )
bool LLImageTGA::decodeTruecolorNonRle( LLImageRaw* raw_image, bool &alpha_opaque )
{
alpha_opaque = TRUE;
alpha_opaque = true;
// Origin is the bottom left
U8* dst = raw_image->getData();
@ -442,7 +442,7 @@ BOOL LLImageTGA::decodeTruecolorNonRle( LLImageRaw* raw_image, BOOL &alpha_opaqu
if (pixels * (mIs15Bit ? 2 : getComponents()) > getDataSize() - mDataOffset)
{ //here we have situation when data size in src less than actually needed
return FALSE;
return false;
}
if (getComponents() == 4)
@ -456,7 +456,7 @@ BOOL LLImageTGA::decodeTruecolorNonRle( LLImageRaw* raw_image, BOOL &alpha_opaqu
dst[3] = src[3]; // Alpha
if (dst[3] != 255)
{
alpha_opaque = FALSE;
alpha_opaque = false;
}
dst += 4;
src += 4;
@ -490,7 +490,7 @@ BOOL LLImageTGA::decodeTruecolorNonRle( LLImageRaw* raw_image, BOOL &alpha_opaqu
memcpy(dst, src, pixels); /* Flawfinder: ignore */
}
return TRUE;
return true;
}
void LLImageTGA::decodeColorMapPixel8( U8* dst, const U8* src )
@ -523,14 +523,14 @@ void LLImageTGA::decodeColorMapPixel32( U8* dst, const U8* src )
}
BOOL LLImageTGA::decodeColorMap( LLImageRaw* raw_image, BOOL rle, BOOL flipped )
bool LLImageTGA::decodeColorMap( LLImageRaw* raw_image, bool rle, bool flipped )
{
// If flipped, origin is the top left. Need to reverse the order of the rows.
// Otherwise the origin is the bottom left.
if( 8 != mPixelSize )
{
return FALSE;
return false;
}
U8* src = getData() + mDataOffset;
@ -544,7 +544,7 @@ BOOL LLImageTGA::decodeColorMap( LLImageRaw* raw_image, BOOL rle, BOOL flipped )
case 2: pixel_decoder = &LLImageTGA::decodeColorMapPixel15; break;
case 3: pixel_decoder = &LLImageTGA::decodeColorMapPixel24; break;
case 4: pixel_decoder = &LLImageTGA::decodeColorMapPixel32; break;
default: llassert(0); return FALSE;
default: llassert(0); return false;
}
if( rle )
@ -613,12 +613,12 @@ BOOL LLImageTGA::decodeColorMap( LLImageRaw* raw_image, BOOL rle, BOOL flipped )
}
}
return TRUE;
return true;
}
BOOL LLImageTGA::encode(const LLImageRaw* raw_image, F32 encode_time)
bool LLImageTGA::encode(const LLImageRaw* raw_image, F32 encode_time)
{
llassert_always(raw_image);
@ -642,7 +642,7 @@ BOOL LLImageTGA::encode(const LLImageRaw* raw_image, F32 encode_time)
mImageType = 2;
break;
default:
return FALSE;
return false;
}
// Color map stuff (unsupported)
@ -678,7 +678,7 @@ BOOL LLImageTGA::encode(const LLImageRaw* raw_image, F32 encode_time)
bytes_per_pixel = 4;
break;
default:
return FALSE;
return false;
}
mPixelSize = U8(bytes_per_pixel * 8); // 8, 16, 24, 32 bits per pixel
@ -765,13 +765,13 @@ BOOL LLImageTGA::encode(const LLImageRaw* raw_image, F32 encode_time)
break;
}
return TRUE;
return true;
}
BOOL LLImageTGA::decodeTruecolorRle32( LLImageRaw* raw_image, BOOL &alpha_opaque )
bool LLImageTGA::decodeTruecolorRle32( LLImageRaw* raw_image, bool &alpha_opaque )
{
llassert( getComponents() == 4 );
alpha_opaque = TRUE;
alpha_opaque = true;
U8* dst = raw_image->getData();
U32* dst_pixels = (U32*) dst;
@ -788,7 +788,7 @@ BOOL LLImageTGA::decodeTruecolorRle32( LLImageRaw* raw_image, BOOL &alpha_opaque
// Read RLE block header
if (src >= last_src)
return FALSE;
return false;
U8 block_header_byte = *src;
src++;
@ -799,7 +799,7 @@ BOOL LLImageTGA::decodeTruecolorRle32( LLImageRaw* raw_image, BOOL &alpha_opaque
// Encoded (duplicate-pixel) block
if (src + 3 >= last_src)
return FALSE;
return false;
rgba_byte_p[0] = src[2];
rgba_byte_p[1] = src[1];
@ -807,7 +807,7 @@ BOOL LLImageTGA::decodeTruecolorRle32( LLImageRaw* raw_image, BOOL &alpha_opaque
rgba_byte_p[3] = src[3];
if (rgba_byte_p[3] != 255)
{
alpha_opaque = FALSE;
alpha_opaque = false;
}
src += 4;
@ -826,7 +826,7 @@ BOOL LLImageTGA::decodeTruecolorRle32( LLImageRaw* raw_image, BOOL &alpha_opaque
do
{
if (src + 3 >= last_src)
return FALSE;
return false;
((U8*)dst_pixels)[0] = src[2];
((U8*)dst_pixels)[1] = src[1];
@ -834,7 +834,7 @@ BOOL LLImageTGA::decodeTruecolorRle32( LLImageRaw* raw_image, BOOL &alpha_opaque
((U8*)dst_pixels)[3] = src[3];
if (src[3] != 255)
{
alpha_opaque = FALSE;
alpha_opaque = false;
}
src += 4;
dst_pixels++;
@ -844,10 +844,10 @@ BOOL LLImageTGA::decodeTruecolorRle32( LLImageRaw* raw_image, BOOL &alpha_opaque
}
}
return TRUE;
return true;
}
BOOL LLImageTGA::decodeTruecolorRle15( LLImageRaw* raw_image )
bool LLImageTGA::decodeTruecolorRle15( LLImageRaw* raw_image )
{
llassert( getComponents() == 3 );
llassert( mIs15Bit );
@ -863,7 +863,7 @@ BOOL LLImageTGA::decodeTruecolorRle15( LLImageRaw* raw_image )
// Read RLE block header
if (src >= last_src)
return FALSE;
return false;
U8 block_header_byte = *src;
src++;
@ -875,7 +875,7 @@ BOOL LLImageTGA::decodeTruecolorRle15( LLImageRaw* raw_image )
do
{
if (src + 2 >= last_src)
return FALSE;
return false;
decodeTruecolorPixel15( dst, src ); // slow
dst += 3;
@ -890,7 +890,7 @@ BOOL LLImageTGA::decodeTruecolorRle15( LLImageRaw* raw_image )
do
{
if (src + 2 >= last_src)
return FALSE;
return false;
decodeTruecolorPixel15( dst, src );
dst += 3;
@ -901,12 +901,12 @@ BOOL LLImageTGA::decodeTruecolorRle15( LLImageRaw* raw_image )
}
}
return TRUE;
return true;
}
BOOL LLImageTGA::decodeTruecolorRle24( LLImageRaw* raw_image )
bool LLImageTGA::decodeTruecolorRle24( LLImageRaw* raw_image )
{
llassert( getComponents() == 3 );
@ -921,7 +921,7 @@ BOOL LLImageTGA::decodeTruecolorRle24( LLImageRaw* raw_image )
// Read RLE block header
if (src >= last_src)
return FALSE;
return false;
U8 block_header_byte = *src;
src++;
@ -933,7 +933,7 @@ BOOL LLImageTGA::decodeTruecolorRle24( LLImageRaw* raw_image )
do
{
if (src + 2 >= last_src)
return FALSE;
return false;
dst[0] = src[2];
dst[1] = src[1];
dst[2] = src[0];
@ -949,7 +949,7 @@ BOOL LLImageTGA::decodeTruecolorRle24( LLImageRaw* raw_image )
do
{
if (src + 2 >= last_src)
return FALSE;
return false;
dst[0] = src[2];
dst[1] = src[1];
@ -962,11 +962,11 @@ BOOL LLImageTGA::decodeTruecolorRle24( LLImageRaw* raw_image )
}
}
return TRUE;
return true;
}
BOOL LLImageTGA::decodeTruecolorRle8( LLImageRaw* raw_image )
bool LLImageTGA::decodeTruecolorRle8( LLImageRaw* raw_image )
{
llassert( getComponents() == 1 );
@ -981,7 +981,7 @@ BOOL LLImageTGA::decodeTruecolorRle8( LLImageRaw* raw_image )
// Read RLE block header
if (src >= last_src)
return FALSE;
return false;
U8 block_header_byte = *src;
src++;
@ -990,7 +990,7 @@ BOOL LLImageTGA::decodeTruecolorRle8( LLImageRaw* raw_image )
if( block_header_byte & 0x80 )
{
if (src >= last_src)
return FALSE;
return false;
// Encoded (duplicate-pixel) block
memset( dst, *src, block_pixel_count );
@ -1003,7 +1003,7 @@ BOOL LLImageTGA::decodeTruecolorRle8( LLImageRaw* raw_image )
do
{
if (src >= last_src)
return FALSE;
return false;
*dst = *src;
dst++;
@ -1014,13 +1014,13 @@ BOOL LLImageTGA::decodeTruecolorRle8( LLImageRaw* raw_image )
}
}
return TRUE;
return true;
}
// Decoded and process the image for use in avatar gradient masks.
// Processing happens during the decode for speed.
BOOL LLImageTGA::decodeAndProcess( LLImageRaw* raw_image, F32 domain, F32 weight )
bool LLImageTGA::decodeAndProcess( LLImageRaw* raw_image, F32 domain, F32 weight )
{
llassert_always(raw_image);
@ -1043,14 +1043,14 @@ BOOL LLImageTGA::decodeAndProcess( LLImageRaw* raw_image, F32 domain, F32 weight
if (!getData() || (0 == getDataSize()))
{
setLastError("LLImageTGA trying to decode an image with no data!");
return FALSE;
return false;
}
// Only works for unflipped monochrome RLE images
if( (getComponents() != 1) || (mImageType != 11) || mOriginTopBit || mOriginRightBit )
{
LL_ERRS() << "LLImageTGA trying to alpha-gradient process an image that's not a standard RLE, one component image" << LL_ENDL;
return FALSE;
return false;
}
raw_image->resize(getWidth(), getHeight(), getComponents());
@ -1136,7 +1136,7 @@ BOOL LLImageTGA::decodeAndProcess( LLImageRaw* raw_image, F32 domain, F32 weight
}
}
}
return TRUE;
return true;
}
// Reads a .tga file and creates an LLImageTGA with its data.

View File

@ -41,25 +41,25 @@ public:
LLImageTGA(const std::string& file_name);
/*virtual*/ std::string getExtension() { return std::string("tga"); }
/*virtual*/ BOOL updateData();
/*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 decode_time=0.0);
/*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 encode_time=0.0);
/*virtual*/ bool updateData();
/*virtual*/ bool decode(LLImageRaw* raw_image, F32 decode_time=0.0);
/*virtual*/ bool encode(const LLImageRaw* raw_image, F32 encode_time=0.0);
BOOL decodeAndProcess(LLImageRaw* raw_image, F32 domain, F32 weight);
bool decodeAndProcess(LLImageRaw* raw_image, F32 domain, F32 weight);
private:
BOOL decodeTruecolor( LLImageRaw* raw_image, BOOL rle, BOOL flipped );
bool decodeTruecolor( LLImageRaw* raw_image, bool rle, bool flipped );
BOOL decodeTruecolorRle8( LLImageRaw* raw_image );
BOOL decodeTruecolorRle15( LLImageRaw* raw_image );
BOOL decodeTruecolorRle24( LLImageRaw* raw_image );
BOOL decodeTruecolorRle32( LLImageRaw* raw_image, BOOL &alpha_opaque );
bool decodeTruecolorRle8( LLImageRaw* raw_image );
bool decodeTruecolorRle15( LLImageRaw* raw_image );
bool decodeTruecolorRle24( LLImageRaw* raw_image );
bool decodeTruecolorRle32( LLImageRaw* raw_image, bool &alpha_opaque );
void decodeTruecolorPixel15( U8* dst, const U8* src );
BOOL decodeTruecolorNonRle( LLImageRaw* raw_image, BOOL &alpha_opaque );
bool decodeTruecolorNonRle( LLImageRaw* raw_image, bool &alpha_opaque );
BOOL decodeColorMap( LLImageRaw* raw_image, BOOL rle, BOOL flipped );
bool decodeColorMap( LLImageRaw* raw_image, bool rle, bool flipped );
void decodeColorMapPixel8(U8* dst, const U8* src);
void decodeColorMapPixel15(U8* dst, const U8* src);
@ -100,7 +100,7 @@ private:
S32 mColorMapLength;
S32 mColorMapBytesPerEntry;
BOOL mIs15Bit;
bool mIs15Bit;
static const U8 s5to8bits[32];
};

View File

@ -31,6 +31,16 @@
#include "llimage.h"
#include "llpngwrapper.h"
#include "llexception.h"
namespace {
// Failure to load an image shouldn't crash the whole viewer.
struct PngError: public LLContinueError
{
PngError(png_const_charp msg): LLContinueError(msg) {}
};
} // anonymous namespace
// ---------------------------------------------------------------------------
// LLPngWrapper
// ---------------------------------------------------------------------------
@ -75,11 +85,10 @@ BOOL LLPngWrapper::isValidPng(U8* src)
}
// Called by the libpng library when a fatal encoding or decoding error
// occurs. We simply throw the error message and let our try/catch
// block clean up.
// occurs. We throw PngError and let our try/catch block clean up.
void LLPngWrapper::errorHandler(png_structp png_ptr, png_const_charp msg)
{
throw msg;
LLTHROW(PngError(msg));
}
// Called by the libpng library when reading (decoding) the PNG file. We
@ -129,7 +138,7 @@ BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInf
this, &errorHandler, NULL);
if (mReadPngPtr == NULL)
{
throw "Problem creating png read structure";
LLTHROW(PngError("Problem creating png read structure"));
}
// Allocate/initialize the memory for image information.
@ -187,9 +196,9 @@ BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInf
mFinalSize = dataPtr.mOffset;
}
catch (png_const_charp msg)
catch (const PngError& msg)
{
mErrorMessage = msg;
mErrorMessage = msg.what();
releaseResources();
return (FALSE);
}
@ -288,14 +297,14 @@ BOOL LLPngWrapper::writePng(const LLImageRaw* rawImage, U8* dest)
if (mColorType == -1)
{
throw "Unsupported image: unexpected number of channels";
LLTHROW(PngError("Unsupported image: unexpected number of channels"));
}
mWritePngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
NULL, &errorHandler, NULL);
if (!mWritePngPtr)
{
throw "Problem creating png write structure";
LLTHROW(PngError("Problem creating png write structure"));
}
mWriteInfoPtr = png_create_info_struct(mWritePngPtr);
@ -339,9 +348,9 @@ BOOL LLPngWrapper::writePng(const LLImageRaw* rawImage, U8* dest)
png_write_end(mWritePngPtr, mWriteInfoPtr);
mFinalSize = dataPtr.mOffset;
}
catch (png_const_charp msg)
catch (const PngError& msg)
{
mErrorMessage = msg;
mErrorMessage = msg.what();
releaseResources();
return (FALSE);
}

View File

@ -33,23 +33,16 @@
#include "lltimer.h"
//#include "llmemory.h"
const char* fallbackEngineInfoLLImageJ2CImpl()
{
static std::string version_string =
std::string("OpenJPEG: " OPENJPEG_VERSION ", Runtime: ")
+ opj_version();
return version_string.c_str();
}
// Factory function: see declaration in llimagej2c.cpp
LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl()
{
return new LLImageJ2COJ();
}
void fallbackDestroyLLImageJ2CImpl(LLImageJ2CImpl* impl)
std::string LLImageJ2COJ::getEngineInfo() const
{
delete impl;
impl = NULL;
return std::string("OpenJPEG: " OPENJPEG_VERSION ", Runtime: ")
+ opj_version();
}
// Return string from message, eliminating final \n if present
@ -107,19 +100,19 @@ LLImageJ2COJ::~LLImageJ2COJ()
{
}
BOOL LLImageJ2COJ::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region)
bool LLImageJ2COJ::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region)
{
// No specific implementation for this method in the OpenJpeg case
return FALSE;
return false;
}
BOOL LLImageJ2COJ::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)
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;
return false;
}
BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
{
//
// FIXME: Get the comment field out of the texture
@ -186,7 +179,7 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod
opj_image_destroy(image);
}
return TRUE; // done
return true; // done
}
// sometimes we get bad data out of the cache - check to see if the decode succeeded
@ -196,8 +189,8 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod
{
// if we didn't get the discard level we're expecting, fail
opj_image_destroy(image);
base.mDecoding = FALSE;
return TRUE;
base.mDecoding = false;
return true;
}
}
@ -209,7 +202,7 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod
opj_image_destroy(image);
}
return TRUE;
return true;
}
// Copy image data into our raw image format (instead of the separate channel format
@ -256,18 +249,18 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod
LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image! (NULL comp data - OpenJPEG bug)" << LL_ENDL;
opj_image_destroy(image);
return TRUE; // done
return true; // done
}
}
/* free image data structure */
opj_image_destroy(image);
return TRUE; // done
return true; // done
}
BOOL LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, BOOL reversible)
bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, bool reversible)
{
const S32 MAX_COMPS = 5;
opj_cparameters_t parameters; /* compression parameters */
@ -388,7 +381,7 @@ BOOL LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con
{
opj_cio_close(cio);
LL_DEBUGS("Texture") << "Failed to encode image." << LL_ENDL;
return FALSE;
return false;
}
codestream_length = cio_tell(cio);
@ -407,10 +400,10 @@ BOOL LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con
/* free image data */
opj_image_destroy(image);
return TRUE;
return true;
}
BOOL LLImageJ2COJ::getMetadata(LLImageJ2C &base)
bool LLImageJ2COJ::getMetadata(LLImageJ2C &base)
{
//
// FIXME: We get metadata by decoding the ENTIRE image.
@ -473,7 +466,7 @@ BOOL LLImageJ2COJ::getMetadata(LLImageJ2C &base)
if(!image)
{
LL_WARNS() << "ERROR -> getMetadata: failed to decode image!" << LL_ENDL;
return FALSE;
return false;
}
// Copy image data into our raw image format (instead of the separate channel format
@ -487,5 +480,5 @@ BOOL LLImageJ2COJ::getMetadata(LLImageJ2C &base)
/* free image data structure */
opj_image_destroy(image);
return TRUE;
return true;
}

View File

@ -35,12 +35,13 @@ public:
LLImageJ2COJ();
virtual ~LLImageJ2COJ();
protected:
/*virtual*/ BOOL getMetadata(LLImageJ2C &base);
/*virtual*/ BOOL decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count);
/*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, int levels = 0);
virtual bool getMetadata(LLImageJ2C &base);
virtual bool decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count);
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, int levels = 0);
virtual std::string getEngineInfo() const;
};
#endif

View File

@ -1,4 +1,4 @@
/**
/**
* @file llimagej2ckdu.cpp
* @brief This is an implementation of JPEG2000 encode/decode using Kakadu
*
@ -31,9 +31,66 @@
#include "llpointer.h"
#include "llmath.h"
#include "llkdumem.h"
#include "stringize.h"
#include "kdu_block_coding.h"
#include "llexception.h"
#include <boost/exception/diagnostic_information.hpp>
#include <sstream>
#include <iomanip>
namespace {
// Failure to load an image shouldn't crash the whole viewer.
struct KDUError: public LLContinueError
{
KDUError(const std::string& msg): LLContinueError(msg) {}
};
// KDU defines int error codes as hex values, so we should log them in hex
// so we can grep KDU headers for the hex. However those hex values
// generally "happen" to encode big-endian multibyte character sequences,
// e.g. KDU_ERROR_EXCEPTION is 0x6b647545: 'kduE'
// But beware because KDU_NULL_EXCEPTION is simply 0 -- which doesn't
// preclude somebody from throwing it.
std::string report_kdu_exception(kdu_exception mb)
{
std::ostringstream out;
// always report mb in hex
out << "kdu_exception " << std::hex << mb;
// Also display as many chars as are encoded in the kdu_exception
// value. Make a char array; reserve 1 extra byte for nul terminator.
char bytes[sizeof(kdu_exception) + 1];
// Back up through 'bytes'
char *bptr = bytes + sizeof(bytes);
*(--bptr) = '\0';
while (mb)
{
// store low-order byte of mb in next-left char
*(--bptr) = char(mb & 0xFF);
// then shift mb right by one byte
mb >>= 8;
}
// did that produce any characters?
if (*bptr)
{
out << " (" << bptr << ')';
}
return out.str();
}
} // anonymous namespace
// stream kdu_dims to std::ostream
// Turns out this must NOT be in the anonymous namespace!
inline
std::ostream& operator<<(std::ostream& out, const kdu_dims& dims)
{
return out << "(" << dims.pos.x << "," << dims.pos.y << "),"
"[" << dims.size.x << "x" << dims.size.y << "]";
}
class kdc_flow_control {
public:
@ -72,37 +129,15 @@ private:
//
void set_default_colour_weights(kdu_params *siz);
const char* engineInfoLLImageJ2CKDU()
{
static std::string version = llformat("KDU %s", KDU_CORE_VERSION);
return version.c_str();
}
LLImageJ2CKDU* createLLImageJ2CKDU()
{
return new LLImageJ2CKDU();
}
void destroyLLImageJ2CKDU(LLImageJ2CKDU* kdu)
{
delete kdu;
kdu = NULL;
}
// Factory function: see declaration in llimagej2c.cpp
LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl()
{
return new LLImageJ2CKDU();
}
void fallbackDestroyLLImageJ2CImpl(LLImageJ2CImpl* impl)
std::string LLImageJ2CKDU::getEngineInfo() const
{
delete impl;
impl = NULL;
}
const char* fallbackEngineInfoLLImageJ2CImpl()
{
return engineInfoLLImageJ2CKDU();
return llformat("KDU %s", KDU_CORE_VERSION);
}
class LLKDUDecodeState
@ -110,11 +145,11 @@ class LLKDUDecodeState
public:
LLKDUDecodeState(kdu_tile tile, kdu_byte *buf, S32 row_gap);
~LLKDUDecodeState();
BOOL processTileDecode(F32 decode_time, BOOL limit_time = TRUE);
bool processTileDecode(F32 decode_time, bool limit_time = true);
private:
S32 mNumComponents;
BOOL mUseYCC;
bool mUseYCC;
kdu_dims mDims;
kdu_sample_allocator mAllocator;
kdu_tile_comp mComps[4];
@ -128,74 +163,91 @@ private:
S32 mRowGap;
};
void ll_kdu_error( void )
{
// *FIX: This exception is bad, bad, bad. It gets thrown from a
// destructor which can lead to immediate program termination!
throw "ll_kdu_error() throwing an exception";
}
// Stuff for new kdu error handling
class LLKDUMessageWarning : public kdu_message
class LLKDUMessage: public kdu_message
{
public:
/*virtual*/ void put_text(const char *s);
/*virtual*/ void put_text(const kdu_uint16 *s);
LLKDUMessage(const std::string& type):
mType(type)
{}
static LLKDUMessageWarning sDefaultMessage;
};
class LLKDUMessageError : public kdu_message
{
public:
/*virtual*/ void put_text(const char *s);
/*virtual*/ void put_text(const kdu_uint16 *s);
/*virtual*/ void flush(bool end_of_message = false);
static LLKDUMessageError sDefaultMessage;
};
void LLKDUMessageWarning::put_text(const char *s)
{
LL_INFOS() << "KDU Warning: " << s << LL_ENDL;
}
void LLKDUMessageWarning::put_text(const kdu_uint16 *s)
{
LL_INFOS() << "KDU Warning: " << s << LL_ENDL;
}
void LLKDUMessageError::put_text(const char *s)
{
LL_INFOS() << "KDU Error: " << s << LL_ENDL;
}
void LLKDUMessageError::put_text(const kdu_uint16 *s)
{
LL_INFOS() << "KDU Error: " << s << LL_ENDL;
}
void LLKDUMessageError::flush(bool end_of_message)
{
if (end_of_message)
virtual void put_text(const char *s)
{
throw "KDU throwing an exception";
LL_INFOS() << "KDU " << mType << ": " << s << LL_ENDL;
}
}
LLKDUMessageWarning LLKDUMessageWarning::sDefaultMessage;
LLKDUMessageError LLKDUMessageError::sDefaultMessage;
static bool kdu_message_initialized = false;
virtual void put_text(const kdu_uint16 *s)
{
// The previous implementation simply streamed 's' to the log. So
// either this put_text() override was never called -- or it produced
// some baffling log messages -- because I assert that streaming a
// const kdu_uint16* to a std::ostream will display only the hex value
// of the pointer.
LL_INFOS() << "KDU " << mType << ": "
<< utf16str_to_utf8str(llutf16string(s)) << LL_ENDL;
}
private:
std::string mType;
};
struct LLKDUMessageWarning : public LLKDUMessage
{
LLKDUMessageWarning():
LLKDUMessage("Warning")
{
kdu_customize_warnings(this);
}
};
// Instantiating LLKDUMessageWarning calls kdu_customize_warnings() with the
// new instance. Make it static so this only happens once.
static LLKDUMessageWarning sWarningHandler;
struct LLKDUMessageError : public LLKDUMessage
{
LLKDUMessageError():
LLKDUMessage("Error")
{
kdu_customize_errors(this);
}
virtual void flush(bool end_of_message = false)
{
// According to the documentation nat found:
// http://pirlwww.lpl.arizona.edu/resources/guide/software/Kakadu/html_pages/globals__kdu$mize_errors.html
// "If a kdu_error object is destroyed, handler→flush will be called with
// an end_of_message argument equal to true and the process will
// subsequently be terminated through exit. The termination may be
// avoided, however, by throwing an exception from within the message
// terminating handler→flush call."
// So throwing an exception here isn't arbitrary: we MUST throw an
// exception if we want to recover from a KDU error.
// Because this confused me: the above quote specifically refers to
// the kdu_error class, which is constructed internally within KDU at
// the point where a fatal error is discovered and reported. It is NOT
// talking about the kdu_message subclass passed to
// kdu_customize_errors(). Destroying this static object at program
// shutdown will NOT engage the behavior described above.
if (end_of_message)
{
LLTHROW(KDUError("LLKDUMessageError::flush()"));
}
}
};
// Instantiating LLKDUMessageError calls kdu_customize_errors() with the new
// instance. Make it static so this only happens once.
static LLKDUMessageError sErrorHandler;
LLImageJ2CKDU::LLImageJ2CKDU() : LLImageJ2CImpl(),
mInputp(NULL),
mCodeStreamp(NULL),
mTPosp(NULL),
mTileIndicesp(NULL),
mRawImagep(NULL),
mDecodeState(NULL),
mBlocksSize(-1),
mPrecinctsSize(-1),
mLevels(0)
mInputp(),
mCodeStreamp(),
mTPosp(),
mTileIndicesp(),
mRawImagep(NULL),
mDecodeState(),
mBlocksSize(-1),
mPrecinctsSize(-1),
mLevels(0)
{
}
@ -207,7 +259,11 @@ LLImageJ2CKDU::~LLImageJ2CKDU()
// Stuff for new simple decode
void transfer_bytes(kdu_byte *dest, kdu_line_buf &src, int gap, int precision);
void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECodeStreamMode mode)
// This is called by the real (private) initDecode() (keep_codestream true)
// and getMetadata() methods (keep_codestream false). As far as nat can tell,
// mode is always MODE_FAST. It was called by findDiscardLevelsBoundaries()
// as well, when that still existed, with keep_codestream true and MODE_FAST.
void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECodeStreamMode mode)
{
S32 data_size = base.getDataSize();
S32 max_bytes = (base.getMaxBytes() ? base.getMaxBytes() : data_size);
@ -215,38 +271,33 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECod
//
// Initialization
//
if (!kdu_message_initialized)
{
kdu_message_initialized = true;
kdu_customize_errors(&LLKDUMessageError::sDefaultMessage);
kdu_customize_warnings(&LLKDUMessageWarning::sDefaultMessage);
}
if (mCodeStreamp)
{
mCodeStreamp->destroy();
delete mCodeStreamp;
mCodeStreamp = NULL;
}
mCodeStreamp.reset();
// It's not clear to nat under what circumstances we would reuse a
// pre-existing LLKDUMemSource instance. As of 2016-08-05, it consists of
// two U32s and a pointer, so it's not as if it would be a huge overhead
// to allocate a new one every time.
// Also -- why is base.getData() tested specifically here? If that returns
// NULL, shouldn't we bail out of the whole method?
if (!mInputp && base.getData())
{
// The compressed data has been loaded
// Setup the source for the codestream
mInputp = new LLKDUMemSource(base.getData(), data_size);
mInputp.reset(new LLKDUMemSource(base.getData(), data_size));
}
if (mInputp)
{
// This is LLKDUMemSource::reset(), not boost::scoped_ptr::reset().
mInputp->reset();
}
mCodeStreamp = new kdu_codestream;
mCodeStreamp->create(mInputp);
mCodeStreamp->create(mInputp.get());
// Set the maximum number of bytes to use from the codestream
// *TODO: This seems to be wrong. The base class should have no idea of how j2c compression works so no
// good way of computing what's the byte range to be used.
// *TODO: This seems to be wrong. The base class should have no idea of
// how j2c compression works so no good way of computing what's the byte
// range to be used.
mCodeStreamp->set_max_bytes(max_bytes,true);
// If you want to flip or rotate the image for some reason, change
@ -284,13 +335,19 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECod
S32 components = mCodeStreamp->get_num_components();
if (components >= 3)
{ // Check that components have consistent dimensions (for PPM file)
kdu_dims dims1; mCodeStreamp->get_dims(1,dims1);
kdu_dims dims2; mCodeStreamp->get_dims(2,dims2);
if ((dims1 != dims) || (dims2 != dims))
// Check that components have consistent dimensions (for PPM file)
for (int idx = 1; idx < components; ++idx)
{
kdu_dims other_dims;
mCodeStreamp->get_dims(idx, other_dims);
if (other_dims != dims)
{
LL_ERRS() << "Components don't have matching dimensions!" << LL_ENDL;
// This method is only called from methods that catch KDUError.
// We want to fail the image load, not crash the viewer.
LLTHROW(KDUError(STRINGIZE("Component " << idx << " dimensions "
<< other_dims
<< " do not match component 0 dimensions "
<< dims << "!")));
}
}
@ -303,42 +360,29 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECod
if (!keep_codestream)
{
mCodeStreamp->destroy();
delete mCodeStreamp;
mCodeStreamp = NULL;
delete mInputp;
mInputp = NULL;
mCodeStreamp.reset();
mInputp.reset();
}
}
void LLImageJ2CKDU::cleanupCodeStream()
{
delete mInputp;
mInputp = NULL;
delete mDecodeState;
mDecodeState = NULL;
if (mCodeStreamp)
{
mCodeStreamp->destroy();
delete mCodeStreamp;
mCodeStreamp = NULL;
}
delete mTPosp;
mTPosp = NULL;
delete mTileIndicesp;
mTileIndicesp = NULL;
mInputp.reset();
mDecodeState.reset();
mCodeStreamp.reset();
mTPosp.reset();
mTileIndicesp.reset();
}
BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region)
// This is the protected virtual method called by LLImageJ2C::initDecode().
// However, as far as nat can tell, LLImageJ2C::initDecode() is called only by
// llimage_libtest.cpp's load_image() function. No detectable production use.
bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region)
{
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, int levels)
bool LLImageJ2CKDU::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels)
{
mPrecinctsSize = precincts_size;
if (mPrecinctsSize != -1)
@ -362,10 +406,13 @@ BOOL LLImageJ2CKDU::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int bloc
mLevels = llclamp(mLevels,MIN_DECOMPOSITION_LEVELS,MAX_DECOMPOSITION_LEVELS);
base.setLevels(mLevels);
}
return TRUE;
return true;
}
BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count, int discard_level, int* region)
// This is the real (private) initDecode() called both by the protected
// initDecode() method and by decodeImpl(). As far as nat can tell, only the
// decodeImpl() usage matters for production.
bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count, int discard_level, int* region)
{
base.resetLastError();
@ -377,7 +424,7 @@ BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
//findDiscardLevelsBoundaries(base);
base.updateRawDiscardLevel();
setupCodeStream(base, TRUE, mode);
setupCodeStream(base, true, mode);
mRawImagep = &raw_image;
mCodeStreamp->change_appearance(false, true, false);
@ -412,45 +459,55 @@ BOOL LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
if (!mTileIndicesp)
{
mTileIndicesp = new kdu_dims;
mTileIndicesp.reset(new kdu_dims);
}
mCodeStreamp->get_valid_tiles(*mTileIndicesp);
if (!mTPosp)
{
mTPosp = new kdu_coords;
mTPosp.reset(new kdu_coords);
mTPosp->y = 0;
mTPosp->x = 0;
}
}
catch (const char* msg)
catch (const KDUError& msg)
{
base.setLastError(ll_safe_string(msg));
return FALSE;
base.setLastError(msg.what());
return false;
}
catch (kdu_exception kdu_value)
{
// KDU internally throws kdu_exception. It's possible that such an
// exception might leak out into our code. Catch kdu_exception
// specially because boost::current_exception_diagnostic_information()
// could do nothing with it.
base.setLastError(report_kdu_exception(kdu_value));
return false;
}
catch (...)
{
base.setLastError("Unknown J2C error");
return FALSE;
base.setLastError("Unknown J2C error: " +
boost::current_exception_diagnostic_information());
return false;
}
return TRUE;
return true;
}
// Returns TRUE to mean done, whether successful or not.
BOOL LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
// Returns true to mean done, whether successful or not.
bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
{
ECodeStreamMode mode = MODE_FAST;
LLTimer decode_timer;
if (!mCodeStreamp)
if (!mCodeStreamp->exists())
{
if (!initDecode(base, raw_image, decode_time, mode, first_channel, max_channel_count))
{
// Initializing the J2C decode failed, bail out.
cleanupCodeStream();
return TRUE; // done
return true; // done
}
}
@ -460,6 +517,13 @@ BOOL LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
// Now we are ready to walk through the tiles processing them one-by-one.
kdu_byte *buffer = raw_image.getData();
if (!buffer)
{
base.setLastError("Memory error");
base.decodeFailed();
cleanupCodeStream();
return true; // done
}
while (mTPosp->y < mTileIndicesp->size.y)
{
@ -495,36 +559,47 @@ BOOL LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
kdu_coords offset = tile_dims.pos - dims.pos;
int row_gap = channels*dims.size.x; // inter-row separation
kdu_byte *buf = buffer + offset.y*row_gap + offset.x*channels;
mDecodeState = new LLKDUDecodeState(tile, buf, row_gap);
mDecodeState.reset(new LLKDUDecodeState(tile, buf, row_gap));
}
// Do the actual processing
F32 remaining_time = decode_time - decode_timer.getElapsedTimeF32();
// This is where we do the actual decode. If we run out of time, return false.
if (mDecodeState->processTileDecode(remaining_time, (decode_time > 0.0f)))
{
delete mDecodeState;
mDecodeState = NULL;
mDecodeState.reset();
}
else
{
// Not finished decoding yet.
// setLastError("Ran out of time while decoding");
return FALSE;
return false;
}
}
catch (const char* msg)
catch (const KDUError& msg)
{
base.setLastError(ll_safe_string(msg));
base.setLastError(msg.what());
base.decodeFailed();
cleanupCodeStream();
return TRUE; // done
return true; // done
}
catch (kdu_exception kdu_value)
{
// KDU internally throws kdu_exception. It's possible that such an
// exception might leak out into our code. Catch kdu_exception
// specially because boost::current_exception_diagnostic_information()
// could do nothing with it.
base.setLastError(report_kdu_exception(kdu_value));
base.decodeFailed();
cleanupCodeStream();
return true; // done
}
catch (...)
{
base.setLastError( "Unknown J2C error" );
base.setLastError("Unknown J2C error: " +
boost::current_exception_diagnostic_information());
base.decodeFailed();
cleanupCodeStream();
return TRUE; // done
return true; // done
}
@ -536,11 +611,11 @@ BOOL LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
cleanupCodeStream();
return TRUE;
return true;
}
BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, BOOL reversible)
bool LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, bool reversible)
{
// Declare and set simple arguments
bool transpose = false;
@ -705,39 +780,59 @@ BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co
base.updateData(); // set width, height
delete[] output_buffer;
}
catch(const char* msg)
catch(const KDUError& msg)
{
base.setLastError(ll_safe_string(msg));
return FALSE;
base.setLastError(msg.what());
return false;
}
catch (kdu_exception kdu_value)
{
// KDU internally throws kdu_exception. It's possible that such an
// exception might leak out into our code. Catch kdu_exception
// specially because boost::current_exception_diagnostic_information()
// could do nothing with it.
base.setLastError(report_kdu_exception(kdu_value));
return false;
}
catch( ... )
{
base.setLastError( "Unknown J2C error" );
return FALSE;
base.setLastError("Unknown J2C error: " +
boost::current_exception_diagnostic_information());
return false;
}
return TRUE;
return true;
}
BOOL LLImageJ2CKDU::getMetadata(LLImageJ2C &base)
bool LLImageJ2CKDU::getMetadata(LLImageJ2C &base)
{
// *FIX: kdu calls our callback function if there's an error, and
// then bombs. To regain control, we throw an exception, and
// catch it here.
try
{
setupCodeStream(base, FALSE, MODE_FAST);
return TRUE;
setupCodeStream(base, false, MODE_FAST);
return true;
}
catch (const char* msg)
catch (const KDUError& msg)
{
base.setLastError(ll_safe_string(msg));
return FALSE;
base.setLastError(msg.what());
return false;
}
catch (kdu_exception kdu_value)
{
// KDU internally throws kdu_exception. It's possible that such an
// exception might leak out into our code. Catch kdu_exception
// specially because boost::current_exception_diagnostic_information()
// could do nothing with it.
base.setLastError(report_kdu_exception(kdu_value));
return false;
}
catch (...)
{
base.setLastError( "Unknown J2C error" );
return FALSE;
base.setLastError("Unknown J2C error: " +
boost::current_exception_diagnostic_information());
return false;
}
}
@ -745,6 +840,8 @@ BOOL LLImageJ2CKDU::getMetadata(LLImageJ2C &base)
/* STATIC copy_block */
/*****************************************************************************/
/*==========================================================================*|
// Only called by copy_tile(), which is itself commented out
static void copy_block(kdu_block *in, kdu_block *out)
{
if (in->K_max_prime != out->K_max_prime)
@ -773,11 +870,14 @@ static void copy_block(kdu_block *in, kdu_block *out)
out->set_max_bytes(num_bytes,false);
memcpy(out->byte_buffer,in->byte_buffer,(size_t) num_bytes);
}
|*==========================================================================*/
/*****************************************************************************/
/* STATIC copy_tile */
/*****************************************************************************/
/*==========================================================================*|
// Only called by findDiscardLevelsBoundaries(), which is itself commented out
static void
copy_tile(kdu_tile tile_in, kdu_tile tile_out, int tnum_in, int tnum_out,
kdu_params *siz_in, kdu_params *siz_out, int skip_components,
@ -834,10 +934,13 @@ copy_tile(kdu_tile tile_in, kdu_tile tile_out, int tnum_in, int tnum_out,
}
}
}
|*==========================================================================*/
// Find the block boundary for each discard level in the input image.
// We parse the input blocks and copy them in a temporary output stream.
// For the moment, we do nothing more that parsing the raw list of blocks and outputing result.
/*==========================================================================*|
// See comments in header file for why this is commented out.
void LLImageJ2CKDU::findDiscardLevelsBoundaries(LLImageJ2C &base)
{
// We need the number of levels in that image before starting.
@ -847,7 +950,7 @@ void LLImageJ2CKDU::findDiscardLevelsBoundaries(LLImageJ2C &base)
{
//std::cout << "Parsing discard level = " << discard_level << std::endl;
// Create the input codestream object.
setupCodeStream(base, TRUE, MODE_FAST);
setupCodeStream(base, true, MODE_FAST);
mCodeStreamp->apply_input_restrictions(0, 4, discard_level, 0, NULL);
mCodeStreamp->set_max_bytes(KDU_LONG_MAX,true);
siz_params *siz_in = mCodeStreamp->access_siz();
@ -941,6 +1044,7 @@ void LLImageJ2CKDU::findDiscardLevelsBoundaries(LLImageJ2C &base)
}
return;
}
|*==========================================================================*/
void set_default_colour_weights(kdu_params *siz)
{
@ -1206,7 +1310,7 @@ LLKDUDecodeState::~LLKDUDecodeState()
mTile.close();
}
BOOL LLKDUDecodeState::processTileDecode(F32 decode_time, BOOL limit_time)
bool LLKDUDecodeState::processTileDecode(F32 decode_time, bool limit_time)
/* Decompresses a tile, writing the data into the supplied byte buffer.
The buffer contains interleaved image components, if there are any.
Although you may think of the buffer as belonging entirely to this tile,
@ -1238,11 +1342,11 @@ separation between consecutive rows in the real buffer. */
{
if (limit_time && decode_timer.getElapsedTimeF32() > decode_time)
{
return FALSE;
return false;
}
}
}
return TRUE;
return true;
}
// kdc_flow_control

View File

@ -48,6 +48,8 @@
#endif
#include "kdu_sample_processing.h"
#include <boost/scoped_ptr.hpp>
#include <boost/noncopyable.hpp>
class LLKDUDecodeState;
class LLKDUMemSource;
@ -65,43 +67,70 @@ public:
virtual ~LLImageJ2CKDU();
protected:
/*virtual*/ BOOL getMetadata(LLImageJ2C &base);
/*virtual*/ BOOL decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count);
/*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, int levels = 0);
void findDiscardLevelsBoundaries(LLImageJ2C &base);
virtual bool getMetadata(LLImageJ2C &base);
virtual bool decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count);
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, int levels = 0);
virtual std::string getEngineInfo() const;
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);
void setupCodeStream(LLImageJ2C &base, BOOL keep_codestream, ECodeStreamMode mode);
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);
void setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECodeStreamMode mode);
void cleanupCodeStream();
// This method was public, but the only call to it is commented out in our
// own initDecode() method. I (nat 2016-08-04) don't know what it does or
// why. Even if it should be uncommented, it should probably still be
// private.
// void findDiscardLevelsBoundaries(LLImageJ2C &base);
// Helper class to hold a kdu_codestream, which is a handle to the
// underlying implementation object. When CodeStreamHolder is reset() or
// destroyed, it calls kdu_codestream::destroy() -- which kdu_codestream
// itself does not.
//
// Call through it like a smart pointer using operator->().
//
// Every RAII class must be noncopyable. For this we don't need move
// support.
class CodeStreamHolder: public boost::noncopyable
{
public:
~CodeStreamHolder()
{
reset();
}
void reset()
{
if (mCodeStream.exists())
{
mCodeStream.destroy();
}
}
kdu_codestream* operator->() { return &mCodeStream; }
private:
kdu_codestream mCodeStream;
};
// Encode variable
LLKDUMemSource *mInputp;
kdu_codestream *mCodeStreamp;
kdu_coords *mTPosp; // tile position
kdu_dims *mTileIndicesp;
boost::scoped_ptr<LLKDUMemSource> mInputp;
CodeStreamHolder mCodeStreamp;
boost::scoped_ptr<kdu_coords> mTPosp; // tile position
boost::scoped_ptr<kdu_dims> mTileIndicesp;
int mBlocksSize;
int mPrecinctsSize;
int mLevels;
// Temporary variables for in-progress decodes...
// We don't own this LLImageRaw. We're simply pointing to an instance
// passed into initDecode().
LLImageRaw *mRawImagep;
LLKDUDecodeState *mDecodeState;
boost::scoped_ptr<LLKDUDecodeState> mDecodeState;
};
#if LL_WINDOWS
# define LLSYMEXPORT __declspec(dllexport)
#elif LL_LINUX
# define LLSYMEXPORT __attribute__ ((visibility("default")))
#else
# define LLSYMEXPORT
#endif
extern "C" LLSYMEXPORT const char* engineInfoLLImageJ2CKDU();
extern "C" LLSYMEXPORT LLImageJ2CKDU* createLLImageJ2CKDU();
extern "C" LLSYMEXPORT void destroyLLImageJ2CKDU(LLImageJ2CKDU* kdu);
#endif

View File

@ -60,7 +60,7 @@ LLImageRaw::~LLImageRaw() { }
U8* LLImageRaw::allocateData(S32 ) { return NULL; }
void LLImageRaw::deleteData() { }
U8* LLImageRaw::reallocateData(S32 ) { return NULL; }
BOOL LLImageRaw::resize(U16, U16, S8) { return TRUE; } // this method always returns TRUE...
bool LLImageRaw::resize(U16, U16, S8) { return true; } // this method always returns true...
LLImageBase::LLImageBase()
: LLTrace::MemTrackable<LLImageBase>("LLImageBase"),
@ -89,8 +89,8 @@ LLImageFormatted::~LLImageFormatted() { }
U8* LLImageFormatted::allocateData(S32 ) { return NULL; }
S32 LLImageFormatted::calcDataSize(S32 ) { return 0; }
S32 LLImageFormatted::calcDiscardLevelBytes(S32 ) { return 0; }
BOOL LLImageFormatted::decodeChannels(LLImageRaw*, F32, S32, S32) { return FALSE; }
BOOL LLImageFormatted::copyData(U8 *, S32) { return TRUE; } // this method always returns TRUE...
bool LLImageFormatted::decodeChannels(LLImageRaw*, F32, S32, S32) { return false; }
bool LLImageFormatted::copyData(U8 *, S32) { return true; } // this method always returns true...
void LLImageFormatted::deleteData() { }
void LLImageFormatted::dump() { }
U8* LLImageFormatted::reallocateData(S32 ) { return NULL; }
@ -103,14 +103,14 @@ LLImageJ2C::~LLImageJ2C() { }
S32 LLImageJ2C::calcDataSize(S32 ) { return 0; }
S32 LLImageJ2C::calcDiscardLevelBytes(S32 ) { return 0; }
S32 LLImageJ2C::calcHeaderSize() { return 0; }
BOOL LLImageJ2C::decode(LLImageRaw*, F32) { return FALSE; }
BOOL LLImageJ2C::decodeChannels(LLImageRaw*, F32, S32, S32 ) { return FALSE; }
bool LLImageJ2C::decode(LLImageRaw*, F32) { return false; }
bool LLImageJ2C::decodeChannels(LLImageRaw*, F32, S32, S32 ) { return false; }
void LLImageJ2C::decodeFailed() { }
BOOL LLImageJ2C::encode(const LLImageRaw*, F32) { return FALSE; }
bool LLImageJ2C::encode(const LLImageRaw*, F32) { return false; }
S8 LLImageJ2C::getRawDiscardLevel() { return 0; }
void LLImageJ2C::resetLastError() { }
void LLImageJ2C::setLastError(const std::string&, const std::string&) { }
BOOL LLImageJ2C::updateData() { return FALSE; }
bool LLImageJ2C::updateData() { return false; }
void LLImageJ2C::updateRawDiscardLevel() { }
LLKDUMemIn::LLKDUMemIn(const U8*, const U32, const U16, const U16, const U8, siz_params*) { }
@ -212,12 +212,12 @@ namespace tut
{
public:
// Provides public access to some protected methods for testing
BOOL callGetMetadata(LLImageJ2C &base) { return getMetadata(base); }
BOOL callDecodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
bool callGetMetadata(LLImageJ2C &base) { return getMetadata(base); }
bool callDecodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
{
return decodeImpl(base, raw_image, decode_time, first_channel, max_channel_count);
}
BOOL callEncodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text)
bool callEncodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text)
{
return encodeImpl(base, raw_image, comment_text);
}
@ -254,10 +254,10 @@ namespace tut
void llimagej2ckdu_object_t::test<1>()
{
LLImageJ2C* image = new LLImageJ2C();
BOOL res = mImage->callGetMetadata(*image);
// Trying to set up a data stream with all NIL values and stubbed KDU will "work" and return TRUE
// Note that is linking with KDU, that call will throw an exception and fail, returning FALSE
ensure("getMetadata() test failed", res == TRUE);
bool res = mImage->callGetMetadata(*image);
// Trying to set up a data stream with all NIL values and stubbed KDU will "work" and return true
// Note that is linking with KDU, that call will throw an exception and fail, returning false
ensure("getMetadata() test failed", res);
}
// Test 2 : test decodeImpl()
@ -266,9 +266,9 @@ namespace tut
{
LLImageJ2C* image = new LLImageJ2C();
LLImageRaw* raw = new LLImageRaw();
BOOL res = mImage->callDecodeImpl(*image, *raw, 0.0, 0, 0);
// Decoding returns TRUE whenever there's nothing else to do, including if decoding failed, so we'll get TRUE here
ensure("decodeImpl() test failed", res == TRUE);
bool res = mImage->callDecodeImpl(*image, *raw, 0.0, 0, 0);
// Decoding returns true whenever there's nothing else to do, including if decoding failed, so we'll get true here
ensure("decodeImpl() test failed", res);
}
// Test 3 : test encodeImpl()
@ -277,8 +277,8 @@ namespace tut
{
LLImageJ2C* image = new LLImageJ2C();
LLImageRaw* raw = new LLImageRaw();
BOOL res = mImage->callEncodeImpl(*image, *raw, NULL);
// Encoding returns TRUE unless an exception was raised, so we'll get TRUE here though nothing really was done
ensure("encodeImpl() test failed", res == TRUE);
bool res = mImage->callEncodeImpl(*image, *raw, NULL);
// Encoding returns true unless an exception was raised, so we'll get true here though nothing really was done
ensure("encodeImpl() test failed", res);
}
}

View File

@ -181,6 +181,10 @@ protected:
// Map of known bad assets
typedef std::map<LLUUID,U64,lluuid_less> toxic_asset_map_t;
// *TODO: these typedefs are passed into the VFS via a legacy C function pointer
// future project would be to convert these to C++ callables (std::function<>) so that
// we can use bind and remove the userData parameter.
//
typedef void (*LLGetAssetCallback)(LLVFS *vfs, const LLUUID &asset_id,
LLAssetType::EType asset_type, void *user_data, S32 status, LLExtStat ext_status);

View File

@ -166,7 +166,7 @@ void LLAvatarName::setExpires(F64 expires)
mExpires = LLFrameTimer::getTotalSeconds() + expires;
}
std::string LLAvatarName::getCompleteName() const
std::string LLAvatarName::getCompleteName(bool use_parentheses) const
{
std::string name;
if (sUseDisplayNames)
@ -182,7 +182,14 @@ std::string LLAvatarName::getCompleteName() const
name = mDisplayName;
if(sUseUsernames)
{
name += " (" + mUsername + ")";
if(use_parentheses)
{
name += " (" + mUsername + ")";
}
else
{
name += " [ " + mUsername + " ]";
}
}
}
}
@ -220,7 +227,7 @@ std::string LLAvatarName::getDisplayName() const
}
}
std::string LLAvatarName::getUserName() const
std::string LLAvatarName::getUserName(bool lowercase) const
{
std::string name;
if (mLegacyLastName.empty() || (mLegacyLastName == "Resident"))
@ -238,7 +245,15 @@ std::string LLAvatarName::getUserName() const
}
else
{
name = mLegacyFirstName + " " + mLegacyLastName;
if(lowercase)
{
name = mLegacyFirstName + "." + mLegacyLastName;
LLStringUtil::toLower(name);
}
else
{
name = mLegacyFirstName + " " + mLegacyLastName;
}
}
return name;
}

View File

@ -65,7 +65,7 @@ public:
// For normal names, returns "James Linden (james.linden)"
// When display names are disabled returns just "James Linden"
std::string getCompleteName() const;
std::string getCompleteName(bool use_parentheses = true) const;
// Returns "James Linden" or "bobsmith123 Resident" for backwards
// compatibility with systems like voice and muting
@ -80,7 +80,7 @@ public:
// Returns "James Linden" or "bobsmith123 Resident"
// Used where we explicitely prefer or need a non UTF-8 legacy (ASCII) name
// Also used for backwards compatibility with systems like voice and muting
std::string getUserName() const;
std::string getUserName(bool lowercase = false) const;
// Returns "james.linden" or the legacy name for very old names
std::string getAccountName() const { return mUsername; }

View File

@ -43,6 +43,8 @@
#include "llcoros.h"
#include "lleventcoro.h"
#include "llcorehttputil.h"
#include "llexception.h"
#include "stringize.h"
#include <map>
#include <set>
@ -231,13 +233,12 @@ void LLAvatarNameCache::requestAvatarNameCache_(std::string url, std::vector<LLU
LLAvatarNameCache::handleAvNameCacheSuccess(results, httpResults);
}
catch (std::exception e)
{
LL_WARNS() << "Caught exception '" << e.what() << "'" << LL_ENDL;
}
catch (...)
{
LL_WARNS() << "Caught unknown exception." << LL_ENDL;
LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::instance().getName()
<< "('" << url << "', " << agentIds.size()
<< " Agent Ids)"));
throw;
}
}

View File

@ -27,6 +27,8 @@
#include "linden_common.h"
#include "llcoproceduremanager.h"
#include "llexception.h"
#include "stringize.h"
#include <boost/assign.hpp>
//=========================================================================
@ -388,14 +390,14 @@ void LLCoprocedurePool::coprocedureInvokerCoro(LLCoreHttpUtil::HttpCoroutineAdap
{
coproc->mProc(httpAdapter, coproc->mId);
}
catch (std::exception &e)
{
LL_WARNS() << "Coprocedure(" << coproc->mName << ") id=" << coproc->mId.asString() <<
" threw an exception! Message=\"" << e.what() << "\"" << LL_ENDL;
}
catch (...)
{
LL_WARNS() << "A non std::exception was thrown from " << coproc->mName << " with id=" << coproc->mId << "." << " in pool \"" << mPoolName << "\"" << LL_ENDL;
LOG_UNHANDLED_EXCEPTION(STRINGIZE("Coprocedure('" << coproc->mName
<< "', id=" << coproc->mId.asString()
<< ") in pool '" << mPoolName << "'"));
// must NOT omit this or we deplete the pool
mActiveCoprocs.erase(itActive);
throw;
}
LL_INFOS() << "Finished coprocedure(" << coproc->mName << ")" << " in pool \"" << mPoolName << "\"" << LL_ENDL;

View File

@ -31,6 +31,7 @@
#include "llstl.h"
#include "llhttpconstants.h"
#include "llexception.h"
const std::string CONTEXT_HEADERS("headers");
const std::string CONTEXT_PATH("path");
@ -92,27 +93,28 @@ LLHTTPNode::~LLHTTPNode()
namespace {
class NotImplemented
struct NotImplemented: public LLException
{
NotImplemented(): LLException("LLHTTPNode::NotImplemented") {}
};
}
// virtual
LLSD LLHTTPNode::simpleGet() const
{
throw NotImplemented();
LLTHROW(NotImplemented());
}
// virtual
LLSD LLHTTPNode::simplePut(const LLSD& input) const
{
throw NotImplemented();
LLTHROW(NotImplemented());
}
// virtual
LLSD LLHTTPNode::simplePost(const LLSD& input) const
{
throw NotImplemented();
LLTHROW(NotImplemented());
}
@ -172,7 +174,7 @@ void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) cons
// virtual
LLSD LLHTTPNode::simpleDel(const LLSD&) const
{
throw NotImplemented();
LLTHROW(NotImplemented());
}
// virtual

View File

@ -33,15 +33,15 @@
#include "llevents.h"
#include "llsd.h"
#include "llhost.h"
#include "llexception.h"
#include "stringize.h"
#include <map>
#include <string>
#include <stdexcept>
#include <boost/lexical_cast.hpp>
struct CommtestError: public std::runtime_error
struct CommtestError: public LLException
{
CommtestError(const std::string& what): std::runtime_error(what) {}
CommtestError(const std::string& what): LLException(what) {}
};
static bool query_verbose()
@ -68,7 +68,7 @@ static int query_port(const std::string& var)
const char* cport = getenv(var.c_str());
if (! cport)
{
throw CommtestError(STRINGIZE("missing environment variable" << var));
LLTHROW(CommtestError(STRINGIZE("missing environment variable" << var)));
}
// This will throw, too, if the value of PORT isn't numeric.
int port(boost::lexical_cast<int>(cport));

View File

@ -34,6 +34,7 @@
#include "llares.h"
#include "llpumpio.h"
#include "llhttpclient.h"
#include "llexception.h"
/*****************************************************************************
* NetworkIO
@ -51,7 +52,7 @@ public:
ll_init_apr();
if (! gAPRPoolp)
{
throw std::runtime_error("Can't initialize APR");
LLTHROW(LLException("Can't initialize APR"));
}
// Create IO Pump to use for HTTP Requests.
@ -59,7 +60,7 @@ public:
LLHTTPClient::setPump(*mServicePump);
if (ll_init_ares() == NULL || !gAres->isInitialized())
{
throw std::runtime_error("Can't start DNS resolver");
LLTHROW(LLException("Can't start DNS resolver"));
}
// You can interrupt pump() without waiting the full timeout duration

View File

@ -116,7 +116,7 @@ void LLPluginClassMedia::reset()
mMediaHeight = 0;
mDirtyRect = LLRect::null;
mAutoScaleMedia = false;
mRequestedVolume = 1.0f;
mRequestedVolume = 0.0f;
mPriority = PRIORITY_NORMAL;
mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT;
mAllowDownsample = false;

View File

@ -2235,7 +2235,11 @@ std::string LLDAELoader::getElementLabel(daeElement *element)
// retrieve index to distinguish items inside same parent
size_t ind = 0;
parent->getChildren().find(element, ind);
index_string = "_" + boost::lexical_cast<std::string>(ind);
if (ind > 0)
{
index_string = "_" + boost::lexical_cast<std::string>(ind);
}
// if parent has a name or ID, use it
std::string name = parent->getAttribute("name");

View File

@ -349,8 +349,8 @@ void LLGLSLShader::unloadInternal()
for (GLsizei i = 0; i < count; i++)
{
glDetachObjectARB(mProgramObject, obj[i]);
glDeleteObjectARB(obj[i]);
}
glDeleteObjectARB(obj[i]);
}
glDeleteObjectARB(mProgramObject);

View File

@ -520,7 +520,7 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns, const std::string&
if (!filename.empty())
{
LL_CONT << "From " << filename << ":\n";
}
}
LL_CONT << log << LL_ENDL;
}
}

View File

@ -1326,7 +1326,7 @@ void LLFloater::setMinimized(BOOL minimize)
}
mMinimized = FALSE;
setFrontmost();
// Reshape *after* setting mMinimized
reshape( mExpandedRect.getWidth(), mExpandedRect.getHeight(), TRUE );
}
@ -1575,6 +1575,7 @@ BOOL LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
if(offerClickToButton(x, y, mask, BUTTON_TEAR_OFF)) return TRUE;
if(offerClickToButton(x, y, mask, BUTTON_DOCK)) return TRUE;
setFrontmost(TRUE, FALSE);
// Otherwise pass to drag handle for movement
return mDragHandle->handleMouseDown(x, y, mask);
}
@ -1649,7 +1650,7 @@ void LLFloater::setVisibleAndFrontmost(BOOL take_focus,const LLSD& key)
}
}
void LLFloater::setFrontmost(BOOL take_focus)
void LLFloater::setFrontmost(BOOL take_focus, BOOL restore)
{
LLMultiFloater* hostp = getHost();
if (hostp)
@ -1665,7 +1666,7 @@ void LLFloater::setFrontmost(BOOL take_focus)
LLFloaterView * parent = dynamic_cast<LLFloaterView*>( getParent() );
if (parent)
{
parent->bringToFront(this, take_focus);
parent->bringToFront(this, take_focus, restore);
}
// Make sure to set the appropriate transparency type (STORM-732).
@ -2262,7 +2263,7 @@ void LLFloaterView::reshape(S32 width, S32 height, BOOL called_from_parent)
for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
{
LLView* viewp = *child_it;
LLFloater* floaterp = (LLFloater*)viewp;
LLFloater* floaterp = dynamic_cast<LLFloater*>(viewp);
if (floaterp->isDependent())
{
// dependents are moved with their "dependee"
@ -2317,10 +2318,14 @@ void LLFloaterView::reshape(S32 width, S32 height, BOOL called_from_parent)
void LLFloaterView::restoreAll()
{
// make sure all subwindows aren't minimized
for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
child_list_t child_list = *(getChildList());
for (child_list_const_iter_t child_it = child_list.begin(); child_it != child_list.end(); ++child_it)
{
LLFloater* floaterp = (LLFloater*)*child_it;
floaterp->setMinimized(FALSE);
LLFloater* floaterp = dynamic_cast<LLFloater*>(*child_it);
if (floaterp)
{
floaterp->setMinimized(FALSE);
}
}
// *FIX: make sure dependents are restored
@ -2394,7 +2399,7 @@ LLRect LLFloaterView::findNeighboringPosition( LLFloater* reference_floater, LLF
}
void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus)
void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus, BOOL restore)
{
if (!child)
return;
@ -2478,7 +2483,12 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus)
{
sendChildToFront(child);
}
child->setMinimized(FALSE);
if(restore)
{
child->setMinimized(FALSE);
}
if (give_focus && !gFocusMgr.childHasKeyboardFocus(child))
{
child->setFocus(TRUE);
@ -2591,7 +2601,7 @@ void LLFloaterView::getMinimizePosition(S32 *left, S32 *bottom)
++child_it) //loop floaters
{
// Examine minimized children.
LLFloater* floater = (LLFloater*)((LLView*)*child_it);
LLFloater* floater = dynamic_cast<LLFloater*>(*child_it);
if(floater->isMinimized())
{
LLRect r = floater->getRect();
@ -2644,7 +2654,7 @@ void LLFloaterView::closeAllChildren(bool app_quitting)
continue;
}
LLFloater* floaterp = (LLFloater*)viewp;
LLFloater* floaterp = dynamic_cast<LLFloater*>(viewp);
// Attempt to close floater. This will cause the "do you want to save"
// dialogs to appear.
@ -2710,8 +2720,7 @@ BOOL LLFloaterView::allChildrenClosed()
// by setting themselves invisible)
for (child_list_const_iter_t it = getChildList()->begin(); it != getChildList()->end(); ++it)
{
LLView* viewp = *it;
LLFloater* floaterp = (LLFloater*)viewp;
LLFloater* floaterp = dynamic_cast<LLFloater*>(*it);
if (floaterp->getVisible() && !floaterp->isDead() && floaterp->isCloseable())
{
@ -2947,7 +2956,7 @@ void LLFloaterView::syncFloaterTabOrder()
// otherwise, make sure the focused floater is in the front of the child list
for ( child_list_const_reverse_iter_t child_it = getChildList()->rbegin(); child_it != getChildList()->rend(); ++child_it)
{
LLFloater* floaterp = (LLFloater*)*child_it;
LLFloater* floaterp = dynamic_cast<LLFloater*>(*child_it);
if (gFocusMgr.childHasKeyboardFocus(floaterp))
{
bringToFront(floaterp, FALSE);
@ -2969,7 +2978,7 @@ LLFloater* LLFloaterView::getParentFloater(LLView* viewp) const
if (parentp == this)
{
return (LLFloater*)viewp;
return dynamic_cast<LLFloater*>(viewp);
}
return NULL;

View File

@ -310,7 +310,7 @@ public:
/*virtual*/ void setVisible(BOOL visible); // do not override
/*virtual*/ void onVisibilityChange ( BOOL new_visibility ); // do not override
void setFrontmost(BOOL take_focus = TRUE);
void setFrontmost(BOOL take_focus = TRUE, BOOL restore = TRUE);
virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD());
// Defaults to false.
@ -547,7 +547,7 @@ public:
void setCycleMode(BOOL mode) { mFocusCycleMode = mode; }
BOOL getCycleMode() const { return mFocusCycleMode; }
void bringToFront( LLFloater* child, BOOL give_focus = TRUE );
void bringToFront( LLFloater* child, BOOL give_focus = TRUE, BOOL restore = TRUE );
void highlightFocusedFloater();
void unhighlightFocusedFloater();
void focusFrontFloater();

View File

@ -186,7 +186,6 @@ void LLFocusMgr::releaseFocusIfNeeded( LLView* view )
LLUI::removePopup(view);
}
void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL keystrokes_only)
{
// notes if keyboard focus is changed again (by onFocusLost/onFocusReceived)

View File

@ -1629,9 +1629,9 @@ void LLFolderView::update()
if (mNeedsAutoSelect)
{
LL_RECORD_BLOCK_TIME(FTM_AUTO_SELECT);
// select new item only if a filtered item not currently selected
// select new item only if a filtered item not currently selected and there was a selection
LLFolderViewItem* selected_itemp = mSelectedItems.empty() ? NULL : mSelectedItems.back();
if (!mAutoSelectOverride && (!selected_itemp || !selected_itemp->getViewModelItem()->potentiallyVisible()))
if (!mAutoSelectOverride && selected_itemp && !selected_itemp->getViewModelItem()->potentiallyVisible())
{
// these are named variables to get around gcc not binding non-const references to rvalues
// and functor application is inherently non-const to allow for stateful functors

View File

@ -242,6 +242,8 @@ public:
bool useLabelSuffix() { return mUseLabelSuffix; }
virtual void updateMenu();
void finishRenamingItem( void );
// Note: We may eventually have to move that method up the hierarchy to LLFolderViewItem.
LLHandle<LLFolderView> getHandle() const { return getDerivedHandle<LLFolderView>(); }
@ -255,7 +257,6 @@ protected:
void commitRename( const LLSD& data );
void onRenamerLost();
void finishRenamingItem( void );
void closeRenamer( void );
bool selectFirstItem();

View File

@ -972,6 +972,11 @@ void LLFolderViewFolder::addToFolder(LLFolderViewFolder* folder)
mIndentation = (getParentFolder())
? getParentFolder()->getIndentation() + mLocalIndentation
: 0;
if(isOpen() && folder->isOpen())
{
requestArrange();
}
}
static LLTrace::BlockTimerStatHandle FTM_ARRANGE("Arrange");

View File

@ -400,12 +400,7 @@ void LLLineEditor::setText(const LLStringExplicit &new_text)
if (mMaxLengthChars)
{
LLWString truncated_wstring = utf8str_to_wstring(truncated_utf8);
if (truncated_wstring.size() > (U32)mMaxLengthChars)
{
truncated_wstring = truncated_wstring.substr(0, mMaxLengthChars);
}
mText.assign(wstring_to_utf8str(truncated_wstring));
mText.assign(utf8str_symbol_truncate(truncated_utf8, mMaxLengthChars));
}
if (all_selected)

View File

@ -177,6 +177,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
: LLUICtrl(p, LLTextViewModelPtr(new LLTextViewModel)),
mURLClickSignal(NULL),
mIsFriendSignal(NULL),
mIsObjectBlockedSignal(NULL),
mMaxTextByteLength( p.max_text_length ),
mFont(p.font),
mFontShadow(p.font_shadow),
@ -268,6 +269,8 @@ LLTextBase::~LLTextBase()
{
mSegments.clear();
delete mURLClickSignal;
delete mIsFriendSignal;
delete mIsObjectBlockedSignal;
}
void LLTextBase::initFromParams(const LLTextBase::Params& p)
@ -1942,6 +1945,7 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)
registrar.add("Url.OpenExternal", boost::bind(&LLUrlAction::openURLExternal, url));
registrar.add("Url.Execute", boost::bind(&LLUrlAction::executeSLURL, url, true));
registrar.add("Url.Block", boost::bind(&LLUrlAction::blockObject, url));
registrar.add("Url.Unblock", boost::bind(&LLUrlAction::unblockObject, url));
registrar.add("Url.Teleport", boost::bind(&LLUrlAction::teleportToLocation, url));
registrar.add("Url.ShowProfile", boost::bind(&LLUrlAction::showProfile, url));
registrar.add("Url.AddFriend", boost::bind(&LLUrlAction::addFriend, url));
@ -1968,6 +1972,19 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)
removeFriendButton->setEnabled(isFriend);
}
}
if (mIsObjectBlockedSignal)
{
bool is_blocked = *(*mIsObjectBlockedSignal)(LLUUID(LLUrlAction::getObjectId(url)), LLUrlAction::getObjectName(url));
LLView* blockButton = mPopupMenu->getChild<LLView>("block_object");
LLView* unblockButton = mPopupMenu->getChild<LLView>("unblock_object");
if (blockButton && unblockButton)
{
blockButton->setVisible(!is_blocked);
unblockButton->setVisible(is_blocked);
}
}
if (mPopupMenu)
{
@ -3022,6 +3039,15 @@ boost::signals2::connection LLTextBase::setIsFriendCallback(const is_friend_sign
return mIsFriendSignal->connect(cb);
}
boost::signals2::connection LLTextBase::setIsObjectBlockedCallback(const is_blocked_signal_t::slot_type& cb)
{
if (!mIsObjectBlockedSignal)
{
mIsObjectBlockedSignal = new is_blocked_signal_t();
}
return mIsObjectBlockedSignal->connect(cb);
}
//
// LLTextSegment
//

View File

@ -270,6 +270,7 @@ public:
friend class LLUICtrlFactory;
typedef boost::signals2::signal<bool (const LLUUID& user_id)> is_friend_signal_t;
typedef boost::signals2::signal<bool (const LLUUID& blocked_id, const std::string from)> is_blocked_signal_t;
struct LineSpacingParams : public LLInitParam::ChoiceBlock<LineSpacingParams>
{
@ -456,6 +457,7 @@ public:
virtual void appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo);
boost::signals2::connection setURLClickedCallback(const commit_signal_t::slot_type& cb);
boost::signals2::connection setIsFriendCallback(const is_friend_signal_t::slot_type& cb);
boost::signals2::connection setIsObjectBlockedCallback(const is_blocked_signal_t::slot_type& cb);
void setWordWrap(bool wrap);
LLScrollContainer* getScrollContainer() const { return mScroller; }
@ -685,6 +687,7 @@ protected:
// Used to check if user with given ID is avatar's friend
is_friend_signal_t* mIsFriendSignal;
is_blocked_signal_t* mIsObjectBlockedSignal;
LLUIString mLabel; // text label that is visible when no user text provided
};

View File

@ -56,6 +56,26 @@ void LLTextUtil::textboxSetHighlightedVal(LLTextBox *txtbox, const LLStyle::Para
txtbox->appendText(text.substr(hl_begin + hl_len), false, normal_style);
}
void LLTextUtil::textboxSetGreyedVal(LLTextBox *txtbox, const LLStyle::Params& normal_style, const std::string& text, const std::string& greyed)
{
static LLUIColor sGreyedTextColor = LLUIColorTable::instance().getColor("Gray", LLColor4::grey);
size_t greyed_begin = 0, greyed_len = greyed.size();
if (greyed_len == 0 || (greyed_begin = text.find(greyed)) == std::string::npos)
{
txtbox->setText(text, normal_style);
return;
}
LLStyle::Params greyed_style = normal_style;
greyed_style.color = sGreyedTextColor;
txtbox->setText(LLStringUtil::null); // clear text
txtbox->appendText(text.substr(0, greyed_begin), false, normal_style);
txtbox->appendText(text.substr(greyed_begin, greyed_len), false, greyed_style);
txtbox->appendText(text.substr(greyed_begin + greyed_len), false, normal_style);
}
const std::string& LLTextUtil::formatPhoneNumber(const std::string& phone_str)
{
static const std::string PHONE_SEPARATOR = LLUI::sSettingGroups["config"]->getString("AvalinePhoneSeparator");

View File

@ -52,6 +52,12 @@ namespace LLTextUtil
const std::string& text,
const std::string& hl);
void textboxSetGreyedVal(
LLTextBox *txtbox,
const LLStyle::Params& normal_style,
const std::string& text,
const std::string& greyed);
/**
* Formats passed phone number to be more human readable.
*

View File

@ -231,3 +231,13 @@ void LLUrlAction::blockObject(std::string url)
executeSLURL("secondlife:///app/agent/" + object_id + "/block/" + LLURI::escape(object_name));
}
}
void LLUrlAction::unblockObject(std::string url)
{
std::string object_id = getObjectId(url);
std::string object_name = getObjectName(url);
if (LLUUID::validate(object_id))
{
executeSLURL("secondlife:///app/agent/" + object_id + "/unblock/" + object_name);
}
}

View File

@ -83,6 +83,7 @@ public:
static void addFriend(std::string url);
static void removeFriend(std::string url);
static void blockObject(std::string url);
static void unblockObject(std::string url);
/// specify the callbacks to enable this class's functionality
typedef boost::function<void (const std::string&)> url_callback_t;

View File

@ -588,6 +588,11 @@ void LLView::onVisibilityChange ( BOOL new_visibility )
BOOL log_visibility_change = LLViewerEventRecorder::instance().getLoggingStatus();
BOOST_FOREACH(LLView* viewp, mChildList)
{
if (!viewp)
{
continue;
}
// only views that are themselves visible will have their overall visibility affected by their ancestors
old_visibility=viewp->getVisible();
@ -807,7 +812,7 @@ LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask)
LLView* LLView::childFromPoint(S32 x, S32 y, bool recur)
{
if (!getVisible())
return false;
return NULL;
BOOST_FOREACH(LLView* viewp, mChildList)
{

View File

@ -41,7 +41,7 @@
@property (retain) NSString *currentInputLanguage;
- (void) mainLoop;
- (void) oneFrame;
- (void) showInputWindow:(bool)show withEvent:(NSEvent*)textEvent;
- (void) languageUpdated;
- (bool) romanScript;

View File

@ -69,7 +69,7 @@ typedef const NativeKeyEventData * NSKeyEventRef;
// These are defined in llappviewermacosx.cpp.
bool initViewer();
void handleQuit();
bool runMainLoop();
bool pumpMainLoop();
void initMainLoop();
void cleanupViewer();
void handleUrl(const char* url);

View File

@ -64,7 +64,7 @@ void LLCrashLoggerMac::gatherPlatformSpecificFiles()
{
}
bool LLCrashLoggerMac::mainLoop()
bool LLCrashLoggerMac::frame()
{
if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND)

View File

@ -37,7 +37,7 @@ public:
LLCrashLoggerMac(void);
~LLCrashLoggerMac(void);
virtual bool init();
virtual bool mainLoop();
virtual bool frame();
virtual bool cleanup();
virtual void gatherPlatformSpecificFiles();
};

View File

@ -49,7 +49,7 @@ int main(int argc, char **argv)
{
// return NSApplicationMain(argc, (const char **)argv);
}
app.mainLoop();
app.frame();
app.cleanup();
LL_INFOS() << "Crash reporter finished normally." << LL_ENDL;

View File

@ -4,15 +4,18 @@ add_subdirectory(base)
if (LINUX)
add_subdirectory(gstreamer010)
add_subdirectory(libvlc)
endif (LINUX)
if (WINDOWS OR DARWIN)
if (DARWIN)
add_subdirectory(quicktime)
add_subdirectory(cef)
endif (WINDOWS OR DARWIN)
endif (DARWIN)
if (WINDOWS)
add_subdirectory(cef)
add_subdirectory(winmmshim)
add_subdirectory(libvlc)
endif (WINDOWS)
### add_subdirectory(example)

View File

@ -100,6 +100,12 @@ private:
LLCEFLib* mLLCEFLib;
VolumeCatcher mVolumeCatcher;
U8 *mPopupBuffer;
U32 mPopupW;
U32 mPopupH;
U32 mPopupX;
U32 mPopupY;
};
////////////////////////////////////////////////////////////////////////////////
@ -127,12 +133,19 @@ MediaPluginBase(host_send_func, host_user_data)
mCookiePath = "";
mPickedFile = "";
mLLCEFLib = new LLCEFLib();
mPopupBuffer = NULL;
mPopupW = 0;
mPopupH = 0;
mPopupX = 0;
mPopupY = 0;
}
////////////////////////////////////////////////////////////////////////////////
//
MediaPluginCEF::~MediaPluginCEF()
{
delete[] mPopupBuffer;
}
////////////////////////////////////////////////////////////////////////////////
@ -155,20 +168,28 @@ void MediaPluginCEF::postDebugMessage(const std::string& msg)
//
void MediaPluginCEF::onPageChangedCallback(unsigned char* pixels, int x, int y, int width, int height, bool is_popup)
{
if (mPixels && pixels)
if( is_popup )
{
delete mPopupBuffer;
mPopupBuffer = NULL;
mPopupH = 0;
mPopupW = 0;
mPopupX = 0;
mPopupY = 0;
}
if( mPixels && pixels )
{
if (is_popup)
{
for (int line = 0; line < height; ++line)
if( width > 0 && height> 0 )
{
int inverted_y = mHeight - y - height;
int src = line * width * mDepth;
int dst = (inverted_y + line) * mWidth * mDepth + x * mDepth;
if (dst + width * mDepth < mWidth * mHeight * mDepth)
{
memcpy(mPixels + dst, pixels + src, width * mDepth);
}
mPopupBuffer = new U8[ width * height * mDepth ];
memcpy( mPopupBuffer, pixels, width * height * mDepth );
mPopupH = height;
mPopupW = width;
mPopupX = x;
mPopupY = mHeight - y - height;
}
}
else
@ -177,6 +198,23 @@ void MediaPluginCEF::onPageChangedCallback(unsigned char* pixels, int x, int y,
{
memcpy(mPixels, pixels, mWidth * mHeight * mDepth);
}
if( mPopupBuffer && mPopupH && mPopupW )
{
U32 bufferSize = mWidth * mHeight * mDepth;
U32 popupStride = mPopupW * mDepth;
U32 bufferStride = mWidth * mDepth;
int dstY = mPopupY;
int src = 0;
int dst = dstY * mWidth * mDepth + mPopupX * mDepth;
for( int line = 0; dst + popupStride < bufferSize && line < mPopupH; ++line )
{
memcpy( mPixels + dst, mPopupBuffer + src, popupStride );
src += popupStride;
dst += bufferStride;
}
}
}
setDirty(0, 0, mWidth, mHeight);
@ -559,6 +597,8 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
S32 x = message_in.getValueS32("x");
S32 y = message_in.getValueS32("y");
y = mHeight - y;
// only even send left mouse button events to LLCEFLib
// (partially prompted by crash in OS X CEF when sending right button events)
// we catch the right click in viewer and display our own context menu anyway

View File

@ -0,0 +1,86 @@
# -*- cmake -*-
project(media_plugin_libvlc)
include(00-Common)
include(LLCommon)
include(LLImage)
include(LLPlugin)
include(LLMath)
include(LLRender)
include(LLWindow)
include(Linking)
include(PluginAPI)
include(MediaPluginBase)
include(OpenGL)
include(LibVLCPlugin)
include_directories(
${LLPLUGIN_INCLUDE_DIRS}
${MEDIA_PLUGIN_BASE_INCLUDE_DIRS}
${LLCOMMON_INCLUDE_DIRS}
${LLMATH_INCLUDE_DIRS}
${LLIMAGE_INCLUDE_DIRS}
${LLRENDER_INCLUDE_DIRS}
${LLWINDOW_INCLUDE_DIRS}
${VLC_INCLUDE_DIR}
)
include_directories(SYSTEM
${LLCOMMON_SYSTEM_INCLUDE_DIRS}
)
### media_plugin_libvlc
if(NOT WORD_SIZE EQUAL 32)
if(WINDOWS)
add_definitions(/FIXED:NO)
else(WINDOWS) # not windows therefore gcc LINUX and DARWIN
add_definitions(-fPIC)
endif(WINDOWS)
endif(NOT WORD_SIZE EQUAL 32)
set(media_plugin_libvlc_SOURCE_FILES
media_plugin_libvlc.cpp
)
add_library(media_plugin_libvlc
SHARED
${media_plugin_libvlc_SOURCE_FILES}
)
target_link_libraries(media_plugin_libvlc
${LLPLUGIN_LIBRARIES}
${MEDIA_PLUGIN_BASE_LIBRARIES}
${LLCOMMON_LIBRARIES}
${VLC_PLUGIN_LIBRARIES}
${PLUGIN_API_WINDOWS_LIBRARIES}
)
add_dependencies(media_plugin_libvlc
${LLPLUGIN_LIBRARIES}
${MEDIA_PLUGIN_BASE_LIBRARIES}
${LLCOMMON_LIBRARIES}
)
if (WINDOWS)
set_target_properties(
media_plugin_libvlc
PROPERTIES
LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /LTCG /NODEFAULTLIB:LIBCMT"
)
endif (WINDOWS)
if (DARWIN)
# Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name
set_target_properties(
media_plugin_libvlc
PROPERTIES
PREFIX ""
BUILD_WITH_INSTALL_RPATH 1
INSTALL_NAME_DIR "@executable_path"
LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp"
)
endif (DARWIN)

View File

@ -0,0 +1,618 @@
/**
* @file media_plugin_libvlc.cpp
* @brief LibVLC 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 "linden_common.h"
#include "llgl.h"
#include "llplugininstance.h"
#include "llpluginmessage.h"
#include "llpluginmessageclasses.h"
#include "media_plugin_base.h"
#include "vlc/vlc.h"
#include "vlc/libvlc_version.h"
////////////////////////////////////////////////////////////////////////////////
//
class MediaPluginLibVLC :
public MediaPluginBase
{
public:
MediaPluginLibVLC(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
~MediaPluginLibVLC();
/*virtual*/ void receiveMessage(const char* message_string);
private:
bool init();
void initVLC();
void playMedia();
void resetVLC();
void setVolume(const F64 volume);
void updateTitle(const char* title);
static void* lock(void* data, void** p_pixels);
static void unlock(void* data, void* id, void* const* raw_pixels);
static void display(void* data, void* id);
/*virtual*/ void setDirty(int left, int top, int right, int bottom) /* override, but that is not supported in gcc 4.6 */;
static void eventCallbacks(const libvlc_event_t* event, void* ptr);
libvlc_instance_t* mLibVLC;
libvlc_media_t* mLibVLCMedia;
libvlc_media_player_t* mLibVLCMediaPlayer;
struct mLibVLCContext
{
unsigned char* texture_pixels;
libvlc_media_player_t* mp;
MediaPluginLibVLC* parent;
};
struct mLibVLCContext mLibVLCCallbackContext;
std::string mURL;
F64 mCurVolume;
bool mIsLooping;
float mCurTime;
float mDuration;
};
////////////////////////////////////////////////////////////////////////////////
//
MediaPluginLibVLC::MediaPluginLibVLC(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) :
MediaPluginBase(host_send_func, host_user_data)
{
mTextureWidth = 0;
mTextureHeight = 0;
mWidth = 0;
mHeight = 0;
mDepth = 4;
mPixels = 0;
mLibVLC = 0;
mLibVLCMedia = 0;
mLibVLCMediaPlayer = 0;
mCurVolume = 0.0;
mIsLooping = false;
mCurTime = 0.0;
mDuration = 0.0;
mURL = std::string();
setStatus(STATUS_NONE);
}
////////////////////////////////////////////////////////////////////////////////
//
MediaPluginLibVLC::~MediaPluginLibVLC()
{
}
/////////////////////////////////////////////////////////////////////////////////
//
void* MediaPluginLibVLC::lock(void* data, void** p_pixels)
{
struct mLibVLCContext* context = (mLibVLCContext*)data;
*p_pixels = context->texture_pixels;
return NULL;
}
/////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginLibVLC::unlock(void* data, void* id, void* const* raw_pixels)
{
// nothing to do here for the moment
// we *could* modify pixels here to, for example, Y flip, but this is done with
// a VLC video filter transform.
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginLibVLC::display(void* data, void* id)
{
struct mLibVLCContext* context = (mLibVLCContext*)data;
context->parent->setDirty(0, 0, context->parent->mWidth, context->parent->mHeight);
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginLibVLC::initVLC()
{
char const* vlc_argv[] =
{
"--no-xlib",
"--video-filter=transform{type=vflip}", // MAINT-6578 Y flip textures in plugin vs client
};
int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv);
mLibVLC = libvlc_new(vlc_argc, vlc_argv);
if (!mLibVLC)
{
// for the moment, if this fails, the plugin will fail and
// the media sub-system will tell the viewer something went wrong.
}
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginLibVLC::resetVLC()
{
libvlc_media_player_stop(mLibVLCMediaPlayer);
libvlc_media_player_release(mLibVLCMediaPlayer);
libvlc_release(mLibVLC);
}
////////////////////////////////////////////////////////////////////////////////
// *virtual*
void MediaPluginLibVLC::setDirty(int left, int top, int right, int bottom)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated");
message.setValueS32("left", left);
message.setValueS32("top", top);
message.setValueS32("right", right);
message.setValueS32("bottom", bottom);
message.setValueReal("current_time", mCurTime);
message.setValueReal("duration", mDuration);
message.setValueReal("current_rate", 1.0f);
sendMessage(message);
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginLibVLC::eventCallbacks(const libvlc_event_t* event, void* ptr)
{
MediaPluginLibVLC* parent = (MediaPluginLibVLC*)ptr;
if (parent == 0)
{
return;
}
switch (event->type)
{
case libvlc_MediaPlayerOpening:
parent->setStatus(STATUS_LOADING);
break;
case libvlc_MediaPlayerPlaying:
parent->mDuration = (float)(libvlc_media_get_duration(parent->mLibVLCMedia)) / 1000.0f;
parent->setStatus(STATUS_PLAYING);
break;
case libvlc_MediaPlayerPaused:
parent->setStatus(STATUS_PAUSED);
break;
case libvlc_MediaPlayerStopped:
parent->setStatus(STATUS_DONE);
break;
case libvlc_MediaPlayerEndReached:
parent->setStatus(STATUS_DONE);
break;
case libvlc_MediaPlayerEncounteredError:
parent->setStatus(STATUS_ERROR);
break;
case libvlc_MediaPlayerTimeChanged:
parent->mCurTime = (float)libvlc_media_player_get_time(parent->mLibVLCMediaPlayer) / 1000.0f;
break;
case libvlc_MediaPlayerPositionChanged:
break;
case libvlc_MediaPlayerLengthChanged:
parent->mDuration = (float)libvlc_media_get_duration(parent->mLibVLCMedia) / 1000.0f;
break;
case libvlc_MediaPlayerTitleChanged:
{
char* title = libvlc_media_get_meta(parent->mLibVLCMedia, libvlc_meta_Title);
if (title)
{
parent->updateTitle(title);
}
}
break;
}
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginLibVLC::playMedia()
{
if (mURL.length() == 0)
{
return;
}
if (mLibVLCMediaPlayer)
{
// stop listening to events while we reset things
libvlc_event_manager_t* em = libvlc_media_player_event_manager(mLibVLCMediaPlayer);
if (em)
{
libvlc_event_detach(em, libvlc_MediaPlayerOpening, eventCallbacks, NULL);
libvlc_event_detach(em, libvlc_MediaPlayerPlaying, eventCallbacks, NULL);
libvlc_event_detach(em, libvlc_MediaPlayerPaused, eventCallbacks, NULL);
libvlc_event_detach(em, libvlc_MediaPlayerStopped, eventCallbacks, NULL);
libvlc_event_detach(em, libvlc_MediaPlayerEndReached, eventCallbacks, NULL);
libvlc_event_detach(em, libvlc_MediaPlayerEncounteredError, eventCallbacks, NULL);
libvlc_event_detach(em, libvlc_MediaPlayerTimeChanged, eventCallbacks, NULL);
libvlc_event_detach(em, libvlc_MediaPlayerPositionChanged, eventCallbacks, NULL);
libvlc_event_detach(em, libvlc_MediaPlayerLengthChanged, eventCallbacks, NULL);
libvlc_event_detach(em, libvlc_MediaPlayerTitleChanged, eventCallbacks, NULL);
};
libvlc_media_player_stop(mLibVLCMediaPlayer);
libvlc_media_player_release(mLibVLCMediaPlayer);
mLibVLCMediaPlayer = 0;
}
if (mLibVLCMedia)
{
libvlc_media_release(mLibVLCMedia);
mLibVLCMedia = 0;
}
mLibVLCMedia = libvlc_media_new_location(mLibVLC, mURL.c_str());
if (!mLibVLCMedia)
{
mLibVLCMediaPlayer = 0;
setStatus(STATUS_ERROR);
return;
}
mLibVLCMediaPlayer = libvlc_media_player_new_from_media(mLibVLCMedia);
if (!mLibVLCMediaPlayer)
{
setStatus(STATUS_ERROR);
return;
}
// listen to events
libvlc_event_manager_t* em = libvlc_media_player_event_manager(mLibVLCMediaPlayer);
if (em)
{
libvlc_event_attach(em, libvlc_MediaPlayerOpening, eventCallbacks, this);
libvlc_event_attach(em, libvlc_MediaPlayerPlaying, eventCallbacks, this);
libvlc_event_attach(em, libvlc_MediaPlayerPaused, eventCallbacks, this);
libvlc_event_attach(em, libvlc_MediaPlayerStopped, eventCallbacks, this);
libvlc_event_attach(em, libvlc_MediaPlayerEndReached, eventCallbacks, this);
libvlc_event_attach(em, libvlc_MediaPlayerEncounteredError, eventCallbacks, this);
libvlc_event_attach(em, libvlc_MediaPlayerTimeChanged, eventCallbacks, this);
libvlc_event_attach(em, libvlc_MediaPlayerPositionChanged, eventCallbacks, this);
libvlc_event_attach(em, libvlc_MediaPlayerLengthChanged, eventCallbacks, this);
libvlc_event_attach(em, libvlc_MediaPlayerTitleChanged, eventCallbacks, this);
}
mLibVLCCallbackContext.parent = this;
mLibVLCCallbackContext.texture_pixels = mPixels;
mLibVLCCallbackContext.mp = mLibVLCMediaPlayer;
// Send a "navigate begin" event.
// This is really a browser message but the QuickTime plugin did it and
// the media system relies on this message to update internal state so we must send it too
// Note: see "navigate_complete" message below too
// https://jira.secondlife.com/browse/MAINT-6528
LLPluginMessage message_begin(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
message_begin.setValue("uri", mURL);
message_begin.setValueBoolean("history_back_available", false);
message_begin.setValueBoolean("history_forward_available", false);
sendMessage(message_begin);
// volume level gets set before VLC is initialized (thanks media system) so we have to record
// it in mCurVolume and set it again here so that volume levels are correctly initialized
setVolume(mCurVolume);
setStatus(STATUS_LOADED);
libvlc_video_set_callbacks(mLibVLCMediaPlayer, lock, unlock, display, &mLibVLCCallbackContext);
libvlc_video_set_format(mLibVLCMediaPlayer, "RV32", mWidth, mHeight, mWidth * mDepth);
// note this relies on the "set_loop" message arriving before the "start" (play) one
// but that appears to always be the case
if (mIsLooping)
{
libvlc_media_add_option(mLibVLCMedia, "input-repeat=-1");
}
libvlc_media_player_play(mLibVLCMediaPlayer);
// send a "location_changed" message - this informs the media system
// that a new URL is the 'current' one and is used extensively.
// Again, this is really a browser message but we will use it here.
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed");
message.setValue("uri", mURL);
sendMessage(message);
// Send a "navigate complete" event.
// This is really a browser message but the QuickTime plugin did it and
// the media system relies on this message to update internal state so we must send it too
// Note: see "navigate_begin" message above too
// https://jira.secondlife.com/browse/MAINT-6528
LLPluginMessage message_complete(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete");
message_complete.setValue("uri", mURL);
message_complete.setValueS32("result_code", 200);
message_complete.setValue("result_string", "OK");
sendMessage(message_complete);
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginLibVLC::updateTitle(const char* title)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
message.setValue("name", title);
sendMessage(message);
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginLibVLC::setVolume(const F64 volume)
{
mCurVolume = volume;
if (mLibVLCMediaPlayer)
{
int result = libvlc_audio_set_volume(mLibVLCMediaPlayer, (int)(volume * 100));
if (result != 0)
{
// volume wasn't set but not much to be done here
}
}
else
{
// volume change was requested but VLC wasn't ready.
// that's okay thought because we saved the value in mCurVolume and
// the next volume change after the VLC system is initilzied will set it
}
}
////////////////////////////////////////////////////////////////////////////////
//
void MediaPluginLibVLC::receiveMessage(const char* message_string)
{
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")
{
initVLC();
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_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION;
message.setValueLLSD("versions", versions);
std::ostringstream s;
s << "LibVLC plugin ";
s << LIBVLC_VERSION_MAJOR;
s << ".";
s << LIBVLC_VERSION_MINOR;
s << ".";
s << LIBVLC_VERSION_REVISION;
message.setValue("plugin_version", s.str());
sendMessage(message);
}
else if (message_name == "idle")
{
}
else if (message_name == "cleanup")
{
resetVLC();
}
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");
mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
}
else if (message_name == "shm_remove")
{
std::string name = message_in.getValue("name");
SharedSegmentMap::iterator iter = mSharedSegments.find(name);
if (iter != mSharedSegments.end())
{
if (mPixels == iter->second.mAddress)
{
libvlc_media_player_stop(mLibVLCMediaPlayer);
libvlc_media_player_release(mLibVLCMediaPlayer);
mLibVLCMediaPlayer = 0;
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)
{
if (message_name == "init")
{
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_RGB);
message.setValueU32("format", GL_BGRA_EXT);
message.setValueU32("type", GL_UNSIGNED_BYTE);
message.setValueBoolean("coords_opengl", true);
sendMessage(message);
}
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");
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;
mTextureWidth = texture_width;
mTextureHeight = texture_height;
playMedia();
};
};
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")
{
mURL = message_in.getValue("uri");
playMedia();
}
}
else
if (message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
{
if (message_name == "stop")
{
if (mLibVLCMediaPlayer)
{
libvlc_media_player_stop(mLibVLCMediaPlayer);
}
}
else if (message_name == "start")
{
if (mLibVLCMediaPlayer)
{
libvlc_media_player_play(mLibVLCMediaPlayer);
}
}
else if (message_name == "pause")
{
if (mLibVLCMediaPlayer)
{
libvlc_media_player_pause(mLibVLCMediaPlayer);
}
}
else if (message_name == "seek")
{
if (mDuration > 0)
{
F64 normalized_offset = message_in.getValueReal("time") / mDuration;
libvlc_media_player_set_position(mLibVLCMediaPlayer, normalized_offset);
}
}
else if (message_name == "set_loop")
{
mIsLooping = true;
}
else if (message_name == "set_volume")
{
// volume comes in 0 -> 1.0
F64 volume = message_in.getValueReal("volume");
setVolume(volume);
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
//
bool MediaPluginLibVLC::init()
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
message.setValue("name", "LibVLC Plugin");
sendMessage(message);
return true;
};
////////////////////////////////////////////////////////////////////////////////
//
int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func,
void* host_user_data,
LLPluginInstance::sendMessageFunction *plugin_send_func,
void **plugin_user_data)
{
MediaPluginLibVLC* self = new MediaPluginLibVLC(host_send_func, host_user_data);
*plugin_send_func = MediaPluginLibVLC::staticReceiveMessage;
*plugin_user_data = (void*)self;
return 0;
}

10
indra/media_plugins/quicktime/CMakeLists.txt Normal file → Executable file
View File

@ -14,7 +14,6 @@ include(PluginAPI)
include(MediaPluginBase)
include(OpenGL)
include(QuickTimePlugin)
include(Boost)
include_directories(
${LLPLUGIN_INCLUDE_DIRS}
@ -54,12 +53,17 @@ target_link_libraries(media_plugin_quicktime
${PLUGIN_API_WINDOWS_LIBRARIES}
)
add_dependencies(media_plugin_quicktime
${LLPLUGIN_LIBRARIES}
${MEDIA_PLUGIN_BASE_LIBRARIES}
${LLCOMMON_LIBRARIES}
)
if (WINDOWS)
set_target_properties(
media_plugin_quicktime
PROPERTIES
LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /NODEFAULTLIB:LIBCMT"
LINK_FLAGS_DEBUG "/MANIFEST:NO /SAFESEH:NO /NODEFAULTLIB:LIBCMTD"
LINK_FLAGS "/MANIFEST:NO"
)
endif (WINDOWS)

View File

@ -837,9 +837,7 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string)
else if(message_name == "cleanup")
{
// TODO: clean up here
LLPluginMessage message("base", "goodbye");
sendMessage(message);
}
}
else if(message_name == "shm_added")
{
SharedSegmentInfo info;
@ -921,6 +919,9 @@ void MediaPluginQuickTime::receiveMessage(const char *message_string)
#endif
message.setValueS32("depth", mDepth);
message.setValueU32("internalformat", GL_RGB);
// note this apparently only has an effect when media is opened in 2D browser.
// see https://jira.secondlife.com/browse/BUG-18252 - media flipped in 2D so flipping it back.
message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left.
message.setValueBoolean("allow_downsample", true);
sendMessage(message);

View File

@ -264,6 +264,7 @@ set(viewer_SOURCE_FILES
llfloaternamedesc.cpp
llfloaternotificationsconsole.cpp
llfloaternotificationstabbed.cpp
llfloateroutfitsnapshot.cpp
llfloaterobjectweights.cpp
llfloateropenobject.cpp
llfloaterpathfindingcharacters.cpp
@ -404,6 +405,7 @@ set(viewer_SOURCE_FILES
llnotificationscripthandler.cpp
llnotificationstorage.cpp
llnotificationtiphandler.cpp
lloutfitgallery.cpp
lloutfitslist.cpp
lloutfitobserver.cpp
lloutputmonitorctrl.cpp
@ -880,6 +882,7 @@ set(viewer_HEADER_FILES
llfloaternamedesc.h
llfloaternotificationsconsole.h
llfloaternotificationstabbed.h
llfloateroutfitsnapshot.h
llfloaterobjectweights.h
llfloateropenobject.h
llfloaterpathfindingcharacters.h
@ -1010,6 +1013,7 @@ set(viewer_HEADER_FILES
llnotificationlistview.h
llnotificationmanager.h
llnotificationstorage.h
lloutfitgallery.h
lloutfitslist.h
lloutfitobserver.h
lloutputmonitorctrl.h
@ -1141,6 +1145,7 @@ set(viewer_HEADER_FILES
llsky.h
llslurl.h
llsnapshotlivepreview.h
llsnapshotmodel.h
llspatialpartition.h
llspeakers.h
llspeakingindicatormanager.h
@ -1316,13 +1321,10 @@ set(viewer_HEADER_FILES
source_group("CMake Rules" FILES ViewerInstall.cmake)
#summary.json creation moved to viewer_manifest.py MAINT-6413
# the viewer_version.txt file created here is for passing to viewer_manifest and autobuild
# the summary.json file is created for the benefit of the TeamCity builds, where
# it is used to provide descriptive information to the build results page
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt"
"${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}\n")
file(WRITE "${CMAKE_BINARY_DIR}/summary.json"
"{\"Type\":\"viewer\",\"Version\":\"${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}\"}\n")
set_source_files_properties(
llversioninfo.cpp tests/llversioninfo_test.cpp
@ -1755,6 +1757,7 @@ if (WINDOWS)
SLPlugin
media_plugin_quicktime
media_plugin_cef
media_plugin_libvlc
winmm_shim
windows-crash-logger
)
@ -1970,6 +1973,7 @@ if (LINUX)
linux-crash-logger
SLPlugin
media_plugin_gstreamer010
media_plugin_libvlc
llcommon
)
@ -2077,7 +2081,7 @@ if (DARWIN)
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
)
add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_cef mac-crash-logger)
add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_libvlc media_plugin_cef mac-crash-logger)
add_dependencies(${VIEWER_BINARY_NAME} mac-crash-logger)
if (ENABLE_SIGNING)

Some files were not shown because too many files have changed in this diff Show More