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