summaryrefslogtreecommitdiff
path: root/indra/llimage
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llimage')
-rw-r--r--indra/llimage/CMakeLists.txt67
-rw-r--r--indra/llimage/llimage.cpp453
-rw-r--r--indra/llimage/llimage.h123
-rw-r--r--indra/llimage/llimagebmp.cpp48
-rw-r--r--indra/llimage/llimagebmp.h40
-rw-r--r--indra/llimage/llimagedimensionsinfo.cpp133
-rw-r--r--indra/llimage/llimagedimensionsinfo.h133
-rw-r--r--indra/llimage/llimagedxt.cpp58
-rw-r--r--indra/llimage/llimagedxt.h45
-rw-r--r--indra/llimage/llimagej2c.cpp249
-rw-r--r--indra/llimage/llimagej2c.h53
-rw-r--r--indra/llimage/llimagejpeg.cpp80
-rw-r--r--indra/llimage/llimagejpeg.h48
-rw-r--r--indra/llimage/llimagepng.cpp55
-rw-r--r--indra/llimage/llimagepng.h45
-rw-r--r--indra/llimage/llimagetga.cpp76
-rw-r--r--indra/llimage/llimagetga.h40
-rw-r--r--indra/llimage/llimageworker.cpp242
-rw-r--r--indra/llimage/llimageworker.h129
-rw-r--r--indra/llimage/llmapimagetype.h35
-rw-r--r--indra/llimage/llpngwrapper.cpp50
-rw-r--r--indra/llimage/llpngwrapper.h43
-rw-r--r--indra/llimage/tests/llimageworker_test.cpp254
23 files changed, 1667 insertions, 832 deletions
diff --git a/indra/llimage/CMakeLists.txt b/indra/llimage/CMakeLists.txt
new file mode 100644
index 0000000000..a69621a57b
--- /dev/null
+++ b/indra/llimage/CMakeLists.txt
@@ -0,0 +1,67 @@
+# -*- cmake -*-
+
+project(llimage)
+
+include(00-Common)
+include(LLAddBuildTest)
+include(LLCommon)
+include(LLImage)
+include(LLMath)
+include(LLVFS)
+include(ZLIB)
+
+include_directories(
+ ${LLCOMMON_INCLUDE_DIRS}
+ ${LLMATH_INCLUDE_DIRS}
+ ${LLVFS_INCLUDE_DIRS}
+ ${PNG_INCLUDE_DIRS}
+ ${ZLIB_INCLUDE_DIRS}
+ )
+
+set(llimage_SOURCE_FILES
+ llimagebmp.cpp
+ llimage.cpp
+ llimagedimensionsinfo.cpp
+ llimagedxt.cpp
+ llimagej2c.cpp
+ llimagejpeg.cpp
+ llimagepng.cpp
+ llimagetga.cpp
+ llimageworker.cpp
+ llpngwrapper.cpp
+ )
+
+set(llimage_HEADER_FILES
+ CMakeLists.txt
+
+ llimage.h
+ llimagebmp.h
+ llimagedimensionsinfo.h
+ llimagedxt.h
+ llimagej2c.h
+ llimagejpeg.h
+ llimagepng.h
+ llimagetga.h
+ llimageworker.h
+ llmapimagetype.h
+ llpngwrapper.h
+ )
+
+set_source_files_properties(${llimage_HEADER_FILES}
+ PROPERTIES HEADER_FILE_ONLY TRUE)
+
+list(APPEND llimage_SOURCE_FILES ${llimage_HEADER_FILES})
+
+add_library (llimage ${llimage_SOURCE_FILES})
+# Libraries on which this library depends, needed for Linux builds
+# Sort by high-level to low-level
+target_link_libraries(llimage
+ llcommon
+ llimagej2coj # *HACK: In theory a noop for KDU builds?
+ ${JPEG_LIBRARIES}
+ ${PNG_LIBRARIES}
+ ${ZLIB_LIBRARIES}
+ )
+
+# Add tests
+#ADD_BUILD_TEST(llimageworker llimage)
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index db19bd6ec6..5c33b675ca 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -2,30 +2,25 @@
* @file llimage.cpp
* @brief Base class for images.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -40,10 +35,47 @@
#include "llimagebmp.h"
#include "llimagetga.h"
#include "llimagej2c.h"
-#if JPEG_SUPPORT
#include "llimagejpeg.h"
-#endif
+#include "llimagepng.h"
#include "llimagedxt.h"
+#include "llimageworker.h"
+
+//---------------------------------------------------------------------------
+// LLImage
+//---------------------------------------------------------------------------
+
+//static
+std::string LLImage::sLastErrorMessage;
+LLMutex* LLImage::sMutex = NULL;
+
+//static
+void LLImage::initClass()
+{
+ sMutex = new LLMutex(NULL);
+ LLImageJ2C::openDSO();
+}
+
+//static
+void LLImage::cleanupClass()
+{
+ LLImageJ2C::closeDSO();
+ delete sMutex;
+ sMutex = NULL;
+}
+
+//static
+const std::string& LLImage::getLastError()
+{
+ static const std::string noerr("No Error");
+ return sLastErrorMessage.empty() ? noerr : sLastErrorMessage;
+}
+
+//static
+void LLImage::setLastError(const std::string& message)
+{
+ LLMutexLock m(sMutex);
+ sLastErrorMessage = message;
+}
//---------------------------------------------------------------------------
// LLImageBase
@@ -55,6 +87,8 @@ LLImageBase::LLImageBase()
mWidth(0),
mHeight(0),
mComponents(0),
+ mBadBufferAllocation(false),
+ mAllowOverSize(false),
mMemType(LLMemType::MTYPE_IMAGEBASE)
{
}
@@ -95,21 +129,6 @@ void LLImageBase::sanityCheck()
}
}
-LLString LLImageBase::sLastErrorMessage;
-BOOL LLImageBase::sSizeOverride = FALSE;
-
-BOOL LLImageBase::setLastError(const LLString& message, const LLString& filename)
-{
- sLastErrorMessage = message;
- if (filename != "")
- {
- sLastErrorMessage += LLString(" FILE:");
- sLastErrorMessage += filename;
- }
- llwarns << sLastErrorMessage << llendl;
- return FALSE;
-}
-
// virtual
void LLImageBase::deleteData()
{
@@ -121,30 +140,42 @@ void LLImageBase::deleteData()
// virtual
U8* LLImageBase::allocateData(S32 size)
{
- LLMemType mt1((LLMemType::EMemType)mMemType);
+ LLMemType mt1(mMemType);
if (size < 0)
{
size = mWidth * mHeight * mComponents;
if (size <= 0)
{
- llerrs << llformat("LLImageBase::allocateData called with bad dimentions: %dx%dx%d",mWidth,mHeight,mComponents) << llendl;
+ llerrs << llformat("LLImageBase::allocateData called with bad dimensions: %dx%dx%d",mWidth,mHeight,(S32)mComponents) << llendl;
}
}
- else if (size <= 0 || (size > 4096*4096*16 && sSizeOverride == FALSE))
+
+ //make this function thread-safe.
+ static const U32 MAX_BUFFER_SIZE = 4096 * 4096 * 16 ; //256 MB
+ if (size < 1 || size > MAX_BUFFER_SIZE)
{
- llerrs << "LLImageBase::allocateData: bad size: " << size << llendl;
+ llinfos << "width: " << mWidth << " height: " << mHeight << " components: " << mComponents << llendl ;
+ if(mAllowOverSize)
+ {
+ llinfos << "Oversize: " << size << llendl ;
+ }
+ else
+ {
+ llerrs << "LLImageBase::allocateData: bad size: " << size << llendl;
+ }
}
-
- resetLastError();
-
if (!mData || size != mDataSize)
{
deleteData(); // virtual
+ mBadBufferAllocation = false ;
mData = new U8[size];
if (!mData)
{
- llerrs << "allocate image data: " << size << llendl;
+ llwarns << "allocate image data: " << size << llendl;
+ size = 0 ;
+ mWidth = mHeight = 0 ;
+ mBadBufferAllocation = true ;
}
mDataSize = size;
}
@@ -155,7 +186,7 @@ U8* LLImageBase::allocateData(S32 size)
// virtual
U8* LLImageBase::reallocateData(S32 size)
{
- LLMemType mt1((LLMemType::EMemType)mMemType);
+ LLMemType mt1(mMemType);
U8 *new_datap = new U8[size];
if (!new_datap)
{
@@ -173,6 +204,30 @@ U8* LLImageBase::reallocateData(S32 size)
return mData;
}
+const U8* LLImageBase::getData() const
+{
+ if(mBadBufferAllocation)
+ {
+ llerrs << "Bad memory allocation for the image buffer!" << llendl ;
+ }
+
+ return mData;
+} // read only
+
+U8* LLImageBase::getData()
+{
+ if(mBadBufferAllocation)
+ {
+ llerrs << "Bad memory allocation for the image buffer!" << llendl ;
+ }
+
+ return mData;
+}
+
+bool LLImageBase::isBufferInvalid()
+{
+ return mBadBufferAllocation || mData == NULL ;
+}
void LLImageBase::setSize(S32 width, S32 height, S32 ncomponents)
{
@@ -205,7 +260,7 @@ LLImageRaw::LLImageRaw(U16 width, U16 height, S8 components)
: LLImageBase()
{
mMemType = LLMemType::MTYPE_IMAGERAW;
- llassert( S32(width) * S32(height) * S32(components) <= MAX_IMAGE_DATA_SIZE );
+ //llassert( S32(width) * S32(height) * S32(components) <= MAX_IMAGE_DATA_SIZE );
allocateDataSize(width, height, components);
++sRawImageCount;
}
@@ -214,12 +269,14 @@ LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components)
: LLImageBase()
{
mMemType = LLMemType::MTYPE_IMAGERAW;
- allocateDataSize(width, height, components);
- memcpy(getData(), data, width*height*components);
+ if(allocateDataSize(width, height, components))
+ {
+ memcpy(getData(), data, width*height*components);
+ }
++sRawImageCount;
}
-LLImageRaw::LLImageRaw(const LLString &filename, bool j2c_lowest_mip_only)
+LLImageRaw::LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only)
: LLImageBase()
{
createFromFile(filename, j2c_lowest_mip_only);
@@ -257,6 +314,21 @@ void LLImageRaw::deleteData()
LLImageBase::deleteData();
}
+void LLImageRaw::setDataAndSize(U8 *data, S32 width, S32 height, S8 components)
+{
+ if(data == getData())
+ {
+ return ;
+ }
+
+ deleteData();
+
+ LLImageBase::setSize(width, height, components) ;
+ LLImageBase::setDataAndSize(data, width * height * components) ;
+
+ sGlobalRawMemory += getDataSize();
+}
+
BOOL LLImageRaw::resize(U16 width, U16 height, S8 components)
{
if ((getWidth() == width) && (getHeight() == height) && (getComponents() == components))
@@ -273,7 +345,7 @@ BOOL LLImageRaw::resize(U16 width, U16 height, S8 components)
U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const
{
- LLMemType mt1((LLMemType::EMemType)mMemType);
+ LLMemType mt1(mMemType);
U8 *data = new U8[width*height*getComponents()];
// Should do some simple bounds checking
@@ -356,24 +428,19 @@ void LLImageRaw::clear(U8 r, U8 g, U8 b, U8 a)
// Reverses the order of the rows in the image
void LLImageRaw::verticalFlip()
{
- LLMemType mt1((LLMemType::EMemType)mMemType);
+ LLMemType mt1(mMemType);
S32 row_bytes = getWidth() * getComponents();
- U8* line_buffer = new U8[row_bytes];
- if (!line_buffer )
- {
- llerrs << "Out of memory in LLImageRaw::verticalFlip()" << llendl;
- return;
- }
+ llassert(row_bytes > 0);
+ std::vector<U8> line_buffer(row_bytes);
S32 mid_row = getHeight() / 2;
for( S32 row = 0; row < mid_row; row++ )
{
U8* row_a_data = getData() + row * row_bytes;
U8* row_b_data = getData() + (getHeight() - 1 - row) * row_bytes;
- memcpy( line_buffer, row_a_data, row_bytes ); /* Flawfinder: ignore */
- memcpy( row_a_data, row_b_data, row_bytes ); /* Flawfinder: ignore */
- memcpy( row_b_data, line_buffer, row_bytes ); /* Flawfinder: ignore */
+ memcpy( &line_buffer[0], row_a_data, row_bytes );
+ memcpy( row_a_data, row_b_data, row_bytes );
+ memcpy( row_b_data, &line_buffer[0], row_bytes );
}
- delete[] line_buffer;
}
@@ -460,8 +527,8 @@ void LLImageRaw::composite( LLImageRaw* src )
{
LLImageRaw* dst = this; // Just for clarity.
- llassert( (3 == src->getComponents()) || (4 == src->getComponents()) );
- llassert( (3 == dst->getComponents()) || (4 == dst->getComponents()) );
+ llassert(3 == src->getComponents());
+ llassert(3 == dst->getComponents());
if( 3 == dst->getComponents() )
{
@@ -489,39 +556,33 @@ void LLImageRaw::composite( LLImageRaw* src )
}
}
}
- else
- {
- // 4 == dst->mComponents
- llassert(0); // not implemented yet.
- }
}
// Src and dst can be any size. Src has 4 components. Dst has 3 components.
void LLImageRaw::compositeScaled4onto3(LLImageRaw* src)
{
- LLMemType mt1((LLMemType::EMemType)mMemType);
+ LLMemType mt1(mMemType);
llinfos << "compositeScaled4onto3" << llendl;
LLImageRaw* dst = this; // Just for clarity.
llassert( (4 == src->getComponents()) && (3 == dst->getComponents()) );
- // Vertical: scale but no composite
S32 temp_data_size = src->getWidth() * dst->getHeight() * src->getComponents();
- U8* temp_buffer = new U8[ temp_data_size ];
+ llassert_always(temp_data_size > 0);
+ std::vector<U8> temp_buffer(temp_data_size);
+
+ // Vertical: scale but no composite
for( S32 col = 0; col < src->getWidth(); col++ )
{
- copyLineScaled( src->getData() + (src->getComponents() * col), temp_buffer + (src->getComponents() * col), src->getHeight(), dst->getHeight(), src->getWidth(), src->getWidth() );
+ copyLineScaled( src->getData() + (src->getComponents() * col), &temp_buffer[0] + (src->getComponents() * col), src->getHeight(), dst->getHeight(), src->getWidth(), src->getWidth() );
}
// Horizontal: scale and composite
for( S32 row = 0; row < dst->getHeight(); row++ )
{
- compositeRowScaled4onto3( temp_buffer + (src->getComponents() * src->getWidth() * row), dst->getData() + (dst->getComponents() * dst->getWidth() * row), src->getWidth(), dst->getWidth() );
+ compositeRowScaled4onto3( &temp_buffer[0] + (src->getComponents() * src->getWidth() * row), dst->getData() + (dst->getComponents() * dst->getWidth() * row), src->getWidth(), dst->getWidth() );
}
-
- // Clean up
- delete[] temp_buffer;
}
@@ -610,10 +671,13 @@ void LLImageRaw::fill( const LLColor4U& color )
// Src and dst can be any size. Src and dst can each have 3 or 4 components.
void LLImageRaw::copy(LLImageRaw* src)
{
- LLImageRaw* dst = this; // Just for clarity.
+ if (!src)
+ {
+ llwarns << "LLImageRaw::copy called with a null src pointer" << llendl;
+ return;
+ }
- llassert( (3 == src->getComponents()) || (4 == src->getComponents()) );
- llassert( (3 == dst->getComponents()) || (4 == dst->getComponents()) );
+ LLImageRaw* dst = this; // Just for clarity.
if( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) )
{
@@ -659,7 +723,7 @@ void LLImageRaw::copyUnscaled(LLImageRaw* src)
{
LLImageRaw* dst = this; // Just for clarity.
- llassert( (3 == src->getComponents()) || (4 == src->getComponents()) );
+ llassert( (1 == src->getComponents()) || (3 == src->getComponents()) || (4 == src->getComponents()) );
llassert( src->getComponents() == dst->getComponents() );
llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) );
@@ -739,11 +803,11 @@ void LLImageRaw::copyUnscaled3onto4( LLImageRaw* src )
// Src and dst can be any size. Src and dst have same number of components.
void LLImageRaw::copyScaled( LLImageRaw* src )
{
- LLMemType mt1((LLMemType::EMemType)mMemType);
+ LLMemType mt1(mMemType);
LLImageRaw* dst = this; // Just for clarity.
- llassert( (3 == src->getComponents()) || (4 == src->getComponents()) );
- llassert( src->getComponents() == dst->getComponents() );
+ llassert_always( (1 == src->getComponents()) || (3 == src->getComponents()) || (4 == src->getComponents()) );
+ llassert_always( src->getComponents() == dst->getComponents() );
if( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) )
{
@@ -751,48 +815,94 @@ void LLImageRaw::copyScaled( LLImageRaw* src )
return;
}
- // Vertical
S32 temp_data_size = src->getWidth() * dst->getHeight() * getComponents();
- U8* temp_buffer = new U8[ temp_data_size ];
+ llassert_always(temp_data_size > 0);
+ std::vector<U8> temp_buffer(temp_data_size);
+
+ // Vertical
for( S32 col = 0; col < src->getWidth(); col++ )
{
- copyLineScaled( src->getData() + (getComponents() * col), temp_buffer + (getComponents() * col), src->getHeight(), dst->getHeight(), src->getWidth(), src->getWidth() );
+ copyLineScaled( src->getData() + (getComponents() * col), &temp_buffer[0] + (getComponents() * col), src->getHeight(), dst->getHeight(), src->getWidth(), src->getWidth() );
}
// Horizontal
for( S32 row = 0; row < dst->getHeight(); row++ )
{
- copyLineScaled( temp_buffer + (getComponents() * src->getWidth() * row), dst->getData() + (getComponents() * dst->getWidth() * row), src->getWidth(), dst->getWidth(), 1, 1 );
+ copyLineScaled( &temp_buffer[0] + (getComponents() * src->getWidth() * row), dst->getData() + (getComponents() * dst->getWidth() * row), src->getWidth(), dst->getWidth(), 1, 1 );
}
-
- // Clean up
- delete[] temp_buffer;
}
+//scale down image by not blending a pixel with its neighbors.
+BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)
+{
+ LLMemType mt1(mMemType);
+
+ S8 c = getComponents() ;
+ llassert((1 == c) || (3 == c) || (4 == c) );
+
+ S32 old_width = getWidth();
+ S32 old_height = getHeight();
+
+ S32 new_data_size = old_width * new_height * c ;
+ llassert_always(new_data_size > 0);
+
+ F32 ratio_x = (F32)old_width / new_width ;
+ F32 ratio_y = (F32)old_height / new_height ;
+ if( ratio_x < 1.0f || ratio_y < 1.0f )
+ {
+ return TRUE; // Nothing to do.
+ }
+ ratio_x -= 1.0f ;
+ ratio_y -= 1.0f ;
+
+ U8* new_data = new U8[new_data_size] ;
+ llassert_always(new_data != NULL) ;
+
+ U8* old_data = getData() ;
+ S32 i, j, k, s, t;
+ for(i = 0, s = 0, t = 0 ; i < new_height ; i++)
+ {
+ for(j = 0 ; j < new_width ; j++)
+ {
+ for(k = 0 ; k < c ; k++)
+ {
+ new_data[s++] = old_data[t++] ;
+ }
+ t += (S32)(ratio_x * c + 0.1f) ;
+ }
+ t += (S32)(ratio_y * old_width * c + 0.1f) ;
+ }
+
+ setDataAndSize(new_data, new_width, new_height, c) ;
+
+ return TRUE ;
+}
-void 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 )
{
- LLMemType mt1((LLMemType::EMemType)mMemType);
- llassert( (3 == getComponents()) || (4 == getComponents()) );
+ LLMemType mt1(mMemType);
+ llassert((1 == getComponents()) || (3 == getComponents()) || (4 == getComponents()) );
S32 old_width = getWidth();
S32 old_height = getHeight();
if( (old_width == new_width) && (old_height == new_height) )
{
- return; // Nothing to do.
+ return TRUE; // Nothing to do.
}
// Reallocate the data buffer.
if (scale_image_data)
{
- // Vertical
S32 temp_data_size = old_width * new_height * getComponents();
- U8* temp_buffer = new U8[ temp_data_size ];
+ llassert_always(temp_data_size > 0);
+ std::vector<U8> temp_buffer(temp_data_size);
+
+ // Vertical
for( S32 col = 0; col < old_width; col++ )
{
- copyLineScaled( getData() + (getComponents() * col), temp_buffer + (getComponents() * col), old_height, new_height, old_width, old_width );
+ copyLineScaled( getData() + (getComponents() * col), &temp_buffer[0] + (getComponents() * col), old_height, new_height, old_width, old_width );
}
deleteData();
@@ -802,23 +912,15 @@ void LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )
// Horizontal
for( S32 row = 0; row < new_height; row++ )
{
- copyLineScaled( temp_buffer + (getComponents() * old_width * row), new_buffer + (getComponents() * new_width * row), old_width, new_width, 1, 1 );
+ copyLineScaled( &temp_buffer[0] + (getComponents() * old_width * row), new_buffer + (getComponents() * new_width * row), old_width, new_width, 1, 1 );
}
-
- // Clean up
- delete[] temp_buffer;
}
else
{
// copy out existing image data
S32 temp_data_size = old_width * old_height * getComponents();
- U8* temp_buffer = new U8[ temp_data_size ];
- if (!temp_buffer)
- {
- llerrs << "Out of memory in LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )" << llendl;
- return;
- }
- memcpy(temp_buffer, getData(), temp_data_size); /* Flawfinder: ignore */
+ 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());
@@ -827,7 +929,7 @@ void LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )
{
if (row < old_height)
{
- memcpy(new_buffer + (new_width * row * getComponents()), temp_buffer + (old_width * row * getComponents()), getComponents() * llmin(old_width, new_width)); /* Flawfinder: ignore */
+ 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
@@ -840,10 +942,9 @@ void LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )
memset(new_buffer + (new_width * row * getComponents()), 0, new_width * getComponents());
}
}
-
- // Clean up
- delete[] temp_buffer;
}
+
+ 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 )
@@ -1063,7 +1164,7 @@ void LLImageRaw::compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S3
static struct
{
const char* exten;
- S8 codec;
+ EImageCodec codec;
}
file_extensions[] =
{
@@ -1078,27 +1179,27 @@ file_extensions[] =
{ "dxt", IMG_CODEC_DXT },
{ "png", IMG_CODEC_PNG }
};
-#define NUM_FILE_EXTENSIONS sizeof(file_extensions)/sizeof(file_extensions[0])
+#define NUM_FILE_EXTENSIONS LL_ARRAY_SIZE(file_extensions)
-static LLString find_file(LLString &name, S8 *codec)
+static std::string find_file(std::string &name, S8 *codec)
{
- LLString tname;
+ std::string tname;
for (int i=0; i<(int)(NUM_FILE_EXTENSIONS); i++)
{
- tname = name + "." + LLString(file_extensions[i].exten);
- llifstream ifs(tname.c_str(), llifstream::binary);
+ tname = name + "." + std::string(file_extensions[i].exten);
+ llifstream ifs(tname, llifstream::binary);
if (ifs.is_open())
{
ifs.close();
if (codec)
*codec = file_extensions[i].codec;
- return LLString(file_extensions[i].exten);
+ return std::string(file_extensions[i].exten);
}
}
- return LLString("");
+ return std::string("");
}
-static S8 get_codec(const LLString& exten)
+EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten)
{
for (int i=0; i<(int)(NUM_FILE_EXTENSIONS); i++)
{
@@ -1108,20 +1209,20 @@ static S8 get_codec(const LLString& exten)
return IMG_CODEC_INVALID;
}
-bool LLImageRaw::createFromFile(const LLString &filename, bool j2c_lowest_mip_only)
+bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip_only)
{
- LLString name = filename;
+ std::string name = filename;
size_t dotidx = name.rfind('.');
S8 codec = IMG_CODEC_INVALID;
- LLString exten;
+ std::string exten;
deleteData(); // delete any existing data
- if (dotidx != LLString::npos)
+ if (dotidx != std::string::npos)
{
exten = name.substr(dotidx+1);
- LLString::toLower(exten);
- codec = get_codec(exten);
+ LLStringUtil::toLower(exten);
+ codec = getCodecFromExtension(exten);
}
else
{
@@ -1133,7 +1234,7 @@ bool LLImageRaw::createFromFile(const LLString &filename, bool j2c_lowest_mip_on
return false; // format not recognized
}
- llifstream ifs(name.c_str(), llifstream::binary);
+ llifstream ifs(name, llifstream::binary);
if (!ifs.is_open())
{
// SJB: changed from llinfos to lldebugs to reduce spam
@@ -1165,11 +1266,9 @@ bool LLImageRaw::createFromFile(const LLString &filename, bool j2c_lowest_mip_on
case IMG_CODEC_TGA:
image = new LLImageTGA();
break;
-#if JPEG_SUPPORT
case IMG_CODEC_JPEG:
image = new LLImageJPEG();
break;
-#endif
case IMG_CODEC_J2C:
image = new LLImageJ2C();
break;
@@ -1182,28 +1281,31 @@ bool LLImageRaw::createFromFile(const LLString &filename, bool j2c_lowest_mip_on
llassert(image.notNull());
U8 *buffer = image->allocateData(length);
- ifs.read ((char*)buffer, length); /* Flawfinder: ignore */
+ ifs.read ((char*)buffer, length);
ifs.close();
- image->updateData();
-
- if (j2c_lowest_mip_only && codec == IMG_CODEC_J2C)
+ BOOL success;
+
+ success = image->updateData();
+ if (success)
{
- S32 width = image->getWidth();
- S32 height = image->getHeight();
- S32 discard_level = 0;
- while (width > 1 && height > 1 && discard_level < MAX_DISCARD_LEVEL)
+ if (j2c_lowest_mip_only && codec == IMG_CODEC_J2C)
{
- width >>= 1;
- height >>= 1;
- discard_level++;
+ S32 width = image->getWidth();
+ S32 height = image->getHeight();
+ S32 discard_level = 0;
+ while (width > 1 && height > 1 && discard_level < MAX_DISCARD_LEVEL)
+ {
+ width >>= 1;
+ height >>= 1;
+ discard_level++;
+ }
+ ((LLImageJ2C *)((LLImageFormatted*)image))->setDiscardLevel(discard_level);
}
- ((LLImageJ2C *)((LLImageFormatted*)image))->setDiscardLevel(discard_level);
+ success = image->decode(this, 100000.0f);
}
-
- BOOL success = image->decode(this, 100000.0f);
- image = NULL; // deletes image
+ image = NULL; // deletes image
if (!success)
{
deleteData();
@@ -1226,7 +1328,7 @@ LLImageFormatted::LLImageFormatted(S8 codec)
mCodec(codec),
mDecoding(0),
mDecoded(0),
- mDiscardLevel(0)
+ mDiscardLevel(-1)
{
mMemType = LLMemType::MTYPE_IMAGEFORMATTED;
}
@@ -1241,6 +1343,23 @@ LLImageFormatted::~LLImageFormatted()
//----------------------------------------------------------------------------
+//virtual
+void LLImageFormatted::resetLastError()
+{
+ LLImage::setLastError("");
+}
+
+//virtual
+void LLImageFormatted::setLastError(const std::string& message, const std::string& filename)
+{
+ std::string error = message;
+ if (!filename.empty())
+ error += std::string(" FILE: ") + filename;
+ LLImage::setLastError(error);
+}
+
+//----------------------------------------------------------------------------
+
// static
LLImageFormatted* LLImageFormatted::createFromType(S8 codec)
{
@@ -1253,11 +1372,12 @@ LLImageFormatted* LLImageFormatted::createFromType(S8 codec)
case IMG_CODEC_TGA:
image = new LLImageTGA();
break;
-#if JPEG_SUPPORT
case IMG_CODEC_JPEG:
image = new LLImageJPEG();
break;
-#endif
+ case IMG_CODEC_PNG:
+ image = new LLImagePNG();
+ break;
case IMG_CODEC_J2C:
image = new LLImageJ2C();
break;
@@ -1272,11 +1392,11 @@ LLImageFormatted* LLImageFormatted::createFromType(S8 codec)
}
// static
-LLImageFormatted* LLImageFormatted::createFromExtension(const LLString& instring)
+LLImageFormatted* LLImageFormatted::createFromExtension(const std::string& instring)
{
- LLString exten;
+ std::string exten;
size_t dotidx = instring.rfind('.');
- if (dotidx != LLString::npos)
+ if (dotidx != std::string::npos)
{
exten = instring.substr(dotidx+1);
}
@@ -1284,7 +1404,7 @@ LLImageFormatted* LLImageFormatted::createFromExtension(const LLString& instring
{
exten = instring;
}
- S8 codec = get_codec(exten);
+ S8 codec = getCodecFromExtension(exten);
return createFromType(codec);
}
//----------------------------------------------------------------------------
@@ -1340,7 +1460,7 @@ S32 LLImageFormatted::calcDiscardLevelBytes(S32 bytes)
//----------------------------------------------------------------------------
// Subclasses that can handle more than 4 channels should override this function.
-BOOL LLImageFormatted::decode(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.
@@ -1427,18 +1547,21 @@ void LLImageFormatted::appendData(U8 *data, S32 size)
S32 newsize = cursize + size;
reallocateData(newsize);
memcpy(getData() + cursize, data, size);
+ delete[] data;
}
}
}
//----------------------------------------------------------------------------
-BOOL LLImageFormatted::load(const LLString &filename)
+BOOL LLImageFormatted::load(const std::string &filename)
{
resetLastError();
S32 file_size = 0;
- apr_file_t* apr_file = ll_apr_file_open(filename, LL_APR_RB, &file_size);
+ LLAPRFile infile ;
+ infile.open(filename, LL_APR_RB, NULL, &file_size);
+ apr_file_t* apr_file = infile.getFileHandle();
if (!apr_file)
{
setLastError("Unable to open file for reading", filename);
@@ -1447,7 +1570,6 @@ BOOL LLImageFormatted::load(const LLString &filename)
if (file_size == 0)
{
setLastError("File is empty",filename);
- apr_file_close(apr_file);
return FALSE;
}
@@ -1465,25 +1587,24 @@ BOOL LLImageFormatted::load(const LLString &filename)
{
res = updateData();
}
- apr_file_close(apr_file);
-
+
return res;
}
-BOOL LLImageFormatted::save(const LLString &filename)
+BOOL LLImageFormatted::save(const std::string &filename)
{
resetLastError();
- apr_file_t* apr_file = ll_apr_file_open(filename, LL_APR_WB);
- if (!apr_file)
+ LLAPRFile outfile ;
+ outfile.open(filename, LL_APR_WB);
+ if (!outfile.getFileHandle())
{
- setLastError("Unable to open file for reading", filename);
+ setLastError("Unable to open file for writing", filename);
return FALSE;
}
- ll_apr_file_write(apr_file, getData(), getDataSize());
- apr_file_close(apr_file);
-
+ outfile.write(getData(), getDataSize());
+ outfile.close() ;
return TRUE;
}
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h
index 65a7c54a50..bca7e915fa 100644
--- a/indra/llimage/llimage.h
+++ b/indra/llimage/llimage.h
@@ -2,30 +2,25 @@
* @file llimage.h
* @brief Object for managing images and their textures.
*
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -34,8 +29,9 @@
#include "lluuid.h"
#include "llstring.h"
-#include "llmemory.h"
+//#include "llmemory.h"
#include "llthread.h"
+#include "llmemtype.h"
const S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2
const S32 MAX_IMAGE_MIP = 11; // 2048x2048
@@ -46,9 +42,10 @@ const S32 MAX_IMAGE_SIZE = (1<<MAX_IMAGE_MIP); // 2048
const S32 MIN_IMAGE_AREA = MIN_IMAGE_SIZE * MIN_IMAGE_SIZE;
const S32 MAX_IMAGE_AREA = MAX_IMAGE_SIZE * MAX_IMAGE_SIZE;
const S32 MAX_IMAGE_COMPONENTS = 8;
-const S32 MAX_IMAGE_DATA_SIZE = MAX_IMAGE_AREA * MAX_IMAGE_COMPONENTS;
+const S32 MAX_IMAGE_DATA_SIZE = MAX_IMAGE_AREA * MAX_IMAGE_COMPONENTS; //2048 * 2048 * 8 = 16 MB
-// Note! These CANNOT be changed without invalidating the viewer VFS files, I think?
+// Note! These CANNOT be changed without modifying simulator code
+// *TODO: change both to 1024 when SIM texture fetching is deprecated
const S32 FIRST_PACKET_SIZE = 600;
const S32 MAX_IMG_PACKET_SIZE = 1000;
@@ -60,7 +57,7 @@ class LLImageFormatted;
class LLImageRaw;
class LLColor4U;
-enum
+typedef enum e_image_codec
{
IMG_CODEC_INVALID = 0,
IMG_CODEC_RGB = 1,
@@ -71,9 +68,27 @@ enum
IMG_CODEC_DXT = 6,
IMG_CODEC_PNG = 7,
IMG_CODEC_EOF = 8
+} EImageCodec;
+
+//============================================================================
+// library initialization class
+
+class LLImage
+{
+public:
+ static void initClass();
+ static void cleanupClass();
+
+ static const std::string& getLastError();
+ static void setLastError(const std::string& message);
+
+protected:
+ static LLMutex* sMutex;
+ static std::string sLastErrorMessage;
};
//============================================================================
+// Image base class
class LLImageBase : public LLThreadSafeRefCount
{
@@ -101,29 +116,28 @@ public:
S8 getComponents() const { return mComponents; }
S32 getDataSize() const { return mDataSize; }
- const U8 *getData() const { return mData; } // read only
- U8 *getData() { return mData; }
-
+ const U8 *getData() const ;
+ U8 *getData() ;
+ bool isBufferInvalid() ;
+
void setSize(S32 width, S32 height, S32 ncomponents);
U8* allocateDataSize(S32 width, S32 height, S32 ncomponents, S32 size = -1); // setSize() + allocateData()
+ void enableOverSize() {mAllowOverSize = true ;}
+ void disableOverSize() {mAllowOverSize = false; }
protected:
// special accessor to allow direct setting of mData and mDataSize by LLImageFormatted
- void setDataAndSize(U8 *data, S32 size) { mData = data; mDataSize = size; };
+ void setDataAndSize(U8 *data, S32 size) { mData = data; mDataSize = size; }
public:
- static const LLString& getLastError() {return sLastErrorMessage;};
- static void resetLastError() {sLastErrorMessage = LLString("No Error"); };
- static BOOL setLastError(const LLString& message, const LLString& filename = LLString()); // returns FALSE
-
static void generateMip(const U8 *indata, U8* mipdata, int width, int height, S32 nchannels);
// Function for calculating the download priority for textures
// <= 0 priority means that there's no need for more data.
static F32 calc_download_priority(F32 virtual_size, F32 visible_area, S32 bytes_sent);
- static void setSizeOverride(BOOL enabled) { sSizeOverride = enabled; }
-
+ static EImageCodec getCodecFromExtension(const std::string& exten);
+
private:
U8 *mData;
S32 mDataSize;
@@ -133,12 +147,10 @@ private:
S8 mComponents;
+ bool mBadBufferAllocation ;
+ bool mAllowOverSize ;
public:
- S16 mMemType; // debug
-
- static LLString sLastErrorMessage;
-
- static BOOL sSizeOverride;
+ LLMemType::DeclareMemType& mMemType; // debug
};
// Raw representation of an image (used for textures, and other uncompressed formats
@@ -152,7 +164,7 @@ public:
LLImageRaw(U16 width, U16 height, S8 components);
LLImageRaw(U8 *data, U16 width, U16 height, S8 components);
// Construct using createFromFile (used by tools)
- LLImageRaw(const LLString& filename, bool j2c_lowest_mip_only = false);
+ LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false);
/*virtual*/ void deleteData();
/*virtual*/ U8* allocateData(S32 size = -1);
@@ -171,7 +183,8 @@ public:
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);
- void scale( S32 new_width, S32 new_height, BOOL scale_image = TRUE );
+ BOOL scale( S32 new_width, S32 new_height, BOOL scale_image = TRUE );
+ BOOL scaleDownWithoutBlending( S32 new_width, S32 new_height) ;
// Fill the buffer with a constant color
void fill( const LLColor4U& color );
@@ -213,13 +226,15 @@ public:
protected:
// Create an image from a local file (generally used in tools)
- bool createFromFile(const LLString& filename, bool j2c_lowest_mip_only = false);
+ bool createFromFile(const std::string& filename, bool j2c_lowest_mip_only = false);
void copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step );
void compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len );
U8 fastFractionalMult(U8 a,U8 b);
+ void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ;
+
public:
static S32 sGlobalRawMemory;
static S32 sRawImageCount;
@@ -231,7 +246,7 @@ class LLImageFormatted : public LLImageBase
{
public:
static LLImageFormatted* createFromType(S8 codec);
- static LLImageFormatted* createFromExtension(const LLString& instring);
+ static LLImageFormatted* createFromExtension(const std::string& instring);
protected:
/*virtual*/ ~LLImageFormatted();
@@ -240,7 +255,6 @@ public:
LLImageFormatted(S8 codec);
// LLImageBase
-public:
/*virtual*/ void deleteData();
/*virtual*/ U8* allocateData(S32 size = -1);
/*virtual*/ U8* reallocateData(S32 size);
@@ -249,7 +263,8 @@ public:
/*virtual*/ void sanityCheck();
// New methods
-public:
+ // subclasses must return a prefered file extension (lowercase without a leading dot)
+ virtual std::string getExtension() = 0;
// calcHeaderSize() returns the maximum size of header;
// 0 indicates we don't know have a header and have to lead the entire file
virtual S32 calcHeaderSize() { return 0; };
@@ -260,19 +275,19 @@ public:
// getRawDiscardLevel()by default returns mDiscardLevel, but may be overridden (LLImageJ2C)
virtual S8 getRawDiscardLevel() { return mDiscardLevel; }
- BOOL load(const LLString& filename);
- BOOL save(const LLString& filename);
+ BOOL load(const std::string& filename);
+ BOOL save(const std::string& filename);
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.0) = 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 decode(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.0) = 0;
+ virtual BOOL encode(const LLImageRaw* raw_image, F32 encode_time) = 0;
S8 getCodec() const;
BOOL isDecoding() const { return mDecoding ? TRUE : FALSE; }
@@ -280,15 +295,19 @@ public:
void setDiscardLevel(S8 discard_level) { mDiscardLevel = discard_level; }
S8 getDiscardLevel() const { return mDiscardLevel; }
+ // setLastError needs to be deferred for J2C images since it may be called from a DLL
+ virtual void resetLastError();
+ virtual void setLastError(const std::string& message, const std::string& filename = std::string());
+
protected:
BOOL copyData(U8 *data, S32 size); // calls updateData()
protected:
S8 mCodec;
S8 mDecoding;
- S8 mDecoded;
+ S8 mDecoded; // unused, but changing LLImage layout requires recompiling static Mac/Linux libs. 2009-01-30 JC
S8 mDiscardLevel;
-
+
public:
static S32 sGlobalFormattedMemory;
};
diff --git a/indra/llimage/llimagebmp.cpp b/indra/llimage/llimagebmp.cpp
index f8423000a8..60b1c628d7 100644
--- a/indra/llimage/llimagebmp.cpp
+++ b/indra/llimage/llimagebmp.cpp
@@ -1,30 +1,25 @@
/**
* @file llimagebmp.cpp
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -552,7 +547,10 @@ BOOL LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time)
int file_bytes = line_bytes*getHeight() + header_bytes;
// Allocate the new buffer for the data.
- allocateData(file_bytes);
+ if(!allocateData(file_bytes)) //memory allocation failed
+ {
+ return FALSE ;
+ }
magic[0] = 'B'; magic[1] = 'M';
magic[2] = (U8) file_bytes;
@@ -644,10 +642,10 @@ BOOL LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time)
break;
}
- for( S32 i = 0; i < alignment_bytes; i++ )
- {
- *dst++ = 0;
- }
+ }
+ for( S32 i = 0; i < alignment_bytes; i++ )
+ {
+ *dst++ = 0;
}
}
diff --git a/indra/llimage/llimagebmp.h b/indra/llimage/llimagebmp.h
index 2924ff412c..db0b45def0 100644
--- a/indra/llimage/llimagebmp.h
+++ b/indra/llimage/llimagebmp.h
@@ -2,30 +2,25 @@
* @file llimagebmp.h
* @brief Image implementation for BMP.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -44,9 +39,10 @@ protected:
public:
LLImageBMP();
+ /*virtual*/ std::string getExtension() { return std::string("bmp"); }
/*virtual*/ BOOL updateData();
- /*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 time=0.0);
- /*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 time=0.0);
+ /*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 );
diff --git a/indra/llimage/llimagedimensionsinfo.cpp b/indra/llimage/llimagedimensionsinfo.cpp
new file mode 100644
index 0000000000..5ea4a236b5
--- /dev/null
+++ b/indra/llimage/llimagedimensionsinfo.cpp
@@ -0,0 +1,133 @@
+/**
+ * @file llimagedimensionsinfo.cpp
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include "stdtypes.h"
+
+#include "llimagejpeg.h"
+
+#include "llimagedimensionsinfo.h"
+
+bool LLImageDimensionsInfo::load(const std::string& src_filename,U32 codec)
+{
+ clean();
+
+ mSrcFilename = src_filename;
+
+ S32 file_size = 0;
+ apr_status_t s = mInfile.open(src_filename, LL_APR_RB, NULL, &file_size);
+
+ if (s != APR_SUCCESS)
+ {
+ setLastError("Unable to open file for reading", src_filename);
+ return false;
+ }
+
+ if (file_size == 0)
+ {
+ setLastError("File is empty",src_filename);
+ return false;
+ }
+
+ switch (codec)
+ {
+ case IMG_CODEC_BMP:
+ return getImageDimensionsBmp();
+ case IMG_CODEC_TGA:
+ return getImageDimensionsTga();
+ case IMG_CODEC_JPEG:
+ return getImageDimensionsJpeg();
+ case IMG_CODEC_PNG:
+ return getImageDimensionsPng();
+ default:
+ return false;
+
+ }
+}
+
+
+bool LLImageDimensionsInfo::getImageDimensionsBmp()
+{
+ const S32 BMP_FILE_HEADER_SIZE = 14;
+
+ mInfile.seek(APR_CUR,BMP_FILE_HEADER_SIZE+4);
+ mWidth = read_reverse_s32();
+ mHeight = read_reverse_s32();
+
+ return true;
+}
+
+bool LLImageDimensionsInfo::getImageDimensionsTga()
+{
+ const S32 TGA_FILE_HEADER_SIZE = 12;
+
+ mInfile.seek(APR_CUR,TGA_FILE_HEADER_SIZE);
+ mWidth = read_byte() | read_byte() << 8;
+ mHeight = read_byte() | read_byte() << 8;
+
+ return true;
+}
+
+bool LLImageDimensionsInfo::getImageDimensionsPng()
+{
+ const S32 PNG_FILE_MARKER_SIZE = 8;
+
+ mInfile.seek(APR_CUR,PNG_FILE_MARKER_SIZE + 8/*header offset+chunk length+chunk type*/);
+ mWidth = read_s32();
+ mHeight = read_s32();
+
+ return true;
+}
+
+
+bool LLImageDimensionsInfo::getImageDimensionsJpeg()
+{
+ clean();
+ FILE *fp = fopen (mSrcFilename.c_str(), "rb");
+ if (fp == NULL)
+ {
+ setLastError("Unable to open file for reading", mSrcFilename);
+ return false;
+ }
+ /* Init jpeg */
+ jpeg_error_mgr jerr;
+ jpeg_decompress_struct cinfo;
+ cinfo.err = jpeg_std_error(&jerr);
+
+ jpeg_create_decompress (&cinfo);
+ jpeg_stdio_src (&cinfo, fp);
+ jpeg_read_header (&cinfo, TRUE);
+ cinfo.out_color_space = JCS_RGB;
+ jpeg_start_decompress (&cinfo);
+
+ mHeight = cinfo.output_width;
+ mHeight = cinfo.output_height;
+
+ jpeg_destroy_decompress(&cinfo);
+ fclose(fp);
+
+ return true;
+}
+
diff --git a/indra/llimage/llimagedimensionsinfo.h b/indra/llimage/llimagedimensionsinfo.h
new file mode 100644
index 0000000000..5384faf3f4
--- /dev/null
+++ b/indra/llimage/llimagedimensionsinfo.h
@@ -0,0 +1,133 @@
+/**
+ * @file llimagedimentionsinfo.h
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+
+#ifndef LL_LLIMAGEDIMENSIONSINFO_H
+#define LL_LLIMAGEDIMENSIONSINFO_H
+
+//-----------------------------------------------------------------------------
+// LLImageDimensionsInfo
+// helper class to get image dimensions WITHOUT loading image to memore
+// usefull when image may be too large...
+//-----------------------------------------------------------------------------
+class LLImageDimensionsInfo
+{
+public:
+ LLImageDimensionsInfo():
+ mData(NULL)
+ ,mHeight(0)
+ ,mWidth(0)
+ {}
+ ~LLImageDimensionsInfo()
+ {
+ clean();
+ }
+
+ bool load(const std::string& src_filename,U32 codec);
+ S32 getWidth() const { return mWidth;}
+ S32 getHeight() const { return mHeight;}
+
+ const std::string& getLastError()
+ {
+ return mLastError;
+ }
+protected:
+
+ void clean()
+ {
+ mInfile.close();
+ delete[] mData;
+ mData = NULL;
+ mWidth = 0;
+ mHeight = 0;
+ }
+
+ U8* getData()
+ {
+ return mData;
+ }
+
+
+ void setLastError(const std::string& message, const std::string& filename)
+ {
+ std::string error = message;
+ if (!filename.empty())
+ error += std::string(" FILE: ") + filename;
+ mLastError = error;
+ }
+
+
+ bool getImageDimensionsBmp();
+ bool getImageDimensionsTga();
+ bool getImageDimensionsPng();
+ bool getImageDimensionsJpeg();
+
+ S32 read_s32()
+ {
+ char p[4];
+ mInfile.read(&p[0],4);
+ S32 temp = (((S32)p[3]) & 0x000000FF) |
+ (((S32)p[2] << 8 ) & 0x0000FF00) |
+ (((S32)p[1] << 16) & 0x00FF0000) |
+ (((S32)p[0] << 24) & 0xFF000000);
+
+ return temp;
+ }
+ S32 read_reverse_s32()
+ {
+ char p[4];
+ mInfile.read(&p[0],4);
+ S32 temp = (((S32)p[0]) & 0x000000FF) |
+ (((S32)p[1] << 8 ) & 0x0000FF00) |
+ (((S32)p[2] << 16) & 0x00FF0000) |
+ (((S32)p[3] << 24) & 0xFF000000);
+
+ return temp;
+ }
+
+ U8 read_byte()
+ {
+ U8 bt;
+ mInfile.read(&bt,1);
+ return bt;
+ }
+
+ U16 read_short()
+ {
+ return read_byte() << 8 | read_byte();
+ }
+
+protected:
+ LLAPRFile mInfile ;
+ std::string mSrcFilename;
+
+ std::string mLastError;
+
+ U8* mData;
+
+ S32 mWidth;
+ S32 mHeight;
+};
+#endif
diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp
index 6feece4ad9..4bd3efddaa 100644
--- a/indra/llimage/llimagedxt.cpp
+++ b/indra/llimage/llimagedxt.cpp
@@ -1,30 +1,25 @@
/**
* @file llimagedxt.cpp
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -263,6 +258,8 @@ void LLImageDXT::setFormat()
// virtual
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!
llassert_always(raw_image);
if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXR5)
@@ -273,8 +270,17 @@ BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time)
S32 width = getWidth(), height = getHeight();
S32 ncomponents = getComponents();
+ U8* data = NULL;
+ if (mDiscardLevel >= 0)
+ {
+ data = getData() + getMipOffset(mDiscardLevel);
+ calcDiscardWidthHeight(mDiscardLevel, mFileFormat, width, height);
+ }
+ else
+ {
+ data = getData() + getMipOffset(0);
+ }
S32 image_size = formatBytes(mFileFormat, width, height);
- U8* data = getData() + getMipOffset(0);
if ((!getData()) || (data + image_size > getData() + getDataSize()))
{
@@ -299,16 +305,14 @@ BOOL LLImageDXT::getMipData(LLPointer<LLImageRaw>& raw, S32 discard)
llerrs << "Request for invalid discard level" << llendl;
}
U8* data = getData() + getMipOffset(discard);
- // I'm not sure these are the correct initial values for height and width,
- // but previously they were being used uninitialized. JC
- S32 width = raw->getWidth();
- S32 height = raw->getHeight();
+ S32 width = 0;
+ S32 height = 0;
calcDiscardWidthHeight(discard, mFileFormat, width, height);
raw = new LLImageRaw(data, width, height, getComponents());
return TRUE;
}
-BOOL LLImageDXT::encode(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);
@@ -396,7 +400,7 @@ BOOL LLImageDXT::encode(const LLImageRaw* raw_image, F32 time, bool explicit_mip
// virtual
BOOL LLImageDXT::encode(const LLImageRaw* raw_image, F32 time)
{
- return encode(raw_image, time, false);
+ return encodeDXT(raw_image, time, false);
}
// virtual
diff --git a/indra/llimage/llimagedxt.h b/indra/llimage/llimagedxt.h
index 23a5047f0d..a8756ba8ed 100644
--- a/indra/llimage/llimagedxt.h
+++ b/indra/llimage/llimagedxt.h
@@ -1,30 +1,25 @@
/**
* @file llimagedxt.h
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -32,6 +27,7 @@
#define LL_LLIMAGEDXT_H
#include "llimage.h"
+#include "llpointer.h"
// This class decodes and encodes LL DXT files (which may unclude uncompressed RGB or RGBA mipped data)
@@ -95,15 +91,18 @@ public:
protected:
/*virtual*/ ~LLImageDXT();
+
+private:
+ 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 decode(LLImageRaw* raw_image, F32 time=0.0);
- BOOL encode(const LLImageRaw* raw_image, F32 time, bool explicit_mips);
- /*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 time=0.0);
+ /*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);
diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp
index 0911c43674..c8c866b7f2 100644
--- a/indra/llimage/llimagej2c.cpp
+++ b/indra/llimage/llimagej2c.cpp
@@ -1,36 +1,31 @@
/**
* @file llimagej2c.cpp
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
-#include <apr-1/apr_pools.h>
-#include <apr-1/apr_dso.h>
+#include "apr_pools.h"
+#include "apr_dso.h"
#include "lldir.h"
#include "llimagej2c.h"
@@ -177,8 +172,8 @@ LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C),
mMaxBytes(0),
mRawDiscardLevel(-1),
mRate(0.0f),
- mReversible(FALSE)
-
+ mReversible(FALSE),
+ mAreaUsedForDataSizeCalcs(0)
{
//We assume here that if we wanted to create via
//a dynamic library that the approriate open calls were made
@@ -194,6 +189,12 @@ LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C),
}
mImpl = j2cimpl_create_func();
+
+ // Clear data size table
+ for( S32 i = 0; i <= MAX_DISCARD_LEVEL; i++)
+ { // Array size is MAX_DISCARD_LEVEL+1
+ mDataSizes[i] = 0;
+ }
}
// virtual
@@ -219,59 +220,86 @@ LLImageJ2C::~LLImageJ2C()
}
// virtual
+void LLImageJ2C::resetLastError()
+{
+ mLastError.clear();
+}
+
+//virtual
+void LLImageJ2C::setLastError(const std::string& message, const std::string& filename)
+{
+ mLastError = message;
+ if (!filename.empty())
+ mLastError += std::string(" FILE: ") + filename;
+}
+
+// virtual
S8 LLImageJ2C::getRawDiscardLevel()
{
return mRawDiscardLevel;
}
BOOL LLImageJ2C::updateData()
-{
+{
+ BOOL res = TRUE;
resetLastError();
// Check to make sure that this instance has been initialized with data
if (!getData() || (getDataSize() < 16))
{
setLastError("LLImageJ2C uninitialized");
- return FALSE;
+ res = FALSE;
+ }
+ else
+ {
+ res = mImpl->getMetadata(*this);
}
- if (!mImpl->getMetadata(*this))
+ if (res)
{
- return FALSE;
+ // SJB: override discard based on mMaxBytes elsewhere
+ S32 max_bytes = getDataSize(); // mMaxBytes ? mMaxBytes : getDataSize();
+ S32 discard = calcDiscardLevelBytes(max_bytes);
+ setDiscardLevel(discard);
}
- // SJB: override discard based on mMaxBytes elsewhere
- S32 max_bytes = getDataSize(); // mMaxBytes ? mMaxBytes : getDataSize();
- S32 discard = calcDiscardLevelBytes(max_bytes);
- setDiscardLevel(discard);
- return TRUE;
+ if (!mLastError.empty())
+ {
+ LLImage::setLastError(mLastError);
+ }
+ return res;
}
BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time)
{
- return decode(raw_imagep, decode_time, 0, 4);
+ return decodeChannels(raw_imagep, decode_time, 0, 4);
}
-BOOL LLImageJ2C::decode(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 )
{
- LLMemType mt1((LLMemType::EMemType)mMemType);
+ LLMemType mt1(mMemType);
+ BOOL res = TRUE;
+
resetLastError();
// Check to make sure that this instance has been initialized with data
if (!getData() || (getDataSize() < 16))
{
setLastError("LLImageJ2C uninitialized");
- return FALSE;
+ res = TRUE; // done
}
-
- // Update the raw discard level
- updateRawDiscardLevel();
-
- mDecoding = TRUE;
- BOOL res = mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count);
+ else
+ {
+ // Update the raw discard level
+ updateRawDiscardLevel();
+ mDecoding = TRUE;
+ res = mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count);
+ }
+
if (res)
{
if (!mDecoding)
@@ -283,9 +311,14 @@ BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time, S32 first_chann
{
mDecoding = FALSE;
}
- return TRUE; // done
}
- return FALSE;
+
+ if (!mLastError.empty())
+ {
+ LLImage::setLastError(mLastError);
+ }
+
+ return res;
}
@@ -297,14 +330,20 @@ BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, F32 encode_time)
BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time)
{
- LLMemType mt1((LLMemType::EMemType)mMemType);
- return mImpl->encodeImpl(*this, *raw_imagep, comment_text, encode_time, mReversible);
+ LLMemType mt1(mMemType);
+ resetLastError();
+ BOOL res = mImpl->encodeImpl(*this, *raw_imagep, comment_text, encode_time, mReversible);
+ if (!mLastError.empty())
+ {
+ LLImage::setLastError(mLastError);
+ }
+ return res;
}
//static
S32 LLImageJ2C::calcHeaderSizeJ2C()
{
- return 600; //2048; // ??? hack... just needs to be >= actual header size...
+ return FIRST_PACKET_SIZE; // Hack. just needs to be >= actual header size...
}
//static
@@ -329,9 +368,45 @@ S32 LLImageJ2C::calcHeaderSize()
return calcHeaderSizeJ2C();
}
+
+// calcDataSize() returns how many bytes to read
+// to load discard_level (including header and higher discard levels)
S32 LLImageJ2C::calcDataSize(S32 discard_level)
{
- return calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), discard_level, mRate);
+ discard_level = llclamp(discard_level, 0, MAX_DISCARD_LEVEL);
+
+ if ( mAreaUsedForDataSizeCalcs != (getHeight() * getWidth())
+ || mDataSizes[0] == 0)
+ {
+ mAreaUsedForDataSizeCalcs = getHeight() * getWidth();
+
+ S32 level = MAX_DISCARD_LEVEL; // Start at the highest discard
+ while ( level >= 0 )
+ {
+ mDataSizes[level] = calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), level, mRate);
+ level--;
+ }
+
+ /* This is technically a more correct way to calculate the size required
+ for each discard level, since they should include the size needed for
+ lower levels. Unfortunately, this doesn't work well and will lead to
+ download stalls. The true correct way is to parse the header. This will
+ all go away with http textures at some point.
+
+ // Calculate the size for each discard level. Lower levels (higher quality)
+ // contain the cumulative size of higher levels
+ S32 total_size = calcHeaderSizeJ2C();
+
+ S32 level = MAX_DISCARD_LEVEL; // Start at the highest discard
+ while ( level >= 0 )
+ { // Add in this discard level and all before it
+ total_size += calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), level, mRate);
+ mDataSizes[level] = total_size;
+ level--;
+ }
+ */
+ }
+ return mDataSizes[discard_level];
}
S32 LLImageJ2C::calcDiscardLevelBytes(S32 bytes)
@@ -374,58 +449,82 @@ void LLImageJ2C::setReversible(const BOOL reversible)
}
-BOOL LLImageJ2C::loadAndValidate(const LLString &filename)
+BOOL LLImageJ2C::loadAndValidate(const std::string &filename)
{
+ BOOL res = TRUE;
+
resetLastError();
S32 file_size = 0;
- apr_file_t* apr_file = ll_apr_file_open(filename, LL_APR_RB, &file_size);
+ LLAPRFile infile ;
+ infile.open(filename, LL_APR_RB, NULL, &file_size);
+ apr_file_t* apr_file = infile.getFileHandle() ;
if (!apr_file)
{
setLastError("Unable to open file for reading", filename);
- return FALSE;
+ res = FALSE;
}
- if (file_size == 0)
+ else if (file_size == 0)
{
setLastError("File is empty",filename);
- apr_file_close(apr_file);
- return FALSE;
+ res = FALSE;
+ }
+ else
+ {
+ U8 *data = new U8[file_size];
+ apr_size_t bytes_read = file_size;
+ apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read
+ infile.close() ;
+
+ if (s != APR_SUCCESS || (S32)bytes_read != file_size)
+ {
+ delete[] data;
+ setLastError("Unable to read entire file");
+ res = FALSE;
+ }
+ else
+ {
+ res = validate(data, file_size);
+ }
}
- U8 *data = new U8[file_size];
- apr_size_t bytes_read = file_size;
- apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read
- if (s != APR_SUCCESS || (S32)bytes_read != file_size)
+ if (!mLastError.empty())
{
- delete[] data;
- setLastError("Unable to read entire file");
- return FALSE;
+ LLImage::setLastError(mLastError);
}
- apr_file_close(apr_file);
-
- return validate(data, file_size);
+
+ return res;
}
BOOL LLImageJ2C::validate(U8 *data, U32 file_size)
{
- LLMemType mt1((LLMemType::EMemType)mMemType);
+ LLMemType mt1(mMemType);
+ resetLastError();
+
setData(data, file_size);
+
BOOL res = updateData();
- if ( !res )
+ if ( res )
{
- return FALSE;
+ // Check to make sure that this instance has been initialized with data
+ if (!getData() || (0 == getDataSize()))
+ {
+ setLastError("LLImageJ2C uninitialized");
+ res = FALSE;
+ }
+ else
+ {
+ res = mImpl->getMetadata(*this);
+ }
}
-
- // Check to make sure that this instance has been initialized with data
- if (!getData() || (0 == getDataSize()))
+
+ if (!mLastError.empty())
{
- setLastError("LLImageJ2C uninitialized");
- return FALSE;
+ LLImage::setLastError(mLastError);
}
-
- return mImpl->getMetadata(*this);
+ return res;
}
void LLImageJ2C::decodeFailed()
diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h
index 35b4d6b8b4..cdb3faa207 100644
--- a/indra/llimage/llimagej2c.h
+++ b/indra/llimage/llimagej2c.h
@@ -2,30 +2,25 @@
* @file llimagej2c.h
* @brief Image implmenation for jpeg2000.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -45,20 +40,25 @@ public:
LLImageJ2C();
// Base class overrides
+ /*virtual*/ std::string getExtension() { return std::string("j2c"); }
/*virtual*/ BOOL updateData();
- /*virtual*/ BOOL decode(LLImageRaw *raw_imagep, F32 decode_time=0.0);
- /*virtual*/ BOOL decode(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count);
- /*virtual*/ BOOL encode(const LLImageRaw *raw_imagep, F32 encode_time=0.0);
+ /*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);
/*virtual*/ S8 getRawDiscardLevel();
+ // Override these so that we don't try to set a global variable from a DLL
+ /*virtual*/ void resetLastError();
+ /*virtual*/ void setLastError(const std::string& message, const std::string& filename = std::string());
+
// Encode with comment text
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 LLString &filename);
+ BOOL loadAndValidate(const std::string &filename);
// Encode accessors
void setReversible(const BOOL reversible); // Use non-lossy?
@@ -81,10 +81,15 @@ protected:
void updateRawDiscardLevel();
S32 mMaxBytes; // Maximum number of bytes of data to use...
+
+ S32 mDataSizes[MAX_DISCARD_LEVEL+1]; // Size of data required to reach a given level
+ U32 mAreaUsedForDataSizeCalcs; // Height * width used to calculate mDataSizes
+
S8 mRawDiscardLevel;
F32 mRate;
BOOL mReversible;
LLImageJ2CImpl *mImpl;
+ std::string mLastError;
};
// Derive from this class to implement JPEG2000 decoding
diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp
index f9b36bd1f6..b70f84efc8 100644
--- a/indra/llimage/llimagejpeg.cpp
+++ b/indra/llimage/llimagejpeg.cpp
@@ -1,30 +1,25 @@
/**
* @file llimagejpeg.cpp
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -35,12 +30,13 @@
#include "llerror.h"
-LLImageJPEG::LLImageJPEG()
+jmp_buf LLImageJPEG::sSetjmpBuffer ;
+LLImageJPEG::LLImageJPEG(S32 quality)
:
LLImageFormatted(IMG_CODEC_JPEG),
mOutputBuffer( NULL ),
mOutputBufferSize( 0 ),
- mEncodeQuality( 75 ) // on a scale from 1 to 100
+ mEncodeQuality( quality ) // on a scale from 1 to 100
{
}
@@ -76,7 +72,16 @@ BOOL LLImageJPEG::updateData()
jerr.error_exit = &LLImageJPEG::errorExit; // Error exit handler: does not return to caller
jerr.emit_message = &LLImageJPEG::errorEmitMessage; // Conditionally emit a trace or warning message
jerr.output_message = &LLImageJPEG::errorOutputMessage; // Routine that actually outputs a trace or error message
-
+
+ //
+ //try/catch will crash on Mac and Linux if LLImageJPEG::errorExit throws an error
+ //so as instead, we use setjmp/longjmp to avoid this crash, which is the best we can get. --bao
+ //
+ if(setjmp(sSetjmpBuffer))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ return FALSE;
+ }
try
{
// Now we can initialize the JPEG decompression object.
@@ -177,6 +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)
{
llassert_always(raw_image);
@@ -187,7 +193,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 FALSE;
+ return TRUE; // done
}
S32 row_stride = 0;
@@ -208,7 +214,15 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
jerr.emit_message = &LLImageJPEG::errorEmitMessage; // Conditionally emit a trace or warning message
jerr.output_message = &LLImageJPEG::errorOutputMessage; // Routine that actually outputs a trace or error message
-
+ //
+ //try/catch will crash on Mac and Linux if LLImageJPEG::errorExit throws an error
+ //so as instead, we use setjmp/longjmp to avoid this crash, which is the best we can get. --bao
+ //
+ if(setjmp(sSetjmpBuffer))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ return TRUE; // done
+ }
try
{
// Now we can initialize the JPEG decompression object.
@@ -301,7 +315,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
catch (int)
{
jpeg_destroy_decompress(&cinfo);
- return FALSE;
+ return TRUE; // done
}
// Check to see whether any corrupt-data warnings occurred
@@ -309,7 +323,7 @@ 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 FALSE;
+ return TRUE; // done
}
return TRUE;
@@ -402,7 +416,7 @@ void LLImageJPEG::errorExit( j_common_ptr cinfo )
jpeg_destroy(cinfo);
// Return control to the setjmp point
- throw 1;
+ longjmp(sSetjmpBuffer, 1) ;
}
// Decide whether to emit a trace or warning message.
@@ -447,7 +461,8 @@ void LLImageJPEG::errorOutputMessage( j_common_ptr cinfo )
char buffer[JMSG_LENGTH_MAX]; /* Flawfinder: ignore */
(*cinfo->err->format_message) (cinfo, buffer);
- ((LLImageJPEG*) cinfo->client_data)->setLastError( buffer );
+ std::string error = buffer ;
+ LLImage::setLastError(error);
BOOL is_decode = (cinfo->is_decompressor != 0);
llwarns << "LLImageJPEG " << (is_decode ? "decode " : "encode ") << " failed: " << buffer << llendl;
@@ -500,8 +515,11 @@ BOOL LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )
jerr.emit_message = &LLImageJPEG::errorEmitMessage; // Conditionally emit a trace or warning message
jerr.output_message = &LLImageJPEG::errorOutputMessage; // Routine that actually outputs a trace or error message
- // Establish the setjmp return context mSetjmpBuffer. Used by library to abort.
- if( setjmp(mSetjmpBuffer) )
+ //
+ //try/catch will crash on Mac and Linux if LLImageJPEG::errorExit throws an error
+ //so as instead, we use setjmp/longjmp to avoid this crash, which is the best we can get. --bao
+ //
+ if( setjmp(sSetjmpBuffer) )
{
// If we get here, the JPEG code has signaled an error.
// We need to clean up the JPEG object, close the input file, and return.
diff --git a/indra/llimage/llimagejpeg.h b/indra/llimage/llimagejpeg.h
index 0be4002791..7ac7f5d2e0 100644
--- a/indra/llimage/llimagejpeg.h
+++ b/indra/llimage/llimagejpeg.h
@@ -2,37 +2,32 @@
* @file llimagejpeg.h
* @brief This class compresses and decompresses JPEG files
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
#ifndef LL_LLIMAGEJPEG_H
#define LL_LLIMAGEJPEG_H
-#include <setjmp.h>
+#include <csetjmp>
#include "llimage.h"
@@ -52,11 +47,12 @@ protected:
virtual ~LLImageJPEG();
public:
- LLImageJPEG();
+ LLImageJPEG(S32 quality = 75);
+ /*virtual*/ std::string getExtension() { return std::string("jpg"); }
/*virtual*/ BOOL updateData();
- /*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 time=0.0);
- /*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 time=0.0);
+ /*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; }
@@ -83,8 +79,8 @@ protected:
S32 mOutputBufferSize; // bytes in mOuputBuffer
S32 mEncodeQuality; // on a scale from 1 to 100
-
- jmp_buf mSetjmpBuffer; // To allow the library to abort.
+private:
+ static jmp_buf sSetjmpBuffer; // To allow the library to abort.
};
#endif // LL_LLIMAGEJPEG_H
diff --git a/indra/llimage/llimagepng.cpp b/indra/llimage/llimagepng.cpp
index 3e0414fd78..8d493ecde0 100644
--- a/indra/llimage/llimagepng.cpp
+++ b/indra/llimage/llimagepng.cpp
@@ -2,30 +2,25 @@
* @file llimagepng.cpp
* @brief LLImageFormatted glue to encode / decode PNG files.
*
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -41,17 +36,12 @@
// LLImagePNG
// ---------------------------------------------------------------------------
LLImagePNG::LLImagePNG()
- : LLImageFormatted(IMG_CODEC_PNG),
- mTmpWriteBuffer(NULL)
+ : LLImageFormatted(IMG_CODEC_PNG)
{
}
LLImagePNG::~LLImagePNG()
{
- if (mTmpWriteBuffer)
- {
- delete[] mTmpWriteBuffer;
- }
}
// Virtual
@@ -122,27 +112,24 @@ BOOL LLImagePNG::encode(const LLImageRaw* raw_image, F32 encode_time)
// Temporary buffer to hold the encoded image. Note: the final image
// size should be much smaller due to compression.
- if (mTmpWriteBuffer)
- {
- delete[] mTmpWriteBuffer;
- }
U32 bufferSize = getWidth() * getHeight() * getComponents() + 1024;
- U8* mTmpWriteBuffer = new U8[ bufferSize ];
+ U8* tmpWriteBuffer = new U8[ bufferSize ];
// Delegate actual encoding work to wrapper
LLPngWrapper pngWrapper;
- if (! pngWrapper.writePng(raw_image, mTmpWriteBuffer))
+ if (! pngWrapper.writePng(raw_image, tmpWriteBuffer))
{
setLastError(pngWrapper.getErrorMessage());
+ delete[] tmpWriteBuffer;
return FALSE;
}
// Resize internal buffer and copy from temp
U32 encodedSize = pngWrapper.getFinalSize();
allocateData(encodedSize);
- memcpy(getData(), mTmpWriteBuffer, encodedSize);
+ memcpy(getData(), tmpWriteBuffer, encodedSize);
- delete[] mTmpWriteBuffer;
+ delete[] tmpWriteBuffer;
return TRUE;
}
diff --git a/indra/llimage/llimagepng.h b/indra/llimage/llimagepng.h
index 7a8e1f93b1..1fbd850a2e 100644
--- a/indra/llimage/llimagepng.h
+++ b/indra/llimage/llimagepng.h
@@ -1,30 +1,25 @@
/*
* @file llimagepng.h
*
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -42,12 +37,10 @@ protected:
public:
LLImagePNG();
- BOOL updateData();
- BOOL decode(LLImageRaw* raw_image, F32 decode_time = 0.0);
- BOOL encode(const LLImageRaw* raw_image, F32 encode_time = 0.0);
-
-private:
- U8* mTmpWriteBuffer;
+ /*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);
};
#endif
diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp
index 805297f8ee..58426d31fa 100644
--- a/indra/llimage/llimagetga.cpp
+++ b/indra/llimage/llimagetga.cpp
@@ -1,38 +1,36 @@
/**
* @file llimagetga.cpp
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llimagetga.h"
+
+#include "lldir.h"
#include "llerror.h"
#include "llmath.h"
+#include "llpointer.h"
// For expanding 5-bit pixel values to 8-bit with best rounding
// static
@@ -63,11 +61,34 @@ LLImageTGA::LLImageTGA()
mColorMapStart( 0 ),
mColorMapLength( 0 ),
mColorMapBytesPerEntry( 0 ),
- mIs15Bit( FALSE )
+ mIs15Bit( FALSE ),
+
+ mAttributeBits(0),
+ mColorMapDepth(0),
+ mColorMapIndexHi(0),
+ mColorMapIndexLo(0),
+ mColorMapLengthHi(0),
+ mColorMapLengthLo(0),
+ mColorMapType(0),
+ mDataOffset(0),
+ mHeightHi(0),
+ mHeightLo(0),
+ mIDLength(0),
+ mImageType(0),
+ mInterleave(0),
+ mOriginRightBit(0),
+ mOriginTopBit(0),
+ mPixelSize(0),
+ mWidthHi(0),
+ mWidthLo(0),
+ mXOffsetHi(0),
+ mXOffsetLo(0),
+ mYOffsetHi(0),
+ mYOffsetLo(0)
{
}
-LLImageTGA::LLImageTGA(const LLString& file_name)
+LLImageTGA::LLImageTGA(const std::string& file_name)
: LLImageFormatted(IMG_CODEC_TGA),
mColorMap( NULL ),
mColorMapStart( 0 ),
@@ -80,7 +101,7 @@ LLImageTGA::LLImageTGA(const LLString& file_name)
LLImageTGA::~LLImageTGA()
{
- delete mColorMap;
+ delete [] mColorMap;
}
BOOL LLImageTGA::updateData()
@@ -1113,7 +1134,7 @@ BOOL LLImageTGA::decodeAndProcess( LLImageRaw* raw_image, F32 domain, F32 weight
}
// Reads a .tga file and creates an LLImageTGA with its data.
-bool LLImageTGA::loadFile( const LLString& path )
+bool LLImageTGA::loadFile( const std::string& path )
{
S32 len = path.size();
if( len < 5 )
@@ -1121,14 +1142,13 @@ bool LLImageTGA::loadFile( const LLString& path )
return false;
}
- LLString extension = path.substr( len - 4, 4 );
- LLString::toLower(extension);
- if( ".tga" != extension )
+ std::string extension = gDirUtilp->getExtension(path);
+ if( "tga" != extension )
{
return false;
}
- FILE* file = LLFile::fopen(path.c_str(), "rb"); /* Flawfinder: ignore */
+ LLFILE* file = LLFile::fopen(path, "rb"); /* Flawfinder: ignore */
if( !file )
{
llwarns << "Couldn't open file " << path << llendl;
diff --git a/indra/llimage/llimagetga.h b/indra/llimage/llimagetga.h
index 3bfe4e6e21..5da3525149 100644
--- a/indra/llimage/llimagetga.h
+++ b/indra/llimage/llimagetga.h
@@ -2,30 +2,25 @@
* @file llimagetga.h
* @brief Image implementation to compresses and decompressed TGA files.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -43,8 +38,9 @@ protected:
public:
LLImageTGA();
- LLImageTGA(const LLString& file_name);
+ 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);
@@ -70,7 +66,7 @@ private:
void decodeColorMapPixel24(U8* dst, const U8* src);
void decodeColorMapPixel32(U8* dst, const U8* src);
- bool loadFile(const LLString& file_name);
+ bool loadFile(const std::string& file_name);
private:
// Class specific data
diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp
index 61b15b2092..d1c74b6fa1 100644
--- a/indra/llimage/llimageworker.cpp
+++ b/indra/llimage/llimageworker.cpp
@@ -2,30 +2,25 @@
* @file llimageworker.cpp
* @brief Base class for images.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -36,152 +31,143 @@
//----------------------------------------------------------------------------
-//static
-LLWorkerThread* LLImageWorker::sWorkerThread = NULL;
-S32 LLImageWorker::sCount = 0;
+// MAIN THREAD
+LLImageDecodeThread::LLImageDecodeThread(bool threaded)
+ : LLQueuedThread("imagedecode", threaded)
+{
+ mCreationMutex = new LLMutex(getAPRPool());
+}
+
+// MAIN THREAD
+// virtual
+S32 LLImageDecodeThread::update(U32 max_time_ms)
+{
+ LLMutexLock lock(mCreationMutex);
+ for (creation_list_t::iterator iter = mCreationList.begin();
+ iter != mCreationList.end(); ++iter)
+ {
+ creation_info& info = *iter;
+ ImageRequest* req = new ImageRequest(info.handle, info.image,
+ info.priority, info.discard, info.needs_aux,
+ info.responder);
+
+ bool res = addRequest(req);
+ if (!res)
+ {
+ llerrs << "request added after LLLFSThread::cleanupClass()" << llendl;
+ }
+ }
+ mCreationList.clear();
+ S32 res = LLQueuedThread::update(max_time_ms);
+ return res;
+}
-//static
-void LLImageWorker::initClass(LLWorkerThread* workerthread)
+LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* image,
+ U32 priority, S32 discard, BOOL needs_aux, Responder* responder)
{
- sWorkerThread = workerthread;
+ LLMutexLock lock(mCreationMutex);
+ handle_t handle = generateHandle();
+ mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder));
+ return handle;
}
-//static
-void LLImageWorker::cleanupClass()
+// Used by unit test only
+// Returns the size of the mutex guarded list as an indication of sanity
+S32 LLImageDecodeThread::tut_size()
+{
+ LLMutexLock lock(mCreationMutex);
+ S32 res = mCreationList.size();
+ return res;
+}
+
+LLImageDecodeThread::Responder::~Responder()
{
}
//----------------------------------------------------------------------------
-LLImageWorker::LLImageWorker(LLImageFormatted* image, U32 priority,
- S32 discard,
- LLPointer<LLResponder> responder)
- : LLWorkerClass(sWorkerThread, "Image"),
+LLImageDecodeThread::ImageRequest::ImageRequest(handle_t handle, LLImageFormatted* image,
+ U32 priority, S32 discard, BOOL needs_aux,
+ LLImageDecodeThread::Responder* responder)
+ : LLQueuedThread::QueuedRequest(handle, priority, FLAG_AUTO_COMPLETE),
mFormattedImage(image),
- mDecodedType(-1),
mDiscardLevel(discard),
- mPriority(priority),
+ mNeedsAux(needs_aux),
+ mDecodedRaw(FALSE),
+ mDecodedAux(FALSE),
mResponder(responder)
{
- ++sCount;
}
-LLImageWorker::~LLImageWorker()
+LLImageDecodeThread::ImageRequest::~ImageRequest()
{
- mDecodedImage = NULL;
+ mDecodedImageRaw = NULL;
+ mDecodedImageAux = NULL;
mFormattedImage = NULL;
- --sCount;
}
//----------------------------------------------------------------------------
-//virtual, main thread
-void LLImageWorker::startWork(S32 param)
-{
- llassert_always(mDecodedImage.isNull());
- mDecodedType = -1;
-}
-bool LLImageWorker::doWork(S32 param)
+// Returns true when done, whether or not decode was successful.
+bool LLImageDecodeThread::ImageRequest::processRequest()
{
- bool decoded = false;
- if(mDecodedImage.isNull())
+ const F32 decode_time_slice = .1f;
+ bool done = true;
+ if (!mDecodedRaw && mFormattedImage.notNull())
{
- if (!mFormattedImage->updateData())
- {
- mDecodedType = -2; // failed
- return true;
- }
- if (mDiscardLevel >= 0)
- {
- mFormattedImage->setDiscardLevel(mDiscardLevel);
- }
- if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents()))
+ // Decode primary channels
+ if (mDecodedImageRaw.isNull())
{
- decoded = true; // failed
- }
- else
- {
- mDecodedImage = new LLImageRaw(); // allow possibly smaller size set during decoding
+ // parse formatted header
+ if (!mFormattedImage->updateData())
+ {
+ return true; // done (failed)
+ }
+ if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents()))
+ {
+ return true; // done (failed)
+ }
+ if (mDiscardLevel >= 0)
+ {
+ mFormattedImage->setDiscardLevel(mDiscardLevel);
+ }
+ mDecodedImageRaw = new LLImageRaw(mFormattedImage->getWidth(),
+ mFormattedImage->getHeight(),
+ mFormattedImage->getComponents());
}
+ done = mFormattedImage->decode(mDecodedImageRaw, decode_time_slice); // 1ms
+ mDecodedRaw = done;
}
- if (!decoded)
+ if (done && mNeedsAux && !mDecodedAux && mFormattedImage.notNull())
{
- if (param == 0)
+ // Decode aux channel
+ if (!mDecodedImageAux)
{
- // Decode primary channels
- decoded = mFormattedImage->decode(mDecodedImage, .1f); // 1ms
- }
- else
- {
- // Decode aux channel
- decoded = mFormattedImage->decode(mDecodedImage, .1f, param, param); // 1ms
- }
- }
- if (decoded)
- {
- // Call the callback immediately; endWork doesn't get called until ckeckWork
- if (mResponder.notNull())
- {
- bool success = (!wasAborted() && mDecodedImage.notNull() && mDecodedImage->getDataSize() != 0);
- mResponder->completed(success);
+ mDecodedImageAux = new LLImageRaw(mFormattedImage->getWidth(),
+ mFormattedImage->getHeight(),
+ 1);
}
+ done = mFormattedImage->decodeChannels(mDecodedImageAux, decode_time_slice, 4, 4); // 1ms
+ mDecodedAux = done;
}
- return decoded;
-}
-void LLImageWorker::endWork(S32 param, bool aborted)
-{
- if (mDecodedType != -2)
- {
- mDecodedType = aborted ? -2 : param;
- }
+ return done;
}
-//----------------------------------------------------------------------------
-
-
-BOOL LLImageWorker::requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, S32 discard)
+void LLImageDecodeThread::ImageRequest::finishRequest(bool completed)
{
- // For most codecs, only mDiscardLevel data is available.
- // (see LLImageDXT for exception)
- if (discard >= 0 && discard != mFormattedImage->getDiscardLevel())
+ if (mResponder.notNull())
{
- llerrs << "Request for invalid discard level" << llendl;
- }
- checkWork();
- if (mDecodedType == -2)
- {
- return TRUE; // aborted, done
- }
- if (mDecodedType != channel)
- {
- if (!haveWork())
- {
- addWork(channel, mPriority);
- }
- return FALSE;
- }
- else
- {
- llassert_always(!haveWork());
- llassert_always(mDecodedType == channel);
- raw = mDecodedImage; // smart pointer acquires ownership of data
- mDecodedImage = NULL;
- return TRUE;
+ bool success = completed && mDecodedRaw && (!mNeedsAux || mDecodedAux);
+ mResponder->completed(success, mDecodedImageRaw, mDecodedImageAux);
}
+ // Will automatically be deleted
}
-BOOL LLImageWorker::requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard)
+// Used by unit test only
+// Checks that a responder exists for this instance so that something can happen when completion is reached
+bool LLImageDecodeThread::ImageRequest::tut_isOK()
{
- if (mFormattedImage->getCodec() == IMG_CODEC_DXT)
- {
- // special case
- LLImageDXT* imagedxt = (LLImageDXT*)((LLImageFormatted*)mFormattedImage);
- return imagedxt->getMipData(raw, discard);
- }
- else
- {
- return requestDecodedAuxData(raw, 0, discard);
- }
+ return mResponder.notNull();
}
diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h
index f9c592fa51..c3c92ec832 100644
--- a/indra/llimage/llimageworker.h
+++ b/indra/llimage/llimageworker.h
@@ -2,30 +2,25 @@
* @file llimageworker.h
* @brief Object for managing images and their textures.
*
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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$
*/
@@ -33,49 +28,75 @@
#define LL_LLIMAGEWORKER_H
#include "llimage.h"
+#include "llpointer.h"
#include "llworkerthread.h"
-class LLImageWorker : public LLWorkerClass
+class LLImageDecodeThread : public LLQueuedThread
{
public:
- static void initClass(LLWorkerThread* workerthread);
- static void cleanupClass();
- static LLWorkerThread* getWorkerThread() { return sWorkerThread; }
+ class Responder : public LLThreadSafeRefCount
+ {
+ protected:
+ virtual ~Responder();
+ public:
+ virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux) = 0;
+ };
- // LLWorkerThread
-public:
- LLImageWorker(LLImageFormatted* image, U32 priority, S32 discard,
- LLPointer<LLResponder> responder);
- ~LLImageWorker();
+ class ImageRequest : public LLQueuedThread::QueuedRequest
+ {
+ protected:
+ virtual ~ImageRequest(); // use deleteRequest()
+
+ public:
+ ImageRequest(handle_t handle, LLImageFormatted* image,
+ U32 priority, S32 discard, BOOL needs_aux,
+ LLImageDecodeThread::Responder* responder);
- // called from WORKER THREAD, returns TRUE if done
- /*virtual*/ bool doWork(S32 param);
-
- BOOL requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard = -1);
- BOOL requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, S32 discard = -1);
- void releaseDecodedData();
- void cancelDecode();
-
-private:
- // called from MAIN THREAD
- /*virtual*/ void startWork(S32 param); // called from addWork()
- /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork()
+ /*virtual*/ bool processRequest();
+ /*virtual*/ void finishRequest(bool completed);
-protected:
- LLPointer<LLImageFormatted> mFormattedImage;
- LLPointer<LLImageRaw> mDecodedImage;
- S32 mDecodedType;
- S32 mDiscardLevel;
-
-private:
- U32 mPriority;
- LLPointer<LLResponder> mResponder;
+ // Used by unit tests to check the consitency of the request instance
+ bool tut_isOK();
+
+ private:
+ // input
+ LLPointer<LLImageFormatted> mFormattedImage;
+ S32 mDiscardLevel;
+ BOOL mNeedsAux;
+ // output
+ LLPointer<LLImageRaw> mDecodedImageRaw;
+ LLPointer<LLImageRaw> mDecodedImageAux;
+ BOOL mDecodedRaw;
+ BOOL mDecodedAux;
+ LLPointer<LLImageDecodeThread::Responder> mResponder;
+ };
-protected:
- static LLWorkerThread* sWorkerThread;
-
public:
- static S32 sCount;
+ LLImageDecodeThread(bool threaded = true);
+ handle_t decodeImage(LLImageFormatted* image,
+ U32 priority, S32 discard, BOOL needs_aux,
+ Responder* responder);
+ S32 update(U32 max_time_ms);
+
+ // Used by unit tests to check the consistency of the thread instance
+ S32 tut_size();
+
+private:
+ struct creation_info
+ {
+ handle_t handle;
+ LLPointer<LLImageFormatted> image;
+ U32 priority;
+ S32 discard;
+ BOOL needs_aux;
+ LLPointer<Responder> responder;
+ creation_info(handle_t h, LLImageFormatted* i, U32 p, S32 d, BOOL aux, Responder* r)
+ : handle(h), image(i), priority(p), discard(d), needs_aux(aux), responder(r)
+ {}
+ };
+ typedef std::list<creation_info> creation_list_t;
+ creation_list_t mCreationList;
+ LLMutex* mCreationMutex;
};
#endif
diff --git a/indra/llimage/llmapimagetype.h b/indra/llimage/llmapimagetype.h
index b9d20d10c6..0a040d3db9 100644
--- a/indra/llimage/llmapimagetype.h
+++ b/indra/llimage/llmapimagetype.h
@@ -1,30 +1,25 @@
/**
* @file llmapimagetype.h
*
- * $LicenseInfo:firstyear=2003&license=viewergpl$
- *
- * Copyright (c) 2003-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2003&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp
index 74a09b2106..fe737e2072 100644
--- a/indra/llimage/llpngwrapper.cpp
+++ b/indra/llimage/llpngwrapper.cpp
@@ -2,30 +2,25 @@
* @file llpngwrapper.cpp
* @brief Encapsulates libpng read/write functionality.
*
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -42,17 +37,22 @@
LLPngWrapper::LLPngWrapper()
: mReadPngPtr( NULL ),
- mReadInfoPtr( NULL ),
+ mReadInfoPtr( NULL ),
mWritePngPtr( NULL ),
mWriteInfoPtr( NULL ),
mRowPointers( NULL ),
+ mWidth( 0 ),
+ mHeight( 0 ),
mBitDepth( 0 ),
mColorType( 0 ),
mChannels( 0 ),
mInterlaceType( 0 ),
mCompressionType( 0 ),
mFilterMethod( 0 ),
- mFinalSize( 0 )
+ mFinalSize( 0 ),
+ mHasBKGD(false),
+ mBackgroundColor(),
+ mGamma(0.f)
{
}
@@ -210,7 +210,7 @@ void LLPngWrapper::normalizeImage()
}
if (mColorType == PNG_COLOR_TYPE_GRAY && mBitDepth < 8)
{
- png_set_gray_1_2_4_to_8(mReadPngPtr);
+ png_set_expand_gray_1_2_4_to_8(mReadPngPtr);
}
if (mColorType == PNG_COLOR_TYPE_GRAY
|| mColorType == PNG_COLOR_TYPE_GRAY_ALPHA)
@@ -358,7 +358,7 @@ void LLPngWrapper::releaseResources()
{
if (mReadPngPtr || mReadInfoPtr)
{
- png_destroy_read_struct(&mReadPngPtr, &mReadInfoPtr, png_infopp_NULL);
+ png_destroy_read_struct(&mReadPngPtr, &mReadInfoPtr, NULL);
mReadPngPtr = NULL;
mReadInfoPtr = NULL;
}
@@ -384,7 +384,7 @@ U32 LLPngWrapper::getFinalSize()
}
// Get last error message, if any
-LLString LLPngWrapper::getErrorMessage()
+const std::string& LLPngWrapper::getErrorMessage()
{
return mErrorMessage;
}
diff --git a/indra/llimage/llpngwrapper.h b/indra/llimage/llpngwrapper.h
index 1c66b8a31c..47a4207d66 100644
--- a/indra/llimage/llpngwrapper.h
+++ b/indra/llimage/llpngwrapper.h
@@ -1,37 +1,32 @@
/*
* @file llpngwrapper.h
*
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLPNGWRAPPER_H
#define LL_LLPNGWRAPPER_H
-#include "libpng12/png.h"
+#include "png.h"
#include "llimage.h"
class LLPngWrapper
@@ -52,7 +47,7 @@ public:
BOOL readPng(U8* src, LLImageRaw* rawImage, ImageInfo *infop = NULL);
BOOL writePng(const LLImageRaw* rawImage, U8* dst);
U32 getFinalSize();
- LLString getErrorMessage();
+ const std::string& getErrorMessage();
protected:
void normalizeImage();
@@ -93,12 +88,12 @@ private:
U32 mFinalSize;
- BOOL mHasBKGD;
+ bool mHasBKGD;
png_color_16p mBackgroundColor;
F64 mGamma;
- LLString mErrorMessage;
+ std::string mErrorMessage;
};
#endif
diff --git a/indra/llimage/tests/llimageworker_test.cpp b/indra/llimage/tests/llimageworker_test.cpp
new file mode 100644
index 0000000000..a109276709
--- /dev/null
+++ b/indra/llimage/tests/llimageworker_test.cpp
@@ -0,0 +1,254 @@
+/**
+ * @file llimageworker_test.cpp
+ * @author Merov Linden
+ * @date 2009-04-28
+ *
+ * $LicenseInfo:firstyear=2006&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$
+ */
+
+// Precompiled header: almost always required for newview cpp files
+#include <list>
+#include <map>
+#include <algorithm>
+// Class to test
+#include "../llimageworker.h"
+// For timer class
+#include "../llcommon/lltimer.h"
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes:
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+LLImageBase::LLImageBase() {}
+LLImageBase::~LLImageBase() {}
+void LLImageBase::dump() { }
+void LLImageBase::sanityCheck() { }
+void LLImageBase::deleteData() { }
+U8* LLImageBase::allocateData(S32 size) { return NULL; }
+U8* LLImageBase::reallocateData(S32 size) { return NULL; }
+
+LLImageRaw::LLImageRaw(U16 width, U16 height, S8 components) { }
+LLImageRaw::~LLImageRaw() { }
+void LLImageRaw::deleteData() { }
+U8* LLImageRaw::allocateData(S32 size) { return NULL; }
+U8* LLImageRaw::reallocateData(S32 size) { return NULL; }
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+
+namespace tut
+{
+ // Test wrapper declarations
+
+ // Note: We derive the responder class for 2 reasons:
+ // 1. It's a pure virtual class and we can't compile without completed() being implemented
+ // 2. We actually need a responder to test that the thread work test completed
+ // We implement this making no assumption on what's done in the thread or worker
+ // though, just that the responder's completed() method is called in the end.
+ // Note on responders: responders are ref counted and *will* be deleted by the request they are
+ // attached to when the queued request is deleted. The recommended way of using them is to
+ // create them when creating a request, put a callback method in completed() and not rely on
+ // anything to survive in the responder object once completed() has been called. Let the request
+ // do the deletion and clean up itself.
+ class responder_test : public LLImageDecodeThread::Responder
+ {
+ public:
+ responder_test(bool* res)
+ {
+ done = res;
+ *done = false;
+ }
+ virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux)
+ {
+ *done = true;
+ }
+ private:
+ // This is what can be thought of as the minimal implementation of a responder
+ // Done will be switched to true when completed() is called and can be tested
+ // outside the responder. A better way of doing this is to store a callback here.
+ bool* done;
+ };
+
+ // Test wrapper declaration : decode thread
+ struct imagedecodethread_test
+ {
+ // Instance to be tested
+ LLImageDecodeThread* mThread;
+
+ // Constructor and destructor of the test wrapper
+ imagedecodethread_test()
+ {
+ mThread = NULL;
+ }
+ ~imagedecodethread_test()
+ {
+ delete mThread;
+ }
+ };
+
+ // Test wrapper declaration : image worker
+ // Note: this class is not meant to be instantiated outside an LLImageDecodeThread instance
+ // but it's not a bad idea to get its public API a good shake as part of a thorough unit test set.
+ // Some gotcha with the destructor though (see below).
+ struct imagerequest_test
+ {
+ // Instance to be tested
+ LLImageDecodeThread::ImageRequest* mRequest;
+ bool done;
+
+ // Constructor and destructor of the test wrapper
+ imagerequest_test()
+ {
+ done = false;
+ mRequest = new LLImageDecodeThread::ImageRequest(0, 0,
+ LLQueuedThread::PRIORITY_NORMAL, 0, FALSE,
+ new responder_test(&done));
+ }
+ ~imagerequest_test()
+ {
+ // We should delete the object *but*, because its destructor is protected, that cannot be
+ // done from outside an LLImageDecodeThread instance... So we leak memory here... It's fine...
+ //delete mRequest;
+ }
+ };
+
+ // Tut templating thingamagic: test group, object and test instance
+ typedef test_group<imagedecodethread_test> imagedecodethread_t;
+ typedef imagedecodethread_t::object imagedecodethread_object_t;
+ tut::imagedecodethread_t tut_imagedecodethread("LLImageDecodeThread");
+
+ typedef test_group<imagerequest_test> imagerequest_t;
+ typedef imagerequest_t::object imagerequest_object_t;
+ tut::imagerequest_t tut_imagerequest("LLImageRequest");
+
+ // ---------------------------------------------------------------------------------------
+ // Test functions
+ // Notes:
+ // * Test as many as you possibly can without requiring a full blown simulation of everything
+ // * The tests are executed in sequence so the test instance state may change between calls
+ // * Remember that you cannot test private methods with tut
+ // ---------------------------------------------------------------------------------------
+
+ // ---------------------------------------------------------------------------------------
+ // Test the LLImageDecodeThread interface
+ // ---------------------------------------------------------------------------------------
+ //
+ // Note on Unit Testing Queued Thread Classes
+ //
+ // Since methods on such a class are called on a separate loop and that we can't insert tut
+ // ensure() calls in there, we exercise the class with 2 sets of tests:
+ // - 1: Test as a single threaded instance: We declare the class but ask for no thread
+ // to be spawned (easy with LLThreads since there's a boolean argument on the constructor
+ // just for that). We can then unit test each public method like we do on a normal class.
+ // - 2: Test as a threaded instance: We let the thread launch and check that its external
+ // behavior is as expected (i.e. it runs, can accept a work order and processes
+ // it). Typically though there's no guarantee that this exercises all the methods of the
+ // class which is why we also need the previous "non threaded" set of unit tests for
+ // complete coverage.
+ //
+ // ---------------------------------------------------------------------------------------
+
+ template<> template<>
+ void imagedecodethread_object_t::test<1>()
+ {
+ // Test a *non threaded* instance of the class
+ mThread = new LLImageDecodeThread(false);
+ ensure("LLImageDecodeThread: non threaded constructor failed", mThread != NULL);
+ // Test that we start with an empty list right at creation
+ ensure("LLImageDecodeThread: non threaded init state incorrect", mThread->tut_size() == 0);
+ // Insert something in the queue
+ bool done = false;
+ LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, LLQueuedThread::PRIORITY_NORMAL, 0, FALSE, new responder_test(&done));
+ // Verifies we got a valid handle
+ ensure("LLImageDecodeThread: non threaded decodeImage(), returned handle is null", decodeHandle != 0);
+ // Verifies that we do now have something in the queued list
+ ensure("LLImageDecodeThread: non threaded decodeImage() insertion in threaded list failed", mThread->tut_size() == 1);
+ // Trigger queue handling "manually" (on a threaded instance, this is done on the thread loop)
+ S32 res = mThread->update(0);
+ // Verifies that we successfully handled the list
+ ensure("LLImageDecodeThread: non threaded update() list handling test failed", res == 0);
+ // Verifies that the list is now empty
+ ensure("LLImageDecodeThread: non threaded update() list emptying test failed", mThread->tut_size() == 0);
+ }
+
+ template<> template<>
+ void imagedecodethread_object_t::test<2>()
+ {
+ // Test a *threaded* instance of the class
+ mThread = new LLImageDecodeThread(true);
+ ensure("LLImageDecodeThread: threaded constructor failed", mThread != NULL);
+ // Test that we start with an empty list right at creation
+ ensure("LLImageDecodeThread: threaded init state incorrect", mThread->tut_size() == 0);
+ // Insert something in the queue
+ bool done = false;
+ LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, LLQueuedThread::PRIORITY_NORMAL, 0, FALSE, new responder_test(&done));
+ // Verifies we get back a valid handle
+ ensure("LLImageDecodeThread: threaded decodeImage(), returned handle is null", decodeHandle != 0);
+ // Wait a little so to simulate the main thread doing something on its main loop...
+ ms_sleep(500); // 500 milliseconds
+ // Verifies that the responder has *not* been called yet in the meantime
+ ensure("LLImageDecodeThread: responder creation failed", done == false);
+ // Ask the thread to update: that means tells the queue to check itself and creates work requests
+ mThread->update(1);
+ // Wait till the thread has time to handle the work order (though it doesn't do much per work order...)
+ const U32 INCREMENT_TIME = 500; // 500 milliseconds
+ const U32 MAX_TIME = 20 * INCREMENT_TIME; // Do the loop 20 times max, i.e. wait 10 seconds but no more
+ U32 total_time = 0;
+ while ((done == false) && (total_time < MAX_TIME))
+ {
+ ms_sleep(INCREMENT_TIME);
+ total_time += INCREMENT_TIME;
+ }
+ // Verifies that the responder has now been called
+ ensure("LLImageDecodeThread: threaded work unit not processed", done == true);
+ }
+
+ // ---------------------------------------------------------------------------------------
+ // Test the LLImageDecodeThread::ImageRequest interface
+ // ---------------------------------------------------------------------------------------
+
+ template<> template<>
+ void imagerequest_object_t::test<1>()
+ {
+ // Test that we start with a correct request at creation
+ ensure("LLImageDecodeThread::ImageRequest::ImageRequest() constructor test failed", mRequest->tut_isOK());
+ bool res = mRequest->processRequest();
+ // Verifies that we processed the request successfully
+ ensure("LLImageDecodeThread::ImageRequest::processRequest() processing request test failed", res == true);
+ // Check that we can call the finishing call safely
+ try {
+ mRequest->finishRequest(false);
+ } catch (...) {
+ fail("LLImageDecodeThread::ImageRequest::finishRequest() test failed");
+ }
+ }
+}