c999e0d3cad1bf132af94a9bbaed3daca07a53d4
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / XamlBinding / Registrar.cs
1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Linq;
5 using System.Reflection;
6 using Tizen.NUI.Binding;
7
8 namespace Tizen.NUI.Binding
9 {
10         // Previewer uses reflection to bind to this method; Removal or modification of visibility will break previewer.
11         internal static class Registrar
12         {
13                 internal static void RegisterAll(Type[] attrTypes) => Internals.Registrar.RegisterAll(attrTypes);
14         }
15 }
16
17 namespace Tizen.NUI.Internals
18 {
19         [EditorBrowsable(EditorBrowsableState.Never)]
20         public class Registrar<TRegistrable> where TRegistrable : class
21         {
22                 readonly Dictionary<Type, Type> _handlers = new Dictionary<Type, Type>();
23
24                 public void Register(Type tview, Type trender)
25                 {
26                         //avoid caching null renderers
27                         if (trender == null)
28                                 return;
29                         _handlers[tview] = trender;
30                 }
31
32                 internal TRegistrable GetHandler(Type type)
33                 {
34                         Type handlerType = GetHandlerType(type);
35                         if (handlerType == null)
36                                 return null;
37
38                         object handler = DependencyResolver.ResolveOrCreate(handlerType);
39
40                         return (TRegistrable)handler;
41                 }
42
43                 internal TRegistrable GetHandler(Type type, params object[] args)
44                 {
45                         if (args.Length == 0)
46                         {
47                                 return GetHandler(type);
48                         }
49
50                         Type handlerType = GetHandlerType(type);
51                         if (handlerType == null)
52                                 return null;
53
54                         return (TRegistrable)DependencyResolver.ResolveOrCreate(handlerType, args);
55                 }
56
57                 public TOut GetHandler<TOut>(Type type) where TOut : TRegistrable
58                 {
59                         return (TOut)GetHandler(type);
60                 }
61
62                 public TOut GetHandler<TOut>(Type type, params object[] args) where TOut : TRegistrable
63                 {
64                         return (TOut)GetHandler(type, args);
65                 }
66
67                 public TOut GetHandlerForObject<TOut>(object obj) where TOut : TRegistrable
68                 {
69                         if (obj == null)
70                                 throw new ArgumentNullException(nameof(obj));
71
72                         var reflectableType = obj as IReflectableType;
73                         var type = reflectableType != null ? reflectableType.GetTypeInfo().AsType() : obj.GetType();
74
75                         return (TOut)GetHandler(type);
76                 }
77
78                 public TOut GetHandlerForObject<TOut>(object obj, params object[] args) where TOut : TRegistrable
79                 {
80                         if (obj == null)
81                                 throw new ArgumentNullException(nameof(obj));
82
83                         var reflectableType = obj as IReflectableType;
84                         var type = reflectableType != null ? reflectableType.GetTypeInfo().AsType() : obj.GetType();
85
86                         return (TOut)GetHandler(type, args);
87                 }
88
89                 public Type GetHandlerType(Type viewType)
90                 {
91                         Type type;
92                         if (LookupHandlerType(viewType, out type))
93                                 return type;
94
95                         // lazy load render-view association with RenderWithAttribute (as opposed to using ExportRenderer)
96                         var attribute = viewType.GetTypeInfo().GetCustomAttribute<RenderWithAttribute>();
97                         if (attribute == null)
98                         {
99                                 Register(viewType, null); // Cache this result so we don't have to do GetCustomAttribute again
100                                 return null;
101                         }
102
103                         type = attribute.Type;
104
105                         if (type.Name.StartsWith("_", StringComparison.Ordinal))
106                         {
107                                 // TODO: Remove attribute2 once renderer names have been unified across all platforms
108                                 var attribute2 = type.GetTypeInfo().GetCustomAttribute<RenderWithAttribute>();
109                                 if (attribute2 != null)
110                                         type = attribute2.Type;
111
112                                 if (type.Name.StartsWith("_", StringComparison.Ordinal))
113                                 {
114                                         Register(viewType, null); // Cache this result so we don't work through this chain again
115                                         return null;
116                                 }
117                         }
118
119                         Register(viewType, type); // Register this so we don't have to look for the RenderWith Attibute again in the future
120
121                         return type;
122                 }
123
124                 public Type GetHandlerTypeForObject(object obj)
125                 {
126                         if (obj == null)
127                                 throw new ArgumentNullException(nameof(obj));
128
129                         var reflectableType = obj as IReflectableType;
130                         var type = reflectableType != null ? reflectableType.GetTypeInfo().AsType() : obj.GetType();
131
132                         return GetHandlerType(type);
133                 }
134
135                 bool LookupHandlerType(Type viewType, out Type handlerType)
136                 {
137                         Type type = viewType;
138
139                         while (type != null)
140                         {
141                                 if (_handlers.ContainsKey(type))
142                                 {
143                                         handlerType = _handlers[type];
144                                         return true;
145                                 }
146
147                                 type = type.GetTypeInfo().BaseType;
148                         }
149
150                         handlerType = null;
151                         return false;
152                 }
153         }
154
155         [EditorBrowsable(EditorBrowsableState.Never)]
156         internal static class Registrar
157         {
158                 static Registrar()
159                 {
160                         Registered = new Registrar<IRegisterable>();
161                 }
162
163                 internal static Dictionary<string, Type> Effects { get; } = new Dictionary<string, Type>();
164                 internal static Dictionary<string, StyleSheets.StylePropertyAttribute> StyleProperties { get; } = new Dictionary<string, StyleSheets.StylePropertyAttribute>();
165
166                 public static IEnumerable<Assembly> ExtraAssemblies { get; set; }
167
168                 public static Registrar<IRegisterable> Registered { get; internal set; }
169
170                 public static void RegisterAll(Type[] attrTypes)
171                 {
172                         Assembly[] assemblies = Device.GetAssemblies();
173                         if (ExtraAssemblies != null)
174                                 assemblies = assemblies.Union(ExtraAssemblies).ToArray();
175
176                         Assembly defaultRendererAssembly = Device.PlatformServices.GetType().GetTypeInfo().Assembly;
177                         int indexOfExecuting = Array.IndexOf(assemblies, defaultRendererAssembly);
178
179                         if (indexOfExecuting > 0)
180                         {
181                                 assemblies[indexOfExecuting] = assemblies[0];
182                                 assemblies[0] = defaultRendererAssembly;
183                         }
184
185                         // Don't use LINQ for performance reasons
186                         // Naive implementation can easily take over a second to run
187                         foreach (Assembly assembly in assemblies)
188                         {
189                                 foreach (Type attrType in attrTypes)
190                                 {
191                                         Attribute[] attributes;
192                                         try
193                                         {
194                                                 attributes = assembly.GetCustomAttributes(attrType).ToArray();
195                                         }
196                                         catch (System.IO.FileNotFoundException)
197                                         {
198                                                 // Sometimes the previewer doesn't actually have everything required for these loads to work
199                                                 Console.WriteLine(nameof(Registrar), "Could not load assembly: {0} for Attibute {1} | Some renderers may not be loaded", assembly.FullName, attrType.FullName);
200                                                 continue;
201                                         }
202                                         var length = attributes.Length;
203                                         for (var i = 0; i < length;i++)
204                                         {
205                                                 var attribute = (HandlerAttribute)attributes[i];
206                                                 if (attribute.ShouldRegister())
207                                                         Registered.Register(attribute.HandlerType, attribute.TargetType);
208                                         }
209                                 }
210
211                                 string resolutionName = assembly.FullName;
212                                 var resolutionNameAttribute = (ResolutionGroupNameAttribute)assembly.GetCustomAttribute(typeof(ResolutionGroupNameAttribute));
213                                 if (resolutionNameAttribute != null)
214                                         resolutionName = resolutionNameAttribute.ShortName;
215
216                                 Attribute[] effectAttributes = assembly.GetCustomAttributes(typeof(ExportEffectAttribute)).ToArray();
217                                 var exportEffectsLength = effectAttributes.Length;
218                                 for (var i = 0; i < exportEffectsLength;i++)
219                                 {
220                                         var effect = (ExportEffectAttribute)effectAttributes[i];
221                                         Effects [resolutionName + "." + effect.Id] = effect.Type;
222                                 }
223
224                                 Attribute[] styleAttributes = assembly.GetCustomAttributes(typeof(StyleSheets.StylePropertyAttribute)).ToArray();
225                                 var stylePropertiesLength = styleAttributes.Length;
226                                 for (var i = 0; i < stylePropertiesLength; i++)
227                                 {
228                                         var attribute = (StyleSheets.StylePropertyAttribute)styleAttributes[i];
229                                         StyleProperties[attribute.CssPropertyName] = attribute;
230                                 }
231                         }
232
233                         DependencyService.Initialize(assemblies);
234                 }
235         }
236 }