context: // Copyright (C) 2014 - 2015 Stephan Bouchard - All Rights Reserved
  // This code can only be used under the standard Unity Asset Store End User License Agreement
  // A Copy of the EULA APPENDIX 1 is available at http://unity3d.com/company/legal/as_terms
  // Release 0.1.52 Beta 3
  
  
  #if UNITY_4_6 || UNITY_5
  
  using UnityEngine;
  using System;
  using System.Collections.Generic;
  using UnityEngine.UI;
  
  #pragma warning disable 0414 // Disabled a few warnings related to serialized variables not used in this script but used in the editor.
  #pragma warning disable 0618 // Disabled warning due to SetVertices being deprecated until new release with SetMesh() is available.
  
  namespace TMPro
  {  
      public partial class TextMeshProUGUI
      {
          // UV Mapping Related Properties
          [SerializeField]
          private Vector2 m_uvOffset = Vector2.zero; // Used to offset UV on Texturing
  
          [SerializeField]
          private float m_uvLineOffset = 0.0f; // Used for UV line offset per line
  
  
          [SerializeField]
          private bool m_hasFontAssetChanged = false; // Used to track when font properties have changed.
  
          private Vector3 m_previousLossyScale; // Used for Tracking lossy scale changes in the transform;
  
          private Vector3[] m_RectTransformCorners = new Vector3[4];
          private CanvasRenderer m_uiRenderer;
          private Canvas m_canvas;
  
  
          private bool m_isFirstAllocation; // Flag to determine if this is the first allocation of the buffers.
          private int m_max_characters = 8; // Determines the initial allocation and size of the character array / buffer.
          //private int m_max_numberOfLines = 4; // Determines the initial allocation and maximum number of lines of text. 
  
          // Global Variables used in conjunction with saving the state of words or lines.
          private WordWrapState m_SavedWordWrapState = new WordWrapState(); // Struct which holds various states / variables used in conjunction with word wrapping.
          private WordWrapState m_SavedLineState = new WordWrapState();
  
  
          // MASKING RELATED PROPERTIES
          private bool m_isMaskingEnabled;
          //private bool m_isStencilUpdateRequired;
  
          private bool m_isScrollRegionSet;
          //private Mask m_mask;
          private int m_stencilID = 0;
        
          [SerializeField]
          private Vector4 m_maskOffset;
  
          // Matrix used to animated Env Map
          private Matrix4x4 m_EnvMapMatrix = new Matrix4x4();
  
  
          private bool m_isAwake;
          [NonSerialized]
          private bool m_isRegisteredForEvents;
  
  
          // DEBUG Variables
          //private System.Diagnostics.Stopwatch m_StopWatch;
          //private int frame = 0;
          private int m_recursiveCount = 0;
          private int m_recursiveCountA = 0;
          private int loopCountA = 0;
          //private int loopCountB = 0;
          //private int loopCountC = 0;
          //private int loopCountD = 0;
          //private int loopCountE = 0;
  
  
          protected override void Awake()
          {
              //base.Awake();
              //Debug.Log("***** Awake() *****");
  
              m_isAwake = true;
              // Cache Reference to the Canvas
              m_canvas = this.canvas;
              m_isOrthographic = true;
  
              // Cache Reference to RectTransform.
              m_rectTransform = gameObject.GetComponent<RectTransform>();
              if (m_rectTransform == null)   
                  m_rectTransform = gameObject.AddComponent<RectTransform>();
  
              // Cache a reference to the UIRenderer.
              m_uiRenderer = GetComponent<CanvasRenderer>();
              if (m_uiRenderer == null) 
                  m_uiRenderer = gameObject.AddComponent<CanvasRenderer> ();
  
              if (m_mesh == null)
              {
                  //Debug.Log("Creating new mesh.");
                  m_mesh = new Mesh();
                  m_mesh.hideFlags = HideFlags.HideAndDontSave;
  
                  //m_mesh.bounds = new Bounds(transform.position, new Vector3(1000, 1000, 0));
              }
  
              // Cache reference to Mask Component if one is present
              //m_stencilID = MaterialManager.GetStencilID(gameObject);
              //m_mask = GetComponentInParent<Mask>();
  
              // Load TMP Settings for new text object instances.
              if (m_settings == null) m_settings = TMP_Settings.LoadDefaultSettings();
              if (m_settings != null)
              {
                  if (m_isNewTextObject)
                  {
                      m_enableWordWrapping = m_settings.enableWordWrapping;
                      m_enableKerning = m_settings.enableKerning;
                      m_enableExtraPadding = m_settings.enableExtraPadding;
                      m_isNewTextObject = false;
                  }
  
                  m_warningsDisabled = m_settings.warningsDisabled;
              }
  
              // Load the font asset and assign material to renderer.
              LoadFontAsset();
  
              // Load Default TMP StyleSheet
              TMP_StyleSheet.LoadDefaultStyleSheet();
  
              // Allocate our initial buffers.
              m_char_buffer = new int[m_max_characters];
              m_cached_TextElement = new TMP_Glyph();
              m_isFirstAllocation = true;
  
              m_textInfo = new TMP_TextInfo(this);
  
              // Check if we have a font asset assigned. Return if we don't because no one likes to see purple squares on screen.
              if (m_fontAsset == null)
              {
                  Debug.LogWarning("Please assign a Font Asset to this " + transform.name + " gameobject.", this);
                  return;
              }
  
              // Set Defaults for Font Auto-sizing
              if (m_fontSizeMin == 0) m_fontSizeMin = m_fontSize / 2;
              if (m_fontSizeMax == 0) m_fontSizeMax = m_fontSize * 2;
  
              //// Set flags to ensure our text is parsed and text re-drawn.
              m_isInputParsingRequired = true;
              m_havePropertiesChanged = true;
              m_isCalculateSizeRequired = true;
  
              //ForceMeshUpdate(); // Force an update of the text object to pre-populate the TextInfo and Preferred values used by Unity's Layout System.
          }
  
  
          protected override void OnEnable()
          {
              //Debug.Log("***** OnEnable() *****");
  
              if (!m_isRegisteredForEvents)
              {
                  //Debug.Log("Registering for Events.");
  #if UNITY_EDITOR
                  // Register Callbacks for various events.
                  TMPro_EventManager.MATERIAL_PROPERTY_EVENT.Add(ON_MATERIAL_PROPERTY_CHANGED);
                  TMPro_EventManager.FONT_PROPERTY_EVENT.Add(ON_FONT_PROPERTY_CHANGED);
                  TMPro_EventManager.TEXTMESHPRO_UGUI_PROPERTY_EVENT.Add(ON_TEXTMESHPRO_UGUI_PROPERTY_CHANGED);
                  TMPro_EventManager.DRAG_AND_DROP_MATERIAL_EVENT.Add(ON_DRAG_AND_DROP_MATERIAL);
                  TMPro_EventManager.TEXT_STYLE_PROPERTY_EVENT.Add(ON_TEXT_STYLE_CHANGED);
  #endif
                  m_isRegisteredForEvents = true;
              }
  
              // Register Graphic Component to receive event triggers
              GraphicRegistry.RegisterGraphicForCanvas(this.canvas, this);
  
              // Cache Reference to the Canvas
              if (m_canvas == null) m_canvas = this.canvas;
  
              // Re-assign the Material to the Canvas Renderer
              if (m_uiRenderer.GetMaterial() == null)
              {
                  // Use Instanced material if one exists otherwise use shared material or base material if needed.
                  if (m_sharedMaterial != null)
                  {
                      m_uiRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.mainTexture);
                  }
                  else
                  {
                      // We likely had a masking material assigned
                      m_isNewBaseMaterial = true;
                      fontSharedMaterial = m_baseMaterial;
                      RecalculateMasking();
                  }
  
                  m_havePropertiesChanged = true;
              }
  
              // Schedule potential text object update (if any of the properties have changed.
              ComputeMarginSize();
  
              m_verticesAlreadyDirty = false;
              SetVerticesDirty();
  
              m_layoutAlreadyDirty = false;
              SetLayoutDirty();
  
              RecalculateClipping();
          }
  
  
          protected override void OnDisable()
          {
              //base.OnDisable();
              //Debug.Log("***** OnDisable() *****"); //for " + this.name + " with ID: " + this.GetInstanceID() + " has been called.");
  
              // UnRegister Graphic Component
              GraphicRegistry.UnregisterGraphicForCanvas(this.canvas, this);
              CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild((ICanvasElement)this);
  
              m_uiRenderer.Clear();  // Might not want to clear since it wipes the Material in addition to the mesh geometry.
  
              LayoutRebuilder.MarkLayoutForRebuild(m_rectTransform);
              RecalculateClipping();
          }
  
  
          protected override void OnDestroy()
          {
              //base.OnDestroy();
              //Debug.Log("***** OnDestroy() *****");
  
              // UnRegister Graphic Component
              GraphicRegistry.UnregisterGraphicForCanvas(this.canvas, this);
  
              if (m_maskingMaterial != null)
              {
                  //Debug.Log("Trying to release Masking Material [" + m_maskingMaterial.name + "] with ID " + m_maskingMaterial.GetInstanceID());
                  MaterialManager.ReleaseStencilMaterial(m_maskingMaterial);
                  m_maskingMaterial = null;
              }
  
              // Clean up any material instances we may have created.
              if (m_fontMaterial != null)
                  DestroyImmediate(m_fontMaterial);
  
  #if UNITY_EDITOR
              // Unregister the event this object was listening to
              TMPro_EventManager.MATERIAL_PROPERTY_EVENT.Remove(ON_MATERIAL_PROPERTY_CHANGED);
              TMPro_EventManager.FONT_PROPERTY_EVENT.Remove(ON_FONT_PROPERTY_CHANGED);
              TMPro_EventManager.TEXTMESHPRO_UGUI_PROPERTY_EVENT.Remove(ON_TEXTMESHPRO_UGUI_PROPERTY_CHANGED);
              TMPro_EventManager.DRAG_AND_DROP_MATERIAL_EVENT.Remove(ON_DRAG_AND_DROP_MATERIAL);
              TMPro_EventManager.TEXT_STYLE_PROPERTY_EVENT.Remove(ON_TEXT_STYLE_CHANGED);
  #endif
              // UnRegister to get callback before Canvas is Rendered.
              //TMPro_EventManager.WILL_RENDER_CANVASES.Remove(OnPreRenderCanvas);
              m_isRegisteredForEvents = false;
          }
  
  
  #if UNITY_EDITOR
          protected override void Reset()
          {
              //base.Reset();
              //Debug.Log("***** Reset() *****"); //has been called.");
              m_isInputParsingRequired = true;
              m_havePropertiesChanged = true;
          }
  
  
          protected override void OnValidate()
          {
              //Debug.Log("***** OnValidate() *****"); // ID " + GetInstanceID()); // New Material [" + m_sharedMaterial.name + "] with ID " + m_sharedMaterial.GetInstanceID() + ". Base Material is [" + m_baseMaterial.name + "] with ID " + m_baseMaterial.GetInstanceID() + ". Previous Base Material is [" + (m_lastBaseMaterial == null ? "Null" : m_lastBaseMaterial.name) + "].");
  
              // Handle Font Asset changes in the inspector.
              if (m_fontAsset == null || m_hasFontAssetChanged)
              {
                  LoadFontAsset();
                  m_isCalculateSizeRequired = true;
                  m_hasFontAssetChanged = false;
              }
  
  
              if (m_uiRenderer == null || m_uiRenderer.GetMaterial() == null || m_uiRenderer.GetMaterial().mainTexture == null || m_fontAsset == null || m_fontAsset.atlas.GetInstanceID() != m_uiRenderer.GetMaterial().mainTexture.GetInstanceID())
              {
                  LoadFontAsset();
                  m_isCalculateSizeRequired = true;
                  m_hasFontAssetChanged = false;
              }
  
              font = m_fontAsset;
  
              text = m_text;
  
              fontSharedMaterial = m_sharedMaterial;
              //checkPaddingRequired = true;
  
              margin = m_margin; // Getting called on assembly reloads.
  
              SetVerticesDirty();
              SetLayoutDirty();
  
          }
  
  
  
          // Event received when custom material editor properties are changed.
          void ON_MATERIAL_PROPERTY_CHANGED(bool isChanged, Material mat)
          {
              //Debug.Log("ON_MATERIAL_PROPERTY_CHANGED event received. Targeted Material is: " + mat.name + "  m_sharedMaterial: " + m_sharedMaterial.name + "  m_renderer.sharedMaterial: " + m_uiRenderer.GetMaterial());
  
              ShaderUtilities.GetShaderPropertyIDs(); // Initialize ShaderUtilities and get shader property IDs.
  
              int materialID = mat.GetInstanceID();
  
              if (m_uiRenderer.GetMaterial() == null)
              {
                  if (m_fontAsset != null)
                  {
                      m_uiRenderer.SetMaterial(m_fontAsset.material, m_sharedMaterial.mainTexture);
                      //Debug.LogWarning("No Material was assigned to " + name + ". " + m_fontAsset.material.name + " was assigned.");
                  }
                  else
                      Debug.LogWarning("No Font Asset assigned to " + name + ". Please assign a Font Asset.", this);
              }
  
  
              if (m_uiRenderer.GetMaterial() != m_sharedMaterial && m_fontAsset == null) //    || m_renderer.sharedMaterials.Contains(mat))
              {
                  //Debug.Log("ON_MATERIAL_PROPERTY_CHANGED Called on Target ID: " + GetInstanceID() + ". Previous Material:" + m_sharedMaterial + "  New Material:" + m_uiRenderer.GetMaterial()); // on Object ID:" + GetInstanceID() + ". m_sharedMaterial: " + m_sharedMaterial.name + "  m_renderer.sharedMaterial: " + m_renderer.sharedMaterial.name);         
                  m_sharedMaterial = m_uiRenderer.GetMaterial();
              }
  
             
              // Is Material being modified my Base Material
              if (m_stencilID > 0 && m_baseMaterial != null && m_maskingMaterial != null)
              {
                  
                  if (materialID == m_baseMaterial.GetInstanceID())
                  {
                      //Debug.Log("Copying Material properties from Base Material [" + mat + "] to Masking Material [" + m_maskingMaterial + "].");
                      float stencilID = m_maskingMaterial.GetFloat(ShaderUtilities.ID_StencilID);
                      float stencilComp = m_maskingMaterial.GetFloat(ShaderUtilities.ID_StencilComp);
                      m_maskingMaterial.CopyPropertiesFromMaterial(mat);
                      m_maskingMaterial.shaderKeywords = mat.shaderKeywords;
  
                      m_maskingMaterial.SetFloat(ShaderUtilities.ID_StencilID, stencilID);
                      m_maskingMaterial.SetFloat(ShaderUtilities.ID_StencilComp, stencilComp);
                  }
                  else if (materialID == m_maskingMaterial.GetInstanceID())
                  {
                      //Debug.Log("Copying Material properties from Masking Material [" + mat + "] to Base Material [" + m_baseMaterial + "].");
                      m_baseMaterial.CopyPropertiesFromMaterial(mat);
                      m_baseMaterial.shaderKeywords = mat.shaderKeywords;
                      m_baseMaterial.SetFloat(ShaderUtilities.ID_StencilID, 0);
                      m_baseMaterial.SetFloat(ShaderUtilities.ID_StencilComp, 8);
                  }
                  else if (MaterialManager.GetBaseMaterial(mat) != null && MaterialManager.GetBaseMaterial(mat).GetInstanceID() == m_baseMaterial.GetInstanceID())
                  {
                      //Debug.Log("Copying Material properties from Masking Material [" + mat + "] to Masking Material [" + m_maskingMaterial + "].");
                      float stencilID = m_maskingMaterial.GetFloat(ShaderUtilities.ID_StencilID);
                      float stencilComp = m_maskingMaterial.GetFloat(ShaderUtilities.ID_StencilComp);
                      m_maskingMaterial.CopyPropertiesFromMaterial(mat);
                      m_maskingMaterial.shaderKeywords = mat.shaderKeywords;
  
                      m_maskingMaterial.SetFloat(ShaderUtilities.ID_StencilID, stencilID);
                      m_maskingMaterial.SetFloat(ShaderUtilities.ID_StencilComp, stencilComp);
                  }
              }
  
  
              //Debug.Log("Assigned Material is " + m_sharedMaterial.name + " with ID " + m_sharedMaterial.GetInstanceID()); // +
              //         ". Target Mat is " + mat.name + " with ID " + mat.GetInstanceID() + 
              //          ". Base Material is " + m_baseMaterial.name + " with ID " + m_baseMaterial.GetInstanceID() + 
              //          ". Masking Material is " + m_maskingMaterial.name + " with ID " + m_maskingMaterial.GetInstanceID());
  
              //m_padding = ShaderUtilities.GetPadding(m_sharedMaterial, m_enableExtraPadding, m_isUsingBold);
              m_padding = GetPaddingForMaterial();
  
              m_havePropertiesChanged = true;
              SetVerticesDirty();
          }
  
  
          // Event received when font asset properties are changed in Font Inspector
          void ON_FONT_PROPERTY_CHANGED(bool isChanged, TMP_FontAsset font)
          {
              if (font == m_fontAsset)
              {
                  //Debug.Log("ON_FONT_PROPERTY_CHANGED event received.");
                  m_havePropertiesChanged = true;
                  //hasFontAssetChanged = true;
                  //LoadFontAsset();
  
                  SetLayoutDirty();
                  SetVerticesDirty();
              }
          }
  
  
          // Event received when UNDO / REDO Event alters the properties of the object.
          void ON_TEXTMESHPRO_UGUI_PROPERTY_CHANGED(bool isChanged, TextMeshProUGUI obj)
          {
              Debug.Log("Event Received by " + obj);
              
              if (obj == this)
              {
                  //Debug.Log("Undo / Redo Event Received by Object ID:" + GetInstanceID());
                  m_havePropertiesChanged = true;
                  m_isInputParsingRequired = true;
  
                  SetVerticesDirty();
              }
          }
  
  
          // Event to Track Material Changed resulting from Drag-n-drop.
          void ON_DRAG_AND_DROP_MATERIAL(GameObject obj, Material currentMaterial, Material newMaterial)
          {
              //Debug.Log("Drag-n-Drop Event - Receiving Object ID " + GetInstanceID() + ". Sender ID " + obj.GetInstanceID()); // +  ". Prefab Parent is " + UnityEditor.PrefabUtility.GetPrefabParent(gameObject).GetInstanceID()); // + ". New Material is " + newMaterial.name + " with ID " + newMaterial.GetInstanceID() + ". Base Material is " + m_baseMaterial.name + " with ID " + m_baseMaterial.GetInstanceID());
  
              // Check if event applies to this current object
              if (obj == gameObject || UnityEditor.PrefabUtility.GetPrefabParent(gameObject) == obj)
              {
                  //Debug.Log("Assigning new Base Material " + newMaterial.name + " to replace " + currentMaterial.name);
  
                  UnityEditor.Undo.RecordObject(this, "Material Assignment");
                  m_baseMaterial = newMaterial;
                  m_isNewBaseMaterial = true;
                  fontSharedMaterial = m_baseMaterial;
  
                  m_padding = GetPaddingForMaterial();
                  SetVerticesDirty();
              }
          }
  
  
          // Event received when Text Styles are changed.
          void ON_TEXT_STYLE_CHANGED(bool isChanged)
          {
              m_havePropertiesChanged = true;
              SetVerticesDirty();
          }
  #endif
  
  
          // Function which loads either the default font or a newly assigned font asset. This function also assigned the appropriate material to the renderer.
          protected override void LoadFontAsset()
          {
              //Debug.Log("***** LoadFontAsset() *****"); //TextMeshPro LoadFontAsset() has been called."); // Current Font Asset is " + (font != null ? font.name: "Null") );
              ShaderUtilities.GetShaderPropertyIDs();
  
              // Load TMP_Settings
              if (m_settings == null) m_settings = TMP_Settings.LoadDefaultSettings();
  
  
              if (m_fontAsset == null)
              {
                  if (m_settings != null && m_settings.fontAsset != null)
                      m_fontAsset = m_settings.fontAsset;
                  else
                      m_fontAsset = Resources.Load("Fonts & Materials/ARIAL SDF", typeof(TMP_FontAsset)) as TMP_FontAsset;
  
                  if (m_fontAsset == null)
                  {
                      Debug.LogWarning("The ARIAL SDF Font Asset was not found. There is no Font Asset assigned to " + gameObject.name + ".", this);
                      return;
                  }
  
                  if (m_fontAsset.characterDictionary == null)
                  {
                      Debug.Log("Dictionary is Null!");
                  }
  
                  //m_uiRenderer.SetMaterial(m_fontAsset.material, null);
                  m_baseMaterial = m_fontAsset.material;
                  m_sharedMaterial = m_baseMaterial;
                  m_isNewBaseMaterial = true;
  
                  //m_renderer.receiveShadows = false;
                  //m_renderer.castShadows = false; // true;
                  // Get a Reference to the Shader
              }
              else
              {
                  if (m_fontAsset.characterDictionary == null)
                  {
                      //Debug.Log("Reading Font Definition and Creating Character Dictionary.");
                      m_fontAsset.ReadFontDefinition();
                  }
  
  
                  // Force the use of the base material
                  m_sharedMaterial = m_baseMaterial;
                  m_isNewBaseMaterial = true;
  
  
                  // If font atlas texture doesn't match the assigned material font atlas, switch back to default material specified in the Font Asset.
                  if (m_sharedMaterial == null || m_sharedMaterial.mainTexture == null || m_fontAsset.atlas.GetInstanceID() != m_sharedMaterial.mainTexture.GetInstanceID())
                  {
                      m_sharedMaterial = m_fontAsset.material;
                      m_baseMaterial = m_sharedMaterial;
                      m_isNewBaseMaterial = true;
                  }
              }
  
              // Check & Assign Underline Character for use with the Underline tag.
              if (!m_fontAsset.characterDictionary.TryGetValue(95, out m_cached_Underline_GlyphInfo)) //95
              {
                  if (m_settings == null && !m_settings.warningsDisabled)
                      Debug.LogWarning("Underscore character wasn't found in the current Font Asset. No characters assigned for Underline.", this);
              }
  
              
              m_stencilID = MaterialManager.GetStencilID(gameObject);
              if (m_stencilID == 0)
              {
                  if (m_maskingMaterial != null)
                  {
                      MaterialManager.ReleaseStencilMaterial(m_maskingMaterial);
                      m_maskingMaterial = null;
                  }
  
                  m_sharedMaterial = m_baseMaterial;
              }
              else
              {
                  if (m_maskingMaterial == null)
                      m_maskingMaterial = MaterialManager.GetStencilMaterial(m_baseMaterial, m_stencilID);
                  else if (m_maskingMaterial.GetInt(ShaderUtilities.ID_StencilID) != m_stencilID || m_isNewBaseMaterial)
                  {
                      MaterialManager.ReleaseStencilMaterial(m_maskingMaterial);
                      m_maskingMaterial = MaterialManager.GetStencilMaterial(m_baseMaterial, m_stencilID);
                  }
  
                  m_sharedMaterial = m_maskingMaterial;
              }
  
              m_isNewBaseMaterial = false;
              
              //m_sharedMaterials.Add(m_sharedMaterial);
              SetShaderDepth(); // Set ZTestMode based on Canvas RenderMode.
  
              if (m_uiRenderer == null) m_uiRenderer = GetComponent<CanvasRenderer>();
  
              m_uiRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.mainTexture);
              m_padding = GetPaddingForMaterial();
          }
  
  
          /// <summary>
          /// Function under development to utilize an Update Manager instead of normal event functions like LateUpdate() or OnWillRenderObject().
          /// </summary>
          //void ScheduleUpdate()
          //{
          //    return;
              /*
              if (!isAlreadyScheduled)
              {
                  m_updateManager.ScheduleObjectForUpdate(this);
                  isAlreadyScheduled = true;
              }
              */
          //}
  
  
  
          void UpdateEnvMapMatrix()
          {
              if (!m_sharedMaterial.HasProperty(ShaderUtilities.ID_EnvMap) || m_sharedMaterial.GetTexture(ShaderUtilities.ID_EnvMap) == null)
                  return;
  
              //Debug.Log("Updating Env Matrix...");
              Vector3 rotation = m_sharedMaterial.GetVector(ShaderUtilities.ID_EnvMatrixRotation);
              m_EnvMapMatrix = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(rotation), Vector3.one);
  
              m_sharedMaterial.SetMatrix(ShaderUtilities.ID_EnvMatrix, m_EnvMapMatrix);
          }
  
  
          // Enable Masking in the Shader
          void EnableMasking()
          {
              if (m_fontMaterial == null)
              {
                  m_fontMaterial = CreateMaterialInstance(m_sharedMaterial);
                  m_uiRenderer.SetMaterial(m_fontMaterial, m_sharedMaterial.mainTexture);
              }
  
              m_sharedMaterial = m_fontMaterial;
              if (m_sharedMaterial.HasProperty(ShaderUtilities.ID_ClipRect))
              {
                  m_sharedMaterial.EnableKeyword(ShaderUtilities.Keyword_MASK_SOFT);
                  m_sharedMaterial.DisableKeyword(ShaderUtilities.Keyword_MASK_HARD);
                  m_sharedMaterial.DisableKeyword(ShaderUtilities.Keyword_MASK_TEX);
  
                  UpdateMask(); // Update Masking Coordinates
              }
  
              m_isMaskingEnabled = true;
  
              //m_uiRenderer.SetMaterial(m_sharedMaterial, null);
  
              //m_padding = ShaderUtilities.GetPadding(m_sharedMaterial, m_enableExtraPadding, m_isUsingBold);
              //m_alignmentPadding = ShaderUtilities.GetFontExtent(m_sharedMaterial);
  
              /*
              Material mat = m_uiRenderer.GetMaterial();
              if (mat.HasProperty(ShaderUtilities.ID_MaskCoord))
              {
                  mat.EnableKeyword("MASK_SOFT");
                  mat.DisableKeyword("MASK_HARD");
                  mat.DisableKeyword("MASK_OFF");
  
                  m_isMaskingEnabled = true;
                  UpdateMask();
              }
              */
          }
  
  
          // Enable Masking in the Shader
          void DisableMasking()
          {
              if (m_fontMaterial != null)
              {
                  if (m_stencilID > 0)
                      m_sharedMaterial = m_maskingMaterial;
                  else
                      m_sharedMaterial = m_baseMaterial;
                             
                  m_uiRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.mainTexture);
  
                  DestroyImmediate(m_fontMaterial);
              }
                
              m_isMaskingEnabled = false;
              
              /*
              if (m_maskingMaterial != null && m_stencilID == 0)
              {
                  m_sharedMaterial = m_baseMaterial;
                  m_uiRenderer.SetMaterial(m_sharedMaterial, null);
              }
              else if (m_stencilID > 0)
              {
                  m_sharedMaterial.EnableKeyword("MASK_OFF");
                  m_sharedMaterial.DisableKeyword("MASK_HARD");
                  m_sharedMaterial.DisableKeyword("MASK_SOFT");
              }
              */
               
            
              /*
              Material mat = m_uiRenderer.GetMaterial();
              if (mat.HasProperty(ShaderUtilities.ID_MaskCoord))
              {
                  mat.EnableKeyword("MASK_OFF");
                  mat.DisableKeyword("MASK_HARD");
                  mat.DisableKeyword("MASK_SOFT");
  
                  m_isMaskingEnabled = false;
                  UpdateMask();
              }
              */
          }
  
  
          // Update & recompute Mask offset
          void UpdateMask()
          {
              //Debug.Log("Updating Mask...");
  
              if (m_rectTransform != null)
              {
                  //Material mat = m_uiRenderer.GetMaterial();
                  //if (mat == null || (m_overflowMode == TextOverflowModes.ScrollRect && m_isScrollRegionSet))
                  //    return;
  
                  if (!ShaderUtilities.isInitialized)
                      ShaderUtilities.GetShaderPropertyIDs();
                  
                  //Debug.Log("Setting Mask for the first time.");
  
                  m_isScrollRegionSet = true;
  
                  float softnessX = Mathf.Min(Mathf.Min(m_margin.x, m_margin.z), m_sharedMaterial.GetFloat(ShaderUtilities.ID_MaskSoftnessX));
                  float softnessY = Mathf.Min(Mathf.Min(m_margin.y, m_margin.w), m_sharedMaterial.GetFloat(ShaderUtilities.ID_MaskSoftnessY));
  
                  softnessX = softnessX > 0 ? softnessX : 0;
                  softnessY = softnessY > 0 ? softnessY : 0;
  
                  float width = (m_rectTransform.rect.width - Mathf.Max(m_margin.x, 0) - Mathf.Max(m_margin.z, 0)) / 2 + softnessX;
                  float height = (m_rectTransform.rect.height - Mathf.Max(m_margin.y, 0) - Mathf.Max(m_margin.w, 0)) / 2 + softnessY;
  
                  
                  Vector2 center = m_rectTransform.localPosition + new Vector3((0.5f - m_rectTransform.pivot.x) * m_rectTransform.rect.width + (Mathf.Max(m_margin.x, 0) - Mathf.Max(m_margin.z, 0)) / 2, (0.5f - m_rectTransform.pivot.y) * m_rectTransform.rect.height + (-Mathf.Max(m_margin.y, 0) + Mathf.Max(m_margin.w, 0)) / 2);                           
          
                  //Vector2 center = m_rectTransform.localPosition + new Vector3((0.5f - m_rectTransform.pivot.x) * m_rectTransform.rect.width + (margin.x - margin.z) / 2, (0.5f - m_rectTransform.pivot.y) * m_rectTransform.rect.height + (-margin.y + margin.w) / 2);
                  Vector4 mask = new Vector4(center.x, center.y, width, height);
                  //Debug.Log(mask);
  
  
  
                  //Rect rect = new Rect(0, 0, m_rectTransform.rect.width + margin.x + margin.z, m_rectTransform.rect.height + margin.y + margin.w);
                  //int softness = (int)m_sharedMaterial.GetFloat(ShaderUtilities.ID_MaskSoftnessX) / 2;
                  m_sharedMaterial.SetVector(ShaderUtilities.ID_ClipRect, mask);
              }
          }
  
  
  
          // Function called internally when a new material is assigned via the fontMaterial property.
          protected override void SetFontMaterial(Material mat)
          {
              // Get Shader PropertyIDs if they haven't been cached already.
              ShaderUtilities.GetShaderPropertyIDs();
              
              // Check in case Object is disabled. If so, we don't have a valid reference to the Renderer.
              // This can occur when the Duplicate Material Context menu is used on an inactive object.
              if (m_uiRenderer == null)
                  m_uiRenderer = GetComponent<CanvasRenderer>();
  
              // Destroy previous instance material.
              //if (m_fontMaterial != null && m_fontMaterial.GetInstanceID() != mat.GetInstanceID()) DestroyImmediate(m_fontMaterial);
  
              // Release masking material
              if (m_maskingMaterial != null)
              {
                  MaterialManager.ReleaseStencilMaterial(m_maskingMaterial);
                  m_maskingMaterial = null;
              } 
  
              // Get Masking ID
              m_stencilID = MaterialManager.GetStencilID(gameObject);
  
              // Create Instance Material only if the new material is not the same instance previously used.
              if (m_fontMaterial == null || m_fontMaterial.GetInstanceID() != mat.GetInstanceID())
                  m_fontMaterial = CreateMaterialInstance(mat);
              
              if (m_stencilID > 0)
                  m_fontMaterial = MaterialManager.SetStencil(m_fontMaterial, m_stencilID);
  
              m_sharedMaterial = m_fontMaterial;
              SetShaderDepth(); // Set ZTestMode based on Canvas RenderMode.
              
              m_uiRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.mainTexture);
  
              m_padding = GetPaddingForMaterial();
              //m_alignmentPadding = ShaderUtilities.GetFontExtent(m_sharedMaterial);
          }
  
  
          // Function called internally when a new shared material is assigned via the fontSharedMaterial property.
          protected override void SetFontSharedMaterial(Material mat) 
          {
              ShaderUtilities.GetShaderPropertyIDs();
  
              // Check in case Object is disabled. If so, we don't have a valid reference to the Renderer.
              // This can occur when the Duplicate Material Context menu is used on an inactive object. 
              if (m_uiRenderer == null)
                  m_uiRenderer = GetComponent<CanvasRenderer>();
  
              if (mat == null) { mat = m_baseMaterial; m_isNewBaseMaterial = true; }
  
       
              // Handle UI Mask
              m_stencilID = MaterialManager.GetStencilID(gameObject);
              if (m_stencilID == 0)
              {
                  if (m_maskingMaterial != null)
                  {
                      MaterialManager.ReleaseStencilMaterial(m_maskingMaterial);
                      m_maskingMaterial = null;
                  }
  
                  m_baseMaterial = mat; // Can Material be a Masking Material?
              }
              else
              {
                  if (m_maskingMaterial == null)
                      m_maskingMaterial = MaterialManager.GetStencilMaterial(mat, m_stencilID);
                  else if (m_maskingMaterial.GetInt(ShaderUtilities.ID_StencilID) != m_stencilID || m_isNewBaseMaterial)
                  {
                      MaterialManager.ReleaseStencilMaterial(m_maskingMaterial);
                      m_maskingMaterial = MaterialManager.GetStencilMaterial(mat, m_stencilID);
                  }
  
                  mat = m_maskingMaterial;
              }
  
              m_isNewBaseMaterial = false;
  
  
              m_sharedMaterial = mat;
              SetShaderDepth(); // Set ZTestMode based on Canvas RenderMode.
              
              m_uiRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.mainTexture);
              m_padding = GetPaddingForMaterial();
              //m_alignmentPadding = ShaderUtilities.GetFontExtent(m_sharedMaterial);
  
              //Debug.Log("New Material [" + mat.name + "] with ID " + mat.GetInstanceID() + " has been assigned. Base Material is [" + m_baseMaterial.name + "] with ID " + m_baseMaterial.GetInstanceID());
  
          }
  
  
          protected override void SetFontBaseMaterial(Material mat)
          {
              Debug.Log("Changing Base Material from [" + (m_lastBaseMaterial == null ? "Null" : m_lastBaseMaterial.name) + "] to [" + mat.name + "].");
          
              // Remove reference to masking material for this base material if one exists.
              //if (m_maskingMaterial != null)           
              //    MaterialManager.ReleaseMaskingMaterial(m_lastBaseMaterial);
              
              // Assign new Base Material
              m_baseMaterial = mat;
              m_lastBaseMaterial = mat;
  
              // Check if Masking is enabled and if so assign the masking material.
              //if (m_mask != null && m_mask.enabled)
              //{
                  //if (m_maskingMaterial == null)
              //    m_maskingMaterial = MaterialManager.GetMaskingMaterial(mat, 1);
              
              //    fontSharedMaterial = m_maskingMaterial;
              //}
  
              //m_isBaseMaterialChanged = false;
          }
  
  
        
          // This function will create an instance of the Font Material.
          protected override void SetOutlineThickness(float thickness)
          {
              // Use material instance if one exists. Otherwise, create a new instance of the shared material.
              if (m_fontMaterial != null && m_sharedMaterial.GetInstanceID() != m_fontMaterial.GetInstanceID())
              {
                  m_sharedMaterial = m_fontMaterial;
                  m_uiRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.mainTexture);
              }
              else if(m_fontMaterial == null)
              {
                  m_fontMaterial = CreateMaterialInstance(m_sharedMaterial);
                  m_sharedMaterial = m_fontMaterial;
                  m_uiRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.mainTexture);
              }
  
              thickness = Mathf.Clamp01(thickness);
              m_sharedMaterial.SetFloat(ShaderUtilities.ID_OutlineWidth, thickness);
              m_padding = GetPaddingForMaterial();
          }
  
  
          // This function will create an instance of the Font Material.
          protected override void SetFaceColor(Color32 color)
          {
              // Use material instance if one exists. Otherwise, create a new instance of the shared material.
              if (m_fontMaterial != null && m_sharedMaterial.GetInstanceID() != m_fontMaterial.GetInstanceID())
              {
                  m_sharedMaterial = m_fontMaterial;
                  m_uiRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.mainTexture);
              }
              else if (m_fontMaterial == null)
              {
                  m_fontMaterial = CreateMaterialInstance(m_sharedMaterial);
                  m_sharedMaterial = m_fontMaterial;
                  m_uiRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.mainTexture);
              }
  
              m_sharedMaterial.SetColor(ShaderUtilities.ID_FaceColor, color);
          }
  
  
          // This function will create an instance of the Font Material.
          protected override void SetOutlineColor(Color32 color)
          {
              // Use material instance if one exists. Otherwise, create a new instance of the shared material.
              if (m_fontMaterial != null && m_sharedMaterial.GetInstanceID() != m_fontMaterial.GetInstanceID())
              {
                  m_sharedMaterial = m_fontMaterial;
                  m_uiRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.mainTexture);
              }
              else if (m_fontMaterial == null)
              {
                  m_fontMaterial = CreateMaterialInstance(m_sharedMaterial);
                  m_sharedMaterial = m_fontMaterial;
                  m_uiRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.mainTexture);
              }
  
              m_sharedMaterial.SetColor(ShaderUtilities.ID_OutlineColor, color);
          }
  
  
          // Function used to create an instance of the material
          Material CreateMaterialInstance(Material source)
          {          
              Material mat = new Material(source);
              mat.shaderKeywords = source.shaderKeywords;
              
              mat.hideFlags = HideFlags.DontSave;
              mat.name += " (Instance)";
  
              return mat;
          }
  
  
          // Sets the Render Queue and Ztest mode 
          protected override void SetShaderDepth()
          {
              if (m_canvas == null || m_sharedMaterial == null)
                  return;
              
              if (m_canvas.renderMode == RenderMode.ScreenSpaceOverlay || m_isOverlay)
              {
                  m_sharedMaterial.SetFloat(ShaderUtilities.ShaderTag_ZTestMode, 0);
                  //m_renderer.material.SetFloat("_ZTestMode", 8);
                  //m_renderer.material.renderQueue = 4000;
  
                  //m_sharedMaterial = m_renderer.material;
              }
              else
  
gt:             {   // TODO: This section needs to be tested.