[NUI] Cache url when we call SetImage + Make way to skip visual creation
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / BaseComponents / ImageView.cs
1 /*
2 * Copyright(c) 2019 Samsung Electronics Co., Ltd.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17 using System;
18 using System.Collections.Generic;
19 using System.Runtime.InteropServices;
20 using System.ComponentModel;
21 using Tizen.NUI.Binding;
22
23 namespace Tizen.NUI.BaseComponents
24 {
25
26     /// <summary>
27     /// ImageView is a class for displaying an image resource.<br />
28     /// An instance of ImageView can be created using a URL or an image instance.<br />
29     /// </summary>
30     /// <since_tizen> 3 </since_tizen>
31     public partial class ImageView : View
32     {
33         static ImageView() { }
34
35         private EventHandler<ResourceReadyEventArgs> _resourceReadyEventHandler;
36         private ResourceReadyEventCallbackType _resourceReadyEventCallback;
37         private EventHandler<ResourceLoadedEventArgs> _resourceLoadedEventHandler;
38         private _resourceLoadedCallbackType _resourceLoadedCallback;
39
40         /// <summary>
41         /// Convert non-null string that some keyword change as application specific directory.
42         /// </summary>
43         /// <param name="value">Inputed and replaced after this function finished</param>
44         /// <returns>Replaced url</returns>
45         private static string ConvertResourceUrl(ref string value)
46         {
47             value ??= "";
48             if (value.StartsWith("*Resource*"))
49             {
50                 string resource = Tizen.Applications.Application.Current.DirectoryInfo.Resource;
51                 value = value.Replace("*Resource*", resource);
52             }
53             return value;
54         }
55
56         // Collection of image-sensitive properties.
57         private static readonly List<int> cachedImagePropertyKeyList = new List<int> {
58             Visual.Property.Type,
59             ImageVisualProperty.URL,
60             ImageVisualProperty.AlphaMaskURL,
61             ImageVisualProperty.CropToMask,
62             Visual.Property.VisualFittingMode,
63             ImageVisualProperty.DesiredWidth,
64             ImageVisualProperty.DesiredHeight,
65             ImageVisualProperty.ReleasePolicy,
66             ImageVisualProperty.WrapModeU,
67             ImageVisualProperty.WrapModeV,
68             ImageVisualProperty.SynchronousLoading,
69             Visual.Property.PremultipliedAlpha,
70             ImageVisualProperty.OrientationCorrection,
71             NpatchImageVisualProperty.Border,
72             NpatchImageVisualProperty.BorderOnly,
73         };
74         internal PropertyMap cachedImagePropertyMap;
75         internal bool imagePropertyUpdatedFlag = false;
76
77         private bool imagePropertyUpdateProcessAttachedFlag = false;
78         private Rectangle _border;
79         private string _resourceUrl = "";
80         private int _desired_width = -1;
81         private int _desired_height = -1;
82         private TriggerableSelector<string> resourceUrlSelector;
83         private TriggerableSelector<Rectangle> borderSelector;
84
85         private RelativeVector4 internalPixelArea;
86
87         /// <summary>
88         /// Creates an initialized ImageView.
89         /// </summary>
90         /// <since_tizen> 3 </since_tizen>
91         public ImageView() : this(Interop.ImageView.New(), true)
92         {
93             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
94         }
95
96         /// This will be public opened in next release of tizen after ACR done. Before ACR, it is used as HiddenAPI (InhouseAPI).
97         [EditorBrowsable(EditorBrowsableState.Never)]
98         public ImageView(ViewStyle viewStyle) : this(Interop.ImageView.New(), true, viewStyle)
99         {
100         }
101
102         /// <summary>
103         /// Creates an initialized ImageView with setting the status of shown or hidden.
104         /// </summary>
105         /// <param name="shown">false : Not displayed (hidden), true : displayed (shown)</param>
106         /// This will be public opened in next release of tizen after ACR done. Before ACR, it is used as HiddenAPI (InhouseAPI).
107         [EditorBrowsable(EditorBrowsableState.Never)]
108         public ImageView(bool shown) : this(Interop.ImageView.New(), true)
109         {
110             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
111             SetVisible(shown);
112         }
113
114         /// <summary>
115         /// Creates an initialized ImageView from a URL to an image resource.<br />
116         /// If the string is empty, ImageView will not display anything.<br />
117         /// </summary>
118         /// <param name="url">The URL of the image resource to display.</param>
119         /// <since_tizen> 3 </since_tizen>
120         public ImageView(string url) : this(Interop.ImageView.New(ConvertResourceUrl(ref url)), true)
121         {
122             _resourceUrl = url;
123
124             // Update cached property. Note that we should not re-create new visual.
125             using (PropertyValue urlValue = new PropertyValue(_resourceUrl))
126             {
127                 UpdateImage(ImageVisualProperty.URL, urlValue, false);
128             }
129             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
130
131         }
132
133         /// <summary>
134         /// Creates an initialized ImageView from a URL to an image resource with setting shown or hidden.
135         /// </summary>
136         /// <param name="url">The URL of the image resource to display.</param>
137         /// <param name="shown">false : Not displayed (hidden), true : displayed (shown)</param>
138         /// This will be public opened in next release of tizen after ACR done. Before ACR, it is used as HiddenAPI (InhouseAPI).
139         [EditorBrowsable(EditorBrowsableState.Never)]
140         public ImageView(string url, bool shown) : this(Interop.ImageView.New(ConvertResourceUrl(ref url)), true)
141         {
142             _resourceUrl = url;
143
144             // Update cached property. Note that we should not re-create new visual.
145             using (PropertyValue urlValue = new PropertyValue(_resourceUrl))
146             {
147                 UpdateImage(ImageVisualProperty.URL, urlValue, false);
148             }
149             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
150             SetVisible(shown);
151         }
152
153         internal ImageView(string url, Uint16Pair size, bool shown = true) : this(Interop.ImageView.New(ConvertResourceUrl(ref url), Uint16Pair.getCPtr(size)), true)
154         {
155             _resourceUrl = url;
156             _desired_width = size?.GetWidth() ?? -1;
157             _desired_height = size?.GetHeight() ?? -1;
158
159             // Update cached property. Note that we should not re-create new visual.
160             using (PropertyValue urlValue = new PropertyValue(_resourceUrl))
161             {
162                 UpdateImage(ImageVisualProperty.URL, urlValue, false);
163             }
164             using (PropertyValue desiredWidthValue = new PropertyValue(_desired_width))
165             {
166                 UpdateImage(ImageVisualProperty.DesiredWidth, desiredWidthValue, false);
167             }
168             using (PropertyValue desiredHeightValue = new PropertyValue(_desired_height))
169             {
170                 UpdateImage(ImageVisualProperty.DesiredWidth, desiredHeightValue, false);
171             }
172             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
173
174             if (!shown)
175             {
176                 SetVisible(false);
177             }
178         }
179
180         internal ImageView(global::System.IntPtr cPtr, bool cMemoryOwn, ViewStyle viewStyle, bool shown = true) : base(cPtr, cMemoryOwn, viewStyle)
181         {
182             if (!shown)
183             {
184                 SetVisible(false);
185             }
186         }
187
188         internal ImageView(global::System.IntPtr cPtr, bool cMemoryOwn, bool shown = true) : base(cPtr, cMemoryOwn, null)
189         {
190             if (!shown)
191             {
192                 SetVisible(false);
193             }
194         }
195
196         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
197         private delegate void ResourceReadyEventCallbackType(IntPtr data);
198         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
199         private delegate void _resourceLoadedCallbackType(IntPtr view);
200
201         /// <summary>
202         /// An event for ResourceReady signal which can be used to subscribe or unsubscribe the event handler.<br />
203         /// This signal is emitted after all resources required by a control are loaded and ready.<br />
204         /// Most resources are only loaded when the control is placed on the stage.<br />
205         /// </summary>
206         /// <since_tizen> 3 </since_tizen>
207         public event EventHandler<ResourceReadyEventArgs> ResourceReady
208         {
209             add
210             {
211                 if (_resourceReadyEventHandler == null)
212                 {
213                     _resourceReadyEventCallback = OnResourceReady;
214                     ViewResourceReadySignal resourceReadySignal = ResourceReadySignal(this);
215                     resourceReadySignal?.Connect(_resourceReadyEventCallback);
216                     resourceReadySignal?.Dispose();
217                 }
218
219                 _resourceReadyEventHandler += value;
220             }
221
222             remove
223             {
224                 _resourceReadyEventHandler -= value;
225
226                 ViewResourceReadySignal resourceReadySignal = ResourceReadySignal(this);
227                 if (_resourceReadyEventHandler == null && resourceReadySignal?.Empty() == false)
228                 {
229                     resourceReadySignal?.Disconnect(_resourceReadyEventCallback);
230                 }
231                 resourceReadySignal?.Dispose();
232             }
233         }
234
235         internal event EventHandler<ResourceLoadedEventArgs> ResourceLoaded
236         {
237             add
238             {
239                 if (_resourceLoadedEventHandler == null)
240                 {
241                     _resourceLoadedCallback = OnResourceLoaded;
242                     ViewResourceReadySignal resourceReadySignal = this.ResourceReadySignal(this);
243                     resourceReadySignal?.Connect(_resourceLoadedCallback);
244                     resourceReadySignal?.Dispose();
245                 }
246
247                 _resourceLoadedEventHandler += value;
248             }
249             remove
250             {
251                 _resourceLoadedEventHandler -= value;
252                 ViewResourceReadySignal resourceReadySignal = this.ResourceReadySignal(this);
253                 if (_resourceLoadedEventHandler == null && resourceReadySignal?.Empty() == false)
254                 {
255                     resourceReadySignal?.Disconnect(_resourceLoadedCallback);
256                 }
257                 resourceReadySignal?.Dispose();
258             }
259         }
260
261         /// <summary>
262         /// Enumeration for LoadingStatus of image.
263         /// </summary>
264         /// <since_tizen> 5 </since_tizen>
265         public enum LoadingStatusType
266         {
267             /// <summary>
268             /// Loading preparing status.
269             /// </summary>
270             /// <since_tizen> 5 </since_tizen>
271             Preparing,
272             /// <summary>
273             /// Loading ready status.
274             /// </summary>
275             /// <since_tizen> 5 </since_tizen>
276             Ready,
277             /// <summary>
278             /// Loading failed status.
279             /// </summary>
280             /// <since_tizen> 5 </since_tizen>
281             Failed
282         }
283
284         /// <summary>
285         /// Enumeration for MaskingMode of image.
286         /// </summary>
287         [EditorBrowsable(EditorBrowsableState.Never)]
288         public enum MaskingModeType
289         {
290             /// <summary>
291             /// Applies alpha masking on rendering time.
292             /// </summary>
293             [EditorBrowsable(EditorBrowsableState.Never)]
294             MaskingOnRendering,
295             /// <summary>
296             /// Applies alpha masking on loading time.
297             /// </summary>
298             [EditorBrowsable(EditorBrowsableState.Never)]
299             MaskingOnLoading
300         }
301
302         /// <summary>
303         /// ImageView ResourceUrl, type string.
304         /// This is one of mandatory property. Even if not set or null set, it sets empty string ("") internally.
305         /// When it is set as null, it gives empty string ("") to be read.
306         /// </summary>
307         /// <since_tizen> 3 </since_tizen>
308         public string ResourceUrl
309         {
310             get
311             {
312                 return (string)GetValue(ResourceUrlProperty);
313             }
314             set
315             {
316                 SetValue(ResourceUrlProperty, value);
317                 NotifyPropertyChanged();
318             }
319         }
320
321         /// <summary>
322         /// This will be deprecated, Use Image instead. <br />
323         /// ImageView ImageMap, type PropertyMap: string if it is a URL, map otherwise.
324         /// </summary>
325         /// <since_tizen> 3 </since_tizen>
326         [Obsolete("Do not use this, that will be deprecated. Use Image property instead.")]
327         [EditorBrowsable(EditorBrowsableState.Never)]
328         public PropertyMap ImageMap
329         {
330             get
331             {
332                 return GetValue(ImageMapProperty) as PropertyMap;
333             }
334             set
335             {
336                 SetValue(ImageMapProperty, value);
337                 NotifyPropertyChanged();
338             }
339         }
340         private PropertyMap InternalImageMap
341         {
342             get
343             {
344                 if (_border == null)
345                 {
346                     // Sync as current properties
347                     UpdateImage();
348
349                     // Get current properties force.
350                     PropertyMap returnValue = new PropertyMap();
351                     PropertyValue image = GetProperty(ImageView.Property.IMAGE);
352                     image?.Get(returnValue);
353                     image?.Dispose();
354
355                     // Update cached property map
356                     if (returnValue != null)
357                     {
358                         MergeCachedImageVisualProperty(returnValue);
359                     }
360                     return returnValue;
361                 }
362                 else
363                 {
364                     return null;
365                 }
366             }
367             set
368             {
369                 if (_border == null)
370                 {
371                     PropertyValue setValue = new Tizen.NUI.PropertyValue(value);
372                     SetProperty(ImageView.Property.IMAGE, setValue);
373
374                     // Image properties are changed hardly. We should ignore lazy UpdateImage
375                     imagePropertyUpdatedFlag = false;
376                     cachedImagePropertyMap?.Dispose();
377                     cachedImagePropertyMap = null;
378                     MergeCachedImageVisualProperty(value);
379
380                     NotifyPropertyChanged();
381                     setValue?.Dispose();
382                 }
383             }
384         }
385
386         /// <summary>
387         /// ImageView Image, type PropertyMap: string if it is a URL, map otherwise.
388         /// </summary>
389         /// <remarks>
390         /// This PropertyMap use a <see cref="ImageVisualProperty"/>. <br />
391         /// See <see cref="ImageVisualProperty"/> for a detailed description. <br />
392         /// you can also use <see cref="Visual.Property"/>. <br />
393         /// See <see cref="Visual.Property"/> for a detailed description. <br />
394         /// </remarks>
395         /// <example>
396         /// The following example demonstrates how to use the Image property.
397         /// <code>
398         /// PropertyMap map = new PropertyMap();
399         /// map.Insert(Visual.Property.Type, new PropertyValue((int)Visual.Type.Image));
400         /// map.Insert(ImageVisualProperty.AlphaMaskURL, new PropertyValue(url));
401         /// map.Insert(ImageVisualProperty.FittingMode, new PropertyValue((int)FittingModeType.ScaleToFill);
402         /// imageview.Image = map;
403         /// </code>
404         /// </example>
405         /// <since_tizen> 4 </since_tizen>
406         public PropertyMap Image
407         {
408             get
409             {
410                 if (_border == null)
411                 {
412                     return (PropertyMap)GetValue(ImageProperty);
413                 }
414                 else
415                 {
416                     return null;
417                 }
418             }
419             set
420             {
421                 if (_border == null)
422                 {
423                     SetValue(ImageProperty, value);
424                     NotifyPropertyChanged();
425                 }
426             }
427         }
428
429         /// <summary>
430         /// ImageView PreMultipliedAlpha, type Boolean.<br />
431         /// Image must be initialized.<br />
432         /// </summary>
433         /// <since_tizen> 3 </since_tizen>
434         public bool PreMultipliedAlpha
435         {
436             get
437             {
438                 return (bool)GetValue(PreMultipliedAlphaProperty);
439             }
440             set
441             {
442                 SetValue(PreMultipliedAlphaProperty, value);
443                 NotifyPropertyChanged();
444             }
445         }
446
447         /// <summary>
448         /// ImageView PixelArea, type Vector4 (Animatable property).<br />
449         /// Pixel area is a relative value with the whole image area as [0.0, 0.0, 1.0, 1.0].<br />
450         /// </summary>
451         /// <remarks>
452         /// The property cascade chaining set is possible. For example, this (imageView.PixelArea.X = 0.1f;) is possible.
453         /// </remarks>
454         /// <since_tizen> 3 </since_tizen>
455         public RelativeVector4 PixelArea
456         {
457             get
458             {
459                 return (RelativeVector4)GetValue(PixelAreaProperty);
460             }
461             set
462             {
463                 SetValue(PixelAreaProperty, value);
464                 NotifyPropertyChanged();
465             }
466         }
467
468         /// <summary>
469         /// The border of the image in the order: left, right, bottom, top.<br />
470         /// If set, ImageMap will be ignored.<br />
471         /// For N-Patch images only.<br />
472         /// Optional.
473         /// </summary>
474         /// <remarks>
475         /// The property cascade chaining set is possible. For example, this (imageView.Border.X = 1;) is possible.
476         /// </remarks>
477         /// <since_tizen> 3 </since_tizen>
478         public Rectangle Border
479         {
480             get
481             {
482                 Rectangle temp = (Rectangle)GetValue(BorderProperty);
483                 if (null == temp)
484                 {
485                     return null;
486                 }
487                 else
488                 {
489                     return new Rectangle(OnBorderChanged, temp.X, temp.Y, temp.Width, temp.Height);
490                 }
491             }
492             set
493             {
494                 SetValue(BorderProperty, value);
495                 NotifyPropertyChanged();
496             }
497         }
498
499         /// <summary>
500         /// Gets or sets whether to draw the borders only (if true).<br />
501         /// If not specified, the default is false.<br />
502         /// For N-Patch images only.<br />
503         /// Optional.
504         /// </summary>
505         /// <since_tizen> 3 </since_tizen>
506         public bool BorderOnly
507         {
508             get
509             {
510                 return (bool)GetValue(BorderOnlyProperty);
511             }
512             set
513             {
514                 SetValue(BorderOnlyProperty, value);
515                 NotifyPropertyChanged();
516             }
517         }
518
519         /// <summary>
520         /// Gets or sets whether to synchronous loading the resourceurl of image.<br />
521         /// </summary>
522         /// <since_tizen> 3 </since_tizen>
523         [Obsolete("This has been deprecated since API9 and will be removed in API11. Use SynchronousLoading instead.")]
524         public bool SynchronosLoading
525         {
526             get
527             {
528                 return SynchronousLoading;
529             }
530             set
531             {
532                 SynchronousLoading = value;
533             }
534         }
535
536         /// <summary>
537         /// Gets or sets whether the image of the ResourceUrl property will be loaded synchronously.<br />
538         /// </summary>
539         /// <remarks>
540         /// Changing this property make this ImageView load image synchronously at the next loading
541         /// by following operation: <see cref="Reload"/>, <see cref="SetImage(string)"/>,
542         /// and by some properties those cause reloading: <see cref="ResourceUrl"/>, <see cref="PreMultipliedAlpha"/> and etc.
543         /// </remarks>
544         /// <since_tizen> 9 </since_tizen>
545         public bool SynchronousLoading
546         {
547             get
548             {
549                 return (bool)GetValue(SynchronousLoadingProperty);
550             }
551             set
552             {
553                 SetValue(SynchronousLoadingProperty, value);
554                 NotifyPropertyChanged();
555             }
556         }
557
558         /// <summary>
559         /// Gets or sets whether to automatically correct the orientation of an image.<br />
560         /// </summary>
561         /// <since_tizen> 5 </since_tizen>
562         public bool OrientationCorrection
563         {
564             get
565             {
566                 return (bool)GetValue(OrientationCorrectionProperty);
567             }
568             set
569             {
570                 SetValue(OrientationCorrectionProperty, value);
571                 NotifyPropertyChanged();
572             }
573         }
574
575         /// <summary>
576         /// Gets or sets whether to apply mask on GPU or not.<br />
577         /// </summary>
578         [EditorBrowsable(EditorBrowsableState.Never)]
579         public MaskingModeType MaskingMode
580         {
581             get
582             {
583                 return (MaskingModeType)GetValue(MaskingModeProperty);
584             }
585             set
586             {
587                 SetValue(MaskingModeProperty, value);
588                 NotifyPropertyChanged();
589             }
590         }
591
592         private MaskingModeType InternalMaskingMode
593         {
594             get
595             {
596                 int ret = (int)MaskingModeType.MaskingOnLoading;
597
598                 PropertyValue maskingMode = GetCachedImageVisualProperty(ImageVisualProperty.MaskingMode);
599                 maskingMode?.Get(out ret);
600                 maskingMode?.Dispose();
601
602                 return (MaskingModeType)ret;
603             }
604             set
605             {
606                 MaskingModeType ret = value;
607                 PropertyValue setValue = new PropertyValue((int)ret);
608                 UpdateImage(ImageVisualProperty.MaskingMode, setValue);
609                 setValue?.Dispose();
610             }
611         }
612
613         /// <summary>
614         /// Gets the loading state of the visual resource.
615         /// </summary>
616         /// <since_tizen> 5 </since_tizen>
617         public ImageView.LoadingStatusType LoadingStatus
618         {
619             get
620             {
621                 return (ImageView.LoadingStatusType)Interop.View.GetVisualResourceStatus(SwigCPtr, (int)Property.IMAGE);
622             }
623         }
624
625         /// <summary>
626         /// Downcasts a handle to imageView handle.
627         /// </summary>
628         /// <exception cref="ArgumentNullException"> Thrown when handle is null. </exception>
629         /// Do not use this, that will be deprecated. Use as keyword instead.
630         /// <since_tizen> 3 </since_tizen>
631         [Obsolete("Do not use this, that will be deprecated. Use as keyword instead. " +
632         "Like: " +
633         "BaseHandle handle = new ImageView(imagePath); " +
634         "ImageView image = handle as ImageView")]
635         [EditorBrowsable(EditorBrowsableState.Never)]
636         public static ImageView DownCast(BaseHandle handle)
637         {
638             if (null == handle)
639             {
640                 throw new ArgumentNullException(nameof(handle));
641             }
642             ImageView ret = Registry.GetManagedBaseHandleFromNativePtr(handle) as ImageView;
643             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
644             return ret;
645         }
646
647         /// <summary>
648         /// Sets this ImageView from the given URL.<br />
649         /// If the URL is empty, ImageView will not display anything.<br />
650         /// </summary>
651         /// <param name="url">The URL to the image resource to display.</param>
652         /// <exception cref="ArgumentNullException"> Thrown when url is null. </exception>
653         /// <since_tizen> 3 </since_tizen>
654         public void SetImage(string url)
655         {
656             if (null == url)
657             {
658                 throw new ArgumentNullException(nameof(url));
659             }
660
661             if (url.Contains(".json"))
662             {
663                 Tizen.Log.Fatal("NUI", "[ERROR] Do not set lottie file in ImageView! This is temporary checking, will be removed soon!");
664                 return;
665             }
666
667             Interop.ImageView.SetImage(SwigCPtr, ConvertResourceUrl(ref url));
668             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
669
670             _resourceUrl = url;
671             // Update cached property. Note that we should not re-create new visual.
672             using (PropertyValue urlValue = new PropertyValue(_resourceUrl))
673             {
674                 UpdateImage(ImageVisualProperty.URL, urlValue, false);
675             }
676             imagePropertyUpdatedFlag = false;
677         }
678
679         /// <summary>
680         /// Queries if all resources required by a control are loaded and ready.<br />
681         /// Most resources are only loaded when the control is placed on the stage.<br />
682         /// True if the resources are loaded and ready, false otherwise.<br />
683         /// </summary>
684         /// <since_tizen> 3 </since_tizen>
685         public new bool IsResourceReady()
686         {
687             bool ret = Interop.View.IsResourceReady(SwigCPtr);
688             if (NDalicPINVOKE.SWIGPendingException.Pending)
689                 throw NDalicPINVOKE.SWIGPendingException.Retrieve();
690             return ret;
691         }
692
693         /// <summary>
694         /// Forcefully reloads the image. All the visuals using this image will reload to the latest image.
695         /// </summary>
696         /// <since_tizen> 5 </since_tizen>
697         public void Reload()
698         {
699             // Sync as current properties
700             UpdateImage();
701
702
703             Interop.View.DoActionWithEmptyAttributes(this.SwigCPtr, ImageView.Property.IMAGE, ActionReload);
704         }
705
706         /// <summary>
707         /// Plays the animated GIF. This is also the default playback mode.
708         /// </summary>
709         /// <since_tizen> 5 </since_tizen>
710         public void Play()
711         {
712             // Sync as current properties
713             UpdateImage();
714
715
716             Interop.View.DoActionWithEmptyAttributes(this.SwigCPtr, ImageView.Property.IMAGE, ActionPlay);
717         }
718
719         /// <summary>
720         /// Pauses the animated GIF.
721         /// </summary>
722         /// <since_tizen> 5 </since_tizen>
723         public void Pause()
724         {
725             // Sync as current properties
726             UpdateImage();
727
728
729             Interop.View.DoActionWithEmptyAttributes(this.SwigCPtr, ImageView.Property.IMAGE, ActionPause);
730         }
731
732         /// <summary>
733         /// Stops the animated GIF.
734         /// </summary>
735         /// <since_tizen> 5 </since_tizen>
736         public void Stop()
737         {
738             // Sync as current properties
739             UpdateImage();
740
741
742
743             Interop.View.DoActionWithEmptyAttributes(this.SwigCPtr, ImageView.Property.IMAGE, ActionStop);
744         }
745
746         /// <summary>
747         /// Gets or sets the URL of the alpha mask.<br />
748         /// Optional.
749         /// </summary>
750         /// <since_tizen> 6</since_tizen>
751         [EditorBrowsable(EditorBrowsableState.Never)]
752         public string AlphaMaskURL
753         {
754             get
755             {
756                 return GetValue(AlphaMaskURLProperty) as string;
757             }
758             set
759             {
760                 SetValue(AlphaMaskURLProperty, value);
761                 NotifyPropertyChanged();
762             }
763         }
764
765         private string InternalAlphaMaskURL
766         {
767             get
768             {
769                 string ret = "";
770
771                 PropertyValue maskUrl = GetCachedImageVisualProperty(ImageVisualProperty.AlphaMaskURL);
772                 maskUrl?.Get(out ret);
773                 maskUrl?.Dispose();
774
775                 return ret;
776             }
777             set
778             {
779                 PropertyValue setValue = new PropertyValue(value ?? "");
780                 UpdateImage(ImageVisualProperty.AlphaMaskURL, setValue);
781                 // When we never set CropToMask property before, we should set default value as true.
782                 using (PropertyValue cropToMask = GetCachedImageVisualProperty(ImageVisualProperty.CropToMask))
783                 {
784                     if (cropToMask == null)
785                     {
786                         using PropertyValue setCropValue = new PropertyValue(true);
787                         UpdateImage(ImageVisualProperty.CropToMask, setCropValue);
788                     }
789                 }
790                 setValue?.Dispose();
791             }
792         }
793
794
795         /// <summary>
796         ///  Whether to crop image to mask or scale mask to fit image.
797         /// </summary>
798         /// <since_tizen> 6 </since_tizen>
799         public bool CropToMask
800         {
801             get
802             {
803                 return (bool)GetValue(CropToMaskProperty);
804             }
805             set
806             {
807                 SetValue(CropToMaskProperty, value);
808                 NotifyPropertyChanged();
809             }
810         }
811         private bool InternalCropToMask
812         {
813             get
814             {
815                 bool ret = false;
816
817                 PropertyValue cropToMask = GetCachedImageVisualProperty(ImageVisualProperty.CropToMask);
818                 cropToMask?.Get(out ret);
819                 cropToMask?.Dispose();
820
821                 return ret;
822             }
823             set
824             {
825                 PropertyValue setValue = new PropertyValue(value);
826                 UpdateImage(ImageVisualProperty.CropToMask, setValue);
827                 setValue?.Dispose();
828             }
829         }
830
831         /// <summary>
832         /// Actions property value for Reload image.
833         /// </summary>
834         private int ActionReload { get; set; } = Interop.ImageView.ImageVisualActionReloadGet();
835
836         /// <summary>
837         /// Actions property value to Play animated images.
838         /// This property can be redefined by child class if it use different value.
839         /// </summary>
840         [EditorBrowsable(EditorBrowsableState.Never)]
841         protected int ActionPlay { get; set; } = Interop.AnimatedImageView.AnimatedImageVisualActionPlayGet();
842
843         /// <summary>
844         /// Actions property value to Pause animated images.
845         /// This property can be redefined by child class if it use different value.
846         /// </summary>
847         [EditorBrowsable(EditorBrowsableState.Never)]
848         protected int ActionPause { get; set; } = Interop.AnimatedImageView.AnimatedImageVisualActionPauseGet();
849
850         /// <summary>
851         /// Actions property value to Stop animated images.
852         /// This property can be redefined by child class if it use different value.
853         /// </summary>
854         [EditorBrowsable(EditorBrowsableState.Never)]
855         protected int ActionStop { get; set; } = Interop.AnimatedImageView.AnimatedImageVisualActionStopGet();
856
857         internal VisualFittingModeType ConvertFittingModetoVisualFittingMode(FittingModeType value)
858         {
859             switch (value)
860             {
861                 case FittingModeType.ShrinkToFit:
862                     return VisualFittingModeType.FitKeepAspectRatio;
863                 case FittingModeType.ScaleToFill:
864                     return VisualFittingModeType.OverFitKeepAspectRatio;
865                 case FittingModeType.Center:
866                     return VisualFittingModeType.Center;
867                 case FittingModeType.Fill:
868                     return VisualFittingModeType.Fill;
869                 case FittingModeType.FitHeight:
870                     return VisualFittingModeType.FitHeight;
871                 case FittingModeType.FitWidth:
872                     return VisualFittingModeType.FitWidth;
873                 default:
874                     return VisualFittingModeType.Fill;
875             }
876         }
877
878         internal FittingModeType ConvertVisualFittingModetoFittingMode(VisualFittingModeType value)
879         {
880             switch (value)
881             {
882                 case VisualFittingModeType.FitKeepAspectRatio:
883                     return FittingModeType.ShrinkToFit;
884                 case VisualFittingModeType.OverFitKeepAspectRatio:
885                     return FittingModeType.ScaleToFill;
886                 case VisualFittingModeType.Center:
887                     return FittingModeType.Center;
888                 case VisualFittingModeType.Fill:
889                     return FittingModeType.Fill;
890                 case VisualFittingModeType.FitHeight:
891                     return FittingModeType.FitHeight;
892                 case VisualFittingModeType.FitWidth:
893                     return FittingModeType.FitWidth;
894                 default:
895                     return FittingModeType.ShrinkToFit;
896             }
897         }
898
899         internal override LayoutItem CreateDefaultLayout()
900         {
901             return new ImageLayout();
902         }
903
904         /// <summary>
905         /// Gets or sets fitting options used when resizing images to fit.<br />
906         /// If not supplied, the default is FittingModeType.Fill.<br />
907         /// For normal quad images only.<br />
908         /// Optional.
909         /// </summary>
910         /// <since_tizen> 6 </since_tizen>
911         [EditorBrowsable(EditorBrowsableState.Never)]
912         public FittingModeType FittingMode
913         {
914             get
915             {
916                 return (FittingModeType)GetValue(FittingModeProperty);
917             }
918             set
919             {
920                 SetValue(FittingModeProperty, value);
921                 NotifyPropertyChanged();
922             }
923         }
924
925         private FittingModeType InternalFittingMode
926         {
927             get
928             {
929                 int ret = (int)VisualFittingModeType.Fill;
930
931                 PropertyValue fittingMode = GetCachedImageVisualProperty(Visual.Property.VisualFittingMode);
932                 fittingMode?.Get(out ret);
933                 fittingMode?.Dispose();
934
935                 return ConvertVisualFittingModetoFittingMode((VisualFittingModeType)ret);
936             }
937             set
938             {
939                 VisualFittingModeType ret = ConvertFittingModetoVisualFittingMode(value);
940                 PropertyValue setValue = new PropertyValue((int)ret);
941                 UpdateImage(Visual.Property.VisualFittingMode, setValue);
942                 setValue?.Dispose();
943             }
944         }
945
946         /// <summary>
947         /// Gets or sets the desired image width.<br />
948         /// If not specified, the actual image width is used.<br />
949         /// For normal quad images only.<br />
950         /// Optional.
951         /// </summary>
952         /// <since_tizen> 6 </since_tizen>
953         [EditorBrowsable(EditorBrowsableState.Never)]
954         public int DesiredWidth
955         {
956             get
957             {
958                 return (int)GetValue(DesiredWidthProperty);
959             }
960             set
961             {
962                 SetValue(DesiredWidthProperty, value);
963                 NotifyPropertyChanged();
964             }
965         }
966         private int InternalDesiredWidth
967         {
968             get
969             {
970                 // Sync as current properties only if both _desired_width and _desired_height are setuped.
971                 if (_desired_width != -1 && _desired_height != -1)
972                 {
973                     UpdateImage();
974                 }
975                 PropertyValue desirewidth = GetCachedImageVisualProperty(ImageVisualProperty.DesiredWidth);
976                 desirewidth?.Get(out _desired_width);
977                 desirewidth?.Dispose();
978
979                 return _desired_width;
980             }
981             set
982             {
983                 if (_desired_width != value)
984                 {
985                     _desired_width = value;
986                     PropertyValue setValue = new PropertyValue(value);
987                     UpdateImage(ImageVisualProperty.DesiredWidth, setValue, false);
988                     setValue?.Dispose();
989                 }
990             }
991         }
992
993         /// <summary>
994         /// Gets or sets the desired image height.<br />
995         /// If not specified, the actual image height is used.<br />
996         /// For normal quad images only.<br />
997         /// Optional.
998         /// </summary>
999         /// <since_tizen> 6 </since_tizen>
1000         [EditorBrowsable(EditorBrowsableState.Never)]
1001         public int DesiredHeight
1002         {
1003             get
1004             {
1005                 return (int)GetValue(DesiredHeightProperty);
1006             }
1007             set
1008             {
1009                 SetValue(DesiredHeightProperty, value);
1010                 NotifyPropertyChanged();
1011             }
1012         }
1013         private int InternalDesiredHeight
1014         {
1015             get
1016             {
1017                 // Sync as current properties only if both _desired_width and _desired_height are setuped.
1018                 if (_desired_width != -1 && _desired_height != -1)
1019                 {
1020                     UpdateImage();
1021                 }
1022                 PropertyValue desireheight = GetCachedImageVisualProperty(ImageVisualProperty.DesiredHeight);
1023                 desireheight?.Get(out _desired_height);
1024                 desireheight?.Dispose();
1025
1026                 return _desired_height;
1027             }
1028             set
1029             {
1030                 if (_desired_height != value)
1031                 {
1032                     _desired_height = value;
1033                     PropertyValue setValue = new PropertyValue(value);
1034                     UpdateImage(ImageVisualProperty.DesiredHeight, setValue, false);
1035                     setValue?.Dispose();
1036                 }
1037             }
1038         }
1039
1040         /// <summary>
1041         /// Gets or sets ReleasePolicy for image.<br />
1042         /// If not supplied, the default is ReleasePolicyType.Detached.<br />
1043         /// </summary>
1044         [EditorBrowsable(EditorBrowsableState.Never)]
1045         public ReleasePolicyType ReleasePolicy
1046         {
1047             get
1048             {
1049                 return (ReleasePolicyType)GetValue(ReleasePolicyProperty);
1050             }
1051             set
1052             {
1053                 SetValue(ReleasePolicyProperty, value);
1054                 NotifyPropertyChanged();
1055             }
1056         }
1057
1058         private ReleasePolicyType InternalReleasePolicy
1059         {
1060             get
1061             {
1062                 int ret = (int)ReleasePolicyType.Detached;
1063
1064                 PropertyValue releasePoli = GetCachedImageVisualProperty(ImageVisualProperty.ReleasePolicy);
1065                 releasePoli?.Get(out ret);
1066                 releasePoli?.Dispose();
1067
1068                 return (ReleasePolicyType)ret;
1069             }
1070             set
1071             {
1072                 PropertyValue setValue = new PropertyValue((int)value);
1073                 UpdateImage(ImageVisualProperty.ReleasePolicy, setValue);
1074                 setValue?.Dispose();
1075             }
1076         }
1077
1078         /// <summary>
1079         /// Gets or sets the wrap mode for the u coordinate.<br />
1080         /// It decides how the texture should be sampled when the u coordinate exceeds the range of 0.0 to 1.0.<br />
1081         /// If not specified, the default is WrapModeType.Default(CLAMP).<br />
1082         /// For normal quad images only.<br />
1083         /// Optional.
1084         /// </summary>
1085         /// <since_tizen> 6 </since_tizen>
1086         [EditorBrowsable(EditorBrowsableState.Never)]
1087         public WrapModeType WrapModeU
1088         {
1089             get
1090             {
1091                 return (WrapModeType)GetValue(WrapModeUProperty);
1092             }
1093             set
1094             {
1095                 SetValue(WrapModeUProperty, value);
1096                 NotifyPropertyChanged();
1097             }
1098         }
1099
1100         private WrapModeType InternalWrapModeU
1101         {
1102             get
1103             {
1104                 int ret = (int)WrapModeType.Default;
1105
1106                 PropertyValue wrapModeU = GetCachedImageVisualProperty(ImageVisualProperty.WrapModeU);
1107                 wrapModeU?.Get(out ret);
1108                 wrapModeU?.Dispose();
1109
1110                 return (WrapModeType)ret;
1111             }
1112             set
1113             {
1114                 PropertyValue setValue = new PropertyValue((int)value);
1115                 UpdateImage(ImageVisualProperty.WrapModeU, setValue);
1116                 setValue?.Dispose();
1117             }
1118         }
1119
1120         /// <summary>
1121         /// Gets or sets the wrap mode for the v coordinate.<br />
1122         /// It decides how the texture should be sampled when the v coordinate exceeds the range of 0.0 to 1.0.<br />
1123         /// The first two elements indicate the top-left position of the area, and the last two elements are the areas of the width and the height respectively.<br />
1124         /// If not specified, the default is WrapModeType.Default(CLAMP).<br />
1125         /// For normal quad images only.
1126         /// Optional.
1127         /// </summary>
1128         /// <since_tizen> 6 </since_tizen>
1129         [EditorBrowsable(EditorBrowsableState.Never)]
1130         public WrapModeType WrapModeV
1131         {
1132             get
1133             {
1134                 return (WrapModeType)GetValue(WrapModeVProperty);
1135             }
1136             set
1137             {
1138                 SetValue(WrapModeVProperty, value);
1139                 NotifyPropertyChanged();
1140             }
1141         }
1142
1143         private WrapModeType InternalWrapModeV
1144         {
1145             get
1146             {
1147                 int ret = (int)WrapModeType.Default;
1148
1149                 PropertyValue wrapModeV = GetCachedImageVisualProperty(ImageVisualProperty.WrapModeV);
1150                 wrapModeV?.Get(out ret);
1151                 wrapModeV?.Dispose();
1152
1153                 return (WrapModeType)ret;
1154             }
1155             set
1156             {
1157                 PropertyValue setValue = new PropertyValue((int)value);
1158                 UpdateImage(ImageVisualProperty.WrapModeV, setValue);
1159                 setValue?.Dispose();
1160             }
1161         }
1162
1163         /// <summary>
1164         /// Gets or sets the mode to adjust view size to preserve the aspect ratio of the image resource.
1165         /// </summary>
1166         /// <remarks>
1167         /// This is false by default.
1168         /// If this is set to be true, then the width or height value, which is not set by user explicitly, can be changed automatically
1169         /// to preserve the aspect ratio of the image resource.
1170         /// AdjustViewSize works only if ImageView is added to a View having Layout.
1171         /// e.g. If the image resource size is (100, 100), then the ImageView requests size (100, 100) to its parent layout by default.
1172         ///      If the ImageView's HeightSpecification is 50 and AdjustViewSize is true, then the ImageView requests size (50, 50) instead of (100, 50).
1173         /// </remarks>
1174         /// <since_tizen> 9 </since_tizen>
1175         public bool AdjustViewSize
1176         {
1177             get
1178             {
1179                 return (bool)GetValue(AdjustViewSizeProperty);
1180             }
1181             set
1182             {
1183                 SetValue(AdjustViewSizeProperty, value);
1184                 NotifyPropertyChanged();
1185             }
1186         }
1187         private bool adjustViewSize = false;
1188
1189         /// <summary>
1190         /// ImageView PlaceHolderUrl, type string.
1191         /// This is one of mandatory property. Even if not set or null set, it sets empty string ("") internally.
1192         /// When it is set as null, it gives empty string ("") to be read.
1193         /// </summary>
1194         /// <since_tizen> 11 </since_tizen>
1195         [EditorBrowsable(EditorBrowsableState.Never)]
1196         public string PlaceHolderUrl
1197         {
1198             get
1199             {
1200                 return (string)GetValue(PlaceHolderUrlProperty);
1201             }
1202             set
1203             {
1204                 SetValue(PlaceHolderUrlProperty, value);
1205                 NotifyPropertyChanged();
1206             }
1207         }
1208
1209         /// <summary>
1210         /// Gets or sets whether the image use TransitionEffect or not<br />
1211         /// </summary>
1212         /// <since_tizen> 11 </since_tizen>
1213         [EditorBrowsable(EditorBrowsableState.Never)]
1214         public bool TransitionEffect
1215         {
1216             get
1217             {
1218                 return (bool)GetValue(TransitionEffectProperty);
1219             }
1220             set
1221             {
1222                 SetValue(TransitionEffectProperty, value);
1223                 NotifyPropertyChanged();
1224             }
1225         }
1226
1227         internal Selector<string> ResourceUrlSelector
1228         {
1229             get => GetSelector<string>(resourceUrlSelector, ImageView.ResourceUrlProperty);
1230             set
1231             {
1232                 resourceUrlSelector?.Reset(this);
1233                 if (value == null) return;
1234
1235                 if (value.HasAll()) SetResourceUrl(value.All);
1236                 else resourceUrlSelector = new TriggerableSelector<string>(this, value, SetResourceUrl, true);
1237             }
1238         }
1239
1240         /// <summary>
1241         /// Get attributes, it is abstract function and must be override.
1242         /// </summary>
1243         [EditorBrowsable(EditorBrowsableState.Never)]
1244         protected override ViewStyle CreateViewStyle()
1245         {
1246             return new ImageViewStyle();
1247         }
1248
1249         internal void SetImage(string url, Uint16Pair size)
1250         {
1251             if (url.Contains(".json"))
1252             {
1253                 Tizen.Log.Fatal("NUI", "[ERROR] Do not set lottie file in ImageView! This is temporary checking, will be removed soon!");
1254                 return;
1255             }
1256
1257             Interop.ImageView.SetImage(SwigCPtr, ConvertResourceUrl(ref url), Uint16Pair.getCPtr(size));
1258             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
1259
1260             _resourceUrl = url;
1261             _desired_width = size?.GetWidth() ?? -1;
1262             _desired_height = size?.GetHeight() ?? -1;
1263
1264             // Update cached property. Note that we should not re-create new visual.
1265             using (PropertyValue urlValue = new PropertyValue(_resourceUrl))
1266             {
1267                 UpdateImage(ImageVisualProperty.URL, urlValue, false);
1268             }
1269             using (PropertyValue desiredWidthValue = new PropertyValue(_desired_width))
1270             {
1271                 UpdateImage(ImageVisualProperty.DesiredWidth, desiredWidthValue, false);
1272             }
1273             using (PropertyValue desiredHeightValue = new PropertyValue(_desired_height))
1274             {
1275                 UpdateImage(ImageVisualProperty.DesiredWidth, desiredHeightValue, false);
1276             }
1277             imagePropertyUpdatedFlag = false;
1278         }
1279
1280         internal ViewResourceReadySignal ResourceReadySignal(View view)
1281         {
1282             ViewResourceReadySignal ret = new ViewResourceReadySignal(Interop.View.ResourceReadySignal(View.getCPtr(view)), false);
1283             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
1284             return ret;
1285         }
1286
1287         internal override void ApplyCornerRadius()
1288         {
1289             base.ApplyCornerRadius();
1290
1291             if (backgroundExtraData == null) return;
1292
1293
1294             // Update corner radius properties to image by ActionUpdateProperty
1295             if (backgroundExtraData.CornerRadius != null)
1296             {
1297                 Interop.View.InternalUpdateVisualPropertyVector4(this.SwigCPtr, ImageView.Property.IMAGE, Visual.Property.CornerRadius, Vector4.getCPtr(backgroundExtraData.CornerRadius));
1298             }
1299             Interop.View.InternalUpdateVisualPropertyInt(this.SwigCPtr, ImageView.Property.IMAGE, Visual.Property.CornerRadiusPolicy, (int)backgroundExtraData.CornerRadiusPolicy);
1300         }
1301
1302         internal override void ApplyBorderline()
1303         {
1304             base.ApplyBorderline();
1305
1306             if (backgroundExtraData == null) return;
1307
1308
1309             // Update borderline properties to image by ActionUpdateProperty
1310             Interop.View.InternalUpdateVisualPropertyFloat(this.SwigCPtr, ImageView.Property.IMAGE, Visual.Property.BorderlineWidth, backgroundExtraData.BorderlineWidth);
1311             Interop.View.InternalUpdateVisualPropertyVector4(this.SwigCPtr, ImageView.Property.IMAGE, Visual.Property.BorderlineColor, Vector4.getCPtr(backgroundExtraData.BorderlineColor ?? Color.Black));
1312             Interop.View.InternalUpdateVisualPropertyFloat(this.SwigCPtr, ImageView.Property.IMAGE, Visual.Property.BorderlineOffset, backgroundExtraData.BorderlineOffset);
1313         }
1314
1315         internal ResourceLoadingStatusType GetResourceStatus()
1316         {
1317             return (ResourceLoadingStatusType)Interop.View.GetVisualResourceStatus(this.SwigCPtr, Property.IMAGE);
1318         }
1319
1320         /// <summary>
1321         /// you can override it to clean-up your own resources.
1322         /// </summary>
1323         /// <param name="type">DisposeTypes</param>
1324         /// <since_tizen> 3 </since_tizen>
1325         protected override void Dispose(DisposeTypes type)
1326         {
1327             if (disposed)
1328             {
1329                 return;
1330             }
1331
1332             internalPixelArea?.Dispose();
1333
1334             if (type == DisposeTypes.Explicit)
1335             {
1336                 //Called by User
1337                 //Release your own managed resources here.
1338                 //You should release all of your own disposable objects here.
1339                 _border?.Dispose();
1340                 _border = null;
1341                 borderSelector?.Reset(this);
1342                 resourceUrlSelector?.Reset(this);
1343                 imagePropertyUpdatedFlag = false;
1344                 if (imagePropertyUpdateProcessAttachedFlag)
1345                 {
1346                     ProcessorController.Instance.ProcessorOnceEvent -= UpdateImage;
1347                     imagePropertyUpdateProcessAttachedFlag = false;
1348                 }
1349                 cachedImagePropertyMap?.Dispose();
1350                 cachedImagePropertyMap = null;
1351             }
1352
1353             base.Dispose(type);
1354         }
1355
1356         /// This will not be public opened.
1357         [EditorBrowsable(EditorBrowsableState.Never)]
1358         protected override void ReleaseSwigCPtr(System.Runtime.InteropServices.HandleRef swigCPtr)
1359         {
1360             Interop.ImageView.DeleteImageView(swigCPtr);
1361         }
1362
1363         // Callback for View ResourceReady signal
1364         private void OnResourceReady(IntPtr data)
1365         {
1366             if (!CheckResourceReady())
1367             {
1368                 return;
1369             }
1370
1371             ResourceReadyEventArgs e = new ResourceReadyEventArgs();
1372             if (data != null)
1373             {
1374                 e.View = Registry.GetManagedBaseHandleFromNativePtr(data) as View;
1375             }
1376
1377             if (_resourceReadyEventHandler != null)
1378             {
1379                 _resourceReadyEventHandler(this, e);
1380             }
1381         }
1382
1383         private void SetResourceUrl(string value)
1384         {
1385             if (_resourceUrl != ConvertResourceUrl(ref value))
1386             {
1387                 _resourceUrl = value;
1388                 if (string.IsNullOrEmpty(_resourceUrl))
1389                 {
1390                     // Special case. If we set ResourceUrl as empty, Unregist visual.
1391                     RemoveImage();
1392                 }
1393                 else
1394                 {
1395                     using (PropertyValue setValue = new PropertyValue(value))
1396                     {
1397                         UpdateImage(ImageVisualProperty.URL, setValue);
1398                     }
1399                     // Special case. If we set GeneratedUrl, Create ImageVisual synchronously.
1400                     if (value.StartsWith("dali://") || value.StartsWith("enbuf://"))
1401                     {
1402                         UpdateImage();
1403                     }
1404                 }
1405             }
1406         }
1407
1408         private void SetBorder(Rectangle value)
1409         {
1410             if (value == null)
1411             {
1412                 return;
1413             }
1414             if (_border != value)
1415             {
1416                 _border = new Rectangle(value);
1417                 UpdateImage(NpatchImageVisualProperty.Border, new PropertyValue(_border));
1418             }
1419         }
1420
1421         /// <summary>
1422         /// Unregist image visual directly. After this operation, we cannot get any properties from Image property.
1423         /// </summary>
1424         private void RemoveImage()
1425         {
1426             // If previous resourceUrl was already empty, we don't need to do anything. just ignore.
1427             // Unregist and detach process only if previous resourceUrl was not empty
1428             string currentResourceUrl = "";
1429             PropertyValue currentResourceUrlValue = GetCachedImageVisualProperty(ImageVisualProperty.URL);
1430             if ((currentResourceUrlValue?.Get(out currentResourceUrl) ?? false) && !string.IsNullOrEmpty(currentResourceUrl))
1431             {
1432                 PropertyValue emptyValue = new PropertyValue();
1433
1434                 // Remove current registed Image.
1435                 SetProperty(ImageView.Property.IMAGE, emptyValue);
1436
1437                 // Image visual is not exist anymore. We should ignore lazy UpdateImage
1438                 imagePropertyUpdatedFlag = false;
1439                 if (imagePropertyUpdateProcessAttachedFlag)
1440                 {
1441                     ProcessorController.Instance.ProcessorOnceEvent -= UpdateImage;
1442                     imagePropertyUpdateProcessAttachedFlag = false;
1443                 }
1444                 // Update resourceUrl as empty value
1445                 cachedImagePropertyMap[ImageVisualProperty.URL] = emptyValue;
1446
1447                 emptyValue?.Dispose();
1448             }
1449             currentResourceUrlValue?.Dispose();
1450         }
1451
1452         /// <summary>
1453         /// Lazy call to UpdateImage.
1454         /// Collect Properties need to be update, and set properties that starts the Processing.
1455         ///
1456         /// If you want to update cachedImagePropertyMap, but don't want to request new visual creation, make requiredVisualCreation value as false.
1457         /// (Example : if we change SynchronousLoading property from 'true' to 'false', or if we call this function during UpdateImage)
1458         /// </summary>
1459         [EditorBrowsable(EditorBrowsableState.Never)]
1460         protected virtual void UpdateImage(int key, PropertyValue value, bool requiredVisualCreation = true)
1461         {
1462             // Update image property map value as inputed value.
1463             if (key != 0)
1464             {
1465                 if (cachedImagePropertyMap == null)
1466                 {
1467                     cachedImagePropertyMap = new PropertyMap();
1468                 }
1469
1470                 // To optimization, we don't check URL duplicate case. We already checked before.
1471                 if (key != ImageVisualProperty.URL)
1472                 {
1473                     using (PropertyValue oldValue = GetCachedImageVisualProperty(key))
1474                     {
1475                         if (oldValue != null && oldValue.EqualTo(value))
1476                         {
1477                             // Ignore UpdateImage query when we try to update equality value.
1478                             return;
1479                         }
1480                     }
1481                 }
1482                 imagePropertyUpdatedFlag = true;
1483                 cachedImagePropertyMap[key] = value;
1484
1485                 // Lazy update only if visual creation required, and _resourceUrl is not empty, and ProcessAttachedFlag is false.
1486                 if (requiredVisualCreation && !string.IsNullOrEmpty(_resourceUrl) && !imagePropertyUpdateProcessAttachedFlag)
1487                 {
1488                     imagePropertyUpdateProcessAttachedFlag = true;
1489                     ProcessorController.Instance.ProcessorOnceEvent += UpdateImage;
1490                     // Call process hardly.
1491                     ProcessorController.Instance.Awake();
1492                 }
1493             }
1494         }
1495
1496         /// <summary>
1497         /// Callback function to Lazy UpdateImage.
1498         /// </summary>
1499         private void UpdateImage(object source, EventArgs e)
1500         {
1501             UpdateImage();
1502             imagePropertyUpdateProcessAttachedFlag = false;
1503         }
1504
1505         /// <summary>
1506         /// Update image-relative properties synchronously.
1507         /// After call this API, All image properties updated.
1508         /// </summary>
1509         /// <remarks>
1510         /// Current version ImageView property update asynchronously.
1511         /// If you want to guarantee that ImageView property setuped,
1512         /// Please call this ImageView.UpdateImage() API.
1513         /// </remarks>
1514         [EditorBrowsable(EditorBrowsableState.Never)]
1515         protected virtual void UpdateImage()
1516         {
1517             if (!imagePropertyUpdatedFlag) return;
1518
1519             imagePropertyUpdatedFlag = false;
1520
1521             if (cachedImagePropertyMap == null)
1522             {
1523                 cachedImagePropertyMap = new PropertyMap();
1524             }
1525
1526             // Checkup the cached visual type is AnimatedImage.
1527             // It is trick to know that this code is running on AnimatedImageView.UpdateImage() / LottieAnimationView.UpdateImage() or not.
1528             int visualType = (int)Visual.Type.Invalid;
1529             if (!((GetCachedImageVisualProperty(Visual.Property.Type)?.Get(out visualType) ?? false) && (visualType == (int)Visual.Type.AnimatedImage || visualType == (int)Visual.Type.AnimatedVectorImage)))
1530             {
1531                 // If ResourceUrl is not setuped, don't set property. fast return.
1532                 if (string.IsNullOrEmpty(_resourceUrl))
1533                 {
1534                     return;
1535                 }
1536                 if (_border == null)
1537                 {
1538                     PropertyValue image = new PropertyValue((int)Visual.Type.Image);
1539                     cachedImagePropertyMap[Visual.Property.Type] = image;
1540                     image?.Dispose();
1541                 }
1542                 else
1543                 {
1544                     PropertyValue nPatch = new PropertyValue((int)Visual.Type.NPatch);
1545                     cachedImagePropertyMap[Visual.Property.Type] = nPatch;
1546                     nPatch?.Dispose();
1547                     PropertyValue border = new PropertyValue(_border);
1548                     cachedImagePropertyMap[NpatchImageVisualProperty.Border] = border;
1549                     border?.Dispose();
1550                 }
1551             }
1552
1553             if (backgroundExtraData != null && backgroundExtraData.CornerRadius != null)
1554             {
1555                 using (var cornerRadius = new PropertyValue(backgroundExtraData.CornerRadius))
1556                 using (var cornerRadiusPolicy = new PropertyValue((int)backgroundExtraData.CornerRadiusPolicy))
1557                 {
1558                     cachedImagePropertyMap[Visual.Property.CornerRadius] = cornerRadius;
1559                     cachedImagePropertyMap[Visual.Property.CornerRadiusPolicy] = new PropertyValue((int)(backgroundExtraData.CornerRadiusPolicy));
1560                 }
1561             }
1562
1563             if (backgroundExtraData != null && backgroundExtraData.BorderlineWidth > 0.0f)
1564             {
1565                 using (var borderlineWidth = new PropertyValue(backgroundExtraData.BorderlineWidth))
1566                 using (var borderlineColor = new PropertyValue(backgroundExtraData.BorderlineColor))
1567                 using (var borderlineOffset = new PropertyValue(backgroundExtraData.BorderlineOffset))
1568                 {
1569                     cachedImagePropertyMap[Visual.Property.BorderlineWidth] = borderlineWidth;
1570                     cachedImagePropertyMap[Visual.Property.BorderlineColor] = borderlineColor;
1571                     cachedImagePropertyMap[Visual.Property.BorderlineOffset] = borderlineOffset;
1572                 }
1573             }
1574
1575             // Do Fitting Buffer when desired dimension is set
1576             if (_desired_width != -1 && _desired_height != -1)
1577             {
1578                 if (_resourceUrl != null)
1579                 {
1580                     Size2D imageSize = ImageLoader.GetOriginalImageSize(_resourceUrl, true);
1581                     if (imageSize.Height > 0 && imageSize.Width > 0 && _desired_width > 0 && _desired_height > 0)
1582                     {
1583                         int adjustedDesiredWidth, adjustedDesiredHeight;
1584                         float aspectOfDesiredSize = (float)_desired_height / (float)_desired_width;
1585                         float aspectOfImageSize = (float)imageSize.Height / (float)imageSize.Width;
1586                         if (aspectOfImageSize > aspectOfDesiredSize)
1587                         {
1588                             adjustedDesiredWidth = _desired_width;
1589                             adjustedDesiredHeight = imageSize.Height * _desired_width / imageSize.Width;
1590                         }
1591                         else
1592                         {
1593                             adjustedDesiredWidth = imageSize.Width * _desired_height / imageSize.Height;
1594                             adjustedDesiredHeight = _desired_height;
1595                         }
1596
1597                         PropertyValue returnWidth = new PropertyValue(adjustedDesiredWidth);
1598                         cachedImagePropertyMap[ImageVisualProperty.DesiredWidth] = returnWidth;
1599                         returnWidth?.Dispose();
1600                         PropertyValue returnHeight = new PropertyValue(adjustedDesiredHeight);
1601                         cachedImagePropertyMap[ImageVisualProperty.DesiredHeight] = returnHeight;
1602                         returnHeight?.Dispose();
1603                         PropertyValue scaleToFit = new PropertyValue((int)FittingModeType.ScaleToFill);
1604                         cachedImagePropertyMap[ImageVisualProperty.FittingMode] = scaleToFit;
1605                         scaleToFit?.Dispose();
1606                     }
1607                     else
1608                     {
1609                         Tizen.Log.Fatal("NUI", "[ERROR] Can't use DesiredSize when ImageLoading is failed.");
1610                     }
1611                     imageSize?.Dispose();
1612                 }
1613             }
1614
1615             UpdateImageMap();
1616         }
1617
1618         /// <summary>
1619         /// Merge our collected properties, and set IMAGE property internally.
1620         /// </summary>
1621         private void UpdateImageMap()
1622         {
1623             // Note : We can't use ImageView.Image property here. Because That property call UpdateImage internally.
1624             using (PropertyMap imageMap = new PropertyMap())
1625             {
1626                 using (PropertyValue returnValue = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE))
1627                 {
1628                     returnValue?.Get(imageMap);
1629                 }
1630                 if (cachedImagePropertyMap != null)
1631                 {
1632                     imageMap?.Merge(cachedImagePropertyMap);
1633                 }
1634                 using (PropertyValue setValue = new PropertyValue(imageMap))
1635                 {
1636                     SetProperty(ImageView.Property.IMAGE, setValue);
1637                 }
1638
1639                 // Update cached image property.
1640                 MergeCachedImageVisualProperty(imageMap);
1641             }
1642         }
1643
1644         /// <summary>
1645         /// Get image visual property by key.
1646         /// If we found value in local Cached result, return that.
1647         /// Else, get synced native map and return that.
1648         /// If there is no matched value, return null.
1649         /// </summary>
1650         [EditorBrowsable(EditorBrowsableState.Never)]
1651         protected virtual PropertyValue GetImageVisualProperty(int key)
1652         {
1653             PropertyValue ret = GetCachedImageVisualProperty(key);
1654             if (ret == null)
1655             {
1656                 // If we cannot find result form cached map, Get value from native engine.
1657                 ret = Image?.Find(key);
1658             }
1659             return ret;
1660         }
1661
1662         /// <summary>
1663         /// Get image visual property from NUI cached image map by key.
1664         /// If there is no matched value, return null.
1665         /// </summary>
1666         [EditorBrowsable(EditorBrowsableState.Never)]
1667         protected virtual PropertyValue GetCachedImageVisualProperty(int key)
1668         {
1669             return cachedImagePropertyMap?.Find(key);
1670         }
1671
1672         /// <summary>
1673         /// Update NUI cached image visual property map by inputed property map.
1674         /// </summary>
1675         /// <remarks>
1676         /// For performance issue, we will collect only "cachedImagePropertyKeyList" hold.
1677         /// </remarks>
1678         [EditorBrowsable(EditorBrowsableState.Never)]
1679         protected virtual void MergeCachedImageVisualProperty(PropertyMap map)
1680         {
1681             if (map == null) return;
1682             if (cachedImagePropertyMap == null)
1683             {
1684                 cachedImagePropertyMap = new PropertyMap();
1685             }
1686             foreach (var key in cachedImagePropertyKeyList)
1687             {
1688                 PropertyValue value = map.Find(key);
1689                 if (value != null)
1690                 {
1691                     // Update-or-Insert new value
1692                     cachedImagePropertyMap[key] = value;
1693                 }
1694             }
1695         }
1696
1697         /// <summary>
1698         /// GetNaturalSize() should be guaranteed that ResourceUrl property setuped.
1699         /// So before get base.GetNaturalSize(), we should synchronous image properties
1700         /// </summary>
1701         internal override Vector3 GetNaturalSize()
1702         {
1703             // Sync as current properties
1704             UpdateImage();
1705             return base.GetNaturalSize();
1706         }
1707
1708         [EditorBrowsable(EditorBrowsableState.Never)]
1709         protected override bool CheckResourceReady()
1710         {
1711             // If we have some properties to be updated, this signal is old thing.
1712             // We need to ignore current signal, and wait next.
1713             return !(imagePropertyUpdateProcessAttachedFlag && imagePropertyUpdatedFlag);
1714         }
1715
1716         private void OnResourceLoaded(IntPtr view)
1717         {
1718             if (!CheckResourceReady())
1719             {
1720                 return;
1721             }
1722             ResourceLoadedEventArgs e = new ResourceLoadedEventArgs();
1723             e.Status = (ResourceLoadingStatusType)Interop.View.GetVisualResourceStatus(this.SwigCPtr, Property.IMAGE);
1724
1725             if (_resourceLoadedEventHandler != null)
1726             {
1727                 _resourceLoadedEventHandler(this, e);
1728             }
1729         }
1730
1731         /// <summary>
1732         /// Event arguments of resource ready.
1733         /// </summary>
1734         /// <since_tizen> 3 </since_tizen>
1735         public class ResourceReadyEventArgs : EventArgs
1736         {
1737             private View _view;
1738
1739             /// <summary>
1740             /// The view whose resource is ready.
1741             /// </summary>
1742             /// <since_tizen> 3 </since_tizen>
1743             public View View
1744             {
1745                 get
1746                 {
1747                     return _view;
1748                 }
1749                 set
1750                 {
1751                     _view = value;
1752                 }
1753             }
1754         }
1755
1756         internal class ResourceLoadedEventArgs : EventArgs
1757         {
1758             private ResourceLoadingStatusType status = ResourceLoadingStatusType.Invalid;
1759             public ResourceLoadingStatusType Status
1760             {
1761                 get
1762                 {
1763                     return status;
1764                 }
1765                 set
1766                 {
1767                     status = value;
1768                 }
1769             }
1770         }
1771
1772         internal new class Property
1773         {
1774             internal static readonly int IMAGE = Interop.ImageView.ImageGet();
1775             internal static readonly int PreMultipliedAlpha = Interop.ImageView.PreMultipliedAlphaGet();
1776             internal static readonly int PixelArea = Interop.ImageView.PixelAreaGet();
1777             internal static readonly int PlaceHolderUrl = Interop.ImageView.PlaceHolderImageGet();
1778             internal static readonly int TransitionEffect = Interop.ImageView.TransitionEffectGet();
1779         }
1780
1781         private enum ImageType
1782         {
1783             /// <summary>
1784             /// For Normal Image.
1785             /// </summary>
1786             Normal = 0,
1787
1788             /// <summary>
1789             /// For normal image, with synchronous loading and orientation correction property
1790             /// </summary>
1791             Specific = 1,
1792
1793             /// <summary>
1794             /// For nine-patch image
1795             /// </summary>
1796             Npatch = 2,
1797         }
1798
1799         private void OnBorderChanged(int x, int y, int width, int height)
1800         {
1801             Border = new Rectangle(x, y, width, height);
1802         }
1803         private void OnPixelAreaChanged(float x, float y, float z, float w)
1804         {
1805             PixelArea = new RelativeVector4(x, y, z, w);
1806         }
1807
1808         private class ImageLayout : LayoutItem
1809         {
1810             /// <summary>
1811             /// Gets or sets the mode to adjust view size to preserve the aspect ratio of the image resource.
1812             /// If this is set to be true, then the width or height, which is not set by user explicitly, can be adjusted to preserve the aspect ratio of the image resource.
1813             /// </summary>
1814             [EditorBrowsable(EditorBrowsableState.Never)]
1815             public bool AdjustViewSize
1816             {
1817                 get
1818                 {
1819                     return (Owner as ImageView)?.AdjustViewSize ?? false;
1820                 }
1821                 set
1822                 {
1823                     if (Owner is ImageView imageView)
1824                     {
1825                         imageView.AdjustViewSize = value;
1826                     }
1827                 }
1828             }
1829
1830             /// <inheritdoc/>
1831             [EditorBrowsable(EditorBrowsableState.Never)]
1832             protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
1833             {
1834                 // To not change the view size by DALi
1835                 Owner.WidthResizePolicy = ResizePolicyType.Fixed;
1836                 Owner.HeightResizePolicy = ResizePolicyType.Fixed;
1837
1838                 float specWidth = widthMeasureSpec.Size.AsDecimal();
1839                 float specHeight = heightMeasureSpec.Size.AsDecimal();
1840                 float naturalWidth = Owner.NaturalSize.Width;
1841                 float naturalHeight = Owner.NaturalSize.Height;
1842                 float minWidth = Owner.MinimumSize.Width;
1843                 float maxWidth = Owner.MaximumSize.Width;
1844                 float minHeight = Owner.MinimumSize.Height;
1845                 float maxHeight = Owner.MaximumSize.Height;
1846                 float aspectRatio = (naturalWidth > 0) ? (naturalHeight / naturalWidth) : 0;
1847
1848                 // Assume that the new width and height are given from the view's suggested size by default.
1849                 float newWidth = Math.Min(Math.Max(naturalWidth, minWidth), (maxWidth < 0 ? Int32.MaxValue : maxWidth));
1850                 float newHeight = Math.Min(Math.Max(naturalHeight, minHeight), (maxHeight < 0 ? Int32.MaxValue : maxHeight));
1851
1852                 // The width and height measure specs are going to be used to set measured size.
1853                 // Mark that the measure specs are changed by default to update measure specs later.
1854                 bool widthSpecChanged = true;
1855                 bool heightSpecChanged = true;
1856
1857                 if (widthMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly)
1858                 {
1859                     newWidth = specWidth;
1860                     widthSpecChanged = false;
1861
1862                     if (heightMeasureSpec.Mode != MeasureSpecification.ModeType.Exactly)
1863                     {
1864                         if ((AdjustViewSize) && (aspectRatio > 0))
1865                         {
1866                             newHeight = newWidth * aspectRatio;
1867                         }
1868                     }
1869                 }
1870
1871                 if (heightMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly)
1872                 {
1873                     newHeight = specHeight;
1874                     heightSpecChanged = false;
1875
1876                     if (widthMeasureSpec.Mode != MeasureSpecification.ModeType.Exactly)
1877                     {
1878                         if ((AdjustViewSize) && (aspectRatio > 0))
1879                         {
1880                             newWidth = newHeight / aspectRatio;
1881                         }
1882                     }
1883                 }
1884
1885                 if (widthSpecChanged)
1886                 {
1887                     widthMeasureSpec = new MeasureSpecification(new LayoutLength(newWidth), MeasureSpecification.ModeType.Exactly);
1888                 }
1889
1890                 if (heightSpecChanged)
1891                 {
1892                     heightMeasureSpec = new MeasureSpecification(new LayoutLength(newHeight), MeasureSpecification.ModeType.Exactly);
1893                 }
1894
1895                 MeasuredSize.StateType childWidthState = MeasuredSize.StateType.MeasuredSizeOK;
1896                 MeasuredSize.StateType childHeightState = MeasuredSize.StateType.MeasuredSizeOK;
1897
1898                 SetMeasuredDimensions(ResolveSizeAndState(new LayoutLength(newWidth), widthMeasureSpec, childWidthState),
1899                                       ResolveSizeAndState(new LayoutLength(newHeight), heightMeasureSpec, childHeightState));
1900             }
1901         }
1902     }
1903 }