File: System\Windows\ClassHandlersStore.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationCore\PresentationCore.csproj (PresentationCore)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using MS.Utility;
 
 
namespace System.Windows
{
    // Container for the class event handlers
    // ClassHandlersStore constitues lists of
    // RoutedEventHandlerInfo keyed on the 
    // RoutedEvent
    internal class ClassHandlersStore
    {
        #region Construction
        
        // Constructor for ClassHandlersStore
        internal ClassHandlersStore(int size)
        {
            _eventHandlersList = new ItemStructList<ClassHandlers>(size);
        }
        
        #endregion Construction
 
        #region Operations
 
        // Adds a routed event handler at the given index of the store
        // Returns updated set of handlers
        // NOTE: index must be valid, i.e. not -1
        internal RoutedEventHandlerInfoList AddToExistingHandlers(
            int index,
            Delegate handler,
            bool handledEventsToo)
        {
            Debug.Assert(index != -1, "There should exist a set of handlers for the given routedEvent");
 
            // Create a new RoutedEventHandler
            RoutedEventHandlerInfo routedEventHandlerInfo = 
                new RoutedEventHandlerInfo(handler, handledEventsToo);            
 
            // Check if we need to create a new node in the linked list
            RoutedEventHandlerInfoList handlers =  _eventHandlersList.List[index].Handlers;
            if (handlers == null || _eventHandlersList.List[index].HasSelfHandlers == false)
            {
                // Create a new node in the linked list of class 
                // handlers for this type and routed event.
                handlers = new RoutedEventHandlerInfoList();
                handlers.Handlers = new RoutedEventHandlerInfo[1];
                handlers.Handlers[0] = routedEventHandlerInfo;
                handlers.Next = _eventHandlersList.List[index].Handlers;
                _eventHandlersList.List[index].Handlers = handlers;
                _eventHandlersList.List[index].HasSelfHandlers = true;
            }
            else
            {
                // Add this handler to the existing node in the linked list 
                // of class handlers for this type and routed event.
                int length = handlers.Handlers.Length;
                RoutedEventHandlerInfo[] mergedHandlers = new RoutedEventHandlerInfo[length + 1];
                Array.Copy(handlers.Handlers, 0, mergedHandlers,  0, length);
                mergedHandlers[length] = routedEventHandlerInfo;
                handlers.Handlers = mergedHandlers;
            }            
 
            return handlers;
         }
 
        // Returns EventHandlers stored at the given index in the datastructure
        // NOTE: index must be valid, i.e. not -1
        internal RoutedEventHandlerInfoList GetExistingHandlers(int index)
        {
            Debug.Assert(index != -1, "There should exist a set of handlers for the given index");
 
            return _eventHandlersList.List[index].Handlers;
        }        
 
        // Creates reference to given handlers and RoutedEvent
        // Returns the index at which the new reference was added
        // NOTE: There should not exist a set of handlers for the 
        // given routedEvent
        internal int CreateHandlersLink(RoutedEvent routedEvent, RoutedEventHandlerInfoList handlers)
        {
            Debug.Assert(GetHandlersIndex(routedEvent) == -1, "There should not exist a set of handlers for the given routedEvent");
 
            ClassHandlers classHandlers = new ClassHandlers();
            classHandlers.RoutedEvent = routedEvent;
            classHandlers.Handlers = handlers;
            classHandlers.HasSelfHandlers = false;
            _eventHandlersList.Add(classHandlers);
 
            return _eventHandlersList.Count - 1;
        }        
 
        // Update Sub Class Handlers with the given base class listeners
        // NOTE : Do not wastefully try to update subclass listeners when 
        // base class listeners are null
        internal void UpdateSubClassHandlers(
            RoutedEvent routedEvent,
            RoutedEventHandlerInfoList baseClassListeners)
        {
            Debug.Assert(baseClassListeners != null, "Update only when there are base class listeners to be updated");
            
            // Get the handlers index corresponding to the given RoutedEvent
            int index = GetHandlersIndex(routedEvent);
            if (index != -1)
            {
                bool hasSelfHandlers = _eventHandlersList.List[index].HasSelfHandlers;
 
                // Fetch the handlers for your baseType that the current node knows of
                
                RoutedEventHandlerInfoList handlers = hasSelfHandlers ? 
                    _eventHandlersList.List[index].Handlers.Next : 
                    _eventHandlersList.List[index].Handlers;
 
                bool needToChange = false;
 
                // If the current node has baseType handlers check if the baseClassListeners 
                // provided is for a super type of that baseType. If it is then you will 
                // replace the baseType handlers for the current node with the provided 
                // baseClassListeners. If the given baseClassListeners is for a sub type 
                // of the current nodes's baseType then we do not need to update the current node.
                //
                // Example: Consider the following class hierarchy A -> B -> C. 
                //
                // Now imagine that we register class handlers in the following order.
                // 1. Register class handler for A.
                // - A's linked list will be A -> NULL.
                // - B's linked list will be NULL.
                // - C's linked list will be NULL.
                // 2. Register class handler for C.
                // - A's linked list will be A -> NULL.
                // - B's linkedList will be NULL.
                // - C's linked list will be C -> A -> NULL.
                // 3. Register class handler for B.
                // - A's linked list will be A -> NULL.
                // - B's linkedList will be B -> A -> NULL.
                // - While updating C's linked list we are given B's linked list for the baseClassListers. 
                //   Now we want to check if B is a super type of A which is the current baseType that C 
                //   knows of. The contains check below determines this. Since it is we now replace C.Next 
                //   to be B. Thus we get C -> B -> A -> NULL.
                //
                // Now imagine that we register class handlers in the following order.
                // 1. Register class handler for C.
                // - A's linked list will be NULL.
                // - B's linked list will be NULL.
                // - C's linked list will be C -> NULL.
                // 2. Register class handler for B.
                // - A's linked list will be NULL.
                // - B's linkedList will be B -> NULL.
                // - While updating C's linked list we are given B's linked list for the baseClassListeners. 
                //   Since C does not know of any baseType listeners already it takes the given 
                //   baseClassListeners as is. Thus it has C -> B -> NULL
                // 3. Register class handler for A.
                // - A's linked list will be A -> NULL.
                // - B's linkedList will be B -> A -> NULL.
                // - While updating C's linked list we are given A's linked list for the baseClassListers. 
                //   Now we want to check if A is a super type of B which is the current baseType that C 
                //   knows of. The contains check below determines this. Since it isn't we do not need to 
                //   change the linked list for C. Since B's linked list has already been updated we get 
                //   C -> B - > A -> NULL.
                
                if (handlers != null)
                {
                    if (baseClassListeners.Next != null && baseClassListeners.Next.Contains(handlers))
                    {
                        needToChange = true;
                    }
                }
 
                // If the current node does not have any baseType handlers then if will 
                // simply use the given baseClassListeners.
                
                else
                {
                    needToChange = true;
                }
 
                if (needToChange)
                {
                    // If current node has self handlers then its next pointer 
                    // needs update if not the current node needs update.
 
                    if (hasSelfHandlers)
                    {
                        _eventHandlersList.List[index].Handlers.Next = baseClassListeners;
                    }
                    else
                    {
                        _eventHandlersList.List[index].Handlers = baseClassListeners;
                    }
                }
            }
        }        
        
        // Returns EventHandlers Index for the given RoutedEvent
        internal int GetHandlersIndex(RoutedEvent routedEvent)
        {            
            // Linear Search
            for (int i=0; i<_eventHandlersList.Count; i++)
            {
                if (_eventHandlersList.List[i].RoutedEvent == routedEvent)
                {
                    return i;
                }
            }
        
            return -1;
        }        
 
        #endregion Operations
 
        #region Data
 
        // Stores list of ClassHandlers keyed on RoutedEvent
        private ItemStructList<ClassHandlers> _eventHandlersList;
 
        #endregion Data
    }
 
    // Stores ClassHandlers for the given RoutedEvent
    internal struct ClassHandlers
    {
        #region Operations
        
        /// <summary>
        ///     Is the given object equals the current
        /// </summary>
        public override bool Equals(object o)
        {
            return Equals((ClassHandlers)o);
        }
        
        /// <summary>
        ///     Is the given ClassHandlers struct equals the current
        /// </summary>
        public bool Equals(ClassHandlers classHandlers)
        {
            return (
                classHandlers.RoutedEvent == this.RoutedEvent &&
                classHandlers.Handlers == this.Handlers);
        }
 
        /// <summary>
        ///     Serves as a hash function for a particular type, suitable for use in 
        ///     hashing algorithms and data structures like a hash table
        /// </summary>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
 
        /// <summary>
        ///     Equals operator overload
        /// </summary>
        public static bool operator== (ClassHandlers classHandlers1, ClassHandlers classHandlers2)
        {
            return classHandlers1.Equals(classHandlers2);
        }
 
        /// <summary>
        ///     NotEquals operator overload
        /// </summary>
        public static bool operator!= (ClassHandlers classHandlers1, ClassHandlers classHandlers2)
        {
            return !classHandlers1.Equals(classHandlers2);
        }
 
        #endregion Operations
        
        #region Data
        
        internal RoutedEvent RoutedEvent;
        internal RoutedEventHandlerInfoList Handlers;
        internal bool HasSelfHandlers;
 
        #endregion Data
    }
 
    /// <summary>
    ///     This data-structure represents a linked list of all 
    ///     the Class Handlers for a type and its base types.
    /// </summary>
    internal class RoutedEventHandlerInfoList
    {
        internal RoutedEventHandlerInfo[] Handlers;
        internal RoutedEventHandlerInfoList Next;
 
        internal bool Contains(RoutedEventHandlerInfoList handlers)
        {
            RoutedEventHandlerInfoList tempHandlers = this;
            while (tempHandlers != null)
            {
                if (tempHandlers == handlers)
                {
                    return true;
                }
                
                tempHandlers = tempHandlers.Next;
            }
 
            return false;
        }
    }
}