[NUI] Fix Svace issue (#491)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / Xaml / MarkupExtensions / StaticResourceExtension.cs
1 using System;
2 using System.Xml;
3 using System.Reflection;
4 using System.Linq;
5 using Tizen.NUI.Binding;
6
7
8 namespace Tizen.NUI.Xaml
9 {
10     [ContentProperty("Key")]
11     internal sealed class StaticResourceExtension : IMarkupExtension
12     {
13         public string Key { get; set; }
14
15         public object ProvideValue(IServiceProvider serviceProvider)
16         {
17             if (serviceProvider == null)
18                 throw new ArgumentNullException(nameof(serviceProvider));
19             if (Key == null) {
20                 var lineInfoProvider = serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider;
21                 var lineInfo = (lineInfoProvider != null) ? lineInfoProvider.XmlLineInfo : new XmlLineInfo();
22                 throw new XamlParseException("you must specify a key in {StaticResource}", lineInfo);
23             }
24             var valueProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideParentValues;
25             if (valueProvider == null)
26                 throw new ArgumentException();
27             var xmlLineInfoProvider = serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider;
28             var xmlLineInfo = xmlLineInfoProvider != null ? xmlLineInfoProvider.XmlLineInfo : null;
29             object resource = null;
30
31             foreach (var p in valueProvider.ParentObjects) {
32                 var irp = p as IResourcesProvider;
33                 var resDict = irp != null && irp.IsResourcesCreated ? irp.XamlResources : p as ResourceDictionary;
34                 if (resDict == null)
35                     continue;
36                 if (resDict.TryGetValue(Key, out resource))
37                     break;
38             }
39             resource = resource ?? GetApplicationLevelResource(Key, xmlLineInfo);
40
41             var bp = valueProvider.TargetProperty as BindableProperty;
42             var pi = valueProvider.TargetProperty as PropertyInfo;
43             var propertyType = bp?.ReturnType ?? pi?.PropertyType;
44             if (propertyType == null) {
45                 if (resource != null) {
46                     if (resource.GetType().GetTypeInfo().IsGenericType && (resource.GetType().GetGenericTypeDefinition() == typeof(OnPlatform<>) || resource.GetType().GetGenericTypeDefinition() == typeof(OnIdiom<>))) {
47                         // This is only there to support our backward compat story with pre 2.3.3 compiled Xaml project who was not providing TargetProperty
48                         var method = resource.GetType().GetRuntimeMethod("op_Implicit", new[] { resource.GetType() });
49                         if (method != null) {
50                             resource = method.Invoke(null, new[] { resource });
51                         }
52                     }
53                 }
54                 return resource;
55             }
56             if (propertyType.IsAssignableFrom(resource?.GetType()))
57                 return resource;
58             var implicit_op =  resource?.GetType().GetImplicitConversionOperator(fromType: resource?.GetType(), toType: propertyType)
59                             ?? propertyType.GetImplicitConversionOperator(fromType: resource?.GetType(), toType: propertyType);
60             if (implicit_op != null)
61                 return implicit_op.Invoke(resource, new [] { resource });
62
63             if (resource != null) { 
64                 //Special case for https://bugzilla.xamarin.com/show_bug.cgi?id=59818
65                 //On OnPlatform, check for an opImplicit from the targetType
66                 if (   Device.Flags != null
67                     && Device.Flags.Contains("xamlDoubleImplicitOpHack")
68                     && resource.GetType().GetTypeInfo().IsGenericType
69                     && (resource.GetType().GetGenericTypeDefinition() == typeof(OnPlatform<>))) {
70                     var tType = resource.GetType().GenericTypeArguments[0];
71                     var opImplicit = tType.GetImplicitConversionOperator(fromType: tType, toType: propertyType)
72                                     ?? propertyType.GetImplicitConversionOperator(fromType: tType, toType: propertyType);
73
74                     if (opImplicit != null) {
75                         //convert the OnPlatform<T> to T
76                         var opPlatformImplicitConversionOperator = resource?.GetType().GetImplicitConversionOperator(fromType: resource?.GetType(), toType: tType);
77                         resource = opPlatformImplicitConversionOperator?.Invoke(null, new[] { resource });
78
79                         //and convert to toType
80                         resource = opImplicit.Invoke(null, new[] { resource });
81                         return resource;
82                     }
83                 }
84             }
85             return resource;
86         }
87
88         internal object GetApplicationLevelResource(string key, IXmlLineInfo xmlLineInfo)
89         {
90             object resource = null;
91             if (Application.Current == null || !((IResourcesProvider)Application.Current).IsResourcesCreated || !Application.Current.XamlResources.TryGetValue(Key, out resource))
92                 throw new XamlParseException($"StaticResource not found for key {Key}", xmlLineInfo);
93             return resource;
94         }
95     }
96 }