From 9496fcc0e6d3bdfbe42a4c82498c14ab5e474c2b Mon Sep 17 00:00:00 2001
From: Brad Nelson <info@play-em.com>
Date: Mon, 10 Jun 2019 10:23:50 +0000
Subject: [PATCH] Code cleanup of TextPic, fixes for text rendering with Unity
 2019.1.5 and above.  Made a default function for hyperlink text to work out
 of the box with a function OnHrefClick to override with own custom
 functionality if desired.  Optimizations and caching of variables.

---
 Scripts/Controls/TextPic.cs | 714 +++++++++++++++++++++++-------------
 1 file changed, 455 insertions(+), 259 deletions(-)

diff --git a/Scripts/Controls/TextPic.cs b/Scripts/Controls/TextPic.cs
index 98e9fe2..693b43e 100644
--- a/Scripts/Controls/TextPic.cs
+++ b/Scripts/Controls/TextPic.cs
@@ -17,12 +17,52 @@ namespace UnityEngine.UI.Extensions {
        
     [ExecuteInEditMode] // Needed for culling images that are not used //
     public class TextPic : Text, IPointerClickHandler, IPointerExitHandler, IPointerEnterHandler, ISelectHandler {
+		// Icon entry to replace text with
+        [Serializable]
+        public struct IconName {
+            public string name;
+            public Sprite sprite;
+			public Vector2 offset;
+			public Vector2 scale;
+        }
+
+		// Icons and text to replace
+        public IconName[] inspectorIconList;
+
+		[Tooltip("Global scaling factor for all images")]
+        public float ImageScalingFactor = 1;
+
+        // Write the name or hex value of the hyperlink color
+        public string hyperlinkColor = "blue";
+
+        // Offset image by x, y
+        public Vector2 imageOffset = Vector2.zero;
+        public bool isCreating_m_HrefInfos = true;
+
+        [Serializable]
+        public class HrefClickEvent : UnityEvent<string> { }
+
+        [SerializeField]
+        private HrefClickEvent m_OnHrefClick = new HrefClickEvent();
+
+        /// <summary>
+        /// Hyperlink Click Event
+        /// </summary>
+        public HrefClickEvent onHrefClick {
+            get { return m_OnHrefClick; }
+            set { m_OnHrefClick = value; }
+        }
+
         /// <summary>
         /// Image Pool
         /// </summary>
         private readonly List<Image> m_ImagesPool = new List<Image>();
         private readonly List<GameObject> culled_ImagesPool = new List<GameObject>();
+
+		// Used for check for culling images
         private bool clearImages = false;
+
+		// Lock to ensure images get culled properly
 		private Object thisLock = new Object();
 
         /// <summary>
@@ -36,82 +76,118 @@ namespace UnityEngine.UI.Extensions {
         private static readonly Regex s_Regex =
             new Regex(@"<quad name=(.+?) size=(\d*\.?\d+%?) width=(\d*\.?\d+%?) />", RegexOptions.Singleline);
 
-        private string fixedString;        [SerializeField]
+        /// <summary>
+        /// Hyperlink Regular Expression
+        /// </summary>
+        private static readonly Regex s_HrefRegex =
+            new Regex(@"<a href=([^>\n\s]+)>(.*?)(</a>)", RegexOptions.Singleline);
 
-        [Tooltip("Allow click events to be received by parents, (default) blocks")]
-
-        private bool m_ClickParents;
+		// String to create quads
+        private string fixedString;
 
 		// Update the quad images when true
 		private bool updateQuad = false;
 
-        public bool AllowClickParents {
-            get { return m_ClickParents; }
-            set { m_ClickParents = value; }
-        }
-
-        public override void SetVerticesDirty() {
-            base.SetVerticesDirty();
-
-			// Update the quad images
-            updateQuad = true;
-        }
-
-#if UNITY_EDITOR
-        protected override void OnValidate() {
-            base.OnValidate();
-
-			// Update the quad images
-            updateQuad = true;
-
-			for (int i = 0; i < inspectorIconList.Length; i++) {
-                if (inspectorIconList[i].scale == Vector2.zero) {
-                    inspectorIconList[i].scale = Vector2.one;
-                }
-            }
-        }
-#endif
-
         /// <summary>
         /// After parsing the final text
         /// </summary>
         private string m_OutputText;
 
-        [System.Serializable]
-        public struct IconName {
-            public string name;
-            public Sprite sprite;
-			public Vector2 offset;
-			public Vector2 scale;
-        }
-
-        public IconName[] inspectorIconList;
-
-		[Tooltip("Global scaling factor for all images")]
-        public float ImageScalingFactor = 1;
-
-        // Write the name or hex value of the hyperlink color
-        public string hyperlinkColor = "blue";
-
-        // Offset image by x, y
-        [SerializeField]
-        public Vector2 imageOffset = Vector2.zero;
-
         private Button button;
 
+        // Used for custom selection as a variable for other scripts
+        private bool selected = false;
+
+		// Positions of images for icon placement
         private List<Vector2> positions = new List<Vector2>();
         
-        /**
-        * Little hack to support multiple hrefs with same name
-        */
+        // Little hack to support multiple hrefs with same name
         private string previousText = "";
-        public bool isCreating_m_HrefInfos = true;
 
-        new void Start() {
-            button = GetComponent<Button>();
-            ResetIconList();
+        /// <summary>
+        /// Hyperlinks Info
+        /// </summary>
+		[Serializable]
+        public class HrefInfo {
+            public int startIndex;
+
+            public int endIndex;
+
+            public string name;
+
+            public readonly List<Rect> boxes = new List<Rect>();
         }
 
+        /// <summary>
+        /// Hyperlink List
+        /// </summary>
+        private readonly List<HrefInfo> m_HrefInfos = new List<HrefInfo>();
+
+        /// <summary>
+        /// Text Builder
+        /// </summary>
+        private static readonly StringBuilder s_TextBuilder = new StringBuilder();
+
+		// Matches for quad tags
+		private MatchCollection matches;
+
+		// Matches for quad tags
+		private MatchCollection href_matches;
+
+		// Matches for removing characters
+		private MatchCollection removeCharacters;
+
+		// Index of current pic
+		private int picIndex;
+
+		// Index of current pic vertex
+		private int vertIndex;
+
+		/// <summary>
+		/// Unity 2019.1.5 Fixes to text placement resulting from the removal of verts for spaces and non rendered characters
+		/// </summary>
+
+		// There is no directive for incremented versions so will have to hack together
+		private bool usesNewRendering = false;
+
+		#if UNITY_2019_1_OR_NEWER
+        /// <summary>
+        /// Regular expression to remove non rendered characters
+        /// </summary>
+        private static readonly Regex remove_Regex =
+            new Regex(@"<b>|</b>|<i>|</i>|<size=.*?>|</size>|<color=.*?>|</color>|<material=.*?>|</material>|<quad name=(.+?) size=(\d*\.?\d+%?) width=(\d*\.?\d+%?) />|<a href=([^>\n\s]+)>|</a>|\s", RegexOptions.Singleline);
+
+		// List of indexes that are compared against matches to remove quad tags
+		List<int> indexes = new List<int>();
+
+		// Characters to remove from string for finding the correct index for vertices for images
+		private int charactersRemoved = 0;
+
+		// Characters to remove from string for finding the correct start index for vertices for href bounds
+		private int startCharactersRemoved = 0;
+
+		// Characters to remove from string for finding the correct end index for vertices for href bounds
+		private int endCharactersRemoved = 0;
+		#endif
+
+		// Count of current href
+		private int count = 0;
+
+		// Index of current href
+		private int indexText = 0;
+
+		// Original text temporary variable holder
+		private string originalText;
+
+		// Vertex we are modifying
+		private UIVertex vert;
+
+		// Local Point for Href
+		private Vector2 lp;
+
+
+		/// METHODS ///
+
 		public void ResetIconList() {
             Reset_m_HrefInfos ();
 			base.Start();
@@ -125,7 +201,7 @@ namespace UnityEngine.UI.Extensions {
 #endif
             m_OutputText = GetOutputText();
 
-			MatchCollection matches = s_Regex.Matches(m_OutputText);
+			matches = s_Regex.Matches(m_OutputText);
 
 			if (matches != null && matches.Count > 0) {
 				for (int i = 0; i < matches.Count; i++) {
@@ -136,10 +212,12 @@ namespace UnityEngine.UI.Extensions {
 					}
 
 					if (matches.Count > m_ImagesPool.Count) {
-						var resources = new DefaultControls.Resources();
-						var go = DefaultControls.CreateImage(resources);
+						DefaultControls.Resources resources = new DefaultControls.Resources();
+						GameObject go = DefaultControls.CreateImage(resources);
+
 						go.layer = gameObject.layer;
-						var rt = go.transform as RectTransform;
+
+						RectTransform rt = go.transform as RectTransform;
 
 						if (rt) {
 							rt.SetParent(rectTransform);
@@ -151,20 +229,22 @@ namespace UnityEngine.UI.Extensions {
 						m_ImagesPool.Add(go.GetComponent<Image>());
 					}
 
-					var spriteName = matches[i].Groups[1].Value;
+					string spriteName = matches[i].Groups[1].Value;
 
-					var img = m_ImagesPool[i];
+					Image img = m_ImagesPool[i];
 
 					Vector2 imgoffset = Vector2.zero;
 
 					if (img.sprite == null || img.sprite.name != spriteName) {
 						if (inspectorIconList != null && inspectorIconList.Length > 0) {
-							foreach (IconName icon in inspectorIconList) {
-								if (icon.name == spriteName) {
-									img.sprite = icon.sprite;
+							for (int s = 0; s < inspectorIconList.Length; s++) {
+								if (inspectorIconList[s].name == spriteName) {
+									img.sprite = inspectorIconList[s].sprite;
 									img.preserveAspect = true;
-									img.rectTransform.sizeDelta = new Vector2(fontSize * ImageScalingFactor * icon.scale.x, fontSize * ImageScalingFactor * icon.scale.y);
-									imgoffset = icon.offset;
+									img.rectTransform.sizeDelta = new Vector2(fontSize * ImageScalingFactor * inspectorIconList[s].scale.x, 
+																				fontSize * ImageScalingFactor * inspectorIconList[s].scale.y);
+									imgoffset = inspectorIconList[s].offset;
+
 									break;
 								}
 							}
@@ -208,100 +288,13 @@ namespace UnityEngine.UI.Extensions {
             }
         }
 
-        protected override void OnPopulateMesh(VertexHelper toFill) {
-            var orignText = m_Text;
-            m_Text = GetOutputText();
-            base.OnPopulateMesh(toFill);
-            m_Text = orignText;
-            positions.Clear();
+        // Reseting m_HrefInfos array if there is any change in text
+        void Reset_m_HrefInfos () {
+            previousText = text;
 
-            UIVertex vert = new UIVertex();
+            m_HrefInfos.Clear();
 
-            for (var i = 0; i < m_ImagesVertexIndex.Count; i++) {
-                var endIndex = m_ImagesVertexIndex[i];
-
-				if (endIndex < toFill.currentVertCount) {
-					toFill.PopulateUIVertex(ref vert, endIndex);
-					positions.Add(new Vector2((vert.position.x + fontSize / 2), (vert.position.y + fontSize / 2)) + imageOffset);
-
-					// Erase the lower left corner of the black specks
-					toFill.PopulateUIVertex(ref vert, endIndex - 3);
-					var pos = vert.position;
-
-					for (int j = endIndex, m = endIndex - 3; j > m; j--) {
-						toFill.PopulateUIVertex(ref vert, endIndex);
-						vert.position = pos;
-						toFill.SetUIVertex(vert, j);
-					}
-				}
-            }
-
-            // Hyperlinks surround processing box
-            foreach (var hrefInfo in m_HrefInfos) {
-                hrefInfo.boxes.Clear();
-
-                if (hrefInfo.startIndex >= toFill.currentVertCount) {
-                    continue;
-                }
-
-                // Hyperlink inside the text is added to surround the vertex index coordinate frame
-                toFill.PopulateUIVertex(ref vert, hrefInfo.startIndex);
-                var pos = vert.position;
-                var bounds = new Bounds(pos, Vector3.zero);
-
-                for (int i = hrefInfo.startIndex, m = hrefInfo.endIndex; i < m; i++) {
-                    if (i >= toFill.currentVertCount) {
-                        break;
-                    }
-
-                    toFill.PopulateUIVertex(ref vert, i);
-                    pos = vert.position;
-
-					// Wrap re-add surround frame
-                    if (pos.x < bounds.min.x)  {
-                        hrefInfo.boxes.Add(new Rect(bounds.min, bounds.size));
-                        bounds = new Bounds(pos, Vector3.zero);
-                    }
-                    else {
-                        bounds.Encapsulate(pos); // Extended enclosed box
-                    }
-                }
-
-                hrefInfo.boxes.Add(new Rect(bounds.min, bounds.size));
-            }
-
-			// Update the quad images
-            updateQuad = true;
-        }
-
-        /// <summary>
-        /// Hyperlink List
-        /// </summary>
-        private readonly List<HrefInfo> m_HrefInfos = new List<HrefInfo>();
-
-        /// <summary>
-        /// Text Builder
-        /// </summary>
-        private static readonly StringBuilder s_TextBuilder = new StringBuilder();
-
-        /// <summary>
-        /// Hyperlink Regular Expression
-        /// </summary>
-        private static readonly Regex s_HrefRegex =
-            new Regex(@"<a href=([^>\n\s]+)>(.*?)(</a>)", RegexOptions.Singleline);
-
-        [Serializable]
-        public class HrefClickEvent : UnityEvent<string> { }
-
-        [SerializeField]
-        private HrefClickEvent m_OnHrefClick = new HrefClickEvent();
-
-        /// <summary>
-        /// Hyperlink Click Event
-        /// </summary>
-        public HrefClickEvent onHrefClick {
-            get { return m_OnHrefClick; }
-            set { m_OnHrefClick = value; }
+            isCreating_m_HrefInfos = true;
         }
 
         /// <summary>
@@ -311,48 +304,56 @@ namespace UnityEngine.UI.Extensions {
         protected string GetOutputText() {
             s_TextBuilder.Length = 0;
             
-            var indexText = 0;
+            indexText = 0;
+
             fixedString = this.text;
 
             if (inspectorIconList != null && inspectorIconList.Length > 0) {
-                foreach (IconName icon in inspectorIconList) {
-                    if (!string.IsNullOrEmpty(icon.name)) {
-                        fixedString = fixedString.Replace(icon.name, "<quad name=" + icon.name + " size=" + fontSize + " width=1 />");
+                for (int i = 0; i < inspectorIconList.Length; i++) {
+                    if (!string.IsNullOrEmpty(inspectorIconList[i].name)) {
+                        fixedString = fixedString.Replace(inspectorIconList[i].name, 
+														"<quad name=" + inspectorIconList[i].name + " size=" + fontSize + " width=1 />");
                     }
                 }
             }
 
-            int count = 0;
+            count = 0;
 
-            foreach (Match match in s_HrefRegex.Matches(fixedString)) {
-                s_TextBuilder.Append(fixedString.Substring(indexText, match.Index - indexText));
-                s_TextBuilder.Append("<color=" + hyperlinkColor + ">");  // Hyperlink color
+			href_matches = s_HrefRegex.Matches(fixedString);
 
-                var group = match.Groups[1];
+			if (href_matches != null && href_matches.Count > 0) {
+				for (int i = 0; i < href_matches.Count; i++ ) {
+					s_TextBuilder.Append(fixedString.Substring(indexText, href_matches[i].Index - indexText));
+					s_TextBuilder.Append("<color=" + hyperlinkColor + ">");  // Hyperlink color
 
-                if (isCreating_m_HrefInfos) {
-                    var hrefInfo = new HrefInfo
+					var group = href_matches[i].Groups[1];
 
-                    {
-                        startIndex = s_TextBuilder.Length * 4, // Hyperlinks in text starting vertex indices
-                        endIndex = (s_TextBuilder.Length + match.Groups[2].Length - 1) * 4 + 3,
-                        name = group.Value
-                    };
+					if (isCreating_m_HrefInfos) {
+						HrefInfo hrefInfo = new HrefInfo {
+							// Hyperlinks in text starting index
+							startIndex = (usesNewRendering ? s_TextBuilder.Length : s_TextBuilder.Length * 4), 
+							endIndex = (usesNewRendering ? (s_TextBuilder.Length + href_matches[i].Groups[2].Length - 1) : (s_TextBuilder.Length + href_matches[i].Groups[2].Length - 1) * 4 + 3),
+							name = group.Value
+						};
 
-                    m_HrefInfos.Add(hrefInfo);
-                }
-				else {
-                    if(m_HrefInfos.Count > 0) {
-                        m_HrefInfos[count].startIndex = s_TextBuilder.Length * 4; // Hyperlinks in text starting vertex indices;
-                        m_HrefInfos[count].endIndex = (s_TextBuilder.Length + match.Groups[2].Length - 1) * 4 + 3;
-                        count++;
-                    }
-                }
+						m_HrefInfos.Add(hrefInfo);
+					}
+					else {
+						if (m_HrefInfos.Count > 0) {
+							// Hyperlinks in text starting index
+							m_HrefInfos[count].startIndex = (usesNewRendering ? s_TextBuilder.Length : s_TextBuilder.Length * 4); 
+							m_HrefInfos[count].endIndex = (usesNewRendering ? (s_TextBuilder.Length + href_matches[i].Groups[2].Length - 1) : (s_TextBuilder.Length + href_matches[i].Groups[2].Length - 1) * 4 + 3);
 
-                s_TextBuilder.Append(match.Groups[2].Value);
-                s_TextBuilder.Append("</color>");
-                indexText = match.Index + match.Length;
-            }
+							count++;
+						}
+					}
+
+					s_TextBuilder.Append(href_matches[i].Groups[2].Value);
+					s_TextBuilder.Append("</color>");
+
+					indexText = href_matches[i].Index + href_matches[i].Length;
+				}
+			}
 
             // we should create array only once or if there is any change in the text
             if (isCreating_m_HrefInfos)
@@ -364,33 +365,189 @@ namespace UnityEngine.UI.Extensions {
 
             m_ImagesVertexIndex.Clear();
 
-			MatchCollection matches = s_Regex.Matches(m_OutputText);
+			matches = s_Regex.Matches(m_OutputText);
+
+			#if UNITY_2019_1_OR_NEWER
+			href_matches = s_HrefRegex.Matches(m_OutputText);
+
+			indexes.Clear();
+
+			for (int r = 0; r < matches.Count; r++) { 
+				indexes.Add(matches[r].Index);
+			}
+			#endif
+
 
 			if (matches != null && matches.Count > 0) {
-				foreach (Match match in matches) {
-					var picIndex = match.Index;
-					var endIndex = picIndex * 4 + 3;
-					m_ImagesVertexIndex.Add(endIndex);
+				for (int i = 0; i < matches.Count; i++) {
+					picIndex = matches[i].Index;
+
+					#if UNITY_2019_1_OR_NEWER
+					if (usesNewRendering) {
+						charactersRemoved = 0;
+
+						removeCharacters = remove_Regex.Matches(m_OutputText);
+
+						for (int r = 0; r < removeCharacters.Count; r++) { 
+							if (removeCharacters[r].Index < picIndex && !indexes.Contains(removeCharacters[r].Index)) {
+								charactersRemoved += removeCharacters[r].Length;
+							}
+						}
+
+						for (int r = 0; r < i; r++) { 
+							charactersRemoved += (matches[r].Length - 1);
+						}
+
+						picIndex -= charactersRemoved;
+					}
+					#endif
+
+					vertIndex = picIndex * 4 + 3;
+
+					m_ImagesVertexIndex.Add(vertIndex);
 				}
 			}
 
+			#if UNITY_2019_1_OR_NEWER
+			if (usesNewRendering) {
+				if (m_HrefInfos != null && m_HrefInfos.Count > 0) {
+					for (int i = 0; i < m_HrefInfos.Count; i++) {
+						startCharactersRemoved = 0;
+						endCharactersRemoved = 0;
+
+						removeCharacters = remove_Regex.Matches(m_OutputText);
+
+						for (int r = 0; r < removeCharacters.Count; r++) { 
+							if (removeCharacters[r].Index < m_HrefInfos[i].startIndex && !indexes.Contains(removeCharacters[r].Index)) {
+								startCharactersRemoved += removeCharacters[r].Length;
+							}
+							else if (removeCharacters[r].Index < m_HrefInfos[i].startIndex && indexes.Contains(removeCharacters[r].Index)) {
+								startCharactersRemoved += removeCharacters[r].Length - 1;
+							}
+
+							if (removeCharacters[r].Index < m_HrefInfos[i].endIndex && !indexes.Contains(removeCharacters[r].Index)) {
+								endCharactersRemoved += removeCharacters[r].Length;
+							}
+							else if (removeCharacters[r].Index < m_HrefInfos[i].endIndex && indexes.Contains(removeCharacters[r].Index)) {
+								endCharactersRemoved += removeCharacters[r].Length - 1;
+							}
+						}
+
+						m_HrefInfos[i].startIndex -= startCharactersRemoved;
+
+						m_HrefInfos[i].startIndex = m_HrefInfos[i].startIndex * 4;
+
+						m_HrefInfos[i].endIndex -= endCharactersRemoved;
+
+						m_HrefInfos[i].endIndex = m_HrefInfos[i].endIndex * 4 + 3;
+					}
+				}
+			}
+			#endif
+
             return m_OutputText;
         }
 
+		// Process href links to open them as a url, can override this function for custom functionality
+		public virtual void OnHrefClick(string hrefName) {
+			Application.OpenURL(hrefName);
+
+			// Debug.Log(hrefName);
+		}
+
+
+		/// UNITY METHODS ///
+
+        protected override void OnPopulateMesh(VertexHelper toFill) {
+            originalText = m_Text;
+            m_Text = GetOutputText();
+
+            base.OnPopulateMesh(toFill);
+
+			m_DisableFontTextureRebuiltCallback = true;
+
+            m_Text = originalText;
+
+            positions.Clear();
+
+            vert = new UIVertex();
+
+            for (int i = 0; i < m_ImagesVertexIndex.Count; i++) {
+                int endIndex = m_ImagesVertexIndex[i];
+
+				if (endIndex < toFill.currentVertCount) {
+					toFill.PopulateUIVertex(ref vert, endIndex);
+
+					positions.Add(new Vector2((vert.position.x + fontSize / 2), (vert.position.y + fontSize / 2)) + imageOffset);
+
+					// Erase the lower left corner of the black specks
+					toFill.PopulateUIVertex(ref vert, endIndex - 3);
+
+					Vector3 pos = vert.position;
+
+					for (int j = endIndex, m = endIndex - 3; j > m; j--) {
+						toFill.PopulateUIVertex(ref vert, endIndex);
+						vert.position = pos;
+						toFill.SetUIVertex(vert, j);
+					}
+				}
+            }
+
+            // Hyperlinks surround processing box
+            for (int h = 0; h < m_HrefInfos.Count; h++) {
+                m_HrefInfos[h].boxes.Clear();
+
+                if (m_HrefInfos[h].startIndex >= toFill.currentVertCount) {
+                    continue;
+                }
+
+                // Hyperlink inside the text is added to surround the vertex index coordinate frame
+                toFill.PopulateUIVertex(ref vert, m_HrefInfos[h].startIndex);
+
+                Vector3 pos = vert.position;
+
+                Bounds bounds = new Bounds(pos, Vector3.zero);
+
+                for (int i = m_HrefInfos[h].startIndex, m = m_HrefInfos[h].endIndex; i < m; i++) {
+                    if (i >= toFill.currentVertCount) {
+                        break;
+                    }
+
+                    toFill.PopulateUIVertex(ref vert, i);
+
+                    pos = vert.position;
+
+					// Wrap re-add surround frame
+                    if (pos.x < bounds.min.x)  {
+                        m_HrefInfos[h].boxes.Add(new Rect(bounds.min, bounds.size));
+                        bounds = new Bounds(pos, Vector3.zero);
+                    }
+                    else {
+                        bounds.Encapsulate(pos); // Extended enclosed box
+                    }
+                }
+
+                m_HrefInfos[h].boxes.Add(new Rect(bounds.min, bounds.size));
+            }
+
+			// Update the quad images
+            updateQuad = true;
+
+			m_DisableFontTextureRebuiltCallback = false;
+        }
+
         /// <summary>
         /// Click event is detected whether to click a hyperlink text
         /// </summary>
         /// <param name="eventData"></param>
-        public void OnPointerClick(PointerEventData eventData) {
-            Vector2 lp;
+        public void OnPointerClick(PointerEventData eventData) { 
             RectTransformUtility.ScreenPointToLocalPointInRectangle(
                 rectTransform, eventData.position, eventData.pressEventCamera, out lp);
 
-            foreach (var hrefInfo in m_HrefInfos) {
-                var boxes = hrefInfo.boxes;
-                for (var i = 0; i < boxes.Count; ++i) {
-                    if (boxes[i].Contains(lp)) {
-                        m_OnHrefClick.Invoke(hrefInfo.name);
+            for (int h = 0; h < m_HrefInfos.Count; h++) {
+                for (int i = 0; i < m_HrefInfos[h].boxes.Count; ++i) {
+                    if (m_HrefInfos[h].boxes[i].Contains(lp)) {
+                        m_OnHrefClick.Invoke(m_HrefInfos[h].name);
                         return;
                     }
                 }
@@ -398,69 +555,144 @@ namespace UnityEngine.UI.Extensions {
         }
 
         public void OnPointerEnter(PointerEventData eventData) {
+            //do your stuff when highlighted
+            selected = true;
 
             if (m_ImagesPool.Count >= 1) {
-                foreach (Image img in m_ImagesPool) {
+                for (int i = 0; i < m_ImagesPool.Count; i++) {
                     if (button != null && button.isActiveAndEnabled) {
-                        img.color = button.colors.highlightedColor;
+                        m_ImagesPool[i].color = button.colors.highlightedColor;
                     }
                 }
             }
         }
 
         public void OnPointerExit(PointerEventData eventData) {
+            //do your stuff when highlighted
+            selected = false;
 
             if (m_ImagesPool.Count >= 1) {
-                foreach (Image img in m_ImagesPool) {
+                for (int i = 0; i < m_ImagesPool.Count; i++) {
                     if (button != null && button.isActiveAndEnabled) {
-                        img.color = button.colors.normalColor;
+                        m_ImagesPool[i].color = button.colors.normalColor;
                     }
                     else {
-                        img.color = color;
+                        m_ImagesPool[i].color = color;
                     }
                 }
             }
         }
 
         public void OnSelect(BaseEventData eventData) {
+            //do your stuff when selected
+            selected = true;
 
             if (m_ImagesPool.Count >= 1) {
-                foreach (Image img in m_ImagesPool) {
+                for (int i = 0; i < m_ImagesPool.Count; i++) {
                     if (button != null && button.isActiveAndEnabled) {
-                        img.color = button.colors.highlightedColor;
+                        m_ImagesPool[i].color = button.colors.highlightedColor;
                     }
                 }
             }
         }
 
         public void OnDeselect(BaseEventData eventData) {
+            //do your stuff when selected
+            selected = false;
 
             if (m_ImagesPool.Count >= 1) {
-                foreach (Image img in m_ImagesPool) {
+                for (int i = 0; i < m_ImagesPool.Count; i++) {
                     if (button != null && button.isActiveAndEnabled) {
-                        img.color = button.colors.normalColor;
+                        m_ImagesPool[i].color = button.colors.normalColor;
                     }
                 }
             }
         }
 
-        /// <summary>
-        /// Hyperlinks Info
-        /// </summary>
-        private class HrefInfo {
-            public int startIndex;
 
-            public int endIndex;
+        public override void SetVerticesDirty() {
+            base.SetVerticesDirty();
 
-            public string name;
-
-            public readonly List<Rect> boxes = new List<Rect>();
+			// Update the quad images
+            updateQuad = true;
         }
-    
+
+#if UNITY_EDITOR
+        protected override void OnValidate() {
+            base.OnValidate();
+
+			// Update the quad images
+            updateQuad = true;
+
+			for (int i = 0; i < inspectorIconList.Length; i++) {
+                if (inspectorIconList[i].scale == Vector2.zero) {
+                    inspectorIconList[i].scale = Vector2.one;
+                }
+            }
+        }
+#endif
+
+		protected override void OnEnable() {
+			#if UNITY_2019_1_OR_NEWER
+			// Here is the hack to see if Unity is using the new rendering system for text
+			usesNewRendering = false;
+
+			if (Application.unityVersion.StartsWith("2019.1.")) { 
+				int number = Convert.ToInt32(Application.unityVersion[7].ToString());
+
+				if (number > 4) {
+					usesNewRendering = true;
+				}
+			}
+			else {
+				usesNewRendering = true;
+			}
+			#endif
+
+			base.OnEnable();
+
+			supportRichText = true;
+			alignByGeometry = true;
+
+			// Enable images on TextPic disable
+            if (m_ImagesPool.Count >= 1) {
+                for (int i = 0; i < m_ImagesPool.Count; i++) {
+                    if(m_ImagesPool[i] != null) {
+						m_ImagesPool[i].enabled = true;
+					}
+                }
+            }
+
+			// Update the quads on re-enable
+			updateQuad = true;
+
+			this.onHrefClick.AddListener(OnHrefClick);
+		}
+
+		protected override void OnDisable() {
+			base.OnDisable();
+
+			// Disable images on TextPic disable
+            if (m_ImagesPool.Count >= 1) {
+                for (int i = 0; i < m_ImagesPool.Count; i++) {
+                    if (m_ImagesPool[i] != null) {
+						m_ImagesPool[i].enabled = false;
+					}
+                }
+            }
+
+			this.onHrefClick.RemoveListener(OnHrefClick);
+		}
+
+        new void Start() {
+            button = GetComponent<Button>();
+            ResetIconList();
+        }
+
         void LateUpdate() {
 			// Reset the hrefs if text is changed
-            if( previousText != text) {
-                Reset_m_HrefInfos ();
+            if (previousText != text) {
+                Reset_m_HrefInfos();
 
 				// Update the quad on text change
 				updateQuad = true;
@@ -486,41 +718,5 @@ namespace UnityEngine.UI.Extensions {
 				}
 			}
         }
-        
-        // Reseting m_HrefInfos array if there is any change in text
-        void Reset_m_HrefInfos () {
-            previousText = text;
-            m_HrefInfos.Clear();
-            isCreating_m_HrefInfos = true;
-        }
-
-		protected override void OnEnable() {
-			base.OnEnable();
-
-			// Enable images on TextPic disable
-            if (m_ImagesPool.Count >= 1) {
-                for (int i = 0; i < m_ImagesPool.Count; i++) {
-                    if(m_ImagesPool[i] != null) {
-						m_ImagesPool[i].enabled = true;
-					}
-                }
-            }
-
-			// Update the quads on re-enable
-			updateQuad = true;
-		}
-
-		protected override void OnDisable() {
-			base.OnDisable();
-
-			// Disable images on TextPic disable
-            if (m_ImagesPool.Count >= 1) {
-                for (int i = 0; i < m_ImagesPool.Count; i++) {
-                    if (m_ImagesPool[i] != null) {
-						m_ImagesPool[i].enabled = false;
-					}
-                }
-            }
-		}
     }
 }
\ No newline at end of file