Merge "Support Asynchronous Loading of Animated Image" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / texture-manager-impl.h
1 #ifndef DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_H
2 #define DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_H
3
4 /*
5  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 // EXTERNAL INCLUDES
21 #include <deque>
22 #include <functional>
23 #include <string>
24 #include <memory>
25 #include <dali/public-api/common/dali-vector.h>
26 #include <dali/public-api/object/ref-object.h>
27 #include <dali/public-api/rendering/texture-set.h>
28 #include <dali/devel-api/common/owner-container.h>
29 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
30
31 // INTERNAL INCLUDES
32 #include <dali-toolkit/devel-api/image-loader/async-image-loader-devel.h>
33 #include <dali-toolkit/devel-api/image-loader/image-atlas.h>
34 #include <dali-toolkit/public-api/image-loader/async-image-loader.h>
35 #include <dali-toolkit/internal/visuals/texture-upload-observer.h>
36 #include <dali-toolkit/internal/visuals/visual-url.h>
37 #include <dali-toolkit/internal/helpers/round-robin-container-view.h>
38 #include <dali-toolkit/internal/image-loader/async-image-loader-impl.h>
39
40
41 namespace Dali
42 {
43
44 namespace Toolkit
45 {
46
47 namespace Internal
48 {
49 class ImageAtlasManager;
50 typedef IntrusivePtr<ImageAtlasManager> ImageAtlasManagerPtr;
51
52 /**
53  * The TextureManager provides a common Image loading API for Visuals.
54  *
55  * The TextureManager is responsible for providing sync, async, atlased and non-atlased loads.
56  * Texture caching is provided and performed when possible.
57  * Broken Images are automatically provided on load failure.
58  */
59 class TextureManager : public ConnectionTracker
60 {
61 public:
62
63   typedef int32_t TextureId;       ///< The TextureId type. This is used as a handle to refer to a particular Texture.
64   static const int INVALID_TEXTURE_ID = -1; ///< Used to represent a null TextureId or error
65
66   /**
67    * Whether the texture should be atlased or uploaded into it's own GPU texture
68    */
69   enum UseAtlas
70   {
71     NO_ATLAS,
72     USE_ATLAS
73   };
74
75   /**
76    * Whether the pixel data should be kept in TextureManager, returned with pixelBuffer or uploaded for rendering
77    */
78   enum StorageType
79   {
80     KEEP_PIXEL_BUFFER,
81     RETURN_PIXEL_BUFFER,
82     UPLOAD_TO_TEXTURE
83   };
84
85   /**
86    * Whether the texture should be loaded synchronously or asynchronously.
87    */
88   enum LoadType
89   {
90     LOAD_ASYNCHRONOUSLY,
91     LOAD_SYNCHRONOUSLY
92   };
93
94   /**
95    * @brief The LoadState Enumeration represents the current state of a particular Texture's life-cycle.
96    */
97   enum LoadState
98   {
99     NOT_STARTED,     ///< Default
100     LOADING,         ///< Loading has been started, but not finished.
101     LOAD_FINISHED,   ///< Loading has finished. (for CPU storage only)
102     WAITING_FOR_MASK,///< Loading has finished, but waiting for mask image
103     MASK_APPLYING,   ///< Loading has finished, Mask is applying
104     MASK_APPLIED,    ///< Loading has finished, Mask is applyied by GPU
105     UPLOADED,        ///< Uploaded and ready. (For GPU upload only)
106     CANCELLED,       ///< Removed before loading completed
107     LOAD_FAILED      ///< Async loading failed, e.g. connection problem
108   };
109
110   /**
111    * @brief Types of reloading policies
112    */
113   enum class ReloadPolicy
114   {
115     CACHED = 0,             ///< Loads cached texture if it exists.
116     FORCED                  ///< Forces reloading of texture.
117   };
118
119   /**
120    * @brief Whether to multiply alpha into color channels on load
121    */
122   enum class MultiplyOnLoad
123   {
124     LOAD_WITHOUT_MULTIPLY = 0, ///< Don't modify the image
125     MULTIPLY_ON_LOAD           ///< Multiply alpha into color channels on load
126   };
127
128 public:
129
130   struct MaskingData
131   {
132     MaskingData();
133     ~MaskingData() = default;
134
135     VisualUrl mAlphaMaskUrl;
136     TextureManager::TextureId mAlphaMaskId;
137     float mContentScaleFactor;
138     bool mCropToMask;
139   };
140   using MaskingDataPointer = std::unique_ptr<MaskingData>;
141
142
143   /**
144    * Class to provide lifecycle event on destruction of texture manager.
145    */
146   struct LifecycleObserver
147   {
148     /**
149      * Called shortly before the texture manager is destroyed.
150      */
151     virtual void TextureManagerDestroyed() = 0;
152   };
153
154   /**
155    * Constructor.
156    */
157   TextureManager();
158
159   /**
160    * Destructor.
161    */
162   ~TextureManager();
163
164   // TextureManager Main API:
165
166   /**
167    * @brief Requests an frame of animated image load.
168    *
169    * The parameters are used to specify how the animated image is loaded.
170    * The observer has the LoadComplete method called when the load is ready.
171    *
172    * @param[in] animatedImageLoading  The AnimatedImageLoading that contain the animated image information
173    * @param[in] frameIndex            The frame index to load.
174    * @param[in] samplingMode          The SamplingMode to use
175    * @param[in] synchronousLoading    true if the frame should be loaded synchronously
176    * @param[out] textureId            The textureId of the frame
177    * @param[in] wrapModeU             Horizontal Wrap mode
178    * @param[in] wrapModeV             Vertical Wrap mode
179    * @param[in] textureObserver       The client object should inherit from this and provide the "UploadCompleted" virtual.
180    *                                  This is called when an image load completes (or fails).
181    *
182    * @return                          The texture set containing the frame of animated image, or empty if still loading.
183    */
184
185   TextureSet LoadAnimatedImageTexture( Dali::AnimatedImageLoading animatedImageLoading,
186                                        uint32_t frameIndex,
187                                        Dali::SamplingMode::Type samplingMode,
188                                        bool synchronousLoading,
189                                        TextureManager::TextureId& textureId,
190                                        Dali::WrapMode::Type wrapModeU, Dali::WrapMode::Type wrapModeV,
191                                        TextureUploadObserver* textureObserver );
192
193   /**
194    * @brief Requests an image load of the given URL to get PixelBuffer.
195    *
196    * The parameters are used to specify how the image is loaded.
197    * The observer has the LoadComplete method called when the load is ready.
198    *
199    * @param[in] url                   The URL of the image to load
200    * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
201    * @param[in] fittingMode           The FittingMode to use
202    * @param[in] samplingMode          The SamplingMode to use
203    * @param[in] synchronousLoading    true if the URL should be loaded synchronously
204    * @param[in] textureObserver       The client object should inherit from this and provide the "UploadCompleted" virtual.
205    *                                  This is called when an image load completes (or fails).
206    * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
207    * @param[in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the
208    *                                  image has no alpha channel
209    *
210    * @return                          The pixel buffer containing the image, or empty if still loading.
211    */
212
213   Devel::PixelBuffer LoadPixelBuffer( const VisualUrl& url,
214                                       Dali::ImageDimensions desiredSize,
215                                       Dali::FittingMode::Type fittingMode,
216                                       Dali::SamplingMode::Type samplingMode,
217                                       bool synchronousLoading,
218                                       TextureUploadObserver* textureObserver,
219                                       bool orientationCorrection,
220                                       TextureManager::MultiplyOnLoad& preMultiplyOnLoad );
221
222
223   /**
224    * @brief Requests an image load of the given URL.
225    *
226    * The parameters are used to specify how the image is loaded.
227    * The observer has the UploadComplete method called when the load is ready.
228    *
229    * When the client has finished with the Texture, Remove() should be called.
230    *
231    * @param[in] url                   The URL of the image to load
232    * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
233    * @param[in] fittingMode           The FittingMode to use
234    * @param[in] samplingMode          The SamplingMode to use
235    * @param[in, out] maskInfo         Mask info structure
236    * @param[in] synchronousLoading    true if the URL should be loaded synchronously
237    * @param[out] textureId,           The textureId of the URL
238    * @param[out] textureRect          The rectangle within the texture atlas that this URL occupies,
239    *                                  this is the rectangle in normalized coordinates.
240    * @param[out] textureRectSize      The rectangle within the texture atlas that this URL occupies,
241    *                                  this is the same rectangle in pixels.
242    * @param[in,out] atlasingStatus    Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still
243    *                                  be loaded, and marked successful, but this will be set to false.
244    *                                  If atlasing succeeds, this will be set to true.
245    * @param[out] loadingStatus        The loading status of the texture
246    * @param[in] wrapModeU             Horizontal Wrap mode
247    * @param[in] wrapModeV             Vertical Wrap mode
248    * @param[in] textureObserver       The client object should inherit from this and provide the "UploadCompleted" virtual.
249    *                                  This is called when an image load completes (or fails).
250    * @param[in] atlasObserver         This is used if the texture is atlased, and will be called instead of
251    *                                  textureObserver.UploadCompleted
252    * @param[in] imageAtlasManager     The atlas manager to use for atlasing textures
253    * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
254    * @param[in] reloadPolicy          Forces a reload of the texture even if already cached
255    * @param[in,out] preMultiplyOnLoad True if the image color should be multiplied by it's alpha. Set to false if the
256    *                                  image has no alpha channel
257    *
258    * @return                          The texture set containing the image, or empty if still loading.
259    */
260
261   TextureSet LoadTexture( const VisualUrl&             url,
262                           Dali::ImageDimensions        desiredSize,
263                           Dali::FittingMode::Type      fittingMode,
264                           Dali::SamplingMode::Type     samplingMode,
265                           MaskingDataPointer&          maskInfo,
266                           bool                         synchronousLoading,
267                           TextureManager::TextureId&   textureId,
268                           Vector4&                     textureRect,
269                           Dali::ImageDimensions&       textureRectSize,
270                           bool&                        atlasingStatus,
271                           bool&                        loadingStatus,
272                           Dali::WrapMode::Type         wrapModeU,
273                           Dali::WrapMode::Type         wrapModeV,
274                           TextureUploadObserver*       textureObserver,
275                           AtlasUploadObserver*         atlasObserver,
276                           ImageAtlasManagerPtr         imageAtlasManager,
277                           bool                         orientationCorrection,
278                           TextureManager::ReloadPolicy reloadPolicy,
279                           MultiplyOnLoad&              preMultiplyOnLoad );
280
281   /**
282    * @brief Requests an image load of the given URL.
283    *
284    * The parameters are used to specify how the image is loaded.
285    * The observer has the UploadComplete method called when the load is ready.
286    *
287    * When the client has finished with the Texture, Remove() should be called.
288    *
289    * @param[in] url                   The URL of the image to load
290    * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
291    * @param[in] fittingMode           The FittingMode to use
292    * @param[in] samplingMode          The SamplingMode to use
293    * @param[in] useAtlasing           Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be loaded, and marked successful,
294    *                                  but "useAtlasing" will be set to false in the "UploadCompleted" callback from the TextureManagerUploadObserver.
295    * @param[in] observer              The client object should inherit from this and provide the "UploadCompleted" virtual.
296    *                                  This is called when an image load completes (or fails).
297    * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
298    * @param[in] reloadPolicy          Forces a reload of the texture even if already cached
299    * @param[in,out] preMultiplyOnLoad     True if the image color should be multiplied by it's alpha. Set to false if the image has no alpha channel
300    * @return                          A TextureId to use as a handle to reference this Texture
301    */
302   TextureId RequestLoad( const VisualUrl&                   url,
303                          const ImageDimensions              desiredSize,
304                          FittingMode::Type                  fittingMode,
305                          Dali::SamplingMode::Type           samplingMode,
306                          const UseAtlas                     useAtlasing,
307                          TextureUploadObserver*             observer,
308                          bool                               orientationCorrection,
309                          TextureManager::ReloadPolicy       reloadPolicy,
310                          MultiplyOnLoad&                    preMultiplyOnLoad );
311
312   /**
313    * @brief Requests an image load of the given URL, when the texture has
314    * have loaded, it will perform a blend with the image mask, and upload
315    * the blended texture.
316    *
317    * The parameters are used to specify how the image is loaded.
318    * The observer has the UploadComplete method called when the load is ready.
319    *
320    * When the client has finished with the Texture, Remove() should be called.
321    *
322    * @param[in] url                   The URL of the image to load
323    * @param[in] maskTextureId         The texture id of an image to mask this with
324    *                                  (can be INVALID if no masking required)
325    * @param[in] contentScale          The scale factor to apply to the image before masking
326    * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
327    * @param[in] fittingMode           The FittingMode to use
328    * @param[in] samplingMode          The SamplingMode to use
329    * @param[in] useAtlasing           Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still
330    *                                  be loaded, and marked successful,
331    *                                  but "useAtlasing" will be set to false in the "UploadCompleted" callback from
332    *                                  the TextureManagerUploadObserver.
333    * @param[in] cropToMask            Only used with masking, this will crop the scaled image to the mask size.
334    *                                  If false, then the mask will be scaled to fit the image before being applied.
335    * @param[in] observer              The client object should inherit from this and provide the "UploadCompleted"
336    *                                  virtual.
337    *                                  This is called when an image load completes (or fails).
338    * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
339    * @param[in] reloadPolicy          Forces a reload of the texture even if already cached
340    * @param[in] preMultiplyOnLoad     True if the image color should be multiplied by it's alpha. Set to false if the
341    *                                  image has no alpha channel
342    * @return                          A TextureId to use as a handle to reference this Texture
343    */
344   TextureId RequestLoad( const VisualUrl&                   url,
345                          TextureId                          maskTextureId,
346                          float                              contentScale,
347                          const ImageDimensions              desiredSize,
348                          FittingMode::Type                  fittingMode,
349                          Dali::SamplingMode::Type           samplingMode,
350                          const UseAtlas                     useAtlasing,
351                          bool                               cropToMask,
352                          TextureUploadObserver*             observer,
353                          bool                               orientationCorrection,
354                          TextureManager::ReloadPolicy       reloadPolicy,
355                          MultiplyOnLoad&                    preMultiplyOnLoad );
356
357   /**
358    * Requests a masking image to be loaded. This mask is not uploaded to GL,
359    * instead, it is stored in CPU memory, and can be used for CPU blending.
360    */
361   TextureId RequestMaskLoad( const VisualUrl& maskUrl );
362
363   /**
364    * @brief Remove a Texture from the TextureManager.
365    *
366    * Textures are cached and therefore only the removal of the last
367    * occurrence of a Texture will cause its removal internally.
368    *
369    * @param[in] textureId The ID of the Texture to remove.
370    * @param[in] textureObserver The texture observer.
371    */
372   void Remove( const TextureManager::TextureId textureId, TextureUploadObserver* textureObserver );
373
374   /**
375    * @brief Get the visualUrl associated with the texture id.
376    * @param[in] textureId The texture Id to get
377    * @return The visual Url associated with the texture id.
378    */
379   VisualUrl GetVisualUrl( TextureId textureId );
380
381   /**
382    * @brief Get the current state of a texture
383    * @param[in] textureId The texture id to query
384    * @return The loading state if the texture is valid, or NOT_STARTED if the textureId
385    * is not valid.
386    */
387   LoadState GetTextureState( TextureId textureId );
388
389   /**
390    * @brief Get the associated texture set if the texture id is valid
391    * @param[in] textureId The texture Id to look up
392    * @return the associated texture set, or an empty handle if textureId is not valid
393    */
394   TextureSet GetTextureSet( TextureId textureId );
395
396   /**
397    * Adds an external texture to the texture manager
398    * @param[in] texture The texture to add
399    * @return string containing the URL for the texture
400    */
401   std::string AddExternalTexture( TextureSet& texture );
402
403   /**
404    * Removes an external texture from texture manager
405    * @param[in] url The string containing the texture to remove
406    * @return handle to the texture
407    */
408   TextureSet RemoveExternalTexture( const std::string& url );
409
410   /**
411    * Add an observer to the object.
412    * @param[in] observer The observer to add.
413    */
414   void AddObserver( TextureManager::LifecycleObserver& observer );
415
416   /**
417    * Remove an observer from the object
418    * @pre The observer has already been added.
419    * @param[in] observer The observer to remove.
420    */
421   void RemoveObserver( TextureManager::LifecycleObserver& observer );
422
423   /**
424    * @brief Set an image to be used when a visual has failed to correctly render
425    * @param[in] brokenImageUrl The broken image url.
426    */
427   void SetBrokenImageUrl(const std::string& brokenImageUrl);
428
429 private:
430
431   /**
432    * @brief Requests an image load of the given URL, when the texture has
433    * have loaded, if there is a valid maskTextureId, it will perform a
434    * CPU blend with the mask, and upload the blend texture.
435    *
436    * The parameters are used to specify how the image is loaded.
437    * The observer has the UploadComplete method called when the load is ready.
438    *
439    * When the client has finished with the Texture, Remove() should be called.
440    *
441    * @param[in] url                   The URL of the image to load
442    * @param[in] maskTextureId         The texture id of an image to use as a mask. If no mask is required, then set
443    *                                  to INVALID_TEXTURE_ID
444    * @param[in] contentScale          The scaling factor to apply to the content when masking
445    * @param[in] desiredSize           The size the image is likely to appear at. This can be set to 0,0 for automatic
446    * @param[in] fittingMode           The FittingMode to use
447    * @param[in] samplingMode          The SamplingMode to use
448    * @param[in] useAtlasing           Set to USE_ATLAS to attempt atlasing. If atlasing fails, the image will still be
449    *                                  loaded, and marked successful, but "useAtlasing" will be set to false in the
450    *                                  "UploadCompleted" callback from the TextureManagerUploadObserver.
451    * @param[in] cropToMask            Whether to crop the target after masking, or scale the mask to the image before
452    *                                  masking.
453    * @param[in] storageType,          Whether the pixel data is stored in the cache or uploaded to the GPU
454    * @param[in] observer              The client object should inherit from this and provide the "UploadCompleted"
455    *                                  virtual.
456    *                                  This is called when an image load completes (or fails).
457    * @param[in] orientationCorrection Whether to rotate image to match embedded orientation data
458    * @param[in] reloadPolicy          Forces a reload of the texture even if already cached
459    * @param[in] preMultiplyOnLoad     True if the image color should be multiplied by it's alpha. Set to false if
460    *                                  there is no alpha
461    * @param[in] animatedImageLoading  The AnimatedImageLoading to load animated image
462    * @param[in] frameIndex            The frame index of a frame to be loaded frame
463    * @return                          A TextureId to use as a handle to reference this Texture
464    */
465   TextureId RequestLoadInternal(
466     const VisualUrl&                    url,
467     TextureId                           maskTextureId,
468     float                               contentScale,
469     const ImageDimensions               desiredSize,
470     FittingMode::Type                   fittingMode,
471     Dali::SamplingMode::Type            samplingMode,
472     UseAtlas                            useAtlas,
473     bool                                cropToMask,
474     StorageType                         storageType,
475     TextureUploadObserver*              observer,
476     bool                                orientationCorrection,
477     TextureManager::ReloadPolicy        reloadPolicy,
478     MultiplyOnLoad&                     preMultiplyOnLoad,
479     Dali::AnimatedImageLoading          animatedImageLoading,
480     uint32_t                            frameIndex );
481
482   /**
483    * @brief Get the current state of a texture
484    * @param[in] textureId The texture id to query
485    * @return The loading state if the texture is valid, or NOT_STARTED if the textureId
486    * is not valid.
487    */
488   LoadState GetTextureStateInternal( TextureId textureId );
489
490   typedef size_t TextureHash; ///< The type used to store the hash used for Texture caching.
491
492   // Structs:
493
494   /**
495    * @brief This struct is used to manage the life-cycle of Texture loading and caching.
496    */
497   struct TextureInfo
498   {
499     TextureInfo( TextureId textureId,
500                  TextureId maskTextureId,
501                  const VisualUrl& url,
502                  ImageDimensions desiredSize,
503                  float scaleFactor,
504                  FittingMode::Type fittingMode,
505                  Dali::SamplingMode::Type samplingMode,
506                  bool loadSynchronously,
507                  bool cropToMask,
508                  UseAtlas useAtlas,
509                  TextureManager::TextureHash hash,
510                  bool orientationCorrection,
511                  bool preMultiplyOnLoad,
512                  Dali::AnimatedImageLoading animatedImageLoading,
513                  uint32_t frameIndex )
514     : url( url ),
515       desiredSize( desiredSize ),
516       useSize( desiredSize ),
517       atlasRect( 0.0f, 0.0f, 1.0f, 1.0f ), // Full atlas rectangle
518       textureId( textureId ),
519       maskTextureId( maskTextureId ),
520       hash( hash ),
521       scaleFactor( scaleFactor ),
522       referenceCount( 1u ),
523       loadState( NOT_STARTED ),
524       fittingMode( fittingMode ),
525       samplingMode( samplingMode ),
526       storageType( UPLOAD_TO_TEXTURE ),
527       animatedImageLoading( animatedImageLoading ),
528       frameIndex( frameIndex ),
529       loadSynchronously( loadSynchronously ),
530       useAtlas( useAtlas ),
531       cropToMask( cropToMask ),
532       orientationCorrection( true ),
533       preMultiplyOnLoad( preMultiplyOnLoad ),
534       preMultiplied( false )
535     {
536     }
537
538     /**
539      * Container type used to store all observer clients of this Texture
540      */
541     typedef Dali::Vector< TextureUploadObserver* > ObserverListType;
542
543     ObserverListType observerList; ///< Container used to store all observer clients of this Texture
544     Toolkit::ImageAtlas atlas;     ///< The atlas this Texture lays within (if any)
545     Devel::PixelBuffer pixelBuffer;///< The PixelBuffer holding the image data (May be empty after upload)
546     TextureSet textureSet;         ///< The TextureSet holding the Texture
547     VisualUrl url;                 ///< The URL of the image
548     ImageDimensions desiredSize;   ///< The size requested
549     ImageDimensions useSize;       ///< The size used
550     Vector4 atlasRect;             ///< The atlas rect used if atlased
551     TextureId textureId;           ///< The TextureId associated with this Texture
552     TextureId maskTextureId;       ///< The mask TextureId to be applied on load
553     TextureManager::TextureHash hash; ///< The hash used to cache this Texture
554     float scaleFactor;             ///< The scale factor to apply to the Texture when masking
555     int16_t referenceCount;        ///< The reference count of clients using this Texture
556     LoadState loadState:4;         ///< The load state showing the load progress of the Texture
557     FittingMode::Type fittingMode:3; ///< The requested FittingMode
558     Dali::SamplingMode::Type samplingMode:3; ///< The requested SamplingMode
559     StorageType storageType:2;     ///< CPU storage / GPU upload;
560     Dali::AnimatedImageLoading animatedImageLoading; ///< AnimatedImageLoading that contains animated image information.
561     uint32_t frameIndex;           ///< frame index that be loaded, in case of animated image
562     bool loadSynchronously:1;      ///< True if synchronous loading was requested
563     UseAtlas useAtlas:2;           ///< USE_ATLAS if an atlas was requested.
564                                    ///< This is updated to false if atlas is not used
565     bool cropToMask:1;             ///< true if the image should be cropped to the mask size.
566     bool orientationCorrection:1;  ///< true if the image should be rotated to match exif orientation data
567     bool preMultiplyOnLoad:1;      ///< true if the image's color should be multiplied by it's alpha
568     bool preMultiplied:1;          ///< true if the image's color was multiplied by it's alpha
569   };
570
571   /**
572    * Structure to hold info about a texture load queued during NotifyObservers
573    */
574   struct LoadQueueElement
575   {
576     LoadQueueElement( TextureId textureId, TextureUploadObserver* observer )
577     : mTextureId( textureId ),
578       mObserver( observer )
579     {
580     }
581
582     TextureId mTextureId; ///< The texture id of the requested load.
583     TextureUploadObserver* mObserver; ///< Observer of texture load.
584   };
585
586   /**
587    * Struct to hold information about a requested Async load.
588    * This is used to look up a TextureManager::TextureId from the returned AsyncLoad Id.
589    */
590   struct AsyncLoadingInfo
591   {
592     AsyncLoadingInfo( TextureId textureId )
593     : textureId( textureId ),
594       loadId( 0 )
595     {
596     }
597
598     TextureId           textureId;   ///< The external Texture Id assigned to this load
599     uint32_t            loadId;      ///< The load Id used by the async loader to reference this load
600   };
601
602   // Private typedefs:
603
604   typedef std::deque<AsyncLoadingInfo>  AsyncLoadingInfoContainerType;  ///< The container type used to manage Asynchronous loads in progress
605   typedef std::vector<TextureInfo>      TextureInfoContainerType;       ///< The container type used to manage the life-cycle and caching of Textures
606
607   /**
608    * @brief Initiate a load or queue load if NotifyObservers is invoking callbacks
609    * @param[in] textureInfo The TextureInfo struct associated with the Texture
610    * @param[in] observer The observer wishing to observe the texture upload
611    */
612   void LoadOrQueueTexture( TextureInfo& textureInfo, TextureUploadObserver* observer );
613
614   /**
615    * @brief Queue a texture load to be subsequently handled by ProcessQueuedTextures.
616    * @param[in] textureInfo The TextureInfo struct associated with the Texture
617    * @param[in] observer The observer wishing to observe the texture upload
618    */
619   void QueueLoadTexture( TextureInfo& textureInfo, TextureUploadObserver* observer );
620
621   /**
622    * @brief Used internally to initiate a load.
623    * @param[in] textureInfo The TextureInfo struct associated with the Texture
624    * @param[in] observer The observer wishing to observe the texture upload
625    */
626   void LoadTexture( TextureInfo& textureInfo, TextureUploadObserver* observer );
627
628   /**
629    * @brief Initiate load of textures queued whilst NotifyObservers invoking callbacks.
630    */
631   void ProcessQueuedTextures();
632
633   /**
634    * Add the observer to the observer list
635    * @param[in] textureInfo The TextureInfo struct associated with the texture
636    * @param[in] observer The observer wishing to observe the texture upload
637    */
638   void ObserveTexture( TextureInfo & textureInfo, TextureUploadObserver* observer );
639
640   /**
641    * @brief This signal handler is called when the async local loader finishes loading.
642    * @param[in] id        This is the async image loaders Id
643    * @param[in] pixelBuffer The loaded image data
644    */
645   void AsyncLocalLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
646
647   /**
648    * @brief This signal handler is called when the async local loader finishes loading.
649    * @param[in] id        This is the async image loaders Id
650    * @param[in] pixelBuffer The loaded image data
651    */
652   void AsyncRemoteLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
653
654   /**
655    * Common method to handle loading completion
656    * @param[in] container The Async loading container
657    * @param[in] id        This is the async image loaders Id
658    * @param[in] pixelBuffer The loaded image data
659    */
660   void AsyncLoadComplete( AsyncLoadingInfoContainerType& container, uint32_t id, Devel::PixelBuffer pixelBuffer );
661
662   /**
663    * @brief Performs Post-Load steps including atlasing.
664    * @param[in] textureInfo The struct associated with this Texture
665    * @param[in] pixelBuffer The image pixelBuffer
666    * @return    True if successful
667    */
668   void PostLoad( TextureManager::TextureInfo& textureInfo, Devel::PixelBuffer& pixelBuffer );
669
670   /**
671    * Check if there is a texture waiting to be masked. If there
672    * is then apply this mask and upload it.
673    * @param[in] maskTextureInfo The texture info of the mask that has just loaded.
674    */
675   void CheckForWaitingTexture( TextureInfo& maskTextureInfo );
676
677   /**
678    * Apply the mask to the pixelBuffer.
679    * @param[in] textureInfo The information of texture to apply the mask to
680    * @param[in] maskTextureId The texture id of the mask.
681    */
682   void ApplyMask( TextureInfo& textureInfo, TextureId maskTextureId );
683
684   /**
685    * Upload the texture specified in pixelBuffer to the appropriate location
686    * @param[in] pixelBuffer The image data to upload
687    * @param[in] textureInfo The texture info containing the location to
688    * store the data to.
689    */
690   void UploadTexture( Devel::PixelBuffer& pixelBuffer, TextureInfo& textureInfo );
691
692   /**
693    * Mark the texture as complete, and inform observers
694    * @param[in] textureInfo The struct associated with this Texture
695    */
696   void UploadComplete( TextureInfo& textureInfo );
697
698   /**
699    * Notify the current observers that the texture upload is complete,
700    * then remove the observers from the list.
701    * @param[in] textureInfo The struct associated with this Texture
702    * @param[in] success If the pixel data was retrieved successfully and uploaded to GPU
703    */
704   void NotifyObservers( TextureInfo& textureInfo, bool success );
705
706   /**
707    * @brief Generates a new, unique TextureId
708    * @return A unique TextureId
709    */
710   TextureManager::TextureId GenerateUniqueTextureId();
711
712   /**
713    * @brief Used to lookup an index into the TextureInfoContainer from a TextureId
714    * @param[in] textureId The TextureId to look up
715    * @return              The cache index
716    */
717   int GetCacheIndexFromId( TextureId textureId );
718
719
720   /**
721    * @brief Generates a hash for caching based on the input parameters.
722    * Only applies size, fitting mode andsampling mode if the size is specified.
723    * Only applies maskTextureId if it isn't INVALID_TEXTURE_ID
724    * Always applies useAtlas.
725    * @param[in] url              The URL of the image to load
726    * @param[in] size             The image size
727    * @param[in] fittingMode      The FittingMode to use
728    * @param[in] samplingMode     The SamplingMode to use
729    * @param[in] useAtlas         True if atlased
730    * @param[in] maskTextureId    The masking texture id (or INVALID_TEXTURE_ID)
731    * @param[in] isAnimatedImage  The boolean value to know whether the request is for animated image or not
732    * @param[in] frameIndex       The frame index of a frame to be loaded frame
733    * @return                     A hash of the provided data for caching.
734    */
735   TextureHash GenerateHash( const std::string& url, const ImageDimensions size,
736                             const FittingMode::Type fittingMode,
737                             const Dali::SamplingMode::Type samplingMode, const UseAtlas useAtlas,
738                             TextureId maskTextureId, StorageType storageType, bool isAnimatedImage, uint32_t frameIndex );
739
740   /**
741    * @brief Looks up a cached texture by its hash.
742    * If found, the given parameters are used to check there is no hash-collision.
743    * @param[in] hash              The hash to look up
744    * @param[in] url               The URL of the image to load
745    * @param[in] size              The image size
746    * @param[in] fittingMode       The FittingMode to use
747    * @param[in] samplingMode      The SamplingMode to use
748    * @param[in] useAtlas          True if atlased
749    * @param[in] maskTextureId     Optional texture ID to use to mask this image
750    * @param[in] preMultiplyOnLoad if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha.
751    * @param[in] storageType       Whether the pixel data is stored in the cache, returned with PixelBuffer or uploaded to the GPU
752    * @param[in] isAnimatedImage   The boolean value to know whether the request is for animated image or not
753    * @param[in] frameIndex        The frame index of a frame to be loaded frame
754    * @return                      A TextureId of a cached Texture if found. Or INVALID_TEXTURE_ID if not found.
755    */
756   TextureManager::TextureId FindCachedTexture(
757     const TextureManager::TextureHash hash,
758     const std::string& url,
759     const ImageDimensions size,
760     const FittingMode::Type fittingMode,
761     const Dali::SamplingMode::Type samplingMode,
762     const bool useAtlas,
763     TextureId maskTextureId,
764     MultiplyOnLoad preMultiplyOnLoad,
765     StorageType storageType,
766     bool isAnimatedImage,
767     uint32_t frameIndex );
768
769 private:
770
771   /**
772    * @brief Helper class to keep the relation between AsyncImageLoader and corresponding LoadingInfo container
773    */
774   class AsyncLoadingHelper : public ConnectionTracker
775   {
776   public:
777     /**
778      * @brief Create an AsyncLoadingHelper.
779      * @param[in] textureManager Reference to the texture manager
780      */
781     AsyncLoadingHelper(TextureManager& textureManager);
782
783     /**
784      * @brief Load a new frame of animated image
785      * @param[in] textureId             TextureId to reference the texture that will be loaded
786      * @param[in] animatedImageLoading  The AnimatedImageLoading to load animated image
787      * @param[in] frameIndex            The frame index of a frame to be loaded frame
788      */
789     void LoadAnimatedImage( TextureId textureId,
790                             Dali::AnimatedImageLoading animatedImageLoading,
791                             uint32_t frameIndex);
792
793     /**
794      * @brief Load a new texture.
795      * @param[in] textureId             TextureId to reference the texture that will be loaded
796      * @param[in] url                   The URL of the image to load
797      * @param[in] desiredSize           The size the image is likely to appear at.
798      *                                  This can be set to 0,0 for automatic
799      * @param[in] fittingMode           The FittingMode to use
800      * @param[in] samplingMode          The SamplingMode to use
801      * @param[in] orientationCorrection Whether to use image metadata to rotate or flip the image,
802      *                                  e.g., from portrait to landscape
803      * @param[in] preMultiplyOnLoad     if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha or if the image need to be applied alpha mask.
804      */
805     void Load(TextureId textureId,
806               const VisualUrl& url,
807               ImageDimensions desiredSize,
808               FittingMode::Type fittingMode,
809               SamplingMode::Type samplingMode,
810               bool orientationCorrection,
811               DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad);
812
813     /**
814      * @brief Apply mask
815      * @param [in] id of the texture
816      * @param [in] pixelBuffer of the to be masked image
817      * @param [in] maskPixelBuffer of the mask image
818      * @param [in] contentScale The factor to scale the content
819      * @param [in] cropToMask Whether to crop the content to the mask size
820      * @param [in] preMultiplyOnLoad if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha.
821      */
822     void ApplyMask( TextureId textureId,
823                     Devel::PixelBuffer pixelBuffer,
824                     Devel::PixelBuffer maskPixelBuffer,
825                     float contentScale,
826                     bool cropToMask,
827                     DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad );
828
829   public:
830     AsyncLoadingHelper(const AsyncLoadingHelper&) = delete;
831     AsyncLoadingHelper& operator=(const AsyncLoadingHelper&) = delete;
832
833     AsyncLoadingHelper(AsyncLoadingHelper&& rhs);
834     AsyncLoadingHelper& operator=(AsyncLoadingHelper&&rhs) = delete;
835
836   private:
837     /**
838      * @brief Main constructor that used by all other constructors
839      */
840     AsyncLoadingHelper( Toolkit::AsyncImageLoader loader,
841                         TextureManager& textureManager,
842                         AsyncLoadingInfoContainerType&& loadingInfoContainer );
843
844     /**
845      * @brief Callback to be called when texture loading is complete, it passes the pixel buffer on to texture manager.
846      * @param[in] id          Loader id
847      * @param[in] pixelBuffer Image data
848      */
849     void AsyncLoadComplete( uint32_t id, Devel::PixelBuffer pixelBuffer );
850
851   private:
852     Toolkit::AsyncImageLoader     mLoader;
853     TextureManager&               mTextureManager;
854     AsyncLoadingInfoContainerType mLoadingInfoContainer;
855   };
856
857   struct ExternalTextureInfo
858   {
859     TextureId textureId;
860     TextureSet textureSet;
861   };
862
863 private:
864
865   /**
866    * Deleted copy constructor.
867    */
868   TextureManager( const TextureManager& ) = delete;
869
870   /**
871    * Deleted assignment operator.
872    */
873   TextureManager& operator=( const TextureManager& rhs ) = delete;
874
875   /**
876    * This is called by the TextureManagerUploadObserver when an observer is destroyed.
877    * We use the callback to know when to remove an observer from our notify list.
878    * @param[in] observer The observer that generated the callback
879    */
880   void ObserverDestroyed( TextureUploadObserver* observer );
881
882 private:  // Member Variables:
883
884   TextureInfoContainerType                      mTextureInfoContainer; ///< Used to manage the life-cycle and caching of Textures
885   RoundRobinContainerView< AsyncLoadingHelper > mAsyncLocalLoaders;    ///< The Asynchronous image loaders used to provide all local async loads
886   RoundRobinContainerView< AsyncLoadingHelper > mAsyncRemoteLoaders;   ///< The Asynchronous image loaders used to provide all remote async loads
887   std::vector< ExternalTextureInfo >            mExternalTextures;     ///< Externally provided textures
888   Dali::Vector<LifecycleObserver*>              mLifecycleObservers;   ///< Lifecycle observers of texture manager
889   Dali::Vector<LoadQueueElement>                mLoadQueue;            ///< Queue of textures to load after NotifyObservers
890   std::string                                   mBrokenImageUrl;       ///< Broken image url
891   TextureId                                     mCurrentTextureId;     ///< The current value used for the unique Texture Id generation
892   bool                                          mQueueLoadFlag;        ///< Flag that causes Load Textures to be queued.
893 };
894
895
896 } // name Internal
897
898 } // namespace Toolkit
899
900 } // namespace Dali
901
902 #endif // DALI_TOOLKIT_TEXTURE_MANAGER_IMPL_H