From e6dd045001548da7aeb4f88b1ab5b69de5c84f90 Mon Sep 17 00:00:00 2001 From: "Eunki, Hong" Date: Wed, 2 Mar 2022 23:05:43 +0900 Subject: [PATCH] [NUI] Fix ImageView.Image property bugs + Make AnimatedImageView use LazyUpdate. Previous LazyUpdate feature have some bugs when we try to get ImageView.Image. That API get from native engine side properies forcely. But actually, we didn't send our NUI cached local properties before get from native engine. So the result value was not matched what we expected want to get. and also, LazyUpdate feature have some bugs when we call 'Play', 'Stop', etc. This patch UpdateImage properties synchronously when we call these AnimationAction API. Furthermore, Make AnimatedImageView (which already use LazyUpdate feature internally) also use LazyUpdate feature. We cannot know URLs Property changeness. so keep a way to properties setup forcely. Signed-off-by: Eunki, Hong --- .../src/public/BaseComponents/AnimatedImageView.cs | 247 +++++++--------- .../AnimatedImageViewBindableProperty.cs | 18 -- .../src/public/BaseComponents/ImageView.cs | 319 ++++++++++++++------- .../BaseComponents/ImageViewBindableProperty.cs | 38 +-- .../Tizen.NUI.Devel.Tests/res/dali-logo-anim.gif | Bin 0 -> 85825 bytes .../testcase/TSAnimatedImageView.cs | 288 +++++++++++++++++++ .../Tizen.NUI.Devel.Tests/testcase/TSImageView.cs | 207 +++++++++++++ .../Samples/AnimatedImageViewTest.cs | 1 + 8 files changed, 849 insertions(+), 269 deletions(-) create mode 100644 test/Tizen.NUI.Devel.Tests.Ubuntu/Tizen.NUI.Devel.Tests/res/dali-logo-anim.gif create mode 100644 test/Tizen.NUI.Devel.Tests.Ubuntu/Tizen.NUI.Devel.Tests/testcase/TSAnimatedImageView.cs diff --git a/src/Tizen.NUI/src/public/BaseComponents/AnimatedImageView.cs b/src/Tizen.NUI/src/public/BaseComponents/AnimatedImageView.cs index 7afe68f..c5d3406 100755 --- a/src/Tizen.NUI/src/public/BaseComponents/AnimatedImageView.cs +++ b/src/Tizen.NUI/src/public/BaseComponents/AnimatedImageView.cs @@ -31,15 +31,15 @@ namespace Tizen.NUI.BaseComponents #endregion Internal #region Private - private string url = ""; + // Collection of animated-image-sensitive properties. + private static readonly List cachedAnimatedImagePropertyKeyList = new List { + ImageVisualProperty.BatchSize, + ImageVisualProperty.CacheSize, + ImageVisualProperty.FrameDelay, + ImageVisualProperty.LoopCount, + ImageVisualProperty.StopBehavior, + }; private List resourceURLs = new List(); - private int batchSize = 1; - private int cacheSize = 1; - private int frameDelay = 0; - private int loopCount = -1; - private bool dirtyFlag = false; - private StopBehaviorType stopBehavior; - private PropertyMap propertyMap; #endregion Private #region Constructor, Destructor, Dispose @@ -53,8 +53,6 @@ namespace Tizen.NUI.BaseComponents ActionPlay = Interop.AnimatedImageView.AnimatedImageVisualActionPlayGet(); ActionPause = Interop.AnimatedImageView.AnimatedImageVisualActionPauseGet(); ActionStop = Interop.AnimatedImageView.AnimatedImageVisualActionStopGet(); - - dirtyFlag = true; } /// @@ -79,37 +77,6 @@ namespace Tizen.NUI.BaseComponents #region Property /// - /// Image URL for Animated-GIF - /// - // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) - [EditorBrowsable(EditorBrowsableState.Never)] - public new string ResourceUrl - { - get - { - return GetValue(ResourceUrlProperty) as string; - } - set - { - SetValue(ResourceUrlProperty, value); - NotifyPropertyChanged(); - } - } - - private string InternalResourceUrl - { - get - { - return url; - } - set - { - dirtyFlag = true; - url = value; - } - } - - /// /// Image URL list for Image-Array /// // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) @@ -145,12 +112,18 @@ namespace Tizen.NUI.BaseComponents { get { - return batchSize; + int ret = 1; + + PropertyValue batchSize = GetCachedImageVisualProperty(ImageVisualProperty.BatchSize); + batchSize?.Get(out ret); + batchSize?.Dispose(); + + return ret; } set { - dirtyFlag = true; - batchSize = value; + using PropertyValue setValue = new PropertyValue(value); + UpdateImage(ImageVisualProperty.BatchSize, setValue); } } @@ -181,12 +154,18 @@ namespace Tizen.NUI.BaseComponents { get { - return cacheSize; + int ret = 1; + + PropertyValue cacheSize = GetCachedImageVisualProperty(ImageVisualProperty.CacheSize); + cacheSize?.Get(out ret); + cacheSize?.Dispose(); + + return ret; } set { - dirtyFlag = true; - cacheSize = value; + using PropertyValue setValue = new PropertyValue(value); + UpdateImage(ImageVisualProperty.CacheSize, setValue); } } @@ -216,12 +195,18 @@ namespace Tizen.NUI.BaseComponents { get { - return frameDelay; + int ret = 0; + + PropertyValue frameDelay = GetCachedImageVisualProperty(ImageVisualProperty.FrameDelay); + frameDelay?.Get(out ret); + frameDelay?.Dispose(); + + return ret; } set { - dirtyFlag = true; - frameDelay = value; + using PropertyValue setValue = new PropertyValue(value); + UpdateImage(ImageVisualProperty.FrameDelay, setValue); } } @@ -247,12 +232,18 @@ namespace Tizen.NUI.BaseComponents { get { - return loopCount; + int ret = -1; + + PropertyValue loopCount = GetCachedImageVisualProperty(ImageVisualProperty.LoopCount); + loopCount?.Get(out ret); + loopCount?.Dispose(); + + return ret; } set { - dirtyFlag = true; - loopCount = value; + using PropertyValue setValue = new PropertyValue(value); + UpdateImage(ImageVisualProperty.LoopCount, setValue); } } @@ -275,14 +266,20 @@ namespace Tizen.NUI.BaseComponents private StopBehaviorType InternalStopBehavior { - set + get { - stopBehavior = (StopBehaviorType)value; - dirtyFlag = true; + int ret = 0; + + PropertyValue stopBehavior = GetCachedImageVisualProperty(ImageVisualProperty.StopBehavior); + stopBehavior?.Get(out ret); + stopBehavior?.Dispose(); + + return (StopBehaviorType)ret; } - get + set { - return stopBehavior; + using PropertyValue setValue = new PropertyValue((int)value); + UpdateImage(ImageVisualProperty.StopBehavior, setValue); } } @@ -335,6 +332,9 @@ namespace Tizen.NUI.BaseComponents { set { + // Sync as current properties + UpdateImage(); + DoAction(ImageView.Property.IMAGE, ActionJumpTo, new PropertyValue(value)); } get @@ -372,101 +372,76 @@ namespace Tizen.NUI.BaseComponents [EditorBrowsable(EditorBrowsableState.Never)] public void SetValues() { - if (dirtyFlag == false) - { - return; - } - dirtyFlag = false; + // This API assume that Animated relative properties setuped forcely. + imagePropertyUpdatedFlag = true; - PropertyMap tMap = new PropertyMap(); - PropertyValue animatiedImage = new PropertyValue((int)Visual.Type.AnimatedImage); - tMap.Insert(Visual.Property.Type, animatiedImage); - if (resourceURLs?.Count != 0) - { - PropertyArray indexPropertyArray = new PropertyArray(); - PropertyArray returnedArr = new PropertyArray(); - PropertyValue index = new PropertyValue(); - foreach (var iter in resourceURLs) - { - index = new PropertyValue(iter); - returnedArr = indexPropertyArray.Add(index); - } - index.Dispose(); - returnedArr.Dispose(); - PropertyValue arrayProperty = new PropertyValue(indexPropertyArray); - tMap.Insert(ImageVisualProperty.URL, arrayProperty); - PropertyValue frameDelayProperty = new PropertyValue(frameDelay); - tMap.Insert(ImageVisualProperty.FrameDelay, frameDelayProperty); - - arrayProperty.Dispose(); - indexPropertyArray.Dispose(); - frameDelayProperty.Dispose(); - } - else - { - PropertyValue urlProperty = new PropertyValue(url); - tMap.Insert(ImageVisualProperty.URL, urlProperty); - urlProperty.Dispose(); - } - - PropertyValue batchSizeProperty = new PropertyValue(batchSize); - tMap.Insert(ImageVisualProperty.BatchSize, batchSizeProperty); - PropertyValue cacheSizeProperty = new PropertyValue(cacheSize); - tMap.Insert(ImageVisualProperty.CacheSize, cacheSizeProperty); - PropertyValue loopCountProperty = new PropertyValue(loopCount); - tMap.Insert(ImageVisualProperty.LoopCount, loopCountProperty); - PropertyValue stopBehaviorProperty = new PropertyValue((int)stopBehavior); - tMap.Insert(ImageVisualProperty.StopBehavior, stopBehaviorProperty); - - loopCountProperty.Dispose(); - cacheSizeProperty.Dispose(); - batchSizeProperty.Dispose(); - stopBehaviorProperty.Dispose(); - - propertyMap = tMap; - PropertyValue mapProperty = new PropertyValue(propertyMap); - SetProperty(ImageView.Property.IMAGE, mapProperty); - mapProperty.Dispose(); - - tMap.Dispose(); - animatiedImage.Dispose(); + // Sync as current properties + UpdateImage(); } /// - /// Play animation + /// Update animated-image-relative properties synchronously. + /// After call this API, All image properties updated. /// - // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) [EditorBrowsable(EditorBrowsableState.Never)] - public new void Play() + protected override void UpdateImage() { - SetValues(); - base.Play(); - } + if(!imagePropertyUpdatedFlag) return; - /// - /// Pause animation. Currently pause and stop are same - /// - // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) - [EditorBrowsable(EditorBrowsableState.Never)] - public new void Pause() - { - SetValues(); - base.Pause(); + if (resourceURLs?.Count != 0) + { + using(PropertyArray indexPropertyArray = new PropertyArray()) + { + PropertyArray returnedArr = new PropertyArray(); + foreach (var iter in resourceURLs) + { + using(PropertyValue index = new PropertyValue(iter)) + { + returnedArr = indexPropertyArray.Add(index); + } + } + returnedArr.Dispose(); + using PropertyValue arrayProperty = new PropertyValue(indexPropertyArray); + + // Trigger the ImageView so that we have something update + UpdateImage(ImageVisualProperty.URL, arrayProperty); + } + } + + using PropertyValue animatiedImage = new PropertyValue((int)Visual.Type.AnimatedImage); + UpdateImage(Visual.Property.Type, animatiedImage); + + base.UpdateImage(); } /// - /// Stop animation. Currently pause and stop are same + /// Update NUI cached animated image visual property map by inputed property map. + /// And call base.MergeCachedImageVisualProperty() /// - // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) + /// + /// For performance issue, we will collect only "cachedAnimatedImagePropertyKeyList" hold in this class. + /// [EditorBrowsable(EditorBrowsableState.Never)] - public new void Stop() + protected override void MergeCachedImageVisualProperty(PropertyMap map) { - SetValues(); - base.Stop(); + if(map == null) return; + if(cachedImagePropertyMap == null) + { + cachedImagePropertyMap = new PropertyMap(); + } + foreach(var key in cachedAnimatedImagePropertyKeyList) + { + PropertyValue value = map.Find(key); + if(value != null) + { + // Update-or-Insert new value + cachedImagePropertyMap[key] = value; + } + } + base.MergeCachedImageVisualProperty(map); } #endregion Method - #region Event, Enum, Struct, ETC /// diff --git a/src/Tizen.NUI/src/public/BaseComponents/AnimatedImageViewBindableProperty.cs b/src/Tizen.NUI/src/public/BaseComponents/AnimatedImageViewBindableProperty.cs index fcb0380..804e5d4 100755 --- a/src/Tizen.NUI/src/public/BaseComponents/AnimatedImageViewBindableProperty.cs +++ b/src/Tizen.NUI/src/public/BaseComponents/AnimatedImageViewBindableProperty.cs @@ -23,24 +23,6 @@ namespace Tizen.NUI.BaseComponents public partial class AnimatedImageView { /// - /// ResourceUrlProperty - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public static new readonly BindableProperty ResourceUrlProperty = BindableProperty.Create(nameof(ResourceUrl), typeof(string), typeof(AnimatedImageView), string.Empty, propertyChanged: (bindable, oldValue, newValue) => - { - var instance = (Tizen.NUI.BaseComponents.AnimatedImageView)bindable; - if (newValue != null) - { - instance.InternalResourceUrl = (string)newValue; - } - }, - defaultValueCreator: (bindable) => - { - var instance = (Tizen.NUI.BaseComponents.AnimatedImageView)bindable; - return instance.InternalResourceUrl; - }); - - /// /// BatchSizeProperty /// [EditorBrowsable(EditorBrowsableState.Never)] diff --git a/src/Tizen.NUI/src/public/BaseComponents/ImageView.cs b/src/Tizen.NUI/src/public/BaseComponents/ImageView.cs index 44ea173..83916fb 100755 --- a/src/Tizen.NUI/src/public/BaseComponents/ImageView.cs +++ b/src/Tizen.NUI/src/public/BaseComponents/ImageView.cs @@ -15,6 +15,7 @@ * */ using System; +using System.Collections.Generic; using System.Runtime.InteropServices; using System.ComponentModel; using Tizen.NUI.Binding; @@ -37,9 +38,26 @@ namespace Tizen.NUI.BaseComponents private _resourceLoadedCallbackType _resourceLoadedCallback; // Collection of image-sensitive properties. - private bool _imagePropertyUpdatedFlag = false; - private bool _imagePropertyUpdateProcessAttachedFlag = false; - private PropertyMap _imagePropertyMap; + private static readonly List cachedImagePropertyKeyList = new List { + Visual.Property.Type, + ImageVisualProperty.URL, + ImageVisualProperty.AlphaMaskURL, + ImageVisualProperty.CropToMask, + Visual.Property.VisualFittingMode, + ImageVisualProperty.DesiredWidth, + ImageVisualProperty.DesiredHeight, + ImageVisualProperty.ReleasePolicy, + ImageVisualProperty.WrapModeU, + ImageVisualProperty.WrapModeV, + ImageVisualProperty.SynchronousLoading, + ImageVisualProperty.OrientationCorrection, + NpatchImageVisualProperty.Border, + NpatchImageVisualProperty.BorderOnly, + }; + internal PropertyMap cachedImagePropertyMap; + internal bool imagePropertyUpdatedFlag = false; + + private bool imagePropertyUpdateProcessAttachedFlag = false; private Rectangle _border; private string _resourceUrl = ""; private int _desired_width = -1; @@ -260,12 +278,20 @@ namespace Tizen.NUI.BaseComponents { if (_border == null) { + // Sync as current properties + UpdateImage(); + // Get current properties force. - // TODO: Need to make some flag that we only need cached property map. PropertyMap returnValue = new PropertyMap(); PropertyValue image = GetProperty(ImageView.Property.IMAGE); image?.Get(returnValue); image?.Dispose(); + + // Update cached property map + if(returnValue != null) + { + MergeCachedImageVisualProperty(returnValue); + } return returnValue; } else @@ -279,14 +305,13 @@ namespace Tizen.NUI.BaseComponents { PropertyValue setValue = new Tizen.NUI.PropertyValue(value); SetProperty(ImageView.Property.IMAGE, setValue); + // Image properties are changed hardly. We should ignore lazy UpdateImage - _imagePropertyUpdatedFlag = false; - _imagePropertyMap?.Dispose(); - _imagePropertyMap = null; - if(value != null) - { - _imagePropertyMap = new PropertyMap(value); - } + imagePropertyUpdatedFlag = false; + cachedImagePropertyMap?.Dispose(); + cachedImagePropertyMap = null; + MergeCachedImageVisualProperty(value); + NotifyPropertyChanged(); setValue?.Dispose(); } @@ -564,6 +589,9 @@ namespace Tizen.NUI.BaseComponents /// 5 public void Reload() { + // Sync as current properties + UpdateImage(); + PropertyValue attributes = new PropertyValue(0); this.DoAction(ImageView.Property.IMAGE, ActionReload, attributes); attributes?.Dispose(); @@ -575,6 +603,9 @@ namespace Tizen.NUI.BaseComponents /// 5 public void Play() { + // Sync as current properties + UpdateImage(); + PropertyValue attributes = new PropertyValue(0); this.DoAction(ImageView.Property.IMAGE, ActionPlay, attributes); attributes?.Dispose(); @@ -586,6 +617,9 @@ namespace Tizen.NUI.BaseComponents /// 5 public void Pause() { + // Sync as current properties + UpdateImage(); + PropertyValue attributes = new PropertyValue(0); this.DoAction(ImageView.Property.IMAGE, ActionPause, attributes); attributes?.Dispose(); @@ -597,6 +631,9 @@ namespace Tizen.NUI.BaseComponents /// 5 public void Stop() { + // Sync as current properties + UpdateImage(); + PropertyValue attributes = new PropertyValue(0); this.DoAction(ImageView.Property.IMAGE, ActionStop, attributes); attributes?.Dispose(); @@ -627,7 +664,7 @@ namespace Tizen.NUI.BaseComponents { string ret = ""; - PropertyValue maskUrl = _imagePropertyMap?.Find(ImageVisualProperty.AlphaMaskURL); + PropertyValue maskUrl = GetCachedImageVisualProperty(ImageVisualProperty.AlphaMaskURL); maskUrl?.Get(out ret); maskUrl?.Dispose(); @@ -638,7 +675,7 @@ namespace Tizen.NUI.BaseComponents PropertyValue setValue = new PropertyValue(value ?? ""); UpdateImage(ImageVisualProperty.AlphaMaskURL, setValue); // When we never set CropToMask property before, we should set default value as true. - using(PropertyValue cropToMask = _imagePropertyMap?.Find(ImageVisualProperty.CropToMask)) + using(PropertyValue cropToMask = GetCachedImageVisualProperty(ImageVisualProperty.CropToMask)) { if(cropToMask == null) { @@ -673,7 +710,7 @@ namespace Tizen.NUI.BaseComponents { bool ret = false; - PropertyValue cropToMask = _imagePropertyMap?.Find(ImageVisualProperty.CropToMask); + PropertyValue cropToMask = GetCachedImageVisualProperty(ImageVisualProperty.CropToMask); cropToMask?.Get(out ret); cropToMask?.Dispose(); @@ -787,7 +824,7 @@ namespace Tizen.NUI.BaseComponents { int ret = (int)VisualFittingModeType.Fill; - PropertyValue fittingMode = _imagePropertyMap?.Find(Visual.Property.VisualFittingMode); + PropertyValue fittingMode = GetCachedImageVisualProperty(Visual.Property.VisualFittingMode); fittingMode?.Get(out ret); fittingMode?.Dispose(); @@ -833,7 +870,7 @@ namespace Tizen.NUI.BaseComponents { UpdateImage(); } - PropertyValue desirewidth = _imagePropertyMap?.Find(ImageVisualProperty.DesiredWidth); + PropertyValue desirewidth = GetCachedImageVisualProperty(ImageVisualProperty.DesiredWidth); desirewidth?.Get(out _desired_width); desirewidth?.Dispose(); @@ -880,7 +917,7 @@ namespace Tizen.NUI.BaseComponents { UpdateImage(); } - PropertyValue desireheight = _imagePropertyMap?.Find(ImageVisualProperty.DesiredHeight); + PropertyValue desireheight = GetCachedImageVisualProperty(ImageVisualProperty.DesiredHeight); desireheight?.Get(out _desired_height); desireheight?.Dispose(); @@ -922,7 +959,7 @@ namespace Tizen.NUI.BaseComponents { int ret = (int)ReleasePolicyType.Detached; - PropertyValue releasePoli = _imagePropertyMap?.Find(ImageVisualProperty.ReleasePolicy); + PropertyValue releasePoli = GetCachedImageVisualProperty(ImageVisualProperty.ReleasePolicy); releasePoli?.Get(out ret); releasePoli?.Dispose(); @@ -964,7 +1001,7 @@ namespace Tizen.NUI.BaseComponents { int ret = (int)WrapModeType.Default; - PropertyValue wrapModeU = _imagePropertyMap?.Find(ImageVisualProperty.WrapModeU); + PropertyValue wrapModeU = GetCachedImageVisualProperty(ImageVisualProperty.WrapModeU); wrapModeU?.Get(out ret); wrapModeU?.Dispose(); @@ -1007,7 +1044,7 @@ namespace Tizen.NUI.BaseComponents { int ret = (int)WrapModeType.Default; - PropertyValue wrapModeV = _imagePropertyMap?.Find(ImageVisualProperty.WrapModeV); + PropertyValue wrapModeV = GetCachedImageVisualProperty(ImageVisualProperty.WrapModeV); wrapModeV?.Get(out ret); wrapModeV?.Dispose(); @@ -1169,14 +1206,14 @@ namespace Tizen.NUI.BaseComponents _border = null; borderSelector?.Reset(this); resourceUrlSelector?.Reset(this); - _imagePropertyUpdatedFlag = false; - if (_imagePropertyUpdateProcessAttachedFlag) + imagePropertyUpdatedFlag = false; + if (imagePropertyUpdateProcessAttachedFlag) { ProcessorController.Instance.ProcessorOnceEvent -= UpdateImage; - _imagePropertyUpdateProcessAttachedFlag = false; + imagePropertyUpdateProcessAttachedFlag = false; } - _imagePropertyMap?.Dispose(); - _imagePropertyMap = null; + cachedImagePropertyMap?.Dispose(); + cachedImagePropertyMap = null; } base.Dispose(type); @@ -1215,7 +1252,18 @@ namespace Tizen.NUI.BaseComponents if(_resourceUrl != value) { _resourceUrl = value; - UpdateImage(ImageVisualProperty.URL, new PropertyValue(value)); + if(string.IsNullOrEmpty(_resourceUrl)) + { + // Special case. If we set ResourceUrl as empty, Unregist visual. + RemoveImage(); + } + else + { + using(PropertyValue setValue = new PropertyValue(value)) + { + UpdateImage(ImageVisualProperty.URL, setValue); + } + } } } @@ -1233,55 +1281,57 @@ namespace Tizen.NUI.BaseComponents } /// - /// Lazy call to UpdateImage. - /// Collect Properties need to be update, and set properties that starts the Processing. + /// Unregist image visual directly. After this operation, we cannot get any properties from Image property. /// - [EditorBrowsable(EditorBrowsableState.Never)] - protected void UpdateImage(int key, PropertyValue value) + private void RemoveImage() { - // If we set ResourceUrl as empty, Unregist visual. - if (key == ImageVisualProperty.URL && string.IsNullOrEmpty(_resourceUrl)) + // If previous resourceUrl was already empty, we don't need to do anything. just ignore. + // Unregist and detach process only if previous resourceUrl was not empty + string currentResourceUrl = ""; + PropertyValue currentResourceUrlValue = GetCachedImageVisualProperty(ImageVisualProperty.URL); + if((currentResourceUrlValue?.Get(out currentResourceUrl) ?? false) && !string.IsNullOrEmpty(currentResourceUrl)) { - // If previous resourceUrl was already empty, we don't need to do anything. just ignore. - // Unregist and dettach Process only if previous resourceUrl was not empty - string currentResourceUrl = ""; - PropertyValue currentResourceUrlValue = _imagePropertyMap?.Find(ImageVisualProperty.URL); - if((currentResourceUrlValue?.Get(out currentResourceUrl) ?? false) && !string.IsNullOrEmpty(currentResourceUrl)) - { - PropertyValue emptyValue = new PropertyValue(); - - // Remove current registed Image. - SetProperty(ImageView.Property.IMAGE, emptyValue); + PropertyValue emptyValue = new PropertyValue(); - // Image visual is not exist anymore. We should ignore lazy UpdateImage - _imagePropertyUpdatedFlag = false; - if(_imagePropertyUpdateProcessAttachedFlag) - { - ProcessorController.Instance.ProcessorOnceEvent -= UpdateImage; - _imagePropertyUpdateProcessAttachedFlag = false; - } - // Update resourceUrl as null - _imagePropertyMap[ImageVisualProperty.URL] = emptyValue; + // Remove current registed Image. + SetProperty(ImageView.Property.IMAGE, emptyValue); - emptyValue?.Dispose(); + // Image visual is not exist anymore. We should ignore lazy UpdateImage + imagePropertyUpdatedFlag = false; + if(imagePropertyUpdateProcessAttachedFlag) + { + ProcessorController.Instance.ProcessorOnceEvent -= UpdateImage; + imagePropertyUpdateProcessAttachedFlag = false; } - return; + // Update resourceUrl as empty value + cachedImagePropertyMap[ImageVisualProperty.URL] = emptyValue; + + emptyValue?.Dispose(); } + currentResourceUrlValue?.Dispose(); + } + /// + /// Lazy call to UpdateImage. + /// Collect Properties need to be update, and set properties that starts the Processing. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + protected virtual void UpdateImage(int key, PropertyValue value) + { // Update image property map value as inputed value. if (key != 0) { - if (_imagePropertyMap == null) + if (cachedImagePropertyMap == null) { - _imagePropertyMap = new PropertyMap(); + cachedImagePropertyMap = new PropertyMap(); } - _imagePropertyUpdatedFlag = true; - _imagePropertyMap[key] = value; + imagePropertyUpdatedFlag = true; + cachedImagePropertyMap[key] = value; // Lazy update only if _resourceUrl is not empty and ProcessAttachedFlag is false. - if (!string.IsNullOrEmpty(_resourceUrl) && !_imagePropertyUpdateProcessAttachedFlag) + if (!string.IsNullOrEmpty(_resourceUrl) && !imagePropertyUpdateProcessAttachedFlag) { - _imagePropertyUpdateProcessAttachedFlag = true; + imagePropertyUpdateProcessAttachedFlag = true; ProcessorController.Instance.ProcessorOnceEvent += UpdateImage; // Call process hardly. ProcessorController.Instance.Awake(); @@ -1295,7 +1345,7 @@ namespace Tizen.NUI.BaseComponents private void UpdateImage(object source, EventArgs e) { UpdateImage(); - _imagePropertyUpdateProcessAttachedFlag = false; + imagePropertyUpdateProcessAttachedFlag = false; } /// @@ -1308,31 +1358,42 @@ namespace Tizen.NUI.BaseComponents /// Please call this ImageView.UpdateImage() API. /// [EditorBrowsable(EditorBrowsableState.Never)] - protected void UpdateImage() + protected virtual void UpdateImage() { - if(!_imagePropertyUpdatedFlag) return; + if(!imagePropertyUpdatedFlag) return; - _imagePropertyUpdatedFlag = false; + imagePropertyUpdatedFlag = false; - if(_imagePropertyMap == null) + if(cachedImagePropertyMap == null) { - _imagePropertyMap = new PropertyMap(); + cachedImagePropertyMap = new PropertyMap(); } - if (_border == null) - { - PropertyValue image = new PropertyValue((int)Visual.Type.Image); - _imagePropertyMap[Visual.Property.Type] = image; - image?.Dispose(); - } - else + // Checkup the cached visual type is AnimatedImage. + // It is trick to know that this code is running on AnimatedImageView.UpdateImage() or not. + int visualType = -1; + if(!((GetCachedImageVisualProperty(Visual.Property.Type)?.Get(out visualType) ?? false) && visualType == (int)Visual.Type.AnimatedImage)) { - PropertyValue nPatch = new PropertyValue((int)Visual.Type.NPatch); - _imagePropertyMap[Visual.Property.Type] = nPatch; - nPatch?.Dispose(); - PropertyValue border = new PropertyValue(_border); - _imagePropertyMap[NpatchImageVisualProperty.Border] = border; - border?.Dispose(); + // If ResourceUrl is not setuped, don't set property. fast return. + if(string.IsNullOrEmpty(_resourceUrl)) + { + return; + } + if (_border == null) + { + PropertyValue image = new PropertyValue((int)Visual.Type.Image); + cachedImagePropertyMap[Visual.Property.Type] = image; + image?.Dispose(); + } + else + { + PropertyValue nPatch = new PropertyValue((int)Visual.Type.NPatch); + cachedImagePropertyMap[Visual.Property.Type] = nPatch; + nPatch?.Dispose(); + PropertyValue border = new PropertyValue(_border); + cachedImagePropertyMap[NpatchImageVisualProperty.Border] = border; + border?.Dispose(); + } } if (backgroundExtraData != null && backgroundExtraData.CornerRadius != null) @@ -1340,8 +1401,8 @@ namespace Tizen.NUI.BaseComponents using (var cornerRadius = new PropertyValue(backgroundExtraData.CornerRadius)) using (var cornerRadiusPolicy = new PropertyValue((int)backgroundExtraData.CornerRadiusPolicy)) { - _imagePropertyMap[Visual.Property.CornerRadius] = cornerRadius; - _imagePropertyMap[Visual.Property.CornerRadiusPolicy] = new PropertyValue((int)(backgroundExtraData.CornerRadiusPolicy)); + cachedImagePropertyMap[Visual.Property.CornerRadius] = cornerRadius; + cachedImagePropertyMap[Visual.Property.CornerRadiusPolicy] = new PropertyValue((int)(backgroundExtraData.CornerRadiusPolicy)); } } @@ -1351,9 +1412,9 @@ namespace Tizen.NUI.BaseComponents using (var borderlineColor = new PropertyValue(backgroundExtraData.BorderlineColor)) using (var borderlineOffset = new PropertyValue(backgroundExtraData.BorderlineOffset)) { - _imagePropertyMap[Visual.Property.BorderlineWidth] = borderlineWidth; - _imagePropertyMap[Visual.Property.BorderlineColor] = borderlineColor; - _imagePropertyMap[Visual.Property.BorderlineOffset] = borderlineOffset; + cachedImagePropertyMap[Visual.Property.BorderlineWidth] = borderlineWidth; + cachedImagePropertyMap[Visual.Property.BorderlineColor] = borderlineColor; + cachedImagePropertyMap[Visual.Property.BorderlineOffset] = borderlineOffset; } } @@ -1380,13 +1441,13 @@ namespace Tizen.NUI.BaseComponents } PropertyValue returnWidth = new PropertyValue(adjustedDesiredWidth); - _imagePropertyMap[ImageVisualProperty.DesiredWidth] = returnWidth; + cachedImagePropertyMap[ImageVisualProperty.DesiredWidth] = returnWidth; returnWidth?.Dispose(); PropertyValue returnHeight = new PropertyValue(adjustedDesiredHeight); - _imagePropertyMap[ImageVisualProperty.DesiredHeight] = returnHeight; + cachedImagePropertyMap[ImageVisualProperty.DesiredHeight] = returnHeight; returnHeight?.Dispose(); PropertyValue scaleToFit = new PropertyValue((int)FittingModeType.ScaleToFill); - _imagePropertyMap[ImageVisualProperty.FittingMode] = scaleToFit; + cachedImagePropertyMap[ImageVisualProperty.FittingMode] = scaleToFit; scaleToFit?.Dispose(); } else @@ -1399,24 +1460,84 @@ namespace Tizen.NUI.BaseComponents UpdateImageMap(); } + + /// + /// Merge our collected properties, and set IMAGE property internally. + /// private void UpdateImageMap() { - PropertyMap imageMap = new PropertyMap(); + // Note : We can't use ImageView.Image property here. Because That property call UpdateImage internally. + using(PropertyMap imageMap = new PropertyMap()) + { + using(PropertyValue returnValue = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE)) + { + returnValue?.Get(imageMap); + } + if(cachedImagePropertyMap != null) + { + imageMap?.Merge(cachedImagePropertyMap); + } + using(PropertyValue setValue = new PropertyValue(imageMap)) + { + SetProperty(ImageView.Property.IMAGE, setValue); + } + + // Update cached image property. + MergeCachedImageVisualProperty(imageMap); + } + } - PropertyValue image = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE); - image?.Get(imageMap); - imageMap.Merge(_imagePropertyMap); - PropertyValue setValue = new PropertyValue(imageMap); - SetProperty(ImageView.Property.IMAGE, setValue); + /// + /// Get image visual property by key. + /// If we found value in local Cached result, return that. + /// Else, get synced native map and return that. + /// If there is no matched value, return null. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + protected virtual PropertyValue GetImageVisualProperty(int key) + { + PropertyValue ret = GetCachedImageVisualProperty(key); + if(ret == null) + { + // If we cannot find result form cached map, Get value from native engine. + ret = Image?.Find(key); + } + return ret; + } - // Sync local PropertyMap - // TODO: Do we need to use GetProperty(SwigCPtr, ImageView.Property.IMAGE); here? - _imagePropertyMap.Dispose(); - _imagePropertyMap = new PropertyMap(imageMap); + /// + /// Get image visual property from NUI cached image map by key. + /// If there is no matched value, return null. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + protected virtual PropertyValue GetCachedImageVisualProperty(int key) + { + return cachedImagePropertyMap?.Find(key); + } - imageMap?.Dispose(); - image?.Dispose(); - setValue?.Dispose(); + /// + /// Update NUI cached image visual property map by inputed property map. + /// + /// + /// For performance issue, we will collect only "cachedImagePropertyKeyList" hold. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + protected virtual void MergeCachedImageVisualProperty(PropertyMap map) + { + if(map == null) return; + if(cachedImagePropertyMap == null) + { + cachedImagePropertyMap = new PropertyMap(); + } + foreach(var key in cachedImagePropertyKeyList) + { + PropertyValue value = map.Find(key); + if(value != null) + { + // Update-or-Insert new value + cachedImagePropertyMap[key] = value; + } + } } /// diff --git a/src/Tizen.NUI/src/public/BaseComponents/ImageViewBindableProperty.cs b/src/Tizen.NUI/src/public/BaseComponents/ImageViewBindableProperty.cs index 11ffa69..e7a3226 100755 --- a/src/Tizen.NUI/src/public/BaseComponents/ImageViewBindableProperty.cs +++ b/src/Tizen.NUI/src/public/BaseComponents/ImageViewBindableProperty.cs @@ -44,7 +44,7 @@ namespace Tizen.NUI.BaseComponents var imageView = (ImageView)bindable; string ret = ""; - imageView._imagePropertyMap?.Find(ImageVisualProperty.URL)?.Get(out ret); + imageView.GetCachedImageVisualProperty(ImageVisualProperty.URL)?.Get(out ret); return ret; })); @@ -94,13 +94,11 @@ namespace Tizen.NUI.BaseComponents if (imageView._border == null) { // Image properties are changed hardly. We should ignore lazy UpdateImage - imageView._imagePropertyUpdatedFlag = false; - imageView._imagePropertyMap?.Dispose(); - imageView._imagePropertyMap = null; - if(map != null) - { - imageView._imagePropertyMap = new PropertyMap(map); - } + imageView.imagePropertyUpdatedFlag = false; + imageView.cachedImagePropertyMap?.Dispose(); + imageView.cachedImagePropertyMap = null; + imageView.MergeCachedImageVisualProperty(map); + Tizen.NUI.Object.SetProperty((HandleRef)imageView.SwigCPtr, ImageView.Property.IMAGE, new Tizen.NUI.PropertyValue(map)); } } @@ -110,11 +108,19 @@ namespace Tizen.NUI.BaseComponents var imageView = (ImageView)bindable; if (imageView._border == null) { + // Sync as current properties + imageView.UpdateImage(); + // Get current properties force. - // TODO: Need to make some flag that we only need cached property map. - PropertyMap temp = new PropertyMap(); - Tizen.NUI.Object.GetProperty((HandleRef)imageView.SwigCPtr, ImageView.Property.IMAGE).Get(temp); - return temp; + PropertyMap returnValue = new PropertyMap(); + Tizen.NUI.Object.GetProperty((HandleRef)imageView.SwigCPtr, ImageView.Property.IMAGE).Get(returnValue); + + // Update cached property map + if(returnValue != null) + { + imageView.MergeCachedImageVisualProperty(returnValue); + } + return returnValue; } else { @@ -206,7 +212,7 @@ namespace Tizen.NUI.BaseComponents var imageView = (ImageView)bindable; bool ret = false; - imageView._imagePropertyMap?.Find(NpatchImageVisualProperty.BorderOnly)?.Get(out ret); + imageView.GetCachedImageVisualProperty(NpatchImageVisualProperty.BorderOnly)?.Get(out ret); return ret; })); @@ -235,7 +241,7 @@ namespace Tizen.NUI.BaseComponents var imageView = (ImageView)bindable; bool ret = false; - imageView._imagePropertyMap?.Find(ImageVisualProperty.SynchronousLoading)?.Get(out ret); + imageView.GetCachedImageVisualProperty(ImageVisualProperty.SynchronousLoading)?.Get(out ret); return ret; }); @@ -264,7 +270,7 @@ namespace Tizen.NUI.BaseComponents var imageView = (ImageView)bindable; bool ret = false; - imageView._imagePropertyMap?.Find(ImageVisualProperty.SynchronousLoading)?.Get(out ret); + imageView.GetCachedImageVisualProperty(ImageVisualProperty.SynchronousLoading)?.Get(out ret); return ret; }); @@ -294,7 +300,7 @@ namespace Tizen.NUI.BaseComponents bool ret = false; - imageView._imagePropertyMap?.Find(ImageVisualProperty.OrientationCorrection)?.Get(out ret); + imageView.GetCachedImageVisualProperty(ImageVisualProperty.OrientationCorrection)?.Get(out ret); return ret; })); diff --git a/test/Tizen.NUI.Devel.Tests.Ubuntu/Tizen.NUI.Devel.Tests/res/dali-logo-anim.gif b/test/Tizen.NUI.Devel.Tests.Ubuntu/Tizen.NUI.Devel.Tests/res/dali-logo-anim.gif new file mode 100644 index 0000000000000000000000000000000000000000..9a085ba95a031c676622cacd5da2777ee6c8d3bc GIT binary patch literal 85825 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 urls = testView.URLs; + + urls.Add(image_path); + urls.Add(image_path); + urls.Add(image_path); + + // URLs don't have any change notifier. So we have to update property forcely by SetValues API. + testView.SetValues(); + + int expectedTotalFrame = urls.Count; + int defaultFrameDelay = 100; ///< It can be changed in dali engine side + int expectFrameDelay = 300; + + Assert.AreEqual(expectedTotalFrame, testView.TotalFrame, "Total frame doesn't matched!"); + Assert.AreEqual(defaultFrameDelay, testView.FrameDelay, "Default frame delay doesn't matched!"); + testView.FrameDelay = expectFrameDelay; + Assert.AreEqual(expectFrameDelay, testView.FrameDelay, "frame delay doesn't matched!"); + + testView.Dispose(); + } + } +} diff --git a/test/Tizen.NUI.Devel.Tests.Ubuntu/Tizen.NUI.Devel.Tests/testcase/TSImageView.cs b/test/Tizen.NUI.Devel.Tests.Ubuntu/Tizen.NUI.Devel.Tests/testcase/TSImageView.cs index bde78a9..588549f 100644 --- a/test/Tizen.NUI.Devel.Tests.Ubuntu/Tizen.NUI.Devel.Tests/testcase/TSImageView.cs +++ b/test/Tizen.NUI.Devel.Tests.Ubuntu/Tizen.NUI.Devel.Tests/testcase/TSImageView.cs @@ -181,5 +181,212 @@ namespace Tizen.NUI.Devel.Tests testView.Dispose(); testView2.Dispose(); } + + [Test] + [Category("P1")] + [Description("internal API test in Ubuntu, ImageView.Image with ResourceUrl")] + [Property("SPEC", "Tizen.NUI.BaseComponents.ImageView.Image")] + [Property("SPEC_URL", "-")] + [Property("CRITERIA", "PRO")] + [Property("AUTHOR", "eunkiki.hong@samsung.com")] + public void Image_GET_VALUE_After_Set_ResourceUrl() + { + /* TEST CODE */ + ImageView testView = new ImageView(); + string resultUrl1 = ""; + + PropertyMap map1 = testView.Image; + + bool ret1 = (map1.Find(ImageVisualProperty.URL)?.Get(out resultUrl1) ?? false) && string.IsNullOrEmpty(resultUrl1); + + Assert.AreEqual(false, ret1, "map don't have ResourceUrl"); + + string testUrl1 = "test1"; + testView.ResourceUrl = testUrl1; + + PropertyMap map2 = testView.Image; + + bool ret2 = (map2.Find(ImageVisualProperty.URL)?.Get(out resultUrl1) ?? false) && !string.IsNullOrEmpty(resultUrl1); + + Assert.AreEqual(true, ret2, "map must have ResourceUrl"); + Assert.AreEqual(testUrl1, resultUrl1, "...and That value must be equal what we added"); + + testView.Dispose(); + } + + [Test] + [Category("P1")] + [Description("internal API test in Ubuntu, ImageView.Image with something")] + [Property("SPEC", "Tizen.NUI.BaseComponents.ImageView.Image")] + [Property("SPEC_URL", "-")] + [Property("CRITERIA", "PRO")] + [Property("AUTHOR", "eunkiki.hong@samsung.com")] + public void Image_GET_VALUE_After_Set_something() + { + /* TEST CODE */ + ImageView testView = new ImageView(); + string resultString = ""; + bool resultBool = false; + + using(PropertyMap map = testView.Image) + { + bool ret = (map.Find(ImageVisualProperty.URL)?.Get(out resultString) ?? false) && string.IsNullOrEmpty(resultString); + Assert.AreEqual(false, ret, "map don't have ResourceUrl"); + ret = map.Find(ImageVisualProperty.AlphaMaskURL)?.Get(out resultString) ?? false; + Assert.AreEqual(false, ret, "map don't have AlphaMaskURL"); + ret = map.Find(ImageVisualProperty.CropToMask)?.Get(out resultBool) ?? false; + Assert.AreEqual(false, ret, "map don't have CropToMask"); + ret = map.Find(ImageVisualProperty.SynchronousLoading)?.Get(out resultBool) ?? false; + Assert.AreEqual(false, ret, "map don't have SynchronousLoading"); + } + + string testUrl1 = "test1"; + testView.AlphaMaskURL = testUrl1; + testView.CropToMask = true; + testView.SynchronousLoading = true; + + using(PropertyMap map = testView.Image) + { + bool ret = (map.Find(ImageVisualProperty.URL)?.Get(out resultString) ?? false) && string.IsNullOrEmpty(resultString); + Assert.AreEqual(false, ret, "map don't have ResourceUrl"); + ret = (map.Find(ImageVisualProperty.AlphaMaskURL)?.Get(out resultString) ?? false) && string.IsNullOrEmpty(resultString); + Assert.AreEqual(false, ret, "map don't have AlphaMaskURL cause ResoureUrl is empty"); + ret = map.Find(ImageVisualProperty.CropToMask)?.Get(out resultBool) ?? false; + Assert.AreEqual(false, ret, "map don't have CropToMask cause ResoureUrl is empty"); + ret = map.Find(ImageVisualProperty.SynchronousLoading)?.Get(out resultBool) ?? false; + Assert.AreEqual(false, ret, "map don't have SynchronousLoading cause ResoureUrl is empty"); + } + + testView.ResourceUrl = image_path; + + using(PropertyMap map = testView.Image) + { + bool ret = (map.Find(ImageVisualProperty.URL)?.Get(out resultString) ?? false) && !string.IsNullOrEmpty(resultString); + Assert.AreEqual(true, ret, "map must have ResourceUrl"); + Assert.AreEqual(image_path, resultString, "...and That value must be equal what we added"); + ret = (map.Find(ImageVisualProperty.AlphaMaskURL)?.Get(out resultString) ?? false) && !string.IsNullOrEmpty(resultString); + Assert.AreEqual(true, ret, "map must have AlphaMaskURL"); + Assert.AreEqual(testUrl1, resultString, "...and That value must be equal what we added"); + ret = map.Find(ImageVisualProperty.CropToMask)?.Get(out resultBool) ?? false; + Assert.AreEqual(true, ret, "map must have CropToMask"); + Assert.AreEqual(true, resultBool, "...and That value must be equal what we added"); + ret = map.Find(ImageVisualProperty.SynchronousLoading)?.Get(out resultBool) ?? false; + Assert.AreEqual(true, ret, "map must have SynchronousLoading"); + Assert.AreEqual(true, resultBool, "...and That value must be equal what we added"); + } + + // Insert empty resource Url + testView.ResourceUrl = ""; + + using(PropertyMap map = testView.Image) + { + bool ret = (map.Find(ImageVisualProperty.URL)?.Get(out resultString) ?? false) && string.IsNullOrEmpty(resultString); + Assert.AreEqual(false, ret, "map don't have ResourceUrl"); + ret = (map.Find(ImageVisualProperty.AlphaMaskURL)?.Get(out resultString) ?? false) && string.IsNullOrEmpty(resultString); + Assert.AreEqual(false, ret, "map don't have AlphaMaskURL cause ResoureUrl is empty"); + ret = map.Find(ImageVisualProperty.CropToMask)?.Get(out resultBool) ?? false; + Assert.AreEqual(false, ret, "map don't have CropToMask cause ResoureUrl is empty"); + ret = map.Find(ImageVisualProperty.SynchronousLoading)?.Get(out resultBool) ?? false; + Assert.AreEqual(false, ret, "map don't have SynchronousLoading cause ResoureUrl is empty"); + } + + // Insert valid resource Url + testView.ResourceUrl = mask_path; + + using(PropertyMap map = testView.Image) + { + bool ret = (map.Find(ImageVisualProperty.URL)?.Get(out resultString) ?? false) && !string.IsNullOrEmpty(resultString); + Assert.AreEqual(true, ret, "map must have ResourceUrl"); + Assert.AreEqual(mask_path, resultString, "...and That value must be equal what we added"); + ret = (map.Find(ImageVisualProperty.AlphaMaskURL)?.Get(out resultString) ?? false) && !string.IsNullOrEmpty(resultString); + Assert.AreEqual(true, ret, "map must have AlphaMaskURL"); + Assert.AreEqual(testUrl1, resultString, "...and That value must be equal what we added"); + ret = map.Find(ImageVisualProperty.CropToMask)?.Get(out resultBool) ?? false; + Assert.AreEqual(true, ret, "map must have CropToMask"); + Assert.AreEqual(true, resultBool, "...and That value must be equal what we added"); + ret = map.Find(ImageVisualProperty.SynchronousLoading)?.Get(out resultBool) ?? false; + Assert.AreEqual(true, ret, "map must have SynchronousLoading"); + Assert.AreEqual(true, resultBool, "...and That value must be equal what we added"); + } + + testView.Dispose(); + } + + [Test] + [Category("P1")] + [Description("internal API test in Ubuntu, set ImageView.Image and check cached properties changed")] + [Property("SPEC", "Tizen.NUI.BaseComponents.ImageView.Image")] + [Property("SPEC_URL", "-")] + [Property("CRITERIA", "PRO")] + [Property("AUTHOR", "eunkiki.hong@samsung.com")] + public void Image_SET_VALUE_After_Set_something() + { + /* TEST CODE */ + ImageView testView = new ImageView(); + string resultString = ""; + bool resultBool = false; + + using(PropertyMap map = testView.Image) + { + bool ret = (map.Find(ImageVisualProperty.URL)?.Get(out resultString) ?? false) && string.IsNullOrEmpty(resultString); + Assert.AreEqual(false, ret, "map don't have ResourceUrl"); + ret = map.Find(ImageVisualProperty.AlphaMaskURL)?.Get(out resultString) ?? false; + Assert.AreEqual(false, ret, "map don't have AlphaMaskURL"); + ret = map.Find(ImageVisualProperty.CropToMask)?.Get(out resultBool) ?? false; + Assert.AreEqual(false, ret, "map don't have CropToMask"); + ret = map.Find(ImageVisualProperty.SynchronousLoading)?.Get(out resultBool) ?? false; + Assert.AreEqual(false, ret, "map don't have SynchronousLoading"); + } + + string testUrl1 = "test1"; + string testUrl2 = "test2"; + testView.ResourceUrl = testUrl1; + testView.AlphaMaskURL = testUrl2; + testView.CropToMask = true; + testView.SynchronousLoading = true; + + using(PropertyMap map = testView.Image) + { + bool ret = (map.Find(ImageVisualProperty.URL)?.Get(out resultString) ?? false) && !string.IsNullOrEmpty(resultString); + Assert.AreEqual(true, ret, "map must have ResourceUrl"); + Assert.AreEqual(testUrl1, resultString, "...and That value must be equal what we added"); + ret = (map.Find(ImageVisualProperty.AlphaMaskURL)?.Get(out resultString) ?? false) && !string.IsNullOrEmpty(resultString); + Assert.AreEqual(true, ret, "map must have AlphaMaskURL"); + Assert.AreEqual(testUrl2, resultString, "...and That value must be equal what we added"); + ret = map.Find(ImageVisualProperty.CropToMask)?.Get(out resultBool) ?? false; + Assert.AreEqual(true, ret, "map must have CropToMask"); + Assert.AreEqual(true, resultBool, "...and That value must be equal what we added"); + ret = map.Find(ImageVisualProperty.SynchronousLoading)?.Get(out resultBool) ?? false; + Assert.AreEqual(true, ret, "map must have SynchronousLoading"); + Assert.AreEqual(true, resultBool, "...and That value must be equal what we added"); + } + + // Update Image map by PropertyMap. + // Cached property map will be overwrited. + using(PropertyMap setImageMap = new PropertyMap()) + { + setImageMap[ImageVisualProperty.URL] = new PropertyValue(image_path); + setImageMap[ImageVisualProperty.AlphaMaskURL] = new PropertyValue(mask_path); + setImageMap[ImageVisualProperty.CropToMask] = new PropertyValue(false); + setImageMap[ImageVisualProperty.SynchronousLoading] = new PropertyValue(false); + testView.Image = setImageMap; + } + + using(PropertyMap map = testView.Image) + { + bool ret = (map.Find(ImageVisualProperty.URL)?.Get(out resultString) ?? false) && !string.IsNullOrEmpty(resultString); + Assert.AreEqual(true, ret, "map must have ResourceUrl"); + Assert.AreEqual(image_path, resultString, "...and That value must be equal what we added"); + ret = (map.Find(ImageVisualProperty.AlphaMaskURL)?.Get(out resultString) ?? false) && !string.IsNullOrEmpty(resultString); + Assert.AreEqual(true, ret, "map must have AlphaMaskURL"); + Assert.AreEqual(mask_path, resultString, "...and That value must be equal what we added"); + ret = map.Find(ImageVisualProperty.CropToMask)?.Get(out resultBool) ?? false; + Assert.AreEqual(true, ret, "map must have CropToMask"); + Assert.AreEqual(false, resultBool, "...and That value must be equal what we added"); + ret = map.Find(ImageVisualProperty.SynchronousLoading)?.Get(out resultBool) ?? false; + Assert.AreEqual(true, ret, "map must have SynchronousLoading"); + Assert.AreEqual(false, resultBool, "...and That value must be equal what we added"); + } + } } } diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/AnimatedImageViewTest.cs b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/AnimatedImageViewTest.cs index 5921935..0313329 100755 --- a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/AnimatedImageViewTest.cs +++ b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/AnimatedImageViewTest.cs @@ -167,6 +167,7 @@ namespace Tizen.NUI.Samples { box2.image.URLs.Add(resPath + "images/AGIF/dog-anim-00" + i + ".png"); } + box2.image.SetValues(); box2.image.Play(); box2.but1.Clicked += But1_Clicked1; -- 2.7.4