ResourceBitmapRequester::ResourceBitmapRequester( ResourceLoader& resourceLoader )
: ResourceRequesterBase( resourceLoader )
{
- mThreadImage = new ResourceThreadImage( resourceLoader );
+ mThreadImageLocal = new ResourceThreadImage( resourceLoader, false );
+ mThreadImageRemote = new ResourceThreadImage( resourceLoader, true );
mThreadDistanceField = new ResourceThreadDistanceField( resourceLoader );
}
ResourceBitmapRequester::~ResourceBitmapRequester()
{
- delete mThreadImage;
+ delete mThreadImageLocal;
+ delete mThreadImageRemote;
delete mThreadDistanceField;
}
void ResourceBitmapRequester::Pause()
{
- mThreadImage->Pause();
+ mThreadImageLocal->Pause();
+ mThreadImageRemote->Pause();
mThreadDistanceField->Pause();
}
void ResourceBitmapRequester::Resume()
{
- mThreadImage->Resume();
+ mThreadImageLocal->Resume();
+ mThreadImageRemote->Resume();
mThreadDistanceField->Resume();
}
BitmapResourceType* resType = static_cast<BitmapResourceType*>(request.GetType());
if( resType )
{
- // Work out if the resource is in memory or a file:
- const ResourceThreadBase::RequestType requestType = request.GetResource().Get() ? ResourceThreadBase::RequestDecode : ResourceThreadBase::RequestLoad;
-
// Work out what thread to decode / load the image on:
- ResourceThreadBase* const imageThread = mThreadImage;
+ ResourceThreadBase* const localImageThread = mThreadImageLocal;
+ ResourceThreadBase* const remoteImageThread = mThreadImageRemote;
ResourceThreadBase* const distanceFieldThread = mThreadDistanceField ;
- ResourceThreadBase* const workerThread = ( !resType->imageAttributes.IsDistanceField() ) ? imageThread : distanceFieldThread;
+ ResourceThreadBase* workerThread;
+
+ // Work out if the resource is in memory, a file, or in a remote server:
+ ResourceThreadBase::RequestType requestType;
+ if( request.GetResource().Get() )
+ {
+ requestType = ResourceThreadBase::RequestDecode;
+ workerThread = localImageThread;
+ }
+ else
+ {
+ const std::string& resourcePath = request.GetPath();
+ if( resourcePath.length() > 7 && strncasecmp( resourcePath.c_str(), "http://", 7 ) == 0 )
+ {
+ requestType = ResourceThreadBase::RequestDownload;
+ workerThread = remoteImageThread;
+ }
+ else
+ {
+ requestType = ResourceThreadBase::RequestLoad;
+ workerThread = localImageThread;
+ }
+ }
+
+ if( resType->imageAttributes.IsDistanceField() )
+ {
+ workerThread = distanceFieldThread;
+ }
// Dispatch the job to the right thread:
workerThread->AddRequest( request, requestType );
void ResourceBitmapRequester::CancelLoad(Integration::ResourceId id, Integration::ResourceTypeId typeId)
{
- mThreadImage->CancelRequest(id);
+ mThreadImageLocal->CancelRequest(id);
+ mThreadImageRemote->CancelRequest(id);
mThreadDistanceField->CancelRequest(id);
}
#include <dali/integration-api/debug.h>
#include <dali/integration-api/resource-cache.h>
#include <dali/integration-api/resource-types.h>
+#include <curl/curl.h>
#include "portable/file-closer.h"
#include "image-loaders/image-loader.h"
namespace SlpPlatform
{
-ResourceThreadImage::ResourceThreadImage(ResourceLoader& resourceLoader)
+ResourceThreadImage::ResourceThreadImage(ResourceLoader& resourceLoader, bool forRemoteImage)
: ResourceThreadBase(resourceLoader)
{
}
DALI_LOG_TRACE_METHOD( mLogFilter );
DALI_LOG_INFO( mLogFilter, Debug::Verbose, "%s(%s)\n", __FUNCTION__, request.GetPath().c_str() );
+ LoadImageFromLocalFile(request);
+}
+
+void ResourceThreadImage::Download(const ResourceRequest& request)
+{
+ bool succeeded;
+
+ DALI_LOG_TRACE_METHOD( mLogFilter );
+ DALI_LOG_INFO( mLogFilter, Debug::Verbose, "%s(%s)\n", __FUNCTION__, request.GetPath().c_str() );
+
+ Dali::Vector<uint8_t> dataBuffer;
+ size_t dataSize;
+ succeeded = DownloadRemoteImageIntoMemory( request, dataBuffer, dataSize );
+ if( succeeded )
+ {
+ DecodeImageFromMemory(static_cast<void*>(&dataBuffer[0]), dataBuffer.Size(), request);
+ }
+}
+
+void ResourceThreadImage::Decode(const ResourceRequest& request)
+{
+ DALI_LOG_TRACE_METHOD( mLogFilter );
+ DALI_LOG_INFO(mLogFilter, Debug::Verbose, "%s(%s)\n", __FUNCTION__, request.GetPath().c_str());
+
+ // Get the blob of binary data that we need to decode:
+ DALI_ASSERT_DEBUG( request.GetResource() );
+
+ DALI_ASSERT_DEBUG( 0 != dynamic_cast<Dali::RefCountedVector<uint8_t>*>( request.GetResource().Get() ) && "Only blobs of binary data can be decoded." );
+ Dali::RefCountedVector<uint8_t>* const encodedBlob = reinterpret_cast<Dali::RefCountedVector<uint8_t>*>( request.GetResource().Get() );
+
+ if( 0 != encodedBlob )
+ {
+ const size_t blobSize = encodedBlob->GetVector().Size();
+ uint8_t * const blobBytes = &(encodedBlob->GetVector()[0]);
+ DecodeImageFromMemory(blobBytes, blobSize, request);
+ }
+ else
+ {
+ FailedResource resource(request.GetId(), FailureUnknown);
+ mResourceLoader.AddFailedLoad(resource);
+ }
+}
+
+void ResourceThreadImage::Save(const Integration::ResourceRequest& request)
+{
+ DALI_LOG_TRACE_METHOD( mLogFilter );
+ DALI_ASSERT_DEBUG( request.GetType()->id == ResourceBitmap );
+ DALI_LOG_WARNING( "Image saving not supported on background resource threads." );
+}
+
+bool ResourceThreadImage::DownloadRemoteImageIntoMemory(const Integration::ResourceRequest& request, Dali::Vector<uint8_t>& dataBuffer, size_t& dataSize)
+{
+ bool succeeded = true;
+ CURLcode cresult;
+
+ CURL* curl_handle = curl_easy_init();
+ curl_easy_setopt( curl_handle, CURLOPT_VERBOSE, 0 );
+ curl_easy_setopt( curl_handle, CURLOPT_URL, request.GetPath().c_str() );
+ curl_easy_setopt( curl_handle, CURLOPT_FAILONERROR, 1 );
+
+ // Download header first to get data size
+ char* headerBytes = NULL;
+ size_t headerSize = 0;
+ FILE* header_fp = open_memstream( &headerBytes, &headerSize );
+ double size;
+
+ if( NULL != header_fp)
+ {
+ curl_easy_setopt( curl_handle, CURLOPT_HEADER, 1 );
+ curl_easy_setopt( curl_handle, CURLOPT_NOBODY, 1 );
+ curl_easy_setopt( curl_handle, CURLOPT_WRITEDATA, header_fp );
+
+ cresult = curl_easy_perform( curl_handle );
+ if( cresult == CURLE_OK )
+ {
+ curl_easy_getinfo( curl_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &size );
+ }
+ else
+ {
+ DALI_LOG_WARNING( "Failed to download file to load \"%s\"\n", request.GetPath().c_str() );
+ succeeded = false;
+ }
+
+ fclose( header_fp );
+ }
+ else
+ {
+ succeeded = false;
+ }
+
+ if( NULL != headerBytes )
+ {
+ free( headerBytes );
+ }
+
+ if( succeeded )
+ {
+ // Download file data
+ dataSize = static_cast<size_t>( size );
+ dataBuffer.Reserve( dataSize );
+ dataBuffer.Resize( dataSize );
+
+ Dali::Internal::Platform::FileCloser fileCloser( static_cast<void*>(&dataBuffer[0]), dataSize, "wb" );
+ FILE* data_fp = fileCloser.GetFile();
+ if( NULL != data_fp )
+ {
+ curl_easy_setopt( curl_handle, CURLOPT_HEADER, 0 );
+ curl_easy_setopt( curl_handle, CURLOPT_NOBODY, 0 );
+ curl_easy_setopt( curl_handle, CURLOPT_WRITEDATA, data_fp );
+
+ cresult = curl_easy_perform( curl_handle );
+ if( CURLE_OK != cresult )
+ {
+ DALI_LOG_WARNING( "Failed to download file to load \"%s\"\n", request.GetPath().c_str() );
+ succeeded = false;
+ }
+ }
+ else
+ {
+ succeeded = false;
+ }
+ }
+
+ curl_easy_cleanup( curl_handle );
+
+ if( !succeeded )
+ {
+ FailedResource resource(request.GetId(), FailureUnknown);
+ mResourceLoader.AddFailedLoad(resource);
+ }
+
+ return succeeded;
+}
+
+void ResourceThreadImage::LoadImageFromLocalFile(const Integration::ResourceRequest& request)
+{
bool fileNotFound = false;
BitmapPtr bitmap = 0;
bool result = false;
Dali::Internal::Platform::FileCloser fileCloser( request.GetPath().c_str(), "rb" );
FILE * const fp = fileCloser.GetFile();
- if( fp != NULL )
+ if( NULL != fp )
{
result = ImageLoader::ConvertStreamToBitmap( *request.GetType(), request.GetPath(), fp, *this, bitmap );
// Last chance to interrupt a cancelled load before it is reported back to clients
}
}
-void ResourceThreadImage::Decode(const ResourceRequest& request)
+void ResourceThreadImage::DecodeImageFromMemory(void* blobBytes, size_t blobSize, const Integration::ResourceRequest& request)
{
- DALI_LOG_TRACE_METHOD( mLogFilter );
- DALI_LOG_INFO(mLogFilter, Debug::Verbose, "%s(%s)\n", __FUNCTION__, request.GetPath().c_str());
-
BitmapPtr bitmap = 0;
- // Get the blob of binary data that we need to decode:
- DALI_ASSERT_DEBUG( request.GetResource() );
-
- DALI_ASSERT_DEBUG( 0 != dynamic_cast<Dali::RefCountedVector<uint8_t>*>( request.GetResource().Get() ) && "Only blobs of binary data can be decoded." );
- Dali::RefCountedVector<uint8_t>* const encodedBlob = reinterpret_cast<Dali::RefCountedVector<uint8_t>*>( request.GetResource().Get() );
+ DALI_ASSERT_DEBUG( blobSize > 0U );
+ DALI_ASSERT_DEBUG( blobBytes != 0U );
- if( encodedBlob != 0 )
+ if( blobBytes != 0 && blobSize > 0U )
{
- const size_t blobSize = encodedBlob->GetVector().Size();
- uint8_t * const blobBytes = &(encodedBlob->GetVector()[0]);
- DALI_ASSERT_DEBUG( blobSize > 0U );
- DALI_ASSERT_DEBUG( blobBytes != 0U );
-
- if( blobBytes != 0 && blobSize > 0U )
+ // Open a file handle on the memory buffer:
+ Dali::Internal::Platform::FileCloser fileCloser( blobBytes, blobSize, "rb" );
+ FILE * const fp = fileCloser.GetFile();
+ if ( NULL != fp )
{
- // Open a file handle on the memory buffer:
- Dali::Internal::Platform::FileCloser fileCloser( blobBytes, blobSize, "rb" );
- FILE * const fp = fileCloser.GetFile();
- if ( fp != NULL )
+ bool result = ImageLoader::ConvertStreamToBitmap( *request.GetType(), request.GetPath(), fp, StubbedResourceLoadingClient(), bitmap );
+ if ( result && bitmap )
+ {
+ // Construct LoadedResource and ResourcePointer for image data
+ LoadedResource resource( request.GetId(), request.GetType()->id, ResourcePointer( bitmap.Get() ) );
+ // Queue the loaded resource
+ mResourceLoader.AddLoadedResource( resource );
+ }
+ else
{
- bool result = ImageLoader::ConvertStreamToBitmap( *request.GetType(), request.GetPath(), fp, StubbedResourceLoadingClient(), bitmap );
-
- if ( result && bitmap )
- {
- // Construct LoadedResource and ResourcePointer for image data
- LoadedResource resource( request.GetId(), request.GetType()->id, ResourcePointer( bitmap.Get() ) );
- // Queue the loaded resource
- mResourceLoader.AddLoadedResource( resource );
- }
- else
- {
- DALI_LOG_WARNING( "Unable to decode bitmap supplied as in-memory blob.\n" );
- }
+ DALI_LOG_WARNING( "Unable to decode bitmap supplied as in-memory blob.\n" );
}
}
}
}
}
-void ResourceThreadImage::Save(const Integration::ResourceRequest& request)
-{
- DALI_LOG_TRACE_METHOD( mLogFilter );
- DALI_ASSERT_DEBUG( request.GetType()->id == ResourceBitmap );
- DALI_LOG_WARNING( "Image saving not supported on background resource threads." );
-}
-
-
} // namespace SlpPlatform
} // namespace Dali