Delay image size checking until someone asks for it 64/27364/5
authorKimmo Hoikka <kimmo.hoikka@samsung.com>
Thu, 11 Sep 2014 16:21:38 +0000 (17:21 +0100)
committerKimmo Hoikka <kimmo.hoikka@samsung.com>
Mon, 22 Sep 2014 15:51:56 +0000 (08:51 -0700)
[Problem]
[Cause]
[Solution]

Change-Id: Ib20878cf15484816ada50e90b53249c169358793

dali/internal/event/images/image-factory.cpp
dali/internal/event/images/image-factory.h
dali/internal/event/images/image-impl.cpp
dali/internal/event/images/image-impl.h

index 2bb660f969965a083797921a32bd2d2ce797489a..c7e8f822aca5b3f993e571103a77784f39007442 100644 (file)
@@ -20,6 +20,7 @@
 
 // INTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
+#include <dali/integration-api/platform-abstraction.h>
 #include <dali/public-api/common/dali-common.h>
 #include <dali/public-api/common/constants.h>
 #include <dali/internal/event/common/thread-local-storage.h>
@@ -182,7 +183,7 @@ ResourceTicketPtr ImageFactory::Reload( Request* request )
   return ticket;
 }
 
-const std::string& ImageFactory::GetRequestPath( const Request* request ) const
+const std::string& ImageFactory::GetRequestPath( const ImageFactoryCache::RequestPtr& request ) const
 {
   if( request )
   {
@@ -192,11 +193,8 @@ const std::string& ImageFactory::GetRequestPath( const Request* request ) const
   return String::EMPTY;
 }
 
-const ImageAttributes& ImageFactory::GetActualAttributes( ResourceId resourceId ) const
+const ImageAttributes& ImageFactory::GetActualAttributes( const ResourceTicketPtr& ticket ) const
 {
-  DALI_ASSERT_DEBUG( resourceId );
-
-  ResourceTicketPtr ticket = mResourceClient.RequestResourceTicket( resourceId );
   if( ticket )
   {
     DALI_ASSERT_DEBUG( ticket->GetTypePath().type->id == ResourceBitmap      ||
@@ -205,12 +203,10 @@ const ImageAttributes& ImageFactory::GetActualAttributes( ResourceId resourceId
     const ImageAttributes& attrib = static_cast<ImageTicket*>(ticket.Get())->GetAttributes();
     return attrib;
   }
-
-  DALI_ASSERT_DEBUG( 0 && "Resource no longer exists in cache" );
   return ImageAttributes::DEFAULT_ATTRIBUTES;
 }
 
-const ImageAttributes& ImageFactory::GetRequestAttributes( const Request* request ) const
+const ImageAttributes& ImageFactory::GetRequestAttributes( const ImageFactoryCache::RequestPtr& request ) const
 {
   if( request && request->attributes )
   {
@@ -220,6 +216,21 @@ const ImageAttributes& ImageFactory::GetRequestAttributes( const Request* reques
   return ImageAttributes::DEFAULT_ATTRIBUTES;
 }
 
+void ImageFactory::GetImageSize( const ImageFactoryCache::RequestPtr& request, const ResourceTicketPtr& ticket, Size& size )
+{
+  if( ticket && ticket->GetLoadingState() != ResourceLoading )
+  {
+    // it is loaded so get the size from actual attributes
+    size = GetActualAttributes( ticket ).GetSize();
+  }
+  else
+  {
+    // not loaded so either loading or not yet loaded, ask platform abstraction
+    Integration::PlatformAbstraction& platformAbstraction = Internal::ThreadLocalStorage::Get().GetPlatformAbstraction();
+    platformAbstraction.GetClosestImageSize( GetRequestPath( request ), GetRequestAttributes( request ), size );
+  }
+}
+
 void ImageFactory::ReleaseTicket( ResourceTicket* ticket )
 {
   ResourceTicketPtr ticketPtr(ticket);
index a0dc8f568e539aaf54ef2abad9843f2d35856116..5232ccf71482f9c8364265b5f2cef2099fbbe061 100644 (file)
@@ -85,27 +85,36 @@ public:
 
   /**
    * Get resource path used in request.
-   * @param [in] req request pointer
+   * @param [in] request of the image
    * @return     resource path
    */
-  const std::string& GetRequestPath( const ImageFactoryCache::Request* req ) const;
+  const std::string& GetRequestPath( const ImageFactoryCache::RequestPtr& request ) const;
 
   /**
    * Get ImageAttributes for an already requested image resource.
    * @pre id should mark an existing Resource (Ticket is alive)
-   * @param [in] id resource id
+   * @param [in] ticket of the image
    * @return     ImageAttributes used for request.
    * @throws     Throws exception if id is not valid.
    */
-  const ImageAttributes& GetActualAttributes( ResourceId id ) const;
+  const ImageAttributes& GetActualAttributes( const ResourceTicketPtr& ticket ) const;
 
   /**
    * Get ImageAttributes used for request.
    * @pre req must point to a Request registered with ImageFactory
-   * @param [in] req request pointer
+   * @param [in] request of the image
    * @return     ImageAttributes used for request.
    */
-  const ImageAttributes& GetRequestAttributes( const ImageFactoryCache::Request* req ) const;
+  const ImageAttributes& GetRequestAttributes( const ImageFactoryCache::RequestPtr& request ) const;
+
+  /**
+   * Retrieve the size of an image. This is either the application requested size or
+   * the actual (full size) that is or will be loaded.
+   * @param[in] request of the image
+   * @param[in] ticket of the image
+   * @param[out] size of the image
+   */
+  void GetImageSize( const ImageFactoryCache::RequestPtr& request, const ResourceTicketPtr& ticket, Size& size );
 
   /**
    * Prevents releasing and reloading image resources in the same frame
index 2db8661284e286df596086b9cfdfcc60c5f49345..44579466ff28498ed471afd206a1d9ec8207befe 100644 (file)
@@ -22,7 +22,6 @@
 #include <dali/public-api/common/dali-common.h>
 #include <dali/public-api/object/type-registry.h>
 
-#include <dali/integration-api/platform-abstraction.h>
 #include <dali/integration-api/debug.h>
 #include <dali/internal/event/resources/resource-ticket.h>
 #include <dali/internal/event/common/thread-local-storage.h>
@@ -52,15 +51,16 @@ TypeRegistration mType( typeid(Dali::Image), typeid(Dali::BaseHandle), CreateIma
 
 Dali::SignalConnectorType signalConnector1(mType, Dali::Image::SIGNAL_IMAGE_LOADING_FINISHED,    &Image::DoConnectSignal);
 Dali::SignalConnectorType signalConnector2(mType, Dali::Image::SIGNAL_IMAGE_UPLOADED,            &Image::DoConnectSignal);
+
 }
 
 Image::Image( LoadPolicy loadPol, ReleasePolicy releasePol )
-: mWidth(0),
+: mImageFactory(ThreadLocalStorage::Get().GetImageFactory()),
+  mWidth(0),
   mHeight(0),
-  mLoadPolicy(loadPol),
-  mReleasePolicy(releasePol),
   mConnectionCount(0),
-  mImageFactory(ThreadLocalStorage::Get().GetImageFactory())
+  mLoadPolicy(loadPol),
+  mReleasePolicy(releasePol)
 {
 }
 
@@ -83,34 +83,14 @@ ImagePtr Image::New( const std::string& filename, const Dali::ImageAttributes& a
     image = new Image( loadPol, releasePol );
     image->Initialize();
 
-    // if the attributes have a size, use that as natural size, otherwise get the size
-    const unsigned int width = attributes.GetWidth();
-    const unsigned int height = attributes.GetHeight();
-    // if one is zero, then there is some scaling calculation so we have to ask the loading logic what it will do
-    if( width > 0 && height > 0 )
-    {
-      image->mWidth  = width;
-      image->mHeight = height;
-      image->mRequest = image->mImageFactory.RegisterRequest( filename, &attributes );
-    }
-    else
-    {
-      // TODO do this query only if/when its needed (if someone is calling GetSize)
-      Integration::PlatformAbstraction& platformAbstraction = Internal::ThreadLocalStorage::Get().GetPlatformAbstraction();
-      Vector2 closestSize;
-      platformAbstraction.GetClosestImageSize( filename, attributes, closestSize );
-      image->mWidth = closestSize.width;
-      image->mHeight = closestSize.height;
-      // need a new request object as we will request for the closest size
-      Dali::ImageAttributes newAttributes( attributes );
-      newAttributes.SetSize( closestSize );
-      image->mRequest = image->mImageFactory.RegisterRequest( filename, &newAttributes );
-    }
+    // consider the requested size as natural size, 0 means we don't (yet) know it
+    image->mWidth = attributes.GetWidth();
+    image->mHeight = attributes.GetHeight();
+    image->mRequest = image->mImageFactory.RegisterRequest( filename, &attributes );
 
     if( Dali::Image::Immediate == loadPol )
     {
-      // Trigger loading of the image on a seperate resource thread as soon as it
-      // can be scheduled:
+      // Trigger loading of the image on a as soon as it can be done
       image->mTicket = image->mImageFactory.Load( image->mRequest.Get() );
       image->mTicket->AddObserver( *image );
     }
@@ -189,17 +169,17 @@ const Dali::ImageAttributes& Image::GetAttributes() const
 {
   if( mTicket )
   {
-    return mImageFactory.GetActualAttributes( mTicket->GetId() );
+    return mImageFactory.GetActualAttributes( mTicket );
   }
   else
   {
-    return mImageFactory.GetRequestAttributes( mRequest.Get() );
+    return mImageFactory.GetRequestAttributes( mRequest );
   }
 }
 
 const std::string& Image::GetFilename() const
 {
-  return mImageFactory.GetRequestPath( mRequest.Get() );
+  return mImageFactory.GetRequestPath( mRequest );
 }
 
 void Image::Reload()
@@ -238,17 +218,36 @@ void Image::ResourceSavingFailed( const ResourceTicket& ticket )
 
 unsigned int Image::GetWidth() const
 {
+  // if width is 0, it means we've not yet loaded the image
+  if( 0u == mWidth )
+  {
+    Size size;
+    mImageFactory.GetImageSize( mRequest, mTicket, size );
+    mWidth = size.width;
+  }
   return mWidth;
 }
 
 unsigned int Image::GetHeight() const
 {
+  if( 0u == mHeight )
+  {
+    Size size;
+    mImageFactory.GetImageSize( mRequest, mTicket, size );
+    mHeight = size.height;
+  }
   return mHeight;
 }
 
 Vector2 Image::GetNaturalSize() const
 {
   Vector2 naturalSize(mWidth, mHeight);
+  if( 0u == mWidth || 0u == mHeight )
+  {
+    mImageFactory.GetImageSize( mRequest, mTicket, naturalSize );
+    mWidth = naturalSize.width;
+    mHeight = naturalSize.height;
+  }
   return naturalSize;
 }
 
@@ -312,7 +311,7 @@ void Image::SetTicket( ResourceTicket* ticket )
   }
 }
 
-bool Image::IsNinePatchFileName( std::string filename )
+bool Image::IsNinePatchFileName( const std::string& filename )
 {
   bool match = false;
 
index 45e72ea52cd0034c133f5fe0ccabc45a3a2ebf47..bd7b3263644185ecfd5d88cdfda990587c68ad4a 100644 (file)
@@ -232,6 +232,7 @@ public:
   virtual void Disconnect();
 
 protected:
+
   /**
    * Second stage initialization
    */
@@ -251,22 +252,25 @@ private:
    * @param[in] filename The filename to check
    * @return true if it is a 9 patch image
    */
-  static bool IsNinePatchFileName( std::string filename );
+  static bool IsNinePatchFileName( const std::string& filename );
 
+protected: //@TODO these should not be protected
 
-protected:
-  unsigned int mWidth;
-  unsigned int mHeight;
+  ImageFactory&  mImageFactory;
+
+  ImageFactoryCache::RequestPtr mRequest; ///< contains the initially requested attributes for image. Request is reissued when memory was released.
+  ResourceTicketPtr mTicket;              ///< smart pointer to the ticket object that gets completed when load finishes
 
-  ResourceTicketPtr mTicket;
-  ImageFactoryCache::RequestPtr mRequest;         ///< contains the initially requested attributes for image. Request is reissued when memory was released.
-  LoadPolicy     mLoadPolicy;
-  ReleasePolicy  mReleasePolicy;
+  mutable unsigned int mWidth;     ///< natural width of the image, needs to be mutable for lazy resolving and as the API for GetWidth is const
+  mutable unsigned int mHeight;    ///< natural height of the image, needs to be mutable for lazy resolving and as the API for GetHeight is const
 
   unsigned int   mConnectionCount; ///< number of on-stage objects using this image
-  ImageFactory&  mImageFactory;
+
+  LoadPolicy     mLoadPolicy:2;    ///< 2 bits is enough space
+  ReleasePolicy  mReleasePolicy:2; ///< 2 bits is enough space
 
 private:
+
   Dali::Image::ImageSignalV2 mLoadingFinishedV2;
   Dali::Image::ImageSignalV2 mUploadedV2;