public override void CounterInit()
        {
            string defaultValue = FormatTimeDependence(0, GetDecimals());
            var    label        = CanvasUtility.CreateTextFromSettings(Settings);

            label.text     = "Time Dependence";
            label.fontSize = 3;

            Vector3 leftOffset             = Vector3.up * -0.2f;
            TextAlignmentOptions leftAlign = TextAlignmentOptions.Top;

            if (Configuration.Instance.separateSaber)
            {
                _counterRight             = CanvasUtility.CreateTextFromSettings(Settings, new Vector3(0.2f, -0.2f, 0));
                _counterRight.lineSpacing = -26;
                _counterRight.text        = defaultValue;
                _counterRight.alignment   = TextAlignmentOptions.TopLeft;

                leftOffset = new Vector3(-0.2f, -0.2f, 0);
                leftAlign  = TextAlignmentOptions.TopRight;
            }

            _counterLeft             = CanvasUtility.CreateTextFromSettings(Settings, leftOffset);
            _counterLeft.lineSpacing = -26;
            _counterLeft.text        = defaultValue;
            _counterLeft.alignment   = leftAlign;
        }
Beispiel #2
0
 public void AlignValue(TextAlignmentOptions textAlignmentOptions = TextAlignmentOptions.TopRight)
 {
     if (value != null)
     {
         this.value.alignment = textAlignmentOptions;
     }
 }
        public static TextMeshProUGUI AddTMPTextObject(string name, Transform parent, TMP_FontAsset font, Color color,
                                                       TextAlignmentOptions anchor, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 sizeDelta,
                                                       int fontSize = 14, float rotate = 0, FontStyles fontStyle = FontStyles.Normal, float lineSpacing = 1)
        {
            GameObject txtObj = AddObject(name, parent, anchorMin, anchorMax, pivot, sizeDelta);
            var        txt    = GetOrAddComponent <TextMeshProUGUI>(txtObj);

            txt.font                          = font;
            txt.fontSize                      = fontSize;
            txt.fontStyle                     = fontStyle;
            txt.text                          = "Text";
            txt.alignment                     = anchor;
            txt.color                         = color;
            txt.lineSpacing                   = lineSpacing;
            txt.raycastTarget                 = false;
            txt.enableWordWrapping            = false;
            txtObj.transform.localEulerAngles = new Vector3(0, 0, rotate);

            RectTransform rect = GetOrAddComponent <RectTransform>(txtObj);

            rect.localPosition = Vector3.zero;
            rect.sizeDelta     = sizeDelta;
            rect.anchorMin     = anchorMin;
            rect.anchorMax     = anchorMax;
            rect.pivot         = pivot;
            return(txt);
        }
Beispiel #4
0
        public static TextAnchor TextAlignmentOptions2TextAnchor(TextAlignmentOptions anchor)
        {
            switch (anchor)
            {
            case TextAlignmentOptions.TopJustified:
                return(TextAnchor.UpperLeft);

            case TextAlignmentOptions.Top:
                return(TextAnchor.UpperCenter);

            case TextAlignmentOptions.TopRight:
                return(TextAnchor.UpperRight);

            case TextAlignmentOptions.MidlineJustified:
                return(TextAnchor.MiddleLeft);

            case TextAlignmentOptions.Midline:
                return(TextAnchor.MiddleCenter);

            case TextAlignmentOptions.MidlineRight:
                return(TextAnchor.MiddleRight);

            case TextAlignmentOptions.BottomJustified:
                return(TextAnchor.LowerLeft);

            case TextAlignmentOptions.Bottom:
                return(TextAnchor.LowerCenter);

            case TextAlignmentOptions.BottomRight:
                return(TextAnchor.LowerRight);

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
Beispiel #5
0
        public KsmGuiText(
            KsmGuiBase parent,
            string text,
            string tooltipText = null,
            TextAlignmentOptions alignement = TextAlignmentOptions.TopLeft,
            bool wordWrap = true,
            TextOverflowModes overflowMode = TextOverflowModes.Overflow
            ) : base(parent)
        {
            savedAlignement                  = alignement;
            TextComponent                    = TopObject.AddComponent <TextMeshProUGUI>();
            TextComponent.color              = KsmGuiStyle.textColor;
            TextComponent.font               = KsmGuiStyle.textFont;
            TextComponent.fontSize           = KsmGuiStyle.textSize;
            TextComponent.alignment          = alignement;
            TextComponent.enableWordWrapping = wordWrap;
            TextComponent.overflowMode       = overflowMode;
            TextComponent.text               = text;
            SetLayoutElement(true);
            //TextComponent.raycastTarget = false;

            if (tooltipText != null)
            {
                SetTooltipText(tooltipText);
            }
        }
Beispiel #6
0
        public static AnchoredState FromTextAnchor(this TextAlignmentOptions anchor)
        {
            switch (anchor)
            {
            case TextAlignmentOptions.BottomLeft:
                return(AnchoredState.LeftColumn | AnchoredState.BottomRow);

            case TextAlignmentOptions.Bottom:
                return(AnchoredState.MiddleColumn | AnchoredState.BottomRow);

            case TextAlignmentOptions.BottomRight:
                return(AnchoredState.RightColumn | AnchoredState.BottomRow);

            case TextAlignmentOptions.Left:
                return(AnchoredState.LeftColumn | AnchoredState.MiddleRow);

            case TextAlignmentOptions.Center:
                return(AnchoredState.MiddleColumn | AnchoredState.MiddleRow);

            case TextAlignmentOptions.Right:
                return(AnchoredState.RightColumn | AnchoredState.MiddleRow);

            case TextAlignmentOptions.TopLeft:
                return(AnchoredState.LeftColumn | AnchoredState.TopRow);

            case TextAlignmentOptions.Top:
                return(AnchoredState.MiddleColumn | AnchoredState.TopRow);

            case TextAlignmentOptions.TopRight:
                return(AnchoredState.RightColumn | AnchoredState.TopRow);

            default:
                throw new System.ArgumentException($"Cannot convert {anchor} to a valid AnchoredState!");
            }
        }
Beispiel #7
0
 void AssignTextStyle(int fontSize, FontStyles fontStyles, TextAlignmentOptions alignment, TextOverflowModes overflow)
 {
     text.fontSize     = fontSize;
     text.fontStyle    = fontStyles;
     text.alignment    = alignment;
     text.overflowMode = overflow;
 }
 public void SetAlignment(TextAlignmentOptions alignment)
 {
     if (m_TMPText != null)
     {
         m_TMPText.alignment = alignment;
     }
 }
Beispiel #9
0
    //字体对齐
    public static TextAnchor getTextProAlig(TextAlignmentOptions tx)
    {
        switch (tx)
        {
        case TextAlignmentOptions.Bottom:
            return(TextAnchor.LowerCenter);

        case TextAlignmentOptions.BottomLeft:
            return(TextAnchor.LowerLeft);

        case TextAlignmentOptions.BottomRight:
            return(TextAnchor.LowerRight);

        case TextAlignmentOptions.Center:
            return(TextAnchor.MiddleCenter);

        case TextAlignmentOptions.Left:
            return(TextAnchor.MiddleLeft);

        case TextAlignmentOptions.Right:
            return(TextAnchor.MiddleRight);

        case TextAlignmentOptions.Top:
            return(TextAnchor.UpperCenter);

        case TextAlignmentOptions.TopLeft:
            return(TextAnchor.UpperLeft);

        case TextAlignmentOptions.TopRight:
            return(TextAnchor.UpperRight);

        default:
            return(TextAnchor.UpperLeft);
        }
    }
    private void AdjustPositionToAlignment(TextAlignmentOptions alignment)
    {
        Vector3 adjustment = Vector3.zero;

        switch (alignment)
        {
        case TextAlignmentOptions.Left:
            adjustment = new Vector3(cashText.rectTransform.rect.width, 0);
            break;

        case TextAlignmentOptions.BottomLeft:
            adjustment = new Vector3(cashText.rectTransform.rect.width, cashText.rectTransform.rect.height);
            break;

        case TextAlignmentOptions.TopLeft:
            adjustment = new Vector3(cashText.rectTransform.rect.width, -cashText.rectTransform.rect.height);
            break;

        case TextAlignmentOptions.Right:
            adjustment = new Vector3(-cashText.rectTransform.rect.width, 0);
            break;

        case TextAlignmentOptions.BottomRight:
            adjustment = new Vector3(-cashText.rectTransform.rect.width, cashText.rectTransform.rect.height);
            break;

        case TextAlignmentOptions.TopRight:
            adjustment = new Vector3(-cashText.rectTransform.rect.width, -cashText.rectTransform.rect.height);
            break;
        }

        cashText.rectTransform.localPosition += adjustment;
    }
Beispiel #11
0
 public TMProData(TextMeshProUGUI text)
 {
     this.fontData.font        = text.font;
     this.fontData.material    = text.fontSharedMaterial;
     this.fontStyle            = text.fontStyle;
     this.fontSize             = text.fontSize;
     this.autoSize             = text.enableAutoSizing;
     this.autoSizeOptions.min  = text.fontSizeMin;
     this.autoSizeOptions.max  = text.fontSizeMax;
     this.autoSizeOptions.wd   = text.characterWidthAdjustment;
     this.autoSizeOptions.line = text.lineSpacingAdjustment;
     this.color                = text.color;
     this.overrideTags         = text.overrideColorTags;
     this.spacings.character   = text.characterSpacing;
     this.spacings.word        = text.wordSpacing;
     this.spacings.line        = text.lineSpacing;
     this.spacings.paragraph   = text.paragraphSpacing;
     this.alignment            = text.alignment;
     this.wrapping             = text.enableWordWrapping;
     this.overflow             = text.overflowMode;
     this.horizontalMapping    = text.horizontalMapping;
     this.verticalMapping      = text.verticalMapping;
     this.margins.marginsV4    = text.margin;
     this.geometrySorting      = text.geometrySortingOrder;
     this.richText             = text.richText;
     this.raycastTarget        = text.raycastTarget;
     this.parseEscapeCharaters = text.parseCtrlCharacters;
     this.visibleDescender     = text.useMaxVisibleDescender;
     this.spriteAsset          = text.spriteAsset;
     this.kerning              = text.enableKerning;
     this.extraPadding         = text.extraPadding;
 }
Beispiel #12
0
    public void write(Text textObject, TMP_FontAsset tmpFont)
    {
        color = textObject.color;
        if (textObject.fontSize > 0)
        {
            fontSize = textObject.fontSize;
        }
        else if (textObject.font != null)
        {
            fontSize = textObject.font.lineHeight;
        }
        fontStyle     = GetFontStyle(textObject.fontStyle);
        tmProfont     = tmpFont;
        anchor        = GetTextAlignment(textObject.alignment);
        autoResize    = textObject.resizeTextForBestFit;
        minMaxSize    = new Vector2(textObject.resizeTextMinSize, textObject.resizeTextMaxSize);
        raycastTarget = textObject.raycastTarget;
        enable        = textObject.enabled;
        if (textObject.fontStyle == FontStyle.BoldAndItalic)
        {
            text = string.Format("<i>{0}</i>", textObject.text);
        }
        else
        {
            text = textObject.text;
        }

        ratioFontSize = GetRatioFontSize(textObject.font);
    }
Beispiel #13
0
        public override void CounterInit()
        {
            string defaultValue = FormatLabel(0, 0, Settings.AveragePrecision);

            var label = CanvasUtility.CreateTextFromSettings(Settings);

            label.text     = "Average Cut";
            label.fontSize = 3;

            Vector3 leftOffset             = Vector3.up * -0.2f;
            TextAlignmentOptions leftAlign = TextAlignmentOptions.Top;

            if (Settings.SeparateSaberCounts)
            {
                cutCounterRight             = CanvasUtility.CreateTextFromSettings(Settings, new Vector3(0.2f, -0.2f, 0));
                cutCounterRight.lineSpacing = -26;
                cutCounterRight.text        = Settings.SeparateCutValues ? $"{defaultValue}\n{defaultValue}\n{defaultValue}" : $"{defaultValue}";
                cutCounterRight.alignment   = TextAlignmentOptions.TopLeft;

                leftOffset = new Vector3(-0.2f, -0.2f, 0);
                leftAlign  = TextAlignmentOptions.TopRight;
            }

            cutCounterLeft             = CanvasUtility.CreateTextFromSettings(Settings, leftOffset);
            cutCounterLeft.lineSpacing = -26;
            cutCounterLeft.text        = Settings.SeparateCutValues ? $"{defaultValue}\n{defaultValue}\n{defaultValue}" : $"{defaultValue}";
            cutCounterLeft.alignment   = leftAlign;

            scoreController.scoringForNoteFinishedEvent += ScoreController_scoringForNoteFinishedEvent;
        }
Beispiel #14
0
        public static TextAnchor TextOptionToTextAnchor(TextAlignmentOptions options)
        {
            switch (options)
            {
            case TextAlignmentOptions.TopLeft: return(TextAnchor.UpperLeft);

            case TextAlignmentOptions.Top: return(TextAnchor.UpperCenter);

            case TextAlignmentOptions.TopRight: return(TextAnchor.UpperRight);

            case TextAlignmentOptions.Left: return(TextAnchor.MiddleLeft);

            case TextAlignmentOptions.Center: return(TextAnchor.MiddleCenter);

            case TextAlignmentOptions.Right: return(TextAnchor.MiddleRight);

            case TextAlignmentOptions.BottomLeft: return(TextAnchor.LowerLeft);

            case TextAlignmentOptions.Bottom: return(TextAnchor.LowerCenter);

            case TextAlignmentOptions.BottomRight: return(TextAnchor.LowerRight);
            }

            return(TextAnchor.UpperLeft);
        }
Beispiel #15
0
    private TextAlignmentOptions ParseTextAnchorFromString(string alignString)
    {
        string[]             temp       = alignString.Split(' ');
        TextAlignmentOptions textAnchor = TextAlignmentOptions.Center;

        if (temp.Length == 1 || temp.Length == 2)
        {
            switch (temp [0])
            {
            case "left":
                textAnchor = TextAlignmentOptions.Left;
                break;

            case "right":
                textAnchor = TextAlignmentOptions.Right;
                break;
            }
            if (temp.Length == 2)
            {
                switch (temp [1])
                {
                case "top":
                    switch (temp [0])
                    {
                    case "left":
                        textAnchor = TextAlignmentOptions.TopLeft;
                        break;

                    case "center":
                        textAnchor = TextAlignmentOptions.Top;
                        break;

                    case "right":
                        textAnchor = TextAlignmentOptions.TopRight;
                        break;
                    }
                    break;

                case "bottom":
                    switch (temp [0])
                    {
                    case "left":
                        textAnchor = TextAlignmentOptions.BottomLeft;
                        break;

                    case "center":
                        textAnchor = TextAlignmentOptions.Bottom;
                        break;

                    case "right":
                        textAnchor = TextAlignmentOptions.BottomRight;
                        break;
                    }
                    break;
                }
            }
        }
        return(textAnchor);
    }
Beispiel #16
0
        public void DoLocalize_TMPLabel(string mainTranslation, string secondaryTranslation)
        {
            bool          isPlaying = Application.isPlaying;
            TMP_FontAsset secondaryTranslatedObj = GetSecondaryTranslatedObj <TMP_FontAsset>(ref mainTranslation, ref secondaryTranslation);

            if (secondaryTranslatedObj != null)
            {
                if (mTarget_TMPLabel.font != secondaryTranslatedObj)
                {
                    mTarget_TMPLabel.font = secondaryTranslatedObj;
                }
            }
            else
            {
                Material secondaryTranslatedObj2 = GetSecondaryTranslatedObj <Material>(ref mainTranslation, ref secondaryTranslation);
                if (secondaryTranslatedObj2 != null && mTarget_TMPLabel.fontMaterial != secondaryTranslatedObj2)
                {
                    if (!secondaryTranslatedObj2.name.StartsWith(mTarget_TMPLabel.font.name, StringComparison.Ordinal))
                    {
                        secondaryTranslatedObj = GetTMPFontFromMaterial(secondaryTranslation.EndsWith(secondaryTranslatedObj2.name, StringComparison.Ordinal) ? secondaryTranslation : secondaryTranslatedObj2.name);
                        if (secondaryTranslatedObj != null)
                        {
                            mTarget_TMPLabel.font = secondaryTranslatedObj;
                        }
                    }
                    mTarget_TMPLabel.fontSharedMaterial = secondaryTranslatedObj2;
                }
            }
            if (mInitializeAlignment)
            {
                mInitializeAlignment = false;
                mAlignmentTMPwasRTL  = LocalizationManager.IsRight2Left;
                InitAlignment_TMPro(mAlignmentTMPwasRTL, mTarget_TMPLabel.alignment, out mAlignmentTMPro_LTR, out mAlignmentTMPro_RTL);
            }
            else
            {
                InitAlignment_TMPro(mAlignmentTMPwasRTL, mTarget_TMPLabel.alignment, out TextAlignmentOptions alignLTR, out TextAlignmentOptions alignRTL);
                if ((mAlignmentTMPwasRTL && mAlignmentTMPro_RTL != alignRTL) || (!mAlignmentTMPwasRTL && mAlignmentTMPro_LTR != alignLTR))
                {
                    mAlignmentTMPro_LTR = alignLTR;
                    mAlignmentTMPro_RTL = alignRTL;
                }
                mAlignmentTMPwasRTL = LocalizationManager.IsRight2Left;
            }
            if (mainTranslation == null || !(mTarget_TMPLabel.text != mainTranslation))
            {
                return;
            }
            if (CurrentLocalizeComponent.CorrectAlignmentForRTL)
            {
                mTarget_TMPLabel.alignment         = (LocalizationManager.IsRight2Left ? mAlignmentTMPro_RTL : mAlignmentTMPro_LTR);
                mTarget_TMPLabel.isRightToLeftText = LocalizationManager.IsRight2Left;
                if (LocalizationManager.IsRight2Left)
                {
                    mainTranslation = ReverseText(mainTranslation);
                }
            }
            mTarget_TMPLabel.text = mainTranslation;
        }
Beispiel #17
0
        public void UpdateAlignmentByLocation(Location location)
        {
#if dUI_TextMeshPro
            m_TMPAlignment = location.runtimeTMPTextAlignment;
#else
            m_Alignment = location.runtimeTextAlignment;
#endif
        }
        private void CreateDetailCell(string text, TextAlignmentOptions alignment, Transform parent)
        {
            var cell     = Instantiate(m_detailCell, parent);
            var cellText = cell.GetComponent <TextMeshProUGUI>();

            cellText.text      = text;
            cellText.alignment = alignment;
        }
Beispiel #19
0
        private void TMProFromText(TextHandler handler)
        {
            if (handler == null)
            {
                return;
            }

            //The TextHandler element should be attached only to objects with a Unity Text element
            //Note that the "[RequireComponent(typeof(Text))]" attribute cannot be attached to TextHandler since Unity will not allow the Text element to be removed
            Text text = handler.GetComponent <Text>();

            if (text == null)
            {
                return;
            }

            //Cache all of the relevent information from the Text element
            string               t       = text.text;
            Color                c       = text.color;
            int                  i       = text.fontSize;
            bool                 resize  = text.resizeTextForBestFit;
            int                  maxs    = text.resizeTextMaxSize;
            int                  mins    = text.resizeTextMinSize;
            bool                 r       = text.raycastTarget;
            FontStyles           sty     = TMPProUtil.FontStyle(text.fontStyle);
            TextAlignmentOptions align   = TMPProUtil.TextAlignment(text.alignment);
            float                spacing = text.lineSpacing;
            GameObject           obj     = text.gameObject;

            //The existing Text element must by destroyed since Unity will not allow two UI elements to be placed on the same GameObject
            DestroyImmediate(text);

            PTTextMeshProHolder tmp = obj.AddComponent <PTTextMeshProHolder>();

            //Populate the TextMeshPro fields with the cached data from the old Text element
            tmp.text             = t;
            tmp.color            = c;
            tmp.fontSize         = i;
            tmp.enableAutoSizing = resize;
            tmp.fontSizeMax      = maxs;
            tmp.fontSizeMin      = mins;
            tmp.raycastTarget    = r;
            tmp.alignment        = align;
            tmp.fontStyle        = sty;
            tmp.lineSpacing      = spacing;

            tmp.font = UISkinManager.TMPFont;
            tmp.fontSharedMaterial = Resources.Load("Fonts/Materials/Calibri Dropshadow", typeof(Material)) as Material;

            tmp.enableWordWrapping = true;
            tmp.isOverlay          = false;
            tmp.richText           = true;

            //No idea why this is needed, but TMP needs this field to be set to true for correct initialization of the alignment style
            var prop = tmp.GetType().GetField("m_isAlignmentEnumConverted", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

            prop.SetValue(tmp, true);
        }
Beispiel #20
0
        public virtual void SetDialogueTextAlign(TextAlignmentOptions eAlign)
        {
            if (!HasDialogueText())
            {
                return;
            }

            m_hDialogueText.alignment = eAlign;
        }
        private TextMeshProUGUI UpgradeText(Text text)
        {
            if (!text)
            {
                return(null);
            }

            GameObject go = text.gameObject;

            stringBuilder.AppendLine("Upgrading Text: " + GetPathOfObject(go.transform));

            // Copy fields
            Vector2 sizeDelta = text.rectTransform.sizeDelta;

            TextAlignmentOptions alignment   = GetTMPAlignment(text.alignment, text.alignByGeometry);
            bool              bestFit        = text.resizeTextForBestFit;
            int               bestFitMaxSize = text.resizeTextMaxSize;
            int               bestFitMinSize = text.resizeTextMinSize;
            Color             color          = text.color;
            bool              enabled        = text.enabled;
            Material          fontMaterial;
            TMP_FontAsset     font               = GetCorrespondingTMPFontAsset(text.font, text, out fontMaterial);
            int               fontSize           = text.fontSize;
            FontStyles        fontStyle          = GetTMPFontStyle(text.fontStyle);
            bool              horizontalWrapMode = text.horizontalOverflow == HorizontalWrapMode.Wrap;
            float             lineSpacing        = (text.lineSpacing - 1) * 100f;
            bool              raycastTarget      = text.raycastTarget;
            bool              supportRichText    = text.supportRichText;
            string            _text              = text.text;
            TextOverflowModes verticalOverflow   = GetTMPVerticalOverflow(text.verticalOverflow, text.horizontalOverflow);

            // Replace Text with TextMeshProUGUI
            DestroyImmediate(text, true);
            TextMeshProUGUI tmp = go.AddComponent <TextMeshProUGUI>();

            // Paste fields
            tmp.alignment          = alignment;
            tmp.enableAutoSizing   = bestFit;
            tmp.fontSizeMax        = bestFitMaxSize;
            tmp.fontSizeMin        = bestFitMinSize;
            tmp.color              = color;
            tmp.enabled            = enabled;
            tmp.font               = font;
            tmp.fontMaterial       = fontMaterial;
            tmp.fontSize           = fontSize;
            tmp.fontStyle          = fontStyle;
            tmp.enableWordWrapping = horizontalWrapMode;
            tmp.lineSpacing        = lineSpacing;
            tmp.raycastTarget      = raycastTarget;
            tmp.richText           = supportRichText;
            tmp.text               = _text;
            tmp.overflowMode       = verticalOverflow;

            tmp.rectTransform.sizeDelta = sizeDelta;

            return(tmp);
        }
Beispiel #22
0
 public static TextMeshPro CreateWorldText(string text, Transform parent = null, Vector3 localPosition = default(Vector3),
                                           int fontsize = 40, Color?color = null, TextAlignmentOptions textAlignment = TextAlignmentOptions.Center)
 {
     if (color == null)
     {
         color = Color.white;
     }
     return(CreateWorldText(parent, text, localPosition, fontsize, (Color)color, textAlignment));
 }
Beispiel #23
0
        public virtual void SetTalkerTextAlign(TextAlignmentOptions eAlign)
        {
            if (!HasTalkerText())
            {
                return;
            }

            m_hTalkerText.alignment = eAlign;
        }
Beispiel #24
0
        public virtual void SetTextAlign(int nIndex, TextAlignmentOptions eAlign)
        {
            if (!TryGetBehaviourComponent(nIndex, out var hText))
            {
                return;
            }

            hText.alignment = eAlign;
        }
Beispiel #25
0
 void UpdateAlignment(TextAlignmentOptions newAlignment)
 {
     alignment  = newAlignment;
     _alignment = newAlignment;
     foreach (TMP_Text item in refs.textComponents)
     {
         item.alignment = newAlignment;
     }
 }
Beispiel #26
0
 public TextFieldBuilder(string name, Transform parent, Rect pos, TextAlignmentOptions textAlignment, RectTransformAnchoring anchor, Vector2 pivot, bool isDigitOnly = false)
 {
     this.name          = name;
     this.parent        = parent;
     this.rect          = pos;
     this.textAlignment = textAlignment;
     this.anchor        = anchor;
     this.pivot         = pivot;
     this.isDigitOnly   = isDigitOnly;
 }
        private void TMProFromText(TextHandler handler)
        {
            if (handler == null)
            {
                return;
            }

            Text text = handler.GetComponent <Text>();

            if (text == null)
            {
                return;
            }

            string               t       = text.text;
            Color                c       = text.color;
            int                  i       = text.fontSize;
            bool                 r       = text.raycastTarget;
            FontStyles           sty     = TMPProUtil.FontStyle(text.fontStyle);
            TextAlignmentOptions align   = TMPProUtil.TextAlignment(text.alignment);
            float                spacing = text.lineSpacing;
            GameObject           obj     = text.gameObject;

            DestroyImmediate(text);

            BasicDeltaV_TextMeshPro tmp = obj.AddComponent <BasicDeltaV_TextMeshPro>();

            tmp.text = t;

            if (handler.ReadoutField && BasicDeltaV_Settings.Instance != null)
            {
                tmp.color = BasicDeltaV_Settings.Instance.ReadoutColor;
            }
            else if (handler.ReadoutLabel && BasicDeltaV_Settings.Instance != null)
            {
                tmp.color = BasicDeltaV_Settings.Instance.LabelColor;
            }
            else
            {
                tmp.color = c;
            }

            tmp.fontSize      = i;
            tmp.raycastTarget = r;
            tmp.alignment     = align;
            tmp.fontStyle     = sty;
            tmp.lineSpacing   = spacing;

            tmp.font = UISkinManager.TMPFont;
            tmp.fontSharedMaterial = Resources.Load("Fonts/Materials/Calibri Dropshadow", typeof(Material)) as Material;

            tmp.enableWordWrapping = true;
            tmp.isOverlay          = false;
            tmp.richText           = true;
        }
Beispiel #28
0
        static TextAlignmentOptions?ParseAlignment(string str)
        {
            if (String.IsNullOrEmpty(str))
            {
                return(null);
            }
            TextAlignmentOptions alignment = TextAlignmentOptions.TopLeft;

            alignment = KodeUI_Utils.ToEnum <TextAlignmentOptions> (str, alignment);
            return(alignment);
        }
Beispiel #29
0
    void OnRenderObject()
    {
        if(lastCharWidthMult != characterWidthMult || lastText != m_TextComponent.text || textAlign != m_TextComponent.alignment)
        {
            UpdateTextPosition();
        }

        lastCharWidthMult = characterWidthMult;
        lastText = m_TextComponent.text;
        textAlign = m_TextComponent.alignment;
    }
Beispiel #30
0
 /// <summary>
 /// Configures a Text Mesh Pro field.
 /// </summary>
 /// <param name="component">The text component to configure.</param>
 /// <param name="style">The desired text color, font, and style.</param>
 /// <param name="alignment">The text alignment.</param>
 /// <returns>The component, for call chaining.</returns>
 internal static TextMeshProUGUI ConfigureField(TextMeshProUGUI component,
                                                TextStyleSetting style, TextAlignmentOptions alignment)
 {
     component.alignment             = alignment;
     component.autoSizeTextContainer = false;
     component.enabled      = true;
     component.color        = style.textColor;
     component.font         = style.sdfFont;
     component.fontSize     = style.fontSize;
     component.fontStyle    = style.style;
     component.overflowMode = TextOverflowModes.Overflow;
     return(component);
 }
 public void Init(DialogueDisplayData displayData, TextAlignmentOptions alignment, Color characterNameColor,
                  Color textColor, string materialName, DialogueEntryLayoutSetting layoutSetting, int textLeftExtraPadding)
 {
     InitReferences();
     this.displayData          = displayData;
     this.alignment            = alignment;
     this.characterNameColor   = characterNameColor;
     this.textColor            = textColor;
     this.materialName         = materialName;
     this.layoutSetting        = layoutSetting;
     this.textLeftExtraPadding = textLeftExtraPadding;
     UpdateText();
 }
Beispiel #32
0
        /// <summary>
        /// This is the main function that is responsible for creating / displaying the text.
        /// </summary>
        void GenerateTextMesh()
        {
            //Debug.Log("***** GenerateTextMesh() ***** Iteration Count: " + loopCountA + ".  Min: " + m_minFontSize + "  Max: " + m_maxFontSize + "  Font size is " + m_fontSize);
            
            // Early exit if no font asset was assigned. This should not be needed since Arial SDF will be assigned by default.
            if (m_fontAsset.characterDictionary == null)
            {
                Debug.Log("Can't Generate Mesh! No Font Asset has been assigned to Object ID: " + this.GetInstanceID());
                return;
            }

            // Reset TextInfo
            if (m_textInfo != null)
                m_textInfo.Clear();


            // Early exit if we don't have any Text to generate.          
            if (m_char_buffer == null || m_char_buffer.Length == 0 || m_char_buffer[0] == (char)0)
            {
                //Debug.Log("Early Out!");
                if (m_vertices != null)
                {
                    Array.Clear(m_vertices, 0, m_vertices.Length);
                    m_mesh.vertices = m_vertices;
                }

                m_preferredWidth = 0;
                m_preferredHeight = 0;
                return;
            }
            
            // Determine how many characters will be visible and make the necessary allocations (if needed).
            int totalCharacterCount = SetArraySizes(m_char_buffer);

            m_fontIndex = 0; // Will be used when support for using different font assets or sprites within the same object will be added.
            m_fontAssetArray[m_fontIndex] = m_fontAsset;

            // Scale the font to approximately match the point size
            m_fontScale = (m_fontSize / m_fontAssetArray[m_fontIndex].fontInfo.PointSize * (m_isOrthographic ? 1 : 0.1f));
            float baseScale = m_fontScale; // BaseScale keeps the character aligned vertically since <size=+000> results in font of different scale.
            m_maxFontScale = 0;
            float previousFontScale = 0;
            //float lastVisibleCharacterScale = 0;
            m_currentFontSize = m_fontSize;
            float fontSizeDelta = 0;

            int charCode = 0; // Holds the character code of the currently being processed character.
            //int prev_charCode = 0;
            bool isMissingCharacter; // Used to handle missing characters in the Font Atlas / Definition.

            m_style = m_fontStyle; // Set the default style.
            m_lineJustification = m_textAlignment; // Sets the line justification mode to match editor alignment.

            // GetPadding to adjust the size of the mesh due to border thickness, softness, glow, etc...
            if (checkPaddingRequired)
            {
                checkPaddingRequired = false;
                m_padding = ShaderUtilities.GetPadding(m_renderer.sharedMaterials, m_enableExtraPadding, m_isUsingBold);
                m_alignmentPadding = ShaderUtilities.GetFontExtent(m_sharedMaterial);
                m_isMaskingEnabled = ShaderUtilities.IsMaskingEnabled(m_sharedMaterial);
            }

            float style_padding = 0; // Extra padding required to accommodate Bold style.
            float xadvance_multiplier = 1; // Used to increase spacing between character when style is bold.

            m_baselineOffset = 0; // Used by subscript characters.

            // Underline
            bool beginUnderline = false;
            Vector3 underline_start = Vector3.zero; // Used to track where underline starts & ends.
            Vector3 underline_end = Vector3.zero;

            // Strike-through
            bool beginStrikethrough = false;
            Vector3 strikethrough_start = Vector3.zero;
            Vector3 strikethrough_end = Vector3.zero;

            m_fontColor32 = m_fontColor;
            Color32 vertexColor;
            m_htmlColor = m_fontColor32;
            m_colorStackIndex = 0;
            Array.Clear(m_colorStack, 0, m_colorStack.Length);

            m_styleStackIndex = 0;
            Array.Clear(m_styleStack, 0, m_styleStack.Length);

            m_lineOffset = 0; // Amount of space between lines (font line spacing + m_linespacing).
            m_lineHeight = 0;
            float maxLineHeight = 0;

            m_cSpacing = 0;
            m_monoSpacing = 0;
            float lineOffsetDelta = 0;
            m_xAdvance = 0; // Used to track the position of each character.
            m_maxXAdvance = 0; // Used to determine Preferred Width.

            tag_LineIndent = 0; // Used for indentation of text.
            tag_Indent = 0;

            m_characterCount = 0; // Total characters in the char[]
            m_visibleCharacterCount = 0; // # of visible characters.

            // Tracking of line information
            m_firstCharacterOfLine = 0;
            m_lastCharacterOfLine = 0;
            m_firstVisibleCharacterOfLine = 0;
            m_lastVisibleCharacterOfLine = 0;
            m_lineNumber = 0;
            bool isStartOfNewLine = true;

            m_pageNumber = 0;
            int pageToDisplay = Mathf.Clamp(m_pageToDisplay - 1, 0, m_textInfo.pageInfo.Length - 1);

            int ellipsisIndex = 0;

            Vector3[] corners = m_textContainer.corners;
            Vector4 margins = m_textContainer.margins;
            m_marginWidth = m_textContainer.rect.width - margins.z - margins.x;
            float marginWidth = m_marginWidth;
            float marginHeight = m_textContainer.rect.height - margins.y - margins.w;
            m_marginLeft = 0;
            m_marginRight = 0;
            m_width = -1;

            float lossyScale = m_transform.lossyScale.z;
            // Used by Unity's Auto Layout system.
            m_preferredWidth = 0;
            m_preferredHeight = 0;

            // Initialize struct to track states of word wrapping
            bool isFirstWord = true;
            bool isLastBreakingChar = false;
            m_SavedLineState = new WordWrapState();
            m_SavedWordWrapState = new WordWrapState();
            int wrappingIndex = 0;

            // Need to initialize these Extents structures
            m_meshExtents = new Extents(k_InfinityVector, -k_InfinityVector);

            // Initialize lineInfo
            if (m_textInfo.lineInfo == null) m_textInfo.lineInfo = new TMP_LineInfo[2];
            for (int i = 0; i < m_textInfo.lineInfo.Length; i++)
            {
                m_textInfo.lineInfo[i] = new TMP_LineInfo();
                m_textInfo.lineInfo[i].lineExtents = new Extents(k_InfinityVector, -k_InfinityVector);
                m_textInfo.lineInfo[i].ascender = -k_InfinityVector.x;
                m_textInfo.lineInfo[i].descender = k_InfinityVector.x;
            }


            // Tracking of the highest Ascender
            m_maxAscender = 0;
            m_maxDescender = 0;
            float pageAscender = 0;
            float maxVisibleDescender = 0;
            bool isMaxVisibleDescenderSet = false;
            m_isNewPage = false;

            //bool isLineOffsetAdjusted = false;
            loopCountA += 1;

            int endTagIndex = 0;
            // Parse through Character buffer to read HTML tags and begin creating mesh.
            for (int i = 0; m_char_buffer[i] != 0; i++)
            {
                charCode = m_char_buffer[i];

                //loopCountE += 1;

                // Parse Rich Text Tag
                #region Parse Rich Text Tag
                if (m_isRichText && charCode == 60)  // '<'
                {
                    m_isParsingText = true;

                    // Check if Tag is valid. If valid, skip to the end of the validated tag.
                    if (ValidateHtmlTag(m_char_buffer, i + 1, out endTagIndex))
                    {
                        i = endTagIndex;

                        if (m_isRecalculateScaleRequired)
                        {
                            m_fontScale = (m_currentFontSize / m_fontAssetArray[m_fontIndex].fontInfo.PointSize * (m_isOrthographic ? 1 : 0.1f));
                            m_isRecalculateScaleRequired = false;
                        }

                        continue;
                    }
                }
                #endregion End Parse Rich Text Tag

                m_isParsingText = false;
                isMissingCharacter = false;

                // Check if we should be using a different font asset
                //if (m_fontIndex != 0)
                //{
                //    // Check if we need to load the new font asset
                //    if (m_fontAssetArray[m_fontIndex] == null)
                //    {
                //        Debug.Log("Loading secondary font asset.");
                //        m_fontAssetArray[m_fontIndex] = Resources.Load("Fonts & Materials/Bangers SDF", typeof(TextMeshProFont)) as TextMeshProFont;
                //        //m_sharedMaterials.Add(m_fontAssetArray[m_fontIndex].material);
                //        //m_renderer.sharedMaterials = new Material[] { m_sharedMaterial, m_fontAssetArray[m_fontIndex].material }; // m_sharedMaterials.ToArray();
                //    }
                //}              
                //Debug.Log("Char [" + (char)charCode + "] ASCII " + charCode); //is using FontIndex: " + m_fontIndex);


                // Handle Font Styles like LowerCase, UpperCase and SmallCaps.
                #region Handling of LowerCase, UpperCase and SmallCaps Font Styles
                if ((m_style & FontStyles.UpperCase) == FontStyles.UpperCase)
                {
                    // If this character is lowercase, switch to uppercase.
                    if (char.IsLower((char)charCode))
                        charCode -= 32;

                }
                else if ((m_style & FontStyles.LowerCase) == FontStyles.LowerCase)
                {
                    // If this character is uppercase, switch to lowercase.
                    if (char.IsUpper((char)charCode))
                        charCode += 32;
                }
                else if ((m_fontStyle & FontStyles.SmallCaps) == FontStyles.SmallCaps || (m_style & FontStyles.SmallCaps) == FontStyles.SmallCaps)
                {
                    if (char.IsLower((char)charCode))
                    {
                        m_fontScale = m_currentFontSize * 0.8f / m_fontAssetArray[m_fontIndex].fontInfo.PointSize * (m_isOrthographic ? 1 : 0.1f);
                        charCode -= 32;
                    }
                    else
                        m_fontScale = m_currentFontSize / m_fontAssetArray[m_fontIndex].fontInfo.PointSize * (m_isOrthographic ? 1 : 0.1f);

                }
                #endregion


                // Look up Character Data from Dictionary and cache it.
                #region Look up Character Data
                m_fontAssetArray[m_fontIndex].characterDictionary.TryGetValue(charCode, out m_cached_GlyphInfo);
                if (m_cached_GlyphInfo == null)
                {
                    // Character wasn't found in the Dictionary.

                    // Check if Lowercase & Replace by Uppercase if possible
                    if (char.IsLower((char)charCode))
                    {
                        if (m_fontAssetArray[m_fontIndex].characterDictionary.TryGetValue(charCode - 32, out m_cached_GlyphInfo))
                            charCode -= 32;
                    }
                    else if (char.IsUpper((char)charCode))
                    {
                        if (m_fontAssetArray[m_fontIndex].characterDictionary.TryGetValue(charCode + 32, out m_cached_GlyphInfo))
                            charCode += 32;
                    }

                    // Still don't have a replacement?
                    if (m_cached_GlyphInfo == null)
                    {
                        m_fontAssetArray[m_fontIndex].characterDictionary.TryGetValue(88, out m_cached_GlyphInfo);
                        if (m_cached_GlyphInfo != null)
                        {
                            Debug.LogWarning("Character with ASCII value of " + charCode + " was not found in the Font Asset Glyph Table.");
                            // Replace the missing character by X (if it is found)
                            charCode = 88;
                            isMissingCharacter = true;
                        }
                        else
                        {  // At this point the character isn't in the Dictionary, the replacement X isn't either so ...                         
                            Debug.LogWarning("Character with ASCII value of " + charCode + " was not found in the Font Asset Glyph Table.");
                            continue;
                        }
                    }
                }
                #endregion

                // Store some of the text object's information
                m_textInfo.characterInfo[m_characterCount].character = (char)charCode;
                m_textInfo.characterInfo[m_characterCount].color = m_htmlColor;
                m_textInfo.characterInfo[m_characterCount].style = m_style;
                m_textInfo.characterInfo[m_characterCount].index = (short)i;


                // Handle Kerning if Enabled.
                #region Handle Kerning
                if (m_enableKerning && m_characterCount >= 1)
                {
                    int prev_charCode = m_textInfo.characterInfo[m_characterCount - 1].character;
                    KerningPairKey keyValue = new KerningPairKey(prev_charCode, charCode);

                    KerningPair pair;

                    m_fontAssetArray[m_fontIndex].kerningDictionary.TryGetValue(keyValue.key, out pair);
                    if (pair != null)
                    {
                        m_xAdvance += pair.XadvanceOffset * m_fontScale;
                    }
                }
                #endregion


                // Handle Mono Spacing
                #region Handle Mono Spacing
                if (m_monoSpacing != 0 && m_xAdvance != 0)
                    m_xAdvance -= (m_cached_GlyphInfo.width / 2 + m_cached_GlyphInfo.xOffset) * m_fontScale * (1 - m_charWidthAdjDelta);
                #endregion


                // Set Padding based on selected font style
                #region Handle Style Padding
                if ((m_style & FontStyles.Bold) == FontStyles.Bold || (m_fontStyle & FontStyles.Bold) == FontStyles.Bold) // Checks for any combination of Bold Style.
                {
                    style_padding = m_fontAssetArray[m_fontIndex].BoldStyle * 2;
                    xadvance_multiplier = 1.07f; // Increase xAdvance for bold characters.
                }
                else
                {
                    style_padding = m_fontAssetArray[m_fontIndex].NormalStyle * 2;
                    xadvance_multiplier = 1.0f;
                }
                #endregion Handle Style Padding


                // Setup Vertices for each character.
                Vector3 top_left = new Vector3(0 + m_xAdvance + ((m_cached_GlyphInfo.xOffset - m_padding - style_padding) * m_fontScale * (1 - m_charWidthAdjDelta)), (m_cached_GlyphInfo.yOffset + m_padding) * m_fontScale - m_lineOffset + m_baselineOffset, 0);
                Vector3 bottom_left = new Vector3(top_left.x, top_left.y - ((m_cached_GlyphInfo.height + m_padding * 2) * m_fontScale), 0);
                Vector3 top_right = new Vector3(bottom_left.x + ((m_cached_GlyphInfo.width + m_padding * 2 + style_padding * 2) * m_fontScale * (1 - m_charWidthAdjDelta)), top_left.y, 0);
                Vector3 bottom_right = new Vector3(top_right.x, bottom_left.y, 0);

                // Check if we need to Shear the rectangles for Italic styles
                #region Handle Italic & Shearing
                if ((m_style & FontStyles.Italic) == FontStyles.Italic || (m_fontStyle & FontStyles.Italic) == FontStyles.Italic)
                {
                    // Shift Top vertices forward by half (Shear Value * height of character) and Bottom vertices back by same amount. 
                    float shear_value = m_fontAssetArray[m_fontIndex].ItalicStyle * 0.01f;
                    Vector3 topShear = new Vector3(shear_value * ((m_cached_GlyphInfo.yOffset + m_padding + style_padding) * m_fontScale), 0, 0);
                    Vector3 bottomShear = new Vector3(shear_value * (((m_cached_GlyphInfo.yOffset - m_cached_GlyphInfo.height - m_padding - style_padding)) * m_fontScale), 0, 0);

                    top_left = top_left + topShear;
                    bottom_left = bottom_left + bottomShear;
                    top_right = top_right + topShear;
                    bottom_right = bottom_right + bottomShear;
                }
                #endregion Handle Italics & Shearing


                // Store position of vertices for each character
                m_textInfo.characterInfo[m_characterCount].topLeft = top_left;
                m_textInfo.characterInfo[m_characterCount].bottomLeft = bottom_left;
                m_textInfo.characterInfo[m_characterCount].topRight = top_right;
                m_textInfo.characterInfo[m_characterCount].bottomRight = bottom_right;
                m_textInfo.characterInfo[m_characterCount].baseLine = 0 - m_lineOffset + m_baselineOffset;


                // Compute MaxAscender & MaxDescender which is used for AutoScaling & other type layout options
                float ascender = (m_fontAsset.fontInfo.Ascender + m_alignmentPadding.y) * m_fontScale + m_baselineOffset;
                if ((charCode == 10 || charCode == 13) && m_characterCount > m_firstVisibleCharacterOfLine)
                    ascender = m_alignmentPadding.y * m_fontScale + m_baselineOffset;

                float descender = (m_fontAsset.fontInfo.Descender + m_alignmentPadding.w) * m_fontScale - m_lineOffset + m_baselineOffset;

                if (m_lineNumber == 0) m_maxAscender = m_maxAscender > ascender ? m_maxAscender : ascender;
                if (m_lineOffset == 0) pageAscender = pageAscender > ascender ? pageAscender : ascender;

                // Track Line Height
                maxLineHeight = Mathf.Max(m_lineHeight, maxLineHeight);

                // Used to adjust line spacing when larger fonts or the size tag is used.
                if (m_baselineOffset == 0)
                    m_maxFontScale = Mathf.Max(m_maxFontScale, m_fontScale);

                // Set Characters to not visible by default.
                m_textInfo.characterInfo[m_characterCount].isVisible = false;


                // Setup Mesh for visible characters. ie. not a SPACE / LINEFEED / CARRIAGE RETURN.
                #region Handle Visible Characters
                if (charCode != 10 && charCode != 13 && charCode != 32)
                {
                    m_textInfo.characterInfo[m_characterCount].isVisible = true;

                    // Check if Character exceeds the width of the Text Container
                    #region Check for Characters Exceeding Width of Text Container
                    float width = m_width != -1 ? Mathf.Min(marginWidth + 0.0001f - m_marginLeft - m_marginRight, m_width) : marginWidth + 0.0001f - m_marginLeft - m_marginRight;

                    m_textInfo.lineInfo[m_lineNumber].width = width;
                    m_textInfo.lineInfo[m_lineNumber].marginLeft = m_marginLeft;

                    if (m_xAdvance + m_cached_GlyphInfo.xAdvance * (1 - m_charWidthAdjDelta) * m_fontScale > width && !m_textContainer.isDefaultWidth)
                    {
                        ellipsisIndex = m_characterCount - 1; // Last safely rendered character

                        // Word Wrapping
                        #region Handle Word Wrapping
                        if (enableWordWrapping && m_characterCount != m_firstCharacterOfLine)
                        {

                            if (wrappingIndex == m_SavedWordWrapState.previous_WordBreak || isFirstWord)
                            {
                                // Word wrapping is no longer possible. Shrink size of text if auto-sizing is enabled.
                                if (m_enableAutoSizing && m_fontSize > m_fontSizeMin)
                                {
                                    // Handle Character Width Adjustments
                                    #region Character Width Adjustments
                                    if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100)
                                    {
                                        loopCountA = 0;
                                        m_charWidthAdjDelta += 0.01f;
                                        GenerateTextMesh();
                                        return;
                                    }
                                    #endregion

                                    // Adjust Point Size
                                    m_maxFontSize = m_fontSize;

                                    m_fontSize -= Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f);
                                    m_fontSize = (int)(Mathf.Max(m_fontSize, m_fontSizeMin) * 20 + 0.5f) / 20f;

                                    if (loopCountA > 20) return; // Added to debug
                                    GenerateTextMesh();
                                    return;
                                }

                                // Word wrapping is no longer possible, now breaking up individual words.
                                if (m_isCharacterWrappingEnabled == false)
                                {
                                    m_isCharacterWrappingEnabled = true; // Should add a check to make sure this mode is available.
                                }
                                else
                                    isLastBreakingChar = true;

                                m_recursiveCount += 1;
                                if (m_recursiveCount > 20)
                                {
                                    //Debug.Log("Recursive count exceeded!");
                                    continue;
                                }
                            }


                            // Restore to previously stored state of last valid (space character or linefeed)
                            i = RestoreWordWrappingState(ref m_SavedWordWrapState);
                            wrappingIndex = i;  // Used to detect when line length can no longer be reduced.

                            //Debug.Log("Line # " + m_lineNumber + " Last Character of Line is [" + m_textInfo.characterInfo[m_characterCount - 1].character + "]. Last Visible Character is [" + m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].character + "].");

                            // Check if we need to Adjust LineOffset & Restore State to the start of the line.
                            if (m_lineNumber > 0 && m_maxFontScale != 0 && m_lineHeight == 0 && m_maxFontScale != previousFontScale && !m_isNewPage)
                            {
                                // Compute Offset
                                float offsetDelta = (m_fontAssetArray[m_fontIndex].fontInfo.LineHeight + m_lineSpacing + m_paragraphSpacing + m_lineSpacingDelta) * m_maxFontScale;
                                m_lineOffset += offsetDelta - lineOffsetDelta;
                                AdjustLineOffset(m_firstCharacterOfLine, m_characterCount - 1, offsetDelta - lineOffsetDelta);
                                m_SavedWordWrapState.lineOffset = m_lineOffset;
                            }
                            m_isNewPage = false;

                            // Calculate lineAscender & make sure if last character is superscript or subscript that we check that as well.
                            float lineAscender = (m_fontAsset.fontInfo.Ascender + m_alignmentPadding.y) * m_maxFontScale - m_lineOffset;
                            float lineAscender2 = (m_fontAsset.fontInfo.Ascender + m_alignmentPadding.y) * m_fontScale - m_lineOffset + m_baselineOffset;
                            lineAscender = lineAscender > lineAscender2 ? lineAscender : lineAscender2;

                            // Calculate lineDescender & make sure if last character is superscript or subscript that we check that as well.
                            float lineDescender = (m_fontAsset.fontInfo.Descender + m_alignmentPadding.w) * m_maxFontScale - m_lineOffset;
                            float lineDescender2 = (m_fontAsset.fontInfo.Descender + m_alignmentPadding.w) * m_fontScale - m_lineOffset + m_baselineOffset;
                            lineDescender = lineDescender < lineDescender2 ? lineDescender : lineDescender2;

                            // Update maxDescender and maxVisibleDescender
                            m_maxDescender = m_maxDescender < lineDescender ? m_maxDescender : lineDescender;
                            if (!isMaxVisibleDescenderSet)
                                maxVisibleDescender = m_maxDescender;

                            if (m_characterCount >= m_maxVisibleCharacters || m_lineNumber >= m_maxVisibleLines)
                                isMaxVisibleDescenderSet = true;

                            // Track & Store lineInfo for the new line
                            m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex = m_firstCharacterOfLine;
                            m_textInfo.lineInfo[m_lineNumber].firstVisibleCharacterIndex = m_firstVisibleCharacterOfLine;
                            m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex = m_characterCount - 1 > 0 ? m_characterCount - 1 : 0;
                            m_textInfo.lineInfo[m_lineNumber].lastVisibleCharacterIndex = m_lastVisibleCharacterOfLine;
                            m_textInfo.lineInfo[m_lineNumber].characterCount = m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex - m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex + 1;

                            m_textInfo.lineInfo[m_lineNumber].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_firstVisibleCharacterOfLine].bottomLeft.x, lineDescender);
                            m_textInfo.lineInfo[m_lineNumber].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].topRight.x, lineAscender);
                            m_textInfo.lineInfo[m_lineNumber].lineLength = m_textInfo.lineInfo[m_lineNumber].lineExtents.max.x - m_padding * m_maxFontScale;
                            m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].xAdvance - m_characterSpacing * m_fontScale;

                            m_firstCharacterOfLine = m_characterCount; // Store first character of the next line.

                            // Compute Preferred Width & Height
                            m_preferredWidth += m_xAdvance; // m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex].topRight.x - m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex].bottomLeft.x;
                            if (m_enableWordWrapping)
                                m_preferredHeight = m_maxAscender - m_maxDescender;
                            else
                                m_preferredHeight = Mathf.Max(m_preferredHeight, lineAscender - lineDescender);


                            //Debug.Log("LineInfo for line # " + (m_lineNumber) + " First character [" + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex].character + "] at Index: " + m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex +
                            //                                                    " Last character [" + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex].character + "] at index: " + m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex +
                            //                                                    " Last Visible character [" + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].lastVisibleCharacterIndex].character + "] at index: " + m_textInfo.lineInfo[m_lineNumber].lastVisibleCharacterIndex +
                            //                                                    " Character Count: " + m_textInfo.lineInfo[m_lineNumber].characterCount + " Line Length: " + m_textInfo.lineInfo[m_lineNumber].lineLength /* +
                            //                                                    "  MinX: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.min.x + "  MinY: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.min.y +
                            //                                                    "  MaxX: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.max.x + "  MaxY: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.max.y +
                            //                                                    "  Line Ascender: " + lineAscender + "  Line Descender: " + lineDescender + "  FontScale: " + m_fontScale + "  MaxFontScale: " + m_maxFontScale +
                            //                                                    "  Line MaxX: " + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex].topRight.x */);

                            // Store the state of the line before starting on the new line.
                            SaveWordWrappingState(ref m_SavedLineState, i, m_characterCount - 1);

                            m_lineNumber += 1;
                            isStartOfNewLine = true;

                            // Check to make sure Array is large enough to hold a new line.
                            if (m_lineNumber >= m_textInfo.lineInfo.Length)
                                ResizeLineExtents(m_lineNumber);

                            // Apply Line Spacing based on scale of the last character of the line.
                            if (maxLineHeight == 0)
                            {
                                lineOffsetDelta = (m_fontAssetArray[m_fontIndex].fontInfo.LineHeight + m_lineSpacing + m_lineSpacingDelta) * m_fontScale;
                                m_lineOffset += lineOffsetDelta;
                            }
                            else
                                m_lineOffset += (maxLineHeight + m_lineSpacing) * baseScale; // Special handling when line-height tag is used.

                            previousFontScale = m_fontScale;
                            m_xAdvance = 0 + tag_Indent;
                            m_maxFontScale = 0;
                            maxLineHeight = 0;

                            continue;
                        }
                        #endregion End Word Wrapping


                        // Text Auto-Sizing (text exceeding Width of container. 
                        #region Handle Text Auto-Sizing
                        if (m_enableAutoSizing && m_fontSize > m_fontSizeMin)
                        {
                            // Handle Character Width Adjustments
                            #region Character Width Adjustments
                            if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100)
                            {
                                loopCountA = 0;
                                m_charWidthAdjDelta += 0.01f;
                                GenerateTextMesh();
                                return;
                            }
                            #endregion

                            // Adjust Point Size
                            m_maxFontSize = m_fontSize;

                            m_fontSize -= Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f);
                            m_fontSize = (int)(Mathf.Max(m_fontSize, m_fontSizeMin) * 20 + 0.5f) / 20f;

                            m_recursiveCount = 0;
                            if (loopCountA > 20) return; // Added to debug 
                            GenerateTextMesh();
                            return;
                        }
                        #endregion End Text Auto-Sizing


                        // Handle Text Overflow
                        #region Handle Text Overflow
                        switch (m_overflowMode)
                        {
                            case TextOverflowModes.Overflow:
                                if (m_isMaskingEnabled)
                                    DisableMasking();

                                break;
                            case TextOverflowModes.Ellipsis:
                                if (m_isMaskingEnabled)
                                    DisableMasking();

                                m_isTextTruncated = true;

                                if (m_characterCount < 1)
                                {
                                    m_textInfo.characterInfo[m_characterCount].isVisible = false;
                                    m_visibleCharacterCount -= 1;
                                    break;
                                }

                                m_char_buffer[i - 1] = 8230;
                                m_char_buffer[i] = (char)0;

                                GenerateTextMesh();
                                return;
                            case TextOverflowModes.Masking:
                                if (!m_isMaskingEnabled)
                                    EnableMasking();
                                break;
                            case TextOverflowModes.ScrollRect:
                                if (!m_isMaskingEnabled)
                                    EnableMasking();
                                break;
                            case TextOverflowModes.Truncate:
                                if (m_isMaskingEnabled)
                                    DisableMasking();

                                m_textInfo.characterInfo[m_characterCount].isVisible = false;
                                break;
                        }
                        #endregion End Text Overflow

                    }
                    #endregion End Check for Characters Exceeding Width of Text Container

                    if (charCode != 9)
                    {
                        // Setup Mesh
                        int index_X4 = m_visibleCharacterCount * 4;

                        //m_textInfo.characterInfo[m_characterCount].isVisible = true;
                        m_textInfo.characterInfo[m_characterCount].vertexIndex = (short)(0 + index_X4);

                        m_vertices[0 + index_X4] = m_textInfo.characterInfo[m_characterCount].bottomLeft;
                        m_vertices[1 + index_X4] = m_textInfo.characterInfo[m_characterCount].topLeft;
                        m_vertices[2 + index_X4] = m_textInfo.characterInfo[m_characterCount].bottomRight;
                        m_vertices[3 + index_X4] = m_textInfo.characterInfo[m_characterCount].topRight;


                        // Determine what color gets assigned to vertex.
                        #region Handle Vertex Colors
                        if (isMissingCharacter)
                            vertexColor = Color.red;
                        else if (m_overrideHtmlColors)
                            vertexColor = m_fontColor32;
                        else
                            vertexColor = m_htmlColor;


                        // Set Alpha to the lesser of vertex color or color tag alpha).                 
                        vertexColor.a = m_fontColor32.a < vertexColor.a ? m_fontColor32.a : vertexColor.a;

                        if (!m_enableVertexGradient)
                        {
                            m_vertColors[0 + index_X4] = vertexColor;
                            m_vertColors[1 + index_X4] = vertexColor;
                            m_vertColors[2 + index_X4] = vertexColor;
                            m_vertColors[3 + index_X4] = vertexColor;
                        }
                        else
                        {
                            if (!m_overrideHtmlColors && !m_htmlColor.CompareRGB(m_fontColor32))
                            {
                                m_vertColors[0 + index_X4] = vertexColor;
                                m_vertColors[1 + index_X4] = vertexColor;
                                m_vertColors[2 + index_X4] = vertexColor;
                                m_vertColors[3 + index_X4] = vertexColor;
                            }
                            else
                            {
                                m_vertColors[0 + index_X4] = m_fontColorGradient.bottomLeft;
                                m_vertColors[1 + index_X4] = m_fontColorGradient.topLeft;
                                m_vertColors[2 + index_X4] = m_fontColorGradient.bottomRight;
                                m_vertColors[3 + index_X4] = m_fontColorGradient.topRight;
                            }

                            m_vertColors[0 + index_X4].a = vertexColor.a;
                            m_vertColors[1 + index_X4].a = vertexColor.a;
                            m_vertColors[2 + index_X4].a = vertexColor.a;
                            m_vertColors[3 + index_X4].a = vertexColor.a;
                        }
                        #endregion Handle Vertex Colors


                        // Apply style_padding only if this is a SDF Shader.
                        if (!m_sharedMaterial.HasProperty(ShaderUtilities.ID_WeightNormal))
                            style_padding = 0;


                        // Setup UVs for the Mesh
                        #region Setup UVs
                        Vector2 uv0 = new Vector2((m_cached_GlyphInfo.x - m_padding - style_padding) / m_fontAssetArray[m_fontIndex].fontInfo.AtlasWidth, 1 - (m_cached_GlyphInfo.y + m_padding + style_padding + m_cached_GlyphInfo.height) / m_fontAssetArray[m_fontIndex].fontInfo.AtlasHeight);  // bottom left
                        Vector2 uv1 = new Vector2(uv0.x, 1 - (m_cached_GlyphInfo.y - m_padding - style_padding) / m_fontAssetArray[m_fontIndex].fontInfo.AtlasHeight);  // top left
                        Vector2 uv2 = new Vector2((m_cached_GlyphInfo.x + m_padding + style_padding + m_cached_GlyphInfo.width) / m_fontAssetArray[m_fontIndex].fontInfo.AtlasWidth, uv0.y); // bottom right
                        Vector2 uv3 = new Vector2(uv2.x, uv1.y); // top right

                        m_uvs[0 + index_X4] = uv0;
                        m_uvs[1 + index_X4] = uv1;
                        m_uvs[2 + index_X4] = uv2;
                        m_uvs[3 + index_X4] = uv3;
                        #endregion Setup UVs
                    }
                    else
                    {
                        m_textInfo.characterInfo[m_characterCount].isVisible = false;
                        m_lastVisibleCharacterOfLine = m_characterCount;
                        m_textInfo.lineInfo[m_lineNumber].spaceCount += 1;
                        m_textInfo.spaceCount += 1;
                    }


                    if (m_textInfo.characterInfo[m_characterCount].isVisible)
                    {
                        if (isStartOfNewLine) { isStartOfNewLine = false; m_firstVisibleCharacterOfLine = m_characterCount; }
                        m_visibleCharacterCount += 1;
                        m_lastVisibleCharacterOfLine = m_characterCount;
                    }
                }
                else
                {   // This is a Space, LineFeed or Carriage Return

                    // Track # of spaces per line which is used for line justification.
                    if (charCode == 9 || charCode == 32)
                    {
                        m_textInfo.lineInfo[m_lineNumber].spaceCount += 1;
                        m_textInfo.spaceCount += 1;
                    }
                }
                #endregion Handle Visible Characters


                // Store Rectangle positions for each Character.
                #region Store Character Data
                m_textInfo.characterInfo[m_characterCount].lineNumber = (short)m_lineNumber;
                m_textInfo.characterInfo[m_characterCount].pageNumber = (short)m_pageNumber;

                if (charCode != 10 && charCode != 13 && charCode != 8230 || m_textInfo.lineInfo[m_lineNumber].characterCount == 1)
                    m_textInfo.lineInfo[m_lineNumber].alignment = m_lineJustification;
                #endregion Store Character Data


                // Check if text Exceeds the vertical bounds of the margin area.
                #region Check Vertical Bounds & Auto-Sizing
                if (m_maxAscender - descender + (m_alignmentPadding.w * 2 * m_fontScale) > marginHeight + 0.0001f && !m_textContainer.isDefaultHeight)
                {
                    //Debug.Log((m_maxAscender - m_maxDescender) + "  " + marginHeight);
                    //Debug.Log("Character [" + (char)charCode + "] at Index: " + m_characterCount + " has exceeded the Height of the text container. Max Ascender: " + m_maxAscender + "  Max Descender: " + m_maxDescender + "  Margin Height: " + marginHeight + " Bottom Left: " + bottom_left.y);                                              

                    // Handle Line spacing adjustments
                    #region Line Spacing Adjustments
                    if (m_enableAutoSizing && m_lineSpacingDelta > m_lineSpacingMax && m_lineNumber > 0)
                    {
                        m_lineSpacingDelta -= 1;
                        GenerateTextMesh();
                        return;
                    }
                    #endregion


                    // Handle Text Auto-sizing resulting from text exceeding vertical bounds.
                    #region Text Auto-Sizing (Text greater than vertical bounds)
                    if (m_enableAutoSizing && m_fontSize > m_fontSizeMin)
                    {
                        m_maxFontSize = m_fontSize;

                        m_fontSize -= Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f);
                        m_fontSize = (int)(Mathf.Max(m_fontSize, m_fontSizeMin) * 20 + 0.5f) / 20f;

                        m_recursiveCount = 0;
                        if (loopCountA > 20) return; // Added to debug 
                        GenerateTextMesh();
                        return;
                    }
                    #endregion Text Auto-Sizing


                    // Handle Text Overflow
                    #region Text Overflow
                    switch (m_overflowMode)
                    {
                        case TextOverflowModes.Overflow:
                            if (m_isMaskingEnabled)
                                DisableMasking();

                            break;
                        case TextOverflowModes.Ellipsis:
                            if (m_isMaskingEnabled)
                                DisableMasking();

                            if (m_lineNumber > 0)
                            {
                                m_char_buffer[m_textInfo.characterInfo[ellipsisIndex].index] = 8230;
                                m_char_buffer[m_textInfo.characterInfo[ellipsisIndex].index + 1] = (char)0;
                                GenerateTextMesh();
                                m_isTextTruncated = true;
                                return;
                            }
                            else
                            {
                                m_char_buffer[0] = (char)0;
                                GenerateTextMesh();
                                m_isTextTruncated = true;
                                return;
                            }
                        case TextOverflowModes.Masking:
                            if (!m_isMaskingEnabled)
                                EnableMasking();
                            break;
                        case TextOverflowModes.ScrollRect:
                            if (!m_isMaskingEnabled)
                                EnableMasking();
                            break;
                        case TextOverflowModes.Truncate:
                            if (m_isMaskingEnabled)
                                DisableMasking();

                            // TODO : Optimize 
                            if (m_lineNumber > 0)
                            {
                                m_char_buffer[m_textInfo.characterInfo[ellipsisIndex].index + 1] = (char)0;
                                GenerateTextMesh();
                                m_isTextTruncated = true;
                                return;
                            }
                            else
                            {
                                m_char_buffer[0] = (char)0;
                                GenerateTextMesh();
                                m_isTextTruncated = true;
                                return;
                            }
                        case TextOverflowModes.Page:
                            if (m_isMaskingEnabled)
                                DisableMasking();

                            // Ignore Page Break, Linefeed or carriage return
                            if (charCode == 13 || charCode == 10)
                                break;

                            //Debug.Log("Character is [" + (char)charCode + "] with ASCII (" + charCode + ") on Page " + m_pageNumber);

                            // Go back to previous line and re-layout 
                            i = RestoreWordWrappingState(ref m_SavedLineState);
                            if (i == 0)
                            {
                                m_char_buffer[0] = (char)0;
                                GenerateTextMesh();
                                m_isTextTruncated = true;
                                return;
                            }

                            m_isNewPage = true;
                            m_xAdvance = 0 + tag_Indent;
                            m_lineOffset = 0;
                            m_lineNumber += 1;
                            m_pageNumber += 1;
                            continue;
                    }
                    #endregion End Text Overflow

                }
                #endregion Check Vertical Bounds


                // Handle xAdvance & Tabulation Stops. Tab stops at every 25% of Font Size.
                #region XAdvance, Tabulation & Stops
                if (charCode == 9)
                {
                    m_xAdvance += m_fontAsset.fontInfo.TabWidth * m_fontScale; // * m_fontAsset.TabSize;
                }
                else if (m_monoSpacing != 0)
                    m_xAdvance += ((m_monoSpacing + m_cached_GlyphInfo.width / 2 + m_cached_GlyphInfo.xOffset + m_characterSpacing) * m_fontScale + m_cSpacing) * (1 - m_charWidthAdjDelta);
                else
                    m_xAdvance += ((m_cached_GlyphInfo.xAdvance * xadvance_multiplier + m_characterSpacing) * m_fontScale + m_cSpacing) * (1 - m_charWidthAdjDelta);


                // Store xAdvance information
                m_textInfo.characterInfo[m_characterCount].xAdvance = m_xAdvance;

                #endregion Tabulation & Stops


                // Handle Carriage Return
                #region Carriage Return
                if (charCode == 13)
                {
                    m_maxXAdvance = Mathf.Max(m_maxXAdvance, m_preferredWidth + m_xAdvance + (m_alignmentPadding.z * m_fontScale));
                    m_preferredWidth = 0;
                    m_xAdvance = 0 + tag_Indent;
                }
                #endregion Carriage Return


                // Handle Line Spacing Adjustments + Word Wrapping & special case for last line.
                #region Check for Line Feed and Last Character
                if (charCode == 10 || m_characterCount == totalCharacterCount - 1)
                {
                    //Debug.Log("Line # " + m_lineNumber + " Last Character of Line is [" + m_textInfo.characterInfo[m_characterCount].character + "]. Last Visible Character is [" + m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].character + "].");

                    // Handle Line Spacing Changes
                    if (m_lineNumber > 0 && m_maxFontScale != 0 && m_lineHeight == 0 && m_maxFontScale != previousFontScale && !m_isNewPage)
                    {
                        float offsetDelta = (m_fontAssetArray[m_fontIndex].fontInfo.LineHeight + m_lineSpacing + m_paragraphSpacing + m_lineSpacingDelta) * m_maxFontScale;
                        m_lineOffset += offsetDelta - lineOffsetDelta;
                        AdjustLineOffset(m_firstCharacterOfLine, m_characterCount, offsetDelta - lineOffsetDelta);
                    }
                    m_isNewPage = false;

                    // Calculate lineAscender & make sure if last character is superscript or subscript that we check that as well.
                    float lineAscender = (m_fontAsset.fontInfo.Ascender + m_alignmentPadding.y) * m_maxFontScale - m_lineOffset;
                    float lineAscender2 = (m_fontAsset.fontInfo.Ascender + m_alignmentPadding.y) * m_fontScale - m_lineOffset + m_baselineOffset;
                    lineAscender = lineAscender > lineAscender2 ? lineAscender : lineAscender2;

                    // Calculate lineDescender & make sure if last character is superscript or subscript that we check that as well.
                    float lineDescender = (m_fontAsset.fontInfo.Descender + m_alignmentPadding.w) * m_maxFontScale - m_lineOffset;
                    float lineDescender2 = (m_fontAsset.fontInfo.Descender + m_alignmentPadding.w) * m_fontScale - m_lineOffset + m_baselineOffset;
                    lineDescender = lineDescender < lineDescender2 ? lineDescender : lineDescender2;

                    // Update maxDescender and maxVisibleDescender
                    m_maxDescender = m_maxDescender < lineDescender ? m_maxDescender : lineDescender;
                    if (!isMaxVisibleDescenderSet)
                        maxVisibleDescender = m_maxDescender;

                    if (m_characterCount >= m_maxVisibleCharacters || m_lineNumber >= m_maxVisibleLines)
                        isMaxVisibleDescenderSet = true;

                    // Save Line Information
                    m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex = m_firstCharacterOfLine;
                    m_textInfo.lineInfo[m_lineNumber].firstVisibleCharacterIndex = m_firstVisibleCharacterOfLine;
                    m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex = m_characterCount;
                    m_textInfo.lineInfo[m_lineNumber].lastVisibleCharacterIndex = m_lastVisibleCharacterOfLine >= m_firstVisibleCharacterOfLine ? m_lastVisibleCharacterOfLine : m_firstVisibleCharacterOfLine;
                    m_textInfo.lineInfo[m_lineNumber].characterCount = m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex - m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex + 1;

                    m_textInfo.lineInfo[m_lineNumber].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_firstVisibleCharacterOfLine].bottomLeft.x, lineDescender);
                    m_textInfo.lineInfo[m_lineNumber].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].topRight.x, lineAscender);
                    m_textInfo.lineInfo[m_lineNumber].lineLength = m_textInfo.lineInfo[m_lineNumber].lineExtents.max.x - (m_padding * m_maxFontScale);
                    m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].xAdvance - m_characterSpacing * m_fontScale;

                    m_firstCharacterOfLine = m_characterCount + 1;

                    // Store PreferredWidth paying attention to linefeed and last character of text.
                    if (charCode == 10 && m_characterCount != totalCharacterCount - 1)
                    {
                        m_maxXAdvance = Mathf.Max(m_maxXAdvance, m_preferredWidth + m_xAdvance + (m_alignmentPadding.z * m_fontScale));
                        m_preferredWidth = 0;
                    }
                    else
                        m_preferredWidth = Mathf.Max(m_maxXAdvance, m_preferredWidth + m_xAdvance + (m_alignmentPadding.z * m_fontScale));

                    m_preferredHeight = m_maxAscender - m_maxDescender;



                    //Debug.Log("LineInfo for line # " + (m_lineNumber) + " First character [" + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex].character + "] at Index: " + m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex +
                    //                                                    " Last character [" + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex].character + "] at index: " + m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex +
                    //                                                    " Last Visible character [" + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].lastVisibleCharacterIndex].character + "] at index: " + m_textInfo.lineInfo[m_lineNumber].lastVisibleCharacterIndex +
                    //                                                    " Character Count of " + m_textInfo.lineInfo[m_lineNumber].characterCount + " Line Length of " + m_textInfo.lineInfo[m_lineNumber].lineLength /* +
                    //                                                    //" Extent MinX: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.min.x + "  MinY: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.min.y +
                    //                                                    //"  MaxX: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.max.x + "  MaxY: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.max.y +
                    //                                                    //"  Line Ascender: " + lineAscender + "  Line Descender: " + lineDescender +
                    //                                                    //"  Line Max: " + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex].topRight.x */ );


                    // Add new line if not last lines or character.
                    if (charCode == 10)
                    {
                        // Store the state of the line before starting on the new line.
                        SaveWordWrappingState(ref m_SavedLineState, i, m_characterCount);
                        // Store the state of the last Character before the new line.
                        SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);

                        m_lineNumber += 1;
                        isStartOfNewLine = true;

                        // Check to make sure Array is large enough to hold a new line.
                        if (m_lineNumber >= m_textInfo.lineInfo.Length)
                            ResizeLineExtents(m_lineNumber);

                        // Apply Line Spacing based on scale of the last character of the line.
                        if (maxLineHeight == 0)
                        {
                            lineOffsetDelta = (m_fontAssetArray[m_fontIndex].fontInfo.LineHeight + m_paragraphSpacing + m_lineSpacing + m_lineSpacingDelta) * m_fontScale;
                            m_lineOffset += lineOffsetDelta;
                        }
                        else
                            m_lineOffset += (maxLineHeight + m_lineSpacing + m_paragraphSpacing) * baseScale;

                        previousFontScale = m_fontScale;
                        m_maxFontScale = 0;
                        maxLineHeight = 0;
                        m_xAdvance = 0 + tag_LineIndent + tag_Indent;

                        ellipsisIndex = m_characterCount - 1;
                    }
                }
                #endregion Check for Linefeed or Last Character


                // Store Rectangle positions for each Character.
                #region Save CharacterInfo for the current character.
                m_textInfo.characterInfo[m_characterCount].topLine = m_textInfo.characterInfo[m_characterCount].baseLine + (m_fontAssetArray[m_fontIndex].fontInfo.Ascender + m_alignmentPadding.y) * m_fontScale; // Ascender
                m_textInfo.characterInfo[m_characterCount].bottomLine = m_textInfo.characterInfo[m_characterCount].baseLine + (m_fontAssetArray[m_fontIndex].fontInfo.Descender - m_alignmentPadding.w) * m_fontScale; // Descender
                m_textInfo.characterInfo[m_characterCount].padding = m_padding * m_fontScale;
                m_textInfo.characterInfo[m_characterCount].aspectRatio = m_cached_GlyphInfo.width / m_cached_GlyphInfo.height;
                m_textInfo.characterInfo[m_characterCount].scale = m_fontScale;
                //Debug.Log("Char [" + charCode + "] Ascender: " + m_textInfo.characterInfo[m_characterCount].topLine .ToString("f3") + "  Descender: " + m_textInfo.characterInfo[m_characterCount].bottomLine.ToString("f3"));

                // Determine the bounds of the Mesh.
                if (m_textInfo.characterInfo[m_characterCount].isVisible)
                {
                    m_meshExtents.min = new Vector2(Mathf.Min(m_meshExtents.min.x, m_textInfo.characterInfo[m_characterCount].bottomLeft.x), Mathf.Min(m_meshExtents.min.y, m_textInfo.characterInfo[m_characterCount].bottomLeft.y));
                    m_meshExtents.max = new Vector2(Mathf.Max(m_meshExtents.max.x, m_textInfo.characterInfo[m_characterCount].topRight.x), Mathf.Max(m_meshExtents.max.y, m_textInfo.characterInfo[m_characterCount].topLeft.y));
                }


                // Save pageInfo Data
                if (charCode != 13 && charCode != 10 && m_pageNumber < 16)
                {
                    m_textInfo.pageInfo[m_pageNumber].ascender = pageAscender;
                    m_textInfo.pageInfo[m_pageNumber].descender = descender < m_textInfo.pageInfo[m_pageNumber].descender ? descender : m_textInfo.pageInfo[m_pageNumber].descender;
                    //Debug.Log("Char [" + (char)charCode + "] with ASCII (" + charCode + ") on Page # " + m_pageNumber + " with Ascender: " + m_textInfo.pageInfo[m_pageNumber].ascender + ". Descender: " + m_textInfo.pageInfo[m_pageNumber].descender);

                    if (m_pageNumber == 0 && m_characterCount == 0)
                        m_textInfo.pageInfo[m_pageNumber].firstCharacterIndex = m_characterCount;
                    else if (m_characterCount > 0 && m_pageNumber != m_textInfo.characterInfo[m_characterCount - 1].pageNumber)
                    {
                        m_textInfo.pageInfo[m_pageNumber - 1].lastCharacterIndex = m_characterCount - 1;
                        m_textInfo.pageInfo[m_pageNumber].firstCharacterIndex = m_characterCount;
                    }
                    else if (m_characterCount == totalCharacterCount - 1)
                        m_textInfo.pageInfo[m_pageNumber].lastCharacterIndex = m_characterCount;
                }
                #endregion Saving CharacterInfo


                // Save State of the last character
                #region Save Last Character State
                //if (m_overflowMode == TextOverflowModes.Ellipsis)
                //{
                //Debug.Log("Char [" + (char)charCode + "] at Index " + (m_characterCount % 5));
                //    SaveWordWrappingState(ref m_SavedLastCharState, i);
                //    m_SavedCharacterStates[m_characterCount % 5] = m_SavedLastCharState;
                //}
                #endregion End Last Character State


                // Save State of Mesh Creation for handling of Word Wrapping
                #region Save Word Wrapping State
                if (m_enableWordWrapping || m_overflowMode == TextOverflowModes.Truncate || m_overflowMode == TextOverflowModes.Ellipsis)
                {
                    if (charCode == 9 || charCode == 32 && !m_isNonBreakingSpace)
                    {
                        // We store the state of numerous variables for the most recent Space, LineFeed or Carriage Return to enable them to be restored 
                        // for Word Wrapping.
                        SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);
                        m_isCharacterWrappingEnabled = false;
                        isFirstWord = false;
                        //Debug.Log("Storing Word Wrapping Info at CharacterCount " + m_characterCount);
                    }
                    else if ((isFirstWord || m_isCharacterWrappingEnabled == true) && m_characterCount < totalCharacterCount - 1
                        && m_fontAsset.lineBreakingInfo.leadingCharacters.ContainsKey(charCode) == false
                        && m_fontAsset.lineBreakingInfo.followingCharacters.ContainsKey(m_VisibleCharacters[m_characterCount + 1]) == false
                        || isLastBreakingChar)
                        //|| m_characterCount == m_firstVisibleCharacterOfLine)
                    {
                        //Debug.Log("Storing Character [" + (char)charCode + "] at Index: " + i);
                        SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);
                    }
                }
                #endregion Save Word Wrapping State

                m_characterCount += 1;
            }


            // Check Auto Sizing and increase font size to fill text container.
            #region Check Auto-Sizing (Upper Font Size Bounds)
            fontSizeDelta = m_maxFontSize - m_minFontSize;
            if ((!m_textContainer.isDefaultWidth || !m_textContainer.isDefaultHeight) && !m_isCharacterWrappingEnabled && (m_enableAutoSizing && fontSizeDelta > 0.051f && m_fontSize < m_fontSizeMax))
            {
                m_minFontSize = m_fontSize;
                m_fontSize += Mathf.Max((m_maxFontSize - m_fontSize) / 2, 0.05f);
                m_fontSize = (int)(Mathf.Min(m_fontSize, m_fontSizeMax) * 20 + 0.5f) / 20f;

                if (loopCountA > 20) return; // Added to debug
                GenerateTextMesh();
                return;
            }
            #endregion End Auto-sizing Check


            m_isCharacterWrappingEnabled = false;
            
            if (m_renderMode == TextRenderFlags.GetPreferredSizes)
                return;

            // DEBUG & PERFORMANCE CHECKS (0.006ms)
            //Debug.Log("Iteration Count: " + loopCountA + ". Final Point Size: " + m_fontSize);
            //for (int i = 0; i < m_lineNumber + 1; i++)
            //{
            //    Debug.Log("Line: " + (i + 1) + "  # Char: " + m_textInfo.lineInfo[i].characterCount
            //                                 + "  Word Count: " + m_textInfo.lineInfo[i].wordCount
            //                                 + "  Space: " + m_textInfo.lineInfo[i].spaceCount
            //                                 + "  First: [" + m_textInfo.characterInfo[m_textInfo.lineInfo[i].firstCharacterIndex].character + "] at Index: " + m_textInfo.lineInfo[i].firstCharacterIndex
            //                                 + "  Last [" + m_textInfo.characterInfo[m_textInfo.lineInfo[i].lastCharacterIndex].character + "] at Index: " + m_textInfo.lineInfo[i].lastCharacterIndex
            //                                 + "  Length: " + m_textInfo.lineInfo[i].lineLength
            //                                 + "  Line Extents: " + m_textInfo.lineInfo[i].lineExtents);
            //}



            // If there are no visible characters... no need to continue
            if (m_visibleCharacterCount == 0)
            {
                if (m_vertices != null)
                {
                    Array.Clear(m_vertices, 0, m_vertices.Length);
                    m_mesh.vertices = m_vertices;
                }
                return;
            }


            int last_vert_index = m_visibleCharacterCount * 4;
            // Partial clear of the vertices array to mark unused vertices as degenerate.
            Array.Clear(m_vertices, last_vert_index, m_vertices.Length - last_vert_index);


            // Handle Text Alignment
            #region Text Vertical Alignment
            switch (m_textAlignment)
            {
                // Top Vertically
                case TextAlignmentOptions.Top:
                case TextAlignmentOptions.TopLeft:
                case TextAlignmentOptions.TopJustified:
                case TextAlignmentOptions.TopRight:
                    if (m_overflowMode != TextOverflowModes.Page)
                        m_anchorOffset = corners[1] + new Vector3(0 + margins.x, 0 - m_maxAscender - margins.y, 0);
                    else
                        m_anchorOffset = corners[1] + new Vector3(0 + margins.x, 0 - m_textInfo.pageInfo[pageToDisplay].ascender - margins.y, 0);
                    break;

                // Middle Vertically
                case TextAlignmentOptions.Left:
                case TextAlignmentOptions.Right:
                case TextAlignmentOptions.Center:
                case TextAlignmentOptions.Justified:
                    if (m_overflowMode != TextOverflowModes.Page)
                        m_anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_maxAscender + margins.y + maxVisibleDescender - margins.w) / 2, 0);
                    else
                        m_anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_textInfo.pageInfo[pageToDisplay].ascender + margins.y + m_textInfo.pageInfo[pageToDisplay].descender - margins.w) / 2, 0);
                    break;

                // Bottom Vertically
                case TextAlignmentOptions.Bottom:
                case TextAlignmentOptions.BottomLeft:
                case TextAlignmentOptions.BottomRight:
                case TextAlignmentOptions.BottomJustified:
                    if (m_overflowMode != TextOverflowModes.Page)
                        m_anchorOffset = corners[0] + new Vector3(0 + margins.x, 0 - maxVisibleDescender + margins.w, 0);
                    else
                        m_anchorOffset = corners[0] + new Vector3(0 + margins.x, 0 - m_textInfo.pageInfo[pageToDisplay].descender + margins.w, 0);
                    break;

                // Baseline Vertically 
                case TextAlignmentOptions.BaselineLeft:
                case TextAlignmentOptions.BaselineRight:
                case TextAlignmentOptions.Baseline:
                    m_anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0, 0);
                    break;

                // Midline Vertically 
                case TextAlignmentOptions.MidlineLeft:
                case TextAlignmentOptions.Midline:
                case TextAlignmentOptions.MidlineRight:
                case TextAlignmentOptions.MidlineJustified:
                    m_anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_meshExtents.max.y + margins.y + m_meshExtents.min.y - margins.w) / 2, 0);
                    break;
            }
            #endregion


            // Initialization for Second Pass
            Vector3 justificationOffset = Vector3.zero;
            Vector3 offset = Vector3.zero;
            int vert_index_X4 = 0;

            int wordCount = 0;
            int lineCount = 0;
            int lastLine = 0;

            bool isStartOfWord = false;
            int wordFirstChar = 0;
            int wordLastChar = 0;

            Color32 underlineColor = Color.white;
            Color32 strikethroughColor = Color.white;
            float underlineStartScale = 0;
            float underlineEndScale = 0;
            float underlineMaxScale = 0;
            float underlineBaseLine = Mathf.Infinity;
            int lastPage = 0;

            float strikethroughScale = 0;
            float strikethroughBaseline = 0;


            // Second Pass : Line Justification, UV Mapping, Character & Line Visibility & more.
            #region Handle Line Justification & UV Mapping & Character Visibility & More
            for (int i = 0; i < m_characterCount; i++)
            {
                int currentLine = m_textInfo.characterInfo[i].lineNumber;

                char currentCharacter = m_textInfo.characterInfo[i].character;
                TMP_LineInfo lineInfo = m_textInfo.lineInfo[currentLine];
                TextAlignmentOptions lineAlignment = lineInfo.alignment;
                lineCount = currentLine + 1;

                // Process Line Justification
                #region Handle Line Justification
                switch (lineAlignment)
                {
                    case TextAlignmentOptions.TopLeft:
                    case TextAlignmentOptions.Left:
                    case TextAlignmentOptions.BottomLeft:
                    case TextAlignmentOptions.BaselineLeft:
                    case TextAlignmentOptions.MidlineLeft:
                        justificationOffset = new Vector3(0 + lineInfo.marginLeft, 0, 0);
                        break;
                    case TextAlignmentOptions.Top:
                    case TextAlignmentOptions.Center:
                    case TextAlignmentOptions.Bottom:
                    case TextAlignmentOptions.Baseline:
                    case TextAlignmentOptions.Midline:
                        justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width / 2 - lineInfo.maxAdvance / 2, 0, 0);
                        break;
                    case TextAlignmentOptions.TopRight:
                    case TextAlignmentOptions.Right:
                    case TextAlignmentOptions.BottomRight:
                    case TextAlignmentOptions.BaselineRight:
                    case TextAlignmentOptions.MidlineRight:
                        justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width - lineInfo.maxAdvance, 0, 0);
                        break;
                    case TextAlignmentOptions.TopJustified:
                    case TextAlignmentOptions.Justified:
                    case TextAlignmentOptions.BottomJustified:
                    case TextAlignmentOptions.MidlineJustified:
                        charCode = m_textInfo.characterInfo[i].character;
                        char lastCharOfCurrentLine = m_textInfo.characterInfo[lineInfo.lastCharacterIndex].character;
                                  
                        if (char.IsWhiteSpace(lastCharOfCurrentLine) && !char.IsControl(lastCharOfCurrentLine) && currentLine < m_lineNumber)
                        {   // All lines are justified accept the last one.
                            //float gap = (corners[3].x - margins.z) - (corners[0].x + margins.x) - (lineInfo.maxAdvance);
                            float gap = lineInfo.width - lineInfo.maxAdvance;

                            if (currentLine != lastLine || i == 0)
                                justificationOffset = new Vector3(lineInfo.marginLeft, 0, 0);
                            else
                            {
                                if (charCode == 9 || charCode == 32)
                                {
                                    justificationOffset += new Vector3(gap * (1 - m_wordWrappingRatios) / (lineInfo.spaceCount - 1), 0, 0);
                                }
                                else
                                {
                                    justificationOffset += new Vector3(gap * m_wordWrappingRatios / (lineInfo.characterCount - lineInfo.spaceCount - 1), 0, 0);
                                }
                            }
                        }
                        else
                            justificationOffset = new Vector3(lineInfo.marginLeft, 0, 0); // Keep last line left justified.

                        //Debug.Log("Char [" + (char)charCode + "] Code: " + charCode + "  Offset: " + justificationOffset + "  # Spaces: " + lineInfo.spaceCount + "  # Characters: " + lineInfo.characterCount + "  CurrentLine: " + currentLine + "  Last Line: " + lastLine + "  i: " + i);                      
                        break;
                }
                #endregion End Text Justification
              
                offset = m_anchorOffset + justificationOffset;

                // Handle UV2 mapping options and packing of scale information into UV2.
                #region Handling of UV2 mapping & Scale packing
                bool isCharacterVisible = m_textInfo.characterInfo[i].isVisible;
                if (isCharacterVisible)
                {
                    Extents lineExtents = lineInfo.lineExtents;
                    float uvOffset = (m_uvLineOffset * currentLine) % 1 + m_uvOffset.x;
                    

                    // Setup UV2 based on Character Mapping Options Selected
                    #region Handle UV Mapping Options
                    switch (m_horizontalMapping) 
                    {
                        case TextureMappingOptions.Character:
                            m_uv2s[vert_index_X4 + 0].x = 0 + m_uvOffset.x;
                            m_uv2s[vert_index_X4 + 1].x = 0 + m_uvOffset.x;
                            m_uv2s[vert_index_X4 + 2].x = 1 + m_uvOffset.x;
                            m_uv2s[vert_index_X4 + 3].x = 1 + m_uvOffset.x;
                            break;

                        case TextureMappingOptions.Line:                          
                            if (m_textAlignment != TextAlignmentOptions.Justified)
                            {                               
                                m_uv2s[vert_index_X4 + 0].x = (m_vertices[vert_index_X4 + 0].x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
                                m_uv2s[vert_index_X4 + 1].x = (m_vertices[vert_index_X4 + 1].x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
                                m_uv2s[vert_index_X4 + 2].x = (m_vertices[vert_index_X4 + 2].x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
                                m_uv2s[vert_index_X4 + 3].x = (m_vertices[vert_index_X4 + 3].x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
                                break;
                            }
                            else // Special Case if Justified is used in Line Mode.
                            {
                                m_uv2s[vert_index_X4 + 0].x = (m_vertices[vert_index_X4 + 0].x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                                m_uv2s[vert_index_X4 + 1].x = (m_vertices[vert_index_X4 + 1].x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                                m_uv2s[vert_index_X4 + 2].x = (m_vertices[vert_index_X4 + 2].x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                                m_uv2s[vert_index_X4 + 3].x = (m_vertices[vert_index_X4 + 3].x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                                break;
                            }

                        case TextureMappingOptions.Paragraph:                         
                            m_uv2s[vert_index_X4 + 0].x = (m_vertices[vert_index_X4 + 0].x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                            m_uv2s[vert_index_X4 + 1].x = (m_vertices[vert_index_X4 + 1].x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                            m_uv2s[vert_index_X4 + 2].x = (m_vertices[vert_index_X4 + 2].x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                            m_uv2s[vert_index_X4 + 3].x = (m_vertices[vert_index_X4 + 3].x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                            break;

                        case TextureMappingOptions.MatchAspect:

                            switch (m_verticalMapping)
                            {
                                case TextureMappingOptions.Character:
                                    m_uv2s[vert_index_X4 + 0].y = 0 + m_uvOffset.y;
                                    m_uv2s[vert_index_X4 + 1].y = 1 + m_uvOffset.y;
                                    m_uv2s[vert_index_X4 + 2].y = 0 + m_uvOffset.y;
                                    m_uv2s[vert_index_X4 + 3].y = 1 + m_uvOffset.y;
                                    break;

                                case TextureMappingOptions.Line:                                  
                                    m_uv2s[vert_index_X4 + 0].y = (m_vertices[vert_index_X4].y - lineExtents.min.y) / (lineExtents.max.y - lineExtents.min.y) + uvOffset;
                                    m_uv2s[vert_index_X4 + 1].y = (m_vertices[vert_index_X4 + 1].y - lineExtents.min.y) / (lineExtents.max.y - lineExtents.min.y) + uvOffset;
                                    m_uv2s[vert_index_X4 + 2].y = m_uv2s[vert_index_X4].y;
                                    m_uv2s[vert_index_X4 + 3].y = m_uv2s[vert_index_X4 + 1].y;
                                    break;

                                case TextureMappingOptions.Paragraph:                                   
                                    m_uv2s[vert_index_X4 + 0].y = (m_vertices[vert_index_X4].y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y) + uvOffset;
                                    m_uv2s[vert_index_X4 + 1].y = (m_vertices[vert_index_X4 + 1].y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y) + uvOffset;
                                    m_uv2s[vert_index_X4 + 2].y = m_uv2s[vert_index_X4].y;
                                    m_uv2s[vert_index_X4 + 3].y = m_uv2s[vert_index_X4 + 1].y;
                                    break;

                                case TextureMappingOptions.MatchAspect:
                                    Debug.Log("ERROR: Cannot Match both Vertical & Horizontal.");
                                    break;
                            }

                            //float xDelta = 1 - (_uv2s[vert_index + 0].y * textMeshCharacterInfo[i].AspectRatio); // Left aligned
                            float xDelta = (1 - ((m_uv2s[vert_index_X4 + 0].y + m_uv2s[vert_index_X4 + 1].y) * m_textInfo.characterInfo[i].aspectRatio)) / 2; // Center of Rectangle
                            //float xDelta = 0;                           

                            m_uv2s[vert_index_X4 + 0].x = (m_uv2s[vert_index_X4 + 0].y * m_textInfo.characterInfo[i].aspectRatio) + xDelta + uvOffset;
                            m_uv2s[vert_index_X4 + 1].x = m_uv2s[vert_index_X4 + 0].x;
                            m_uv2s[vert_index_X4 + 2].x = (m_uv2s[vert_index_X4 + 1].y * m_textInfo.characterInfo[i].aspectRatio) + xDelta + uvOffset;
                            m_uv2s[vert_index_X4 + 3].x = m_uv2s[vert_index_X4 + 2].x;
                            break;
                    }

                    switch (m_verticalMapping)
                    {
                        case TextureMappingOptions.Character:
                            m_uv2s[vert_index_X4 + 0].y = 0 + m_uvOffset.y;
                            m_uv2s[vert_index_X4 + 1].y = 1 + m_uvOffset.y;
                            m_uv2s[vert_index_X4 + 2].y = 0 + m_uvOffset.y;
                            m_uv2s[vert_index_X4 + 3].y = 1 + m_uvOffset.y;
                            break;

                        case TextureMappingOptions.Line:
                            m_uv2s[vert_index_X4 + 0].y = (m_vertices[vert_index_X4].y - lineExtents.min.y) / (lineExtents.max.y - lineExtents.min.y) + m_uvOffset.y;
                            m_uv2s[vert_index_X4 + 1].y = (m_vertices[vert_index_X4 + 1].y - lineExtents.min.y) / (lineExtents.max.y - lineExtents.min.y) + m_uvOffset.y;
                            m_uv2s[vert_index_X4 + 2].y = m_uv2s[vert_index_X4].y;
                            m_uv2s[vert_index_X4 + 3].y = m_uv2s[vert_index_X4 + 1].y;
                            break;

                        case TextureMappingOptions.Paragraph:
                            m_uv2s[vert_index_X4 + 0].y = (m_vertices[vert_index_X4].y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y) + m_uvOffset.y;
                            m_uv2s[vert_index_X4 + 1].y = (m_vertices[vert_index_X4 + 1].y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y) + m_uvOffset.y;
                            m_uv2s[vert_index_X4 + 2].y = m_uv2s[vert_index_X4].y;
                            m_uv2s[vert_index_X4 + 3].y = m_uv2s[vert_index_X4 + 1].y;
                            break;

                        case TextureMappingOptions.MatchAspect:
                            //float yDelta = 1 - (_uv2s[vert_index + 2].x / textMeshCharacterInfo[i].AspectRatio); // Top Corner                       
                            float yDelta = (1 - ((m_uv2s[vert_index_X4 + 0].x + m_uv2s[vert_index_X4 + 2].x) / m_textInfo.characterInfo[i].aspectRatio)) / 2; // Center of Rectangle
                            //float yDelta = 0;

                            m_uv2s[vert_index_X4 + 0].y = yDelta + (m_uv2s[vert_index_X4 + 0].x / m_textInfo.characterInfo[i].aspectRatio) + m_uvOffset.y;
                            m_uv2s[vert_index_X4 + 1].y = yDelta + (m_uv2s[vert_index_X4 + 2].x / m_textInfo.characterInfo[i].aspectRatio) + m_uvOffset.y;
                            m_uv2s[vert_index_X4 + 2].y = m_uv2s[vert_index_X4 + 0].y;
                            m_uv2s[vert_index_X4 + 3].y = m_uv2s[vert_index_X4 + 1].y;
                            break;
                    }
                    #endregion


                    // Pack UV's so that we can pass Xscale needed for Shader to maintain 1:1 ratio.
                    #region Pack Scale into UV2
                    float xScale = m_textInfo.characterInfo[i].scale * lossyScale * (1 - m_charWidthAdjDelta);
                    if ((m_textInfo.characterInfo[i].style & FontStyles.Bold) == FontStyles.Bold) xScale *= -1;

                    float x0 = m_uv2s[vert_index_X4 + 0].x;
                    float y0 = m_uv2s[vert_index_X4 + 0].y;
                    float x1 = m_uv2s[vert_index_X4 + 3].x;
                    float y1 = m_uv2s[vert_index_X4 + 3].y;

                    float dx = Mathf.Floor(x0);
                    float dy = Mathf.Floor(y0);

                    x0 = x0 - dx;
                    x1 = x1 - dx;
                    y0 = y0 - dy;
                    y1 = y1 - dy;

                    m_uv2s[vert_index_X4 + 0] = PackUV(x0, y0, xScale);
                    m_uv2s[vert_index_X4 + 1] = PackUV(x0, y1, xScale);
                    m_uv2s[vert_index_X4 + 2] = PackUV(x1, y0, xScale);
                    m_uv2s[vert_index_X4 + 3] = PackUV(x1, y1, xScale);


                    // Enables control of the visibility of Characters, Lines and Pages.
                    if (i < m_maxVisibleCharacters && currentLine < m_maxVisibleLines && m_overflowMode != TextOverflowModes.Page)
                    {
                        m_vertices[vert_index_X4 + 0] += offset;
                        m_vertices[vert_index_X4 + 1] += offset;
                        m_vertices[vert_index_X4 + 2] += offset;
                        m_vertices[vert_index_X4 + 3] += offset;
                    }
                    else if (i < m_maxVisibleCharacters && currentLine < m_maxVisibleLines && m_overflowMode == TextOverflowModes.Page && m_textInfo.characterInfo[i].pageNumber == pageToDisplay)
                    {
                        m_vertices[vert_index_X4 + 0] += offset;
                        m_vertices[vert_index_X4 + 1] += offset;
                        m_vertices[vert_index_X4 + 2] += offset;
                        m_vertices[vert_index_X4 + 3] += offset;
                    }
                    else
                    {
                        m_vertices[vert_index_X4 + 0] *= 0;
                        m_vertices[vert_index_X4 + 1] *= 0;
                        m_vertices[vert_index_X4 + 2] *= 0;
                        m_vertices[vert_index_X4 + 3] *= 0;
                    }
                    
                    vert_index_X4 += 4;
                    
                    #endregion
                }
                #endregion

                // Apply Alignment and Justification Offset
                m_textInfo.characterInfo[i].bottomLeft += offset;
                m_textInfo.characterInfo[i].topLeft += offset;
                m_textInfo.characterInfo[i].topRight += offset;
                m_textInfo.characterInfo[i].bottomRight += offset;
        
                m_textInfo.characterInfo[i].topLine += offset.y;
                m_textInfo.characterInfo[i].bottomLine += offset.y;
                m_textInfo.characterInfo[i].baseLine += offset.y;


                // Store Max Ascender & Descender
                m_textInfo.lineInfo[currentLine].ascender = m_textInfo.characterInfo[i].topLine > m_textInfo.lineInfo[currentLine].ascender ? m_textInfo.characterInfo[i].topLine : m_textInfo.lineInfo[currentLine].ascender;
                m_textInfo.lineInfo[currentLine].descender = m_textInfo.characterInfo[i].bottomLine < m_textInfo.lineInfo[currentLine].descender ? m_textInfo.characterInfo[i].bottomLine : m_textInfo.lineInfo[currentLine].descender;


                // Need to recompute lineExtent to account for the offset from justification.
                #region Adjust lineExtents resulting from alignment offset
                if (currentLine != lastLine || i == m_characterCount - 1)
                {
                    // Update the previous line's extents
                    if (currentLine != lastLine)
                    {
                        m_textInfo.lineInfo[lastLine].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[lastLine].firstCharacterIndex].bottomLeft.x, m_textInfo.lineInfo[lastLine].descender);
                        m_textInfo.lineInfo[lastLine].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[lastLine].lastVisibleCharacterIndex].topRight.x, m_textInfo.lineInfo[lastLine].ascender);
                    }

                    // Update the current line's extents
                    if (i == m_characterCount - 1)
                    {
                        m_textInfo.lineInfo[currentLine].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[currentLine].firstCharacterIndex].bottomLeft.x, m_textInfo.lineInfo[currentLine].descender);
                        m_textInfo.lineInfo[currentLine].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[currentLine].lastVisibleCharacterIndex].topRight.x, m_textInfo.lineInfo[currentLine].ascender);
                    }
                }
                #endregion


                // Track Word Count per line and for the object
                #region Track Word Count
                if (char.IsLetterOrDigit(currentCharacter) || currentCharacter == 39 || currentCharacter == 8217)
                {
                    if (isStartOfWord == false)
                    {
                        isStartOfWord = true;
                        wordFirstChar = i;
                    }

                    // If last character is a word
                    if (isStartOfWord && i == m_characterCount - 1)
                    {
                        wordLastChar = i;
                        wordCount += 1;
                        m_textInfo.lineInfo[currentLine].wordCount += 1;

                        TMP_WordInfo wordInfo = new TMP_WordInfo();
                        wordInfo.firstCharacterIndex = wordFirstChar;
                        wordInfo.lastCharacterIndex = wordLastChar;
                        wordInfo.characterCount = wordLastChar - wordFirstChar + 1;
                        m_textInfo.wordInfo.Add(wordInfo);
                    }
                }
                else if (isStartOfWord || i == 0 && (char.IsPunctuation(currentCharacter) || char.IsWhiteSpace(currentCharacter) || i == m_characterCount - 1))
                {
                    wordLastChar = i == m_characterCount - 1 && char.IsLetterOrDigit(currentCharacter) ? i : i - 1;
                    isStartOfWord = false;

                    wordCount += 1;
                    m_textInfo.lineInfo[currentLine].wordCount += 1;

                    TMP_WordInfo wordInfo = new TMP_WordInfo();
                    wordInfo.firstCharacterIndex = wordFirstChar;
                    wordInfo.lastCharacterIndex = wordLastChar;
                    wordInfo.characterCount = wordLastChar - wordFirstChar + 1;
                    m_textInfo.wordInfo.Add(wordInfo);
                    //Debug.Log("Word #" + wordCount + " is [" + wordInfo.word + "] Start Index: " + wordInfo.firstCharacterIndex + "  End Index: " + wordInfo.lastCharacterIndex);
                }
                #endregion


                // Setup & Handle Underline
                #region Underline
                // NOTE: Need to figure out how underline will be handled with multiple fonts and which font will be used for the underline.
                bool isUnderline = (m_textInfo.characterInfo[i].style & FontStyles.Underline) == FontStyles.Underline;
                if (isUnderline)
                {
                    bool isUnderlineVisible = true;
                    int currentPage = m_textInfo.characterInfo[i].pageNumber;

                    if (i > m_maxVisibleCharacters || currentLine > m_maxVisibleLines || (m_overflowMode == TextOverflowModes.Page && currentPage + 1 != m_pageToDisplay))
                        isUnderlineVisible = false;

                    // We only use the scale of visible characters.
                    if (currentCharacter != 10 && currentCharacter != 13 && currentCharacter != 32)
                    {
                        underlineMaxScale = Mathf.Max(underlineMaxScale, m_textInfo.characterInfo[i].scale);
                        underlineBaseLine = Mathf.Min(currentPage == lastPage ? underlineBaseLine : Mathf.Infinity, m_textInfo.characterInfo[i].baseLine + font.fontInfo.Underline * underlineMaxScale);
                        lastPage = currentPage; // Need to track pages to ensure we reset baseline for the new pages.
                    }

                    if (beginUnderline == false && isUnderlineVisible == true && i <= lineInfo.lastVisibleCharacterIndex && currentCharacter != 10 && currentCharacter != 13)
                    {
                        if (i == lineInfo.lastVisibleCharacterIndex && currentCharacter == 32)
                        { }
                        else
                        {
                            beginUnderline = true;
                            underlineStartScale = m_textInfo.characterInfo[i].scale;
                            if (underlineMaxScale == 0) underlineMaxScale = underlineStartScale;
                            underline_start = new Vector3(m_textInfo.characterInfo[i].bottomLeft.x, underlineBaseLine, 0);
                            underlineColor = m_textInfo.characterInfo[i].color;
                        }
                    }

                    // End Underline if text only contains one character.
                    if (beginUnderline && m_characterCount == 1)
                    {
                        beginUnderline = false;
                        underline_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, underlineBaseLine, 0);
                        underlineEndScale = m_textInfo.characterInfo[i].scale;

                        DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, underlineColor);
                        underlineMaxScale = 0;
                        underlineBaseLine = Mathf.Infinity;
                    }
                    else if (beginUnderline && (i == lineInfo.lastCharacterIndex || i >= lineInfo.lastVisibleCharacterIndex))
                    {
                        // Terminate underline at previous visible character if space or carriage return.
                        if (currentCharacter == 32 || currentCharacter == 10 || currentCharacter == 13)
                        {
                            int lastVisibleCharacterIndex = lineInfo.lastVisibleCharacterIndex;
                            underline_end = new Vector3(m_textInfo.characterInfo[lastVisibleCharacterIndex].topRight.x, underlineBaseLine, 0);
                            underlineEndScale = m_textInfo.characterInfo[lastVisibleCharacterIndex].scale;
                        }
                        else
                        {   // End underline if last character of the line.
                            underline_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, underlineBaseLine, 0);
                            underlineEndScale = m_textInfo.characterInfo[i].scale;
                        }

                        beginUnderline = false;
                        DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, underlineColor);
                        underlineMaxScale = 0;
                        underlineBaseLine = Mathf.Infinity;
                    }
                    else if (beginUnderline && !isUnderlineVisible)
                    {
                        beginUnderline = false;
                        underline_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, underlineBaseLine, 0);
                        underlineEndScale = m_textInfo.characterInfo[i - 1].scale;

                        DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, underlineColor);
                        underlineMaxScale = 0;
                        underlineBaseLine = Mathf.Infinity;
                    }
                }
                else
                {
                    // End Underline
                    if (beginUnderline == true)
                    {
                        beginUnderline = false;
                        underline_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, underlineBaseLine, 0);
                        underlineEndScale = m_textInfo.characterInfo[i - 1].scale;

                        DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, underlineColor);
                        underlineMaxScale = 0;
                        underlineBaseLine = Mathf.Infinity;
                    }
                }
                #endregion


                // Setup & Handle Strikethrough
                #region Strikethrough
                // NOTE: Need to figure out how underline will be handled with multiple fonts and which font will be used for the underline.
                bool isStrikethrough = (m_textInfo.characterInfo[i].style & FontStyles.Strikethrough) == FontStyles.Strikethrough;
                if (isStrikethrough)
                {
                    bool isStrikeThroughVisible = true;

                    if (i > m_maxVisibleCharacters || currentLine > m_maxVisibleLines || (m_overflowMode == TextOverflowModes.Page && m_textInfo.characterInfo[i].pageNumber + 1 != m_pageToDisplay))
                        isStrikeThroughVisible = false;

                    if (beginStrikethrough == false && isStrikeThroughVisible && i <= lineInfo.lastVisibleCharacterIndex && currentCharacter != 10 && currentCharacter != 13)
                    {
                        if (i == lineInfo.lastVisibleCharacterIndex && currentCharacter == 32)
                        { }
                        else
                        {
                            beginStrikethrough = true;
                            strikethroughScale = m_textInfo.characterInfo[i].scale;
                            strikethrough_start = new Vector3(m_textInfo.characterInfo[i].bottomLeft.x, m_textInfo.characterInfo[i].baseLine + (font.fontInfo.Ascender + font.fontInfo.Descender) / 2.75f * strikethroughScale, 0);
                            strikethroughColor = m_textInfo.characterInfo[i].color;
                            strikethroughBaseline = m_textInfo.characterInfo[i].baseLine;
                            //Debug.Log("Char [" + currentCharacter + "] Start Strikethrough POS: " + strikethrough_start);
                        }
                    }

                    // End Strikethrough if text only contains one character.
                    if (beginStrikethrough && m_characterCount == 1)
                    {
                        beginStrikethrough = false;
                        strikethrough_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + (font.fontInfo.Ascender + font.fontInfo.Descender) / 2 * strikethroughScale, 0);

                        DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, strikethroughColor);
                    }
                    else if (beginStrikethrough && i == lineInfo.lastCharacterIndex)
                    {
                        // Terminate Strikethrough at previous visible character if space or carriage return.
                        if (currentCharacter == 32 || currentCharacter == 10 || currentCharacter == 13)
                        {
                            int lastVisibleCharacterIndex = lineInfo.lastVisibleCharacterIndex;
                            strikethrough_end = new Vector3(m_textInfo.characterInfo[lastVisibleCharacterIndex].topRight.x, m_textInfo.characterInfo[lastVisibleCharacterIndex].baseLine + (font.fontInfo.Ascender + font.fontInfo.Descender) / 2 * strikethroughScale, 0);
                        }
                        else
                        {
                            // Terminate Strikethrough at last character of line.
                            strikethrough_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + (font.fontInfo.Ascender + font.fontInfo.Descender) / 2 * strikethroughScale, 0);
                        }

                        beginStrikethrough = false;
                        DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, strikethroughColor);
                    }
                    else if (beginStrikethrough && i < m_characterCount && (m_textInfo.characterInfo[i + 1].scale != strikethroughScale || !TMP_Math.Equals(m_textInfo.characterInfo[i + 1].baseLine + offset.y, strikethroughBaseline)))
                    {
                        // Terminate Strikethrough if scale changes.
                        beginStrikethrough = false;

                        int lastVisibleCharacterIndex = lineInfo.lastVisibleCharacterIndex;
                        if (i > lastVisibleCharacterIndex)
                            strikethrough_end = new Vector3(m_textInfo.characterInfo[lastVisibleCharacterIndex].topRight.x, m_textInfo.characterInfo[lastVisibleCharacterIndex].baseLine + (font.fontInfo.Ascender + font.fontInfo.Descender) / 2 * strikethroughScale, 0);
                        else
                            strikethrough_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + (font.fontInfo.Ascender + font.fontInfo.Descender) / 2 * strikethroughScale, 0);

                        DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, strikethroughColor);
                        //Debug.Log("Char [" + currentCharacter + "] at Index: " + i + "  End Strikethrough POS: " + strikethrough_end + "  Baseline: " + m_textInfo.characterInfo[i].baseLine.ToString("f3"));
                    }
                    else if (beginStrikethrough && !isStrikeThroughVisible)
                    {
                        // Terminate Strikethrough if character is not visible.
                        beginStrikethrough = false;
                        strikethrough_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, m_textInfo.characterInfo[i - 1].baseLine + (font.fontInfo.Ascender + font.fontInfo.Descender) / 2 * strikethroughScale, 0);

                        DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, strikethroughColor);
                    }
                }
                else
                {
                    // End Underline
                    if (beginStrikethrough == true)
                    {
                        beginStrikethrough = false;
                        strikethrough_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, m_textInfo.characterInfo[i - 1].baseLine + (font.fontInfo.Ascender + font.fontInfo.Descender) / 2 * m_fontScale, 0);

                        DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, strikethroughColor);
                    }
                }
                #endregion


                lastLine = currentLine;
            }
            #endregion


            // METRICS ABOUT THE TEXT OBJECT
            m_textInfo.characterCount = (short)m_characterCount;
            m_textInfo.lineCount = (short)lineCount;
            m_textInfo.wordCount = wordCount != 0 && m_characterCount > 0 ? (short)wordCount : (short)1;
            m_textInfo.pageCount = m_pageNumber + 1;
            

            // Store Mesh information in MeshInfo
            m_textInfo.meshInfo.vertices = m_vertices;
            m_textInfo.meshInfo.uv0s = m_uvs;
            m_textInfo.meshInfo.uv2s = m_uv2s;
            m_textInfo.meshInfo.vertexColors = m_vertColors;


            // If Advanced Layout Component is present, don't upload the mesh.
            if (m_renderMode == TextRenderFlags.Render)
            {
                //Debug.Log("Uploading Mesh normally.");
                // Upload Mesh Data 
                m_mesh.MarkDynamic();

                m_mesh.vertices = m_vertices;
                m_mesh.uv = m_uvs;
                m_mesh.uv2 = m_uv2s;
                m_mesh.colors32 = m_vertColors;

                //m_maskOffset = new Vector4(m_mesh.bounds.center.x, m_mesh.bounds.center.y, m_mesh.bounds.size.x, m_mesh.bounds.size.y);
            }
 
            // Setting Mesh Bounds manually is more efficient.   
            //m_mesh.bounds = new Bounds(new Vector3((m_meshExtents.max.x + m_meshExtents.min.x) / 2, (m_meshExtents.max.y + m_meshExtents.min.y) / 2, 0), new Vector3(m_meshExtents.max.x - m_meshExtents.min.x, m_meshExtents.max.y - m_meshExtents.min.y, 0));           
            m_mesh.RecalculateBounds();
            

            //m_isCharacterWrappingEnabled = false;
            //Debug.Log("Corners [0] " + corners[0] + "  [1] " + corners[1] + " [2] " + corners[2] + " [3] " + corners[3]);
            //Debug.Log("Done rendering.");


            // Option to re-size the Text Container to match the text.
            if ((m_textContainer.isDefaultWidth || m_textContainer.isDefaultHeight) && m_textContainer.isAutoFitting)
            {
                //Debug.Log("Auto-fitting Text. Default Width:" + m_textContainer.isDefaultWidth + "  Default Height:" + m_textContainer.isDefaultHeight);
                if (m_textContainer.isDefaultWidth)
                {
                    m_textContainer.width = m_preferredWidth + margins.x + margins.z;
                    //Debug.Log("Text Container's Width adjusted to fit text.");
                }

                if (m_textContainer.isDefaultHeight)
                {
                    //m_textContainer.height = m_maxAscender + margins.y - m_maxDescender + margins.w + m_alignmentPadding.y * m_fontScale * 2;
                    m_textContainer.height = m_preferredHeight + margins.y + margins.w;
                    //Debug.Log("Text Container's Height adjusted to fit text.");
                }
             
                //Debug.Log("Auto-fitting Text. Default Width:" + m_textContainer.width + "  Default Height:" + m_textContainer.height);
                if (m_isMaskingEnabled) isMaskUpdateRequired = true;
                
                // Since changing the size of the Text Container with set the .hasChanged flag, the text object with be regenerated.
                GenerateTextMesh();
                return;
            }



            //for (int i = 0; i < m_lineNumber + 1; i++)
            //{
            //    Debug.Log("Line: " + (i + 1) + "  # Char: " + m_textInfo.lineInfo[i].characterCount
            //                                 + "  Word Count: " + m_textInfo.lineInfo[i].wordCount
            //                                 + "  Space: " + m_textInfo.lineInfo[i].spaceCount
            //                                 + "  First: [" + m_textInfo.characterInfo[m_textInfo.lineInfo[i].firstCharacterIndex].character + "] at Index: " + m_textInfo.lineInfo[i].firstCharacterIndex
            //                                 + "  Last [" + m_textInfo.characterInfo[m_textInfo.lineInfo[i].lastCharacterIndex].character + "] at Index: " + m_textInfo.lineInfo[i].lastCharacterIndex
            //                                 + "  Last visible [" + m_textInfo.characterInfo[m_textInfo.lineInfo[i].lastVisibleCharacterIndex].character + "] at Index: " + m_textInfo.lineInfo[i].lastVisibleCharacterIndex
            //                                 + "  Length: " + m_textInfo.lineInfo[i].lineLength
            //                                 + "  Line Extents: " + m_textInfo.lineInfo[i].lineExtents);
            //}
            

           
            //Profiler.EndSample();
            //m_StopWatch.Stop(); 
            //Debug.Log("Preferred Width: " + m_preferredWidth + "  Height: " + m_preferredHeight); // + "  Margin Width: " + marginWidth + "  xAdvance Total: " + totalxAdvance);
            //Debug.Log("Done Rendering Text Object. Total Character Count is " + m_textInfo.characterCount + ".  Preferred Width: " + m_preferredWidth + "  Height: " + m_preferredHeight);
            //Debug.Log("TimeElapsed is:" + (m_StopWatch.ElapsedTicks / 10000f).ToString("f4"));
            //m_StopWatch.Reset();     
        }
        // Function to identify and validate the rich tag. Returns the position of the > if the tag was valid.
        bool ValidateHtmlTag(int[] chars, int startIndex, out int endIndex)
        {
            Array.Clear(m_htmlTag, 0, m_htmlTag.Length);
            int tagCharCount = 0;
            int tagHashCode = 0;
            int attribute1_HashCode = 0;
            //int attribute2_HashCode = 0;

            TagUnits tagUnits = TagUnits.Pixels;

            int numSequenceStart = 0;
            int numSequenceEnd = 0;
            int numSequenceDecimalPos = 0;
            int numSequenceUnitPos = 0;

            endIndex = startIndex;

            bool isValidHtmlTag = false;
            bool hasNumericalValue = false;

            for (int i = startIndex; i < chars.Length && chars[i] != 0 && tagCharCount < m_htmlTag.Length && chars[i] != 60; i++)
            {
                if (chars[i] == 62) // ASC Code of End HTML tag '>'
                {
                    isValidHtmlTag = true;
                    endIndex = i;
                    m_htmlTag[tagCharCount] = (char)0;
                    if (numSequenceEnd == 0) numSequenceEnd = tagCharCount - 1;
                    break;
                }

                m_htmlTag[tagCharCount] = (char)chars[i];
                tagCharCount += 1;


                // Compute HashCode for 1st attribute
                if (numSequenceStart != 0)
                {
                    if (chars[i] != 34) // Exclude quotes from the HashCode.
                        attribute1_HashCode = (attribute1_HashCode << 3) - attribute1_HashCode + chars[i];
                }

                // Extract numerical value and unit type (px, em, %)
                if (chars[i] == 61)  // '='
                    numSequenceStart = tagCharCount;
                else if (chars[i] == 46) // '.'
                    numSequenceDecimalPos = tagCharCount - 1;
                else if (numSequenceStart != 00 && !hasNumericalValue && char.IsDigit((char)chars[i]))
                    hasNumericalValue = true;
                else if (numSequenceStart != 0 && numSequenceUnitPos == 0 && (chars[i] == 112 || chars[i] == 101 || chars[i] == 37))
                {
                    numSequenceEnd = tagCharCount - 2;
                    numSequenceUnitPos = tagCharCount - 1;
                    if (chars[i] == 101) tagUnits = TagUnits.FontUnits;
                    else if (chars[i] == 37) tagUnits = TagUnits.Percentage;
                }

                // Compute HashCode for the <tag>
                if (numSequenceStart == 0)
                    tagHashCode = (tagHashCode << 3) - tagHashCode + chars[i];


            }

            if (!isValidHtmlTag)
            {
                return false;
            }


            //Debug.Log("Tag is [" + m_htmlTag.ArrayToString() + "].  Tag HashCode: " + tagHashCode + "  Attribute HashCode: " + attribute1_HashCode);

            // Color <#FF00FF>
            if (m_htmlTag[0] == 35 && tagCharCount == 7) // if Tag begins with # and contains 7 characters. 
            {
                m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                m_colorStack[m_colorStackIndex] = m_htmlColor;
                m_colorStackIndex += 1;
                return true;
            }
            // Color <#FF00FF00> with alpha
            else if (m_htmlTag[0] == 35 && tagCharCount == 9) // if Tag begins with # and contains 9 characters. 
            {
                m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                m_colorStack[m_colorStackIndex] = m_htmlColor;
                m_colorStackIndex += 1;
                return true;
            }
            else
            {
                switch (tagHashCode)
                {
                    case 98: // <b>
                        m_style |= FontStyles.Bold;
                        return true;
                    case 427: // </b>
                        if ((m_fontStyle & FontStyles.Bold) != FontStyles.Bold)
                            m_style &= ~FontStyles.Bold;
                        return true;
                    case 105: // <i>
                        m_style |= FontStyles.Italic;
                        return true;
                    case 434: // </i>
                        m_style &= ~FontStyles.Italic;
                        return true;
                    case 115: // <s>
                        m_style |= FontStyles.Strikethrough;
                        return true;
                    case 444: // </s>
                        if ((m_fontStyle & FontStyles.Strikethrough) != FontStyles.Strikethrough)
                            m_style &= ~FontStyles.Strikethrough;
                        return true;
                    case 117: // <u>
                        m_style |= FontStyles.Underline;
                        return true;
                    case 446: // </u>
                        if ((m_fontStyle & FontStyles.Underline) != FontStyles.Underline)
                            m_style &= ~FontStyles.Underline;
                        return true;

                    case 6552: // <sub>
                        m_currentFontSize *= m_fontAsset.fontInfo.SubSize > 0 ? m_fontAsset.fontInfo.SubSize : 1; // Subscript characters are half size.
                        m_fontScale = m_currentFontSize / m_fontAsset.fontInfo.PointSize;
                        m_baselineOffset = m_fontAsset.fontInfo.SubscriptOffset * m_fontScale;
                        //m_isRecalculateScaleRequired = true;
                        return true;
                    case 22673: // </sub>
                        m_currentFontSize /= m_fontAsset.fontInfo.SubSize > 0 ? m_fontAsset.fontInfo.SubSize : 1; //m_fontSize / m_fontAsset.FontInfo.PointSize * .1f;
                        m_baselineOffset = 0;
                        m_fontScale = m_currentFontSize / m_fontAsset.fontInfo.PointSize;
                        //m_isRecalculateScaleRequired = true;
                        return true;
                    case 6566: // <sup>
                        m_currentFontSize *= m_fontAsset.fontInfo.SubSize > 0 ? m_fontAsset.fontInfo.SubSize : 1;
                        m_fontScale = m_currentFontSize / m_fontAsset.fontInfo.PointSize;
                        m_baselineOffset = m_fontAsset.fontInfo.SuperscriptOffset * m_fontScale;
                        //m_isRecalculateScaleRequired = true;
                        return true;
                    case 22687: // </sup>
                        m_currentFontSize /= m_fontAsset.fontInfo.SubSize > 0 ? m_fontAsset.fontInfo.SubSize : 1; //m_fontSize / m_fontAsset.FontInfo.PointSize * .1f;
                        m_baselineOffset = 0;
                        m_fontScale = m_currentFontSize / m_fontAsset.fontInfo.PointSize;
                        //m_isRecalculateScaleRequired = true;
                        return true;
                    case 6380: // <pos=000.00px> <pos=0em> <pos=50%>
                        float spacing = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_xAdvance = spacing;
                                return true;
                            case TagUnits.FontUnits:
                                m_xAdvance = spacing * m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.TabSize;
                                return true;
                            case TagUnits.Percentage:
                                m_xAdvance = m_marginWidth * spacing / 100;
                                return true;
                        }
                        return false;
                    case 16034505: // <voffset>
                        float val = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_baselineOffset = val;
                                return true;
                            case TagUnits.FontUnits:
                                m_baselineOffset = val * m_fontScale * m_fontAsset.fontInfo.Ascender;
                                return true;
                            case TagUnits.Percentage:
                                //m_baselineOffset = m_marginHeight * val / 100;
                                return false;
                        }
                        return false;
                    case 54741026: // </voffset>
                        m_baselineOffset = 0;
                        return true;
                    case 43991: // <page>
                        // This tag only works when Overflow - Page mode is used.
                        if (m_overflowMode == TextOverflowModes.Page)
                        {
                            m_xAdvance = 0 + tag_LineIndent + tag_Indent;
                            //m_textInfo.lineInfo[m_lineNumber].marginLeft = m_xAdvance;
                            m_lineOffset = 0;
                            m_pageNumber += 1;
                            m_isNewPage = true;
                        }
                        return true;

                    case 43969: // <nobr>
                        m_isNonBreakingSpace = true;
                        return true;
                    case 156816: // </nobr>
                        m_isNonBreakingSpace = false;
                        return true;
                    case 45545: // <size=>
                        val = 0;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                if (m_htmlTag[5] == 43) // <size=+00>
                                {
                                    val = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                                    m_currentFontSize = m_fontSize + val;
                                    m_isRecalculateScaleRequired = true;
                                    return true;
                                }
                                else if (m_htmlTag[5] == 45) // <size=-00>
                                {
                                    val = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                                    m_currentFontSize = m_fontSize + val;
                                    m_isRecalculateScaleRequired = true;
                                    return true;
                                }
                                else // <size=00.0>
                                {
                                    val = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                                    //if (val == 0) return false; // if tag is <size> with no values.
                                    m_currentFontSize = val;
                                    m_isRecalculateScaleRequired = true;
                                    return true;
                                }
                            case TagUnits.FontUnits:
                                val = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                                m_currentFontSize *= val;
                                m_isRecalculateScaleRequired = true;
                                return true;
                            case TagUnits.Percentage:
                                val = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                                if (val == 0) return false;
                                m_currentFontSize = m_fontSize * val / 100;
                                m_isRecalculateScaleRequired = true;
                                return true;
                        }
                        return false;
                    case 158392: // </size>
                        m_currentFontSize = m_fontSize;
                        m_isRecalculateScaleRequired = true;
                        //m_fontScale = m_fontSize / m_fontAsset.fontInfo.PointSize * .1f;
                        return true;
                    case 41311: // <font=xx>
                        Debug.Log("This feature is coming soon!");

                        /*
                        m_fontIndex = (int)ConvertToFloat(m_htmlTag, numSequenceStart, tagCharCount - 1, numSequenceDecimalPos);

                        if(m_fontAssetArray[m_fontIndex] == null)
                        {
                            // Load new font asset into index
                            //Debug.Log("Loading Font Asset at Index " + m_fontIndex);
                            m_fontAssetArray[m_fontIndex] = m_fontAsset; // Resources.Load("Fonts & Materials/Bangers SDF", typeof(TextMeshProFont)) as TextMeshProFont; // Hard coded right now to a specific font
                        }
                        else
                        {
                            //Debug.Log("Font Asset at Index " + m_fontIndex + " has already been loaded.");
                        }


                        //m_fontScale = (m_fontSize / m_fontAssetArray[m_fontIndex].fontInfo.PointSize * (m_isOrthographic ? 1 : 0.1f));
                        */
                        return true;
                    case 320078: // <space=000.00>
                        spacing = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_xAdvance += spacing;
                                return true;
                            case TagUnits.FontUnits:
                                m_xAdvance += spacing * m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.TabSize;
                                return true;
                            case TagUnits.Percentage:
                                // Not applicable
                                return false;
                        }
                        return false;
                    case 276254: // <alpha=#FF>
                        m_htmlColor.a = (byte)(HexToInt(m_htmlTag[7]) * 16 + HexToInt(m_htmlTag[8]));
                        return true;

                    case 1750458: // <a name=" ">
                        return true;
                    case 426: // </a>
                        return true;
                    case 43066: // <link="name">
                        if (m_isParsingText)
                        {
                            tag_LinkInfo.hashCode = attribute1_HashCode;
                            tag_LinkInfo.firstCharacterIndex = m_characterCount;
                            //Debug.Log("Link begin at Character # " + m_characterCount);
                        }
                        return true;
                    case 155913: // </link>
                        if (m_isParsingText)
                        {
                            tag_LinkInfo.lastCharacterIndex = m_characterCount - 1;
                            tag_LinkInfo.characterCount = m_characterCount - tag_LinkInfo.firstCharacterIndex;
                            m_textInfo.linkInfo.Add(tag_LinkInfo);
                            m_textInfo.linkCount += 1;

                            //Debug.Log("*** LinkInfo Element Added ***\nHashCode: " + tag_LinkInfo.hashCode + "  First Index: " + tag_LinkInfo.firstCharacterIndex + "  Last Index: " + tag_LinkInfo.lastCharacterIndex + "  Link Count: " + m_textInfo.linkCount);
                        }
                        return true;
                    case 275917: // <align=>
                        switch (attribute1_HashCode)
                        {
                            case 42823: // <align=left>
                                m_lineJustification = TextAlignmentOptions.Left;
                                return true;
                            case 315620: // <align=right>
                                m_lineJustification = TextAlignmentOptions.Right;
                                return true;
                            case 1950629: // <align=center>
                                m_lineJustification = TextAlignmentOptions.Center;
                                return true;
                            case 723195727: // <align=justified>
                                m_lineJustification = TextAlignmentOptions.Justified;
                                return true;
                        }
                        return false;
                    case 1065846: // </align>
                        m_lineJustification = m_textAlignment;
                        return true;
                    case 327550: // <width=xx>
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_width = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                                break;
                            case TagUnits.FontUnits:
                                return false;
                            //break;
                            case TagUnits.Percentage:
                                val = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                                m_width = m_marginWidth * val / 100;
                                break;
                        }
                        return true;
                    case 1117479: // </width>
                        m_width = -1;
                        return true;
                    case 322689: // <style="name">
                        TMP_Style style = TMP_StyleSheet.Instance.GetStyle(attribute1_HashCode);

                        if (style == null) return false;

                        m_styleStack[m_styleStackIndex] = style.hashCode;
                        m_styleStackIndex += 1;

                        //// Parse Style Macro
                        for (int i = 0; i < style.styleOpeningTagArray.Length; i++)
                        {
                            if (style.styleOpeningTagArray[i] == 60)
                                ValidateHtmlTag(style.styleOpeningTagArray, i + 1, out i);
                        }
                        return true;
                    case 1112618: // </style>
                        style = TMP_StyleSheet.Instance.GetStyle(attribute1_HashCode);

                        if (style == null)
                        {
                            // Get style from the Style Stack
                            m_styleStackIndex = m_styleStackIndex > 0 ? m_styleStackIndex - 1 : 0;
                            style = TMP_StyleSheet.Instance.GetStyle(m_styleStack[m_styleStackIndex]);

                        }

                        if (style == null) return false;
                        //// Parse Style Macro
                        for (int i = 0; i < style.styleClosingTagArray.Length; i++)
                        {
                            if (style.styleClosingTagArray[i] == 60)
                                ValidateHtmlTag(style.styleClosingTagArray, i + 1, out i);
                        }
                        return true;
                    case 281955: // <color=#FF00FF> or <color=#FF00FF00>
                        // <color=#FF00FF>
                        if (m_htmlTag[6] == 35 && tagCharCount == 13)
                        {
                            m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                            m_colorStack[m_colorStackIndex] = m_htmlColor;
                            m_colorStackIndex += 1;
                            return true;
                        }
                        // <color=#FF00FF00>
                        else if (m_htmlTag[6] == 35 && tagCharCount == 15)
                        {
                            m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                            m_colorStack[m_colorStackIndex] = m_htmlColor;
                            m_colorStackIndex += 1;
                            return true;
                        }

                        // <color=name>
                        switch (attribute1_HashCode)
                        {
                            case 6393: // <color=red>
                                m_htmlColor = Color.red;
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case 39826: // <color=blue>
                                m_htmlColor = Color.blue;
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case 277895: // <color=black>
                                m_htmlColor = Color.black;
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case 292171: // <color=green>
                                m_htmlColor = Color.green;
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case 327449: // <color=white>
                                m_htmlColor = Color.white;
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case 2178774: // <color=orange>
                                m_htmlColor = new Color32(255, 128, 0, 255);
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case 2208748: // <color=purple>
                                m_htmlColor = new Color32(160, 32, 240, 255);
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case 2319380: // <color=yellow>
                                m_htmlColor = Color.yellow;
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                        }
                        return false;
                    case 1983971: // <cspace=xx.x>
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_cSpacing = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                                break;
                            case TagUnits.FontUnits:
                                m_cSpacing = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                                m_cSpacing *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.TabSize;
                                break;
                            case TagUnits.Percentage:
                                return false;
                        }
                        return true;
                    case 7513474: // </cspace>
                        m_cSpacing = 0;
                        return true;
                    case 2152041: // <mspace=xx.x>
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_monoSpacing = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos) / m_fontScale;
                                break;
                            case TagUnits.FontUnits:
                                m_monoSpacing = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                                m_monoSpacing *= m_fontAsset.fontInfo.TabWidth / m_fontAsset.TabSize * 2;
                                break;
                            case TagUnits.Percentage:
                                return false;
                        }
                        return true;
                    case 7681544: // </mspace>
                        m_monoSpacing = 0;
                        return true;
                    case 280416: // <class="name">
                        return false;
                    case 1071884: // </color>
                        m_colorStackIndex -= 1;

                        if (m_colorStackIndex <= 0)
                        {
                            m_htmlColor = m_fontColor32;
                            m_colorStackIndex = 0;
                        }
                        else
                        {
                            m_htmlColor = m_colorStack[m_colorStackIndex - 1];
                        }

                        return true;
                    case 2068980: // <indent=10px> <indent=10em> <indent=50%>
                        tag_Indent = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                //m_xAdvance = tag_Offset;
                                break;
                            case TagUnits.FontUnits:
                                tag_Indent *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.TabSize;
                                break;
                            case TagUnits.Percentage:
                                tag_Indent = m_marginWidth * tag_Indent / 100;
                                break;
                        }

                        m_xAdvance = tag_Indent;
                        return true;
                    case 7598483: // </indent>
                        tag_Indent = 0;
                        return true;
                    case 1109386397: // <line-indent>
                        tag_LineIndent = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos); // * m_fontScale * m_fontAsset.fontInfo.TabWidth;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                //m_xAdvance = tag_Offset;
                                break;
                            case TagUnits.FontUnits:
                                tag_LineIndent *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.TabSize;
                                break;
                            case TagUnits.Percentage:
                                tag_LineIndent = m_marginWidth * tag_LineIndent / 100;
                                break;
                        }

                        m_xAdvance += tag_LineIndent;
                        return true;
                    case -445537194: // </line-indent>
                        tag_LineIndent = 0;
                        return true;
                    case 2246877: // <sprite=x>
                        m_spriteIndex = (int)ConvertToFloat(m_htmlTag, numSequenceStart, tagCharCount - 1, numSequenceDecimalPos);
                        //Debug.Log("Sprite Index is " + ((int)ConvertToFloat(m_htmlTag, numSequenceStart, tagCharCount - 1, numSequenceDecimalPos)));
                        m_isSprite = true;
                        return true;
                    case 13526026: // <allcaps>
                        m_style |= FontStyles.UpperCase;
                        return true;
                    case 52232547: // </allcaps>
                        m_style &= ~FontStyles.UpperCase;
                        return true;
                    case 766244328: // <smallcaps>
                        m_style |= FontStyles.SmallCaps;
                        return true;
                    case -1632103439: // </smallcaps>
                        m_style &= ~FontStyles.SmallCaps;
                        m_isRecalculateScaleRequired = true;
                        return true;
                    case 2109854: // <margin=00.0> <margin=00em> <margin=50%>
                        m_marginLeft = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos); // px
                        if (m_marginLeft == 0) return false;
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                // Default behavior
                                break;
                            case TagUnits.FontUnits:
                                m_marginLeft *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.TabSize;
                                break;
                            case TagUnits.Percentage:
                                m_marginLeft = (m_marginWidth - (m_width != -1 ? m_width : 0)) * m_marginLeft / 100;
                                break;
                        }
                        m_marginLeft = m_marginLeft >= 0 ? m_marginLeft : 0;
                        m_marginRight = m_marginLeft;
                        return true;
                    case 7639357: // </margin>
                        m_marginLeft = 0;
                        m_marginRight = 0;
                        return true;
                    case 1100728678: // <margin-left=xx.x>
                        m_marginLeft = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos); // px
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                // Default behavior
                                break;
                            case TagUnits.FontUnits:
                                m_marginLeft *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.TabSize;
                                break;
                            case TagUnits.Percentage:
                                m_marginLeft = (m_marginWidth - (m_width != -1 ? m_width : 0)) * m_marginLeft / 100;
                                break;
                        }
                        m_marginLeft = m_marginLeft >= 0 ? m_marginLeft : 0;
                        return true;
                    case -884817987: // <margin-right=xx.x>
                        m_marginRight = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos); // px
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                // Default behavior
                                break;
                            case TagUnits.FontUnits:
                                m_marginRight *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.TabSize;
                                break;
                            case TagUnits.Percentage:
                                m_marginRight = (m_marginWidth - (m_width != -1 ? m_width : 0)) * m_marginRight / 100;
                                break;
                        }
                        m_marginRight = m_marginRight >= 0 ? m_marginRight : 0;
                        return true;
                    case 1109349752: // <line-height=xx.x>
                        m_lineHeight = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_lineHeight /= m_fontScale;
                                break;
                            case TagUnits.FontUnits:
                                m_lineHeight *= m_fontAsset.fontInfo.LineHeight;
                                break;
                            case TagUnits.Percentage:
                                m_lineHeight = m_fontAsset.fontInfo.LineHeight * m_lineHeight / 100;
                                break;
                        }
                        return true;
                    case -445573839: // </line-height>
                        m_lineHeight = 0;
                        return true;
                }
            }
            return false;
        }
Beispiel #34
0
        // Function to identify and validate the rich tag. Returns the position of the > if the tag was valid.
        bool ValidateHtmlTag(int[] chars, int startIndex, out int endIndex)
        {
            Array.Clear(m_htmlTag, 0, m_htmlTag.Length);
            int tagCharCount = 0;
            int tagHashCode = 0;

            TagAttribute attribute_1 = new TagAttribute();
            TagAttribute attribute_2 = new TagAttribute();
            byte attributeFlag = 0;

            TagUnits tagUnits = TagUnits.Pixels;

            int numSequenceStart = 0;
            int numSequenceEnd = 0;
            int numSequenceDecimalPos = 0;
            int numSequenceUnitPos = 0;

            endIndex = startIndex;

            bool isValidHtmlTag = false;
            bool hasNumericalValue = false;

            for (int i = startIndex; i < chars.Length && chars[i] != 0 && tagCharCount < m_htmlTag.Length && chars[i] != 60; i++)
            {
                if (chars[i] == 62) // ASCII Code of End HTML tag '>'
                {
                    isValidHtmlTag = true;
                    endIndex = i;
                    m_htmlTag[tagCharCount] = (char)0;
                    if (numSequenceEnd == 0) numSequenceEnd = tagCharCount - 1;
                    break;
                }

                m_htmlTag[tagCharCount] = (char)chars[i];
                tagCharCount += 1;


                // Compute HashCode for 1st attribute
                if (attributeFlag == 1)
                {
                    if (chars[i] != 34) // Exclude quotes from the HashCode.
                    {
                        if (attribute_1.startIndex == 0) attribute_1.startIndex = tagCharCount - 1;

                        attribute_1.hashCode = (attribute_1.hashCode << 5) - attribute_1.hashCode + chars[i];
                        attribute_1.length += 1;
                    }
                    else
                        if (attribute_1.startIndex != 0) attributeFlag = 2;
                }

                // Compute HashCode for 2st attribute
                if (attributeFlag == 3)
                {
                    if (chars[i] != 34) // Exclude quotes from the HashCode.
                    {
                        if (attribute_2.startIndex == 0) attribute_2.startIndex = tagCharCount - 1;

                        attribute_2.hashCode = (attribute_2.hashCode << 5) - attribute_2.hashCode + chars[i];
                        attribute_2.length += 1;
                    }
                    else
                        if (attribute_2.startIndex != 0) attributeFlag = 0;
                }


                // Extract numerical value and unit type (px, em, %)
                if (chars[i] == 61)  // '='
                {
                    numSequenceStart = tagCharCount;
                    attributeFlag += 1;
                }
                else if (chars[i] == 46) // '.'
                    numSequenceDecimalPos = tagCharCount - 1;
                else if (numSequenceStart != 00 && !hasNumericalValue && char.IsDigit((char)chars[i]))
                    hasNumericalValue = true;
                else if (numSequenceStart != 0 && numSequenceUnitPos == 0 && (chars[i] == 112 || chars[i] == 101 || chars[i] == 37))
                {
                    numSequenceEnd = tagCharCount - 2;
                    numSequenceUnitPos = tagCharCount - 1;
                    if (chars[i] == 101) tagUnits = TagUnits.FontUnits;
                    else if (chars[i] == 37) tagUnits = TagUnits.Percentage;
                }

                // Compute HashCode for the <tag>
                if (numSequenceStart == 0)
                    tagHashCode = (tagHashCode << 3) - tagHashCode + chars[i];

            }

            if (!isValidHtmlTag)
            {
                return false;
            }


            //Debug.Log("Tag is [" + m_htmlTag.ArrayToString() + "].  Tag HashCode: " + tagHashCode + "  Attribute HashCode: " + attribute_1.hashCode);

            // Special handling of the NoParsing tag
            if (tag_NoParsing && tagHashCode != 53822163)
                return false;
            else if (tagHashCode == 53822163)
            {
                tag_NoParsing = false;
                return true;
            }

            // Color <#FF00FF>
            if (m_htmlTag[0] == 35 && tagCharCount == 7) // if Tag begins with # and contains 7 characters. 
            {
                m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                m_colorStack[m_colorStackIndex] = m_htmlColor;
                m_colorStackIndex += 1;
                return true;
            }
            // Color <#FF00FF00> with alpha
            else if (m_htmlTag[0] == 35 && tagCharCount == 9) // if Tag begins with # and contains 9 characters. 
            {
                m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                m_colorStack[m_colorStackIndex] = m_htmlColor;
                m_colorStackIndex += 1;
                return true;
            }
            else
            {
                float value = 0;

                switch (tagHashCode)
                {
                    case 98: // <b>
                        m_style |= FontStyles.Bold;
                        return true;
                    case 427: // </b>
                        if ((m_fontStyle & FontStyles.Bold) != FontStyles.Bold)
                            m_style &= ~FontStyles.Bold;
                        return true;
                    case 105: // <i>
                        m_style |= FontStyles.Italic;
                        return true;
                    case 434: // </i>
                        m_style &= ~FontStyles.Italic;
                        return true;
                    case 115: // <s>
                        m_style |= FontStyles.Strikethrough;
                        return true;
                    case 444: // </s>
                        if ((m_fontStyle & FontStyles.Strikethrough) != FontStyles.Strikethrough)
                            m_style &= ~FontStyles.Strikethrough;
                        return true;
                    case 117: // <u>
                        m_style |= FontStyles.Underline;
                        return true;
                    case 446: // </u>
                        if ((m_fontStyle & FontStyles.Underline) != FontStyles.Underline)
                            m_style &= ~FontStyles.Underline;
                        return true;

                    case 6552: // <sub>
                        m_currentFontSize *= m_fontAsset.fontInfo.SubSize > 0 ? m_fontAsset.fontInfo.SubSize : 1; // Subscript characters are half size.
                        m_fontScale = m_currentFontSize / m_fontAsset.fontInfo.PointSize;
                        m_baselineOffset = m_fontAsset.fontInfo.SubscriptOffset * m_fontScale;
                        m_style |= FontStyles.Subscript;
                        //m_isRecalculateScaleRequired = true;
                        return true;
                    case 22673: // </sub>
                        m_currentFontSize /= m_fontAsset.fontInfo.SubSize > 0 ? m_fontAsset.fontInfo.SubSize : 1; //m_fontSize / m_fontAsset.FontInfo.PointSize * .1f;
                        m_baselineOffset = 0;
                        m_fontScale = m_currentFontSize / m_fontAsset.fontInfo.PointSize;
                        m_style &= ~FontStyles.Subscript;
                        //m_isRecalculateScaleRequired = true;
                        return true;
                    case 6566: // <sup>
                        m_currentFontSize *= m_fontAsset.fontInfo.SubSize > 0 ? m_fontAsset.fontInfo.SubSize : 1;
                        m_fontScale = m_currentFontSize / m_fontAsset.fontInfo.PointSize;
                        m_baselineOffset = m_fontAsset.fontInfo.SuperscriptOffset * m_fontScale;
                        m_style |= FontStyles.Superscript;
                        //m_isRecalculateScaleRequired = true;
                        return true;
                    case 22687: // </sup>
                        m_currentFontSize /= m_fontAsset.fontInfo.SubSize > 0 ? m_fontAsset.fontInfo.SubSize : 1; //m_fontSize / m_fontAsset.FontInfo.PointSize * .1f;
                        m_baselineOffset = 0;
                        m_fontScale = m_currentFontSize / m_fontAsset.fontInfo.PointSize;
                        m_style &= ~FontStyles.Superscript;
                        //m_isRecalculateScaleRequired = true;
                        return true;
                    case 6380: // <pos=000.00px> <pos=0em> <pos=50%>
                        value = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_xAdvance = value;
                                //m_isIgnoringAlignment = true;
                                return true;
                            case TagUnits.FontUnits:
                                m_xAdvance = value * m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.TabSize;
                                //m_isIgnoringAlignment = true;
                                return true;
                            case TagUnits.Percentage:
                                m_xAdvance = m_marginWidth * value / 100;
                                //m_isIgnoringAlignment = true;
                                return true;
                        }
                        return false;
                    case 22501: // </pos>
                        m_isIgnoringAlignment = false;
                        return true;
                    case 16034505: // <voffset>
                        value = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_baselineOffset = value;
                                return true;
                            case TagUnits.FontUnits:
                                m_baselineOffset = value * m_fontScale * m_fontAsset.fontInfo.Ascender;
                                return true;
                            case TagUnits.Percentage:
                                //m_baselineOffset = m_marginHeight * val / 100;
                                return false;
                        }
                        return false;
                    case 54741026: // </voffset>
                        m_baselineOffset = 0;
                        return true;
                    case 43991: // <page>
                        // This tag only works when Overflow - Page mode is used.
                        if (m_overflowMode == TextOverflowModes.Page)
                        {
                            m_xAdvance = 0 + tag_LineIndent + tag_Indent;
                            //m_textInfo.lineInfo[m_lineNumber].marginLeft = m_xAdvance;
                            m_lineOffset = 0;
                            m_pageNumber += 1;
                            m_isNewPage = true;
                        }
                        return true;

                    case 43969: // <nobr>
                        m_isNonBreakingSpace = true;
                        return true;
                    case 156816: // </nobr>
                        m_isNonBreakingSpace = false;
                        return true;
                    case 45545: // <size=>
                        value = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                if (m_htmlTag[5] == 43) // <size=+00>
                                {
                                    m_currentFontSize = m_fontSize + value;
                                    m_isRecalculateScaleRequired = true;
                                    return true;
                                }
                                else if (m_htmlTag[5] == 45) // <size=-00>
                                {
                                    m_currentFontSize = m_fontSize + value;
                                    m_isRecalculateScaleRequired = true;
                                    return true;
                                }
                                else // <size=00.0>
                                {
                                    m_currentFontSize = value;
                                    m_isRecalculateScaleRequired = true;
                                    return true;
                                }
                            case TagUnits.FontUnits:
                                m_currentFontSize *= value;
                                m_isRecalculateScaleRequired = true;
                                return true;
                            case TagUnits.Percentage:
                                m_currentFontSize = m_fontSize * value / 100;
                                m_isRecalculateScaleRequired = true;
                                return true;
                        }
                        return false;
                    case 158392: // </size>
                        m_currentFontSize = m_fontSize;
                        m_isRecalculateScaleRequired = true;
                        //m_fontScale = m_fontSize / m_fontAsset.fontInfo.PointSize * .1f;
                        return true;
                    case 41311: // <font=xx>
                        //Debug.Log("Font name: \"" + new string(m_htmlTag, attribute_1.startIndex, attribute_1.length) + "\"   HashCode: " + attribute_1.hashCode + "   Material Name: \"" + new string(m_htmlTag, attribute_2.startIndex, attribute_2.length) + "\"   Hashcode: " + attribute_2.hashCode);

                        int fontHashCode = attribute_1.hashCode;
                        int materialHashCode = attribute_2.hashCode;

                        TextMeshProFont tempFont;
                        Material tempMaterial;

                        // HANDLE NEW FONT ASSET
                        if (m_fontAsset_Dict.TryGetValue(fontHashCode, out tempFont))
                        {
                            if (tempFont != m_currentFontAsset)
                            {
                                //Debug.Log("Assigning Font Asset: " + tempFont.name);
                                m_currentFontAsset = m_fontAsset_Dict[fontHashCode];
                                m_isRecalculateScaleRequired = true;
                            }
                        }
                        else
                        {
                            // Load new font asset
                            tempFont = Resources.Load("Fonts & Materials/" + new string(m_htmlTag, attribute_1.startIndex, attribute_1.length), typeof(TextMeshProFont)) as TextMeshProFont;
                            if (tempFont != null)
                            {
                                //Debug.Log("Loading and Assigning Font Asset: " + tempFont.name);
                                m_fontAsset_Dict.Add(fontHashCode, tempFont);
                                m_currentFontAsset = tempFont;
                                m_isRecalculateScaleRequired = true;
                            }
                            else
                                return false;
                        }


                        // HANDLE NEW MATERIAL
                        if (materialHashCode == 0)
                        {
                            if (!m_fontMaterial_Dict.TryGetValue(m_currentFontAsset.materialHashCode, out tempMaterial))
                                m_fontMaterial_Dict.Add(m_currentFontAsset.materialHashCode, m_currentFontAsset.material);

                            if (m_currentMaterial != m_currentFontAsset.material)
                            {
                                //Debug.Log("Assigning Default Font Asset Material: " + m_currentFontAsset.material.name);
                                m_currentMaterial = m_currentFontAsset.material;
                            }

                        }
                        else if (m_fontMaterial_Dict.TryGetValue(materialHashCode, out tempMaterial))
                        {
                            if (tempMaterial != m_currentMaterial)
                            {
                                //Debug.Log("Assigning Material: " + tempMaterial.name);
                                m_currentMaterial = tempMaterial;
                            }
                        }
                        else
                        {
                            // Load new material
                            tempMaterial = Resources.Load("Fonts & Materials/" + new string(m_htmlTag, attribute_2.startIndex, attribute_2.length), typeof(Material)) as Material;
                            if (tempMaterial != null)
                            {
                                //Debug.Log("Loading and Assigning Material: " + tempMaterial.name);
                                m_fontMaterial_Dict.Add(materialHashCode, tempMaterial);
                                m_currentMaterial = tempMaterial;
                            }
                            else
                                return false;
                        }

                        return true;
                    case 320078: // <space=000.00>
                        value = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_xAdvance += value;
                                return true;
                            case TagUnits.FontUnits:
                                m_xAdvance += value * m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.TabSize;
                                return true;
                            case TagUnits.Percentage:
                                // Not applicable
                                return false;
                        }
                        return false;
                    case 276254: // <alpha=#FF>
                        m_htmlColor.a = (byte)(HexToInt(m_htmlTag[7]) * 16 + HexToInt(m_htmlTag[8]));
                        return true;

                    case 1750458: // <a name=" ">
                        return true;
                    case 426: // </a>
                        return true;
                    case 43066: // <link="name">
                        if (m_isParsingText)
                        {
                            tag_LinkInfo.hashCode = attribute_1.hashCode;
                            tag_LinkInfo.firstCharacterIndex = m_characterCount;
                            //Debug.Log("Link begin at Character # " + m_characterCount);
                        }
                        return true;
                    case 155913: // </link>
                        if (m_isParsingText)
                        {
                            tag_LinkInfo.lastCharacterIndex = m_characterCount - 1;
                            tag_LinkInfo.characterCount = m_characterCount - tag_LinkInfo.firstCharacterIndex;
                            m_textInfo.linkInfo.Add(tag_LinkInfo);
                            m_textInfo.linkCount += 1;

                            //Debug.Log("*** LinkInfo Element Added ***\nHashCode: " + tag_LinkInfo.hashCode + "  First Index: " + tag_LinkInfo.firstCharacterIndex + "  Last Index: " + tag_LinkInfo.lastCharacterIndex + "  Link Count: " + m_textInfo.linkCount);
                        }
                        return true;
                    case 275917: // <align=>
                        switch (attribute_1.hashCode)
                        {
                            case 3317767: // <align=left>
                                m_lineJustification = TextAlignmentOptions.Left;
                                return true;
                            case 108511772: // <align=right>
                                m_lineJustification = TextAlignmentOptions.Right;
                                return true;
                            case -1364013995: // <align=center>
                                m_lineJustification = TextAlignmentOptions.Center;
                                return true;
                            case 1838536479: // <align=justified>
                                m_lineJustification = TextAlignmentOptions.Justified;
                                return true;
                        }
                        return false;
                    case 1065846: // </align>
                        m_lineJustification = m_textAlignment;
                        return true;
                    case 327550: // <width=xx>
                        value = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_width = value;
                                break;
                            case TagUnits.FontUnits:
                                return false;
                            //break;
                            case TagUnits.Percentage:
                                m_width = m_marginWidth * value / 100;
                                break;
                        }
                        return true;
                    case 1117479: // </width>
                        m_width = -1;
                        return true;
                    case 322689: // <style="name">
                        TMP_Style style = TMP_StyleSheet.Instance.GetStyle(attribute_1.hashCode);

                        if (style == null) return false;

                        m_styleStack[m_styleStackIndex] = style.hashCode;
                        m_styleStackIndex += 1;

                        //// Parse Style Macro
                        for (int i = 0; i < style.styleOpeningTagArray.Length; i++)
                        {
                            if (style.styleOpeningTagArray[i] == 60)
                                ValidateHtmlTag(style.styleOpeningTagArray, i + 1, out i);
                        }
                        return true;
                    case 1112618: // </style>
                        style = TMP_StyleSheet.Instance.GetStyle(attribute_1.hashCode);

                        if (style == null)
                        {
                            // Get style from the Style Stack
                            m_styleStackIndex = m_styleStackIndex > 0 ? m_styleStackIndex - 1 : 0;
                            style = TMP_StyleSheet.Instance.GetStyle(m_styleStack[m_styleStackIndex]);

                        }

                        if (style == null) return false;
                        //// Parse Style Macro
                        for (int i = 0; i < style.styleClosingTagArray.Length; i++)
                        {
                            if (style.styleClosingTagArray[i] == 60)
                                ValidateHtmlTag(style.styleClosingTagArray, i + 1, out i);
                        }
                        return true;
                    case 281955: // <color=#FF00FF> or <color=#FF00FF00>
                        // <color=#FF00FF>
                        if (m_htmlTag[6] == 35 && tagCharCount == 13)
                        {
                            m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                            m_colorStack[m_colorStackIndex] = m_htmlColor;
                            m_colorStackIndex += 1;
                            return true;
                        }
                        // <color=#FF00FF00>
                        else if (m_htmlTag[6] == 35 && tagCharCount == 15)
                        {
                            m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                            m_colorStack[m_colorStackIndex] = m_htmlColor;
                            m_colorStackIndex += 1;
                            return true;
                        }

                        // <color=name>
                        switch (attribute_1.hashCode)
                        {
                            case 112785: // <color=red>
                                m_htmlColor = Color.red;
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case 3027034: // <color=blue>
                                m_htmlColor = Color.blue;
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case 93818879: // <color=black>
                                m_htmlColor = Color.black;
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case 98619139: // <color=green>
                                m_htmlColor = Color.green;
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case 113101865: // <color=white>
                                m_htmlColor = Color.white;
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case -1008851410: // <color=orange>
                                m_htmlColor = new Color32(255, 128, 0, 255);
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case -976943172: // <color=purple>
                                m_htmlColor = new Color32(160, 32, 240, 255);
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case -734239628: // <color=yellow>
                                m_htmlColor = Color.yellow;
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                        }
                        return false;
                    case 1983971: // <cspace=xx.x>
                        value = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_cSpacing = value;
                                break;
                            case TagUnits.FontUnits:
                                m_cSpacing = value;
                                m_cSpacing *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.TabSize;
                                break;
                            case TagUnits.Percentage:
                                return false;
                        }
                        return true;
                    case 7513474: // </cspace>
                        m_cSpacing = 0;
                        return true;
                    case 2152041: // <mspace=xx.x>
                        value = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_monoSpacing = value;
                                break;
                            case TagUnits.FontUnits:
                                m_monoSpacing = value;
                                m_monoSpacing *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.TabSize;
                                break;
                            case TagUnits.Percentage:
                                return false;
                        }
                        return true;
                    case 7681544: // </mspace>
                        m_monoSpacing = 0;
                        return true;
                    case 280416: // <class="name">
                        return false;
                    case 1071884: // </color>
                        m_colorStackIndex -= 1;

                        if (m_colorStackIndex <= 0)
                        {
                            m_htmlColor = m_fontColor32;
                            m_colorStackIndex = 0;
                        }
                        else
                        {
                            m_htmlColor = m_colorStack[m_colorStackIndex - 1];
                        }

                        return true;
                    case 2068980: // <indent=10px> <indent=10em> <indent=50%>
                        value = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                tag_Indent = value;
                                break;
                            case TagUnits.FontUnits:
                                tag_Indent *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.TabSize;
                                break;
                            case TagUnits.Percentage:
                                tag_Indent = m_marginWidth * tag_Indent / 100;
                                break;
                        }

                        m_xAdvance = tag_Indent;
                        return true;
                    case 7598483: // </indent>
                        tag_Indent = 0;
                        return true;
                    case 1109386397: // <line-indent>
                        value = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                tag_LineIndent = value;
                                break;
                            case TagUnits.FontUnits:
                                tag_LineIndent = value;
                                tag_LineIndent *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.TabSize;
                                break;
                            case TagUnits.Percentage:
                                tag_LineIndent = m_marginWidth * tag_LineIndent / 100;
                                break;
                        }

                        m_xAdvance += tag_LineIndent;
                        return true;
                    case -445537194: // </line-indent>
                        tag_LineIndent = 0;
                        return true;
                    case 2246877: // <sprite=x>
                        if (m_inlineGraphics == null) m_inlineGraphics = GetComponent<InlineGraphicManager>() ?? gameObject.AddComponent<InlineGraphicManager>();

                        if (char.IsDigit(m_htmlTag[7]))
                        {
                            int index = (int)ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                            m_spriteIndex = m_inlineGraphics.GetSpriteIndexByIndex(index);
                            if (m_spriteIndex == -1)
                                return false;
                        }
                        else
                        {
                            // Get sprite index by looking it up by name.
                            m_spriteIndex = m_inlineGraphics.GetSpriteIndexByHashCode(attribute_1.hashCode);
                            if (m_spriteIndex == -1)
                                return false;
                            //Debug.Log("Sprite name is: \"" + new string(m_htmlTag, attribute_1.startIndex, attribute_1.length) + "\" with HashCode: " + attribute_1.hashCode);
                        }
                        m_isSprite = true;
                        return true;
                    case 13526026: // <allcaps>
                        m_style |= FontStyles.UpperCase;
                        return true;
                    case 52232547: // </allcaps>
                        m_style &= ~FontStyles.UpperCase;
                        return true;
                    case 766244328: // <smallcaps>
                        m_style |= FontStyles.SmallCaps;
                        return true;
                    case -1632103439: // </smallcaps>
                        m_style &= ~FontStyles.SmallCaps;
                        m_isRecalculateScaleRequired = true;
                        return true;
                    case 2109854: // <margin=00.0> <margin=00em> <margin=50%>
                        value = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos); // px
                        if (value == -9999 || value == 0) return false;

                        m_marginLeft = value;
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                // Default behavior
                                break;
                            case TagUnits.FontUnits:
                                m_marginLeft *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.TabSize;
                                break;
                            case TagUnits.Percentage:
                                m_marginLeft = (m_marginWidth - (m_width != -1 ? m_width : 0)) * m_marginLeft / 100;
                                break;
                        }
                        m_marginLeft = m_marginLeft >= 0 ? m_marginLeft : 0;
                        m_marginRight = m_marginLeft;
                        return true;
                    case 7639357: // </margin>
                        m_marginLeft = 0;
                        m_marginRight = 0;
                        return true;
                    case 1100728678: // <margin-left=xx.x>
                        value = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos); // px
                        if (value == -9999 || value == 0) return false;

                        m_marginLeft = value;
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                // Default behavior
                                break;
                            case TagUnits.FontUnits:
                                m_marginLeft *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.TabSize;
                                break;
                            case TagUnits.Percentage:
                                m_marginLeft = (m_marginWidth - (m_width != -1 ? m_width : 0)) * m_marginLeft / 100;
                                break;
                        }
                        m_marginLeft = m_marginLeft >= 0 ? m_marginLeft : 0;
                        return true;
                    case -884817987: // <margin-right=xx.x>
                        value = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos); // px
                        if (value == -9999 || value == 0) return false;

                        m_marginRight = value;
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                // Default behavior
                                break;
                            case TagUnits.FontUnits:
                                m_marginRight *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.TabSize;
                                break;
                            case TagUnits.Percentage:
                                m_marginRight = (m_marginWidth - (m_width != -1 ? m_width : 0)) * m_marginRight / 100;
                                break;
                        }
                        m_marginRight = m_marginRight >= 0 ? m_marginRight : 0;
                        return true;
                    case 1109349752: // <line-height=xx.x>
                        value = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                        if (value == -9999 || value == 0) return false;

                        m_lineHeight = value;
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_lineHeight /= m_fontScale;
                                break;
                            case TagUnits.FontUnits:
                                m_lineHeight *= m_fontAsset.fontInfo.LineHeight;
                                break;
                            case TagUnits.Percentage:
                                m_lineHeight = m_fontAsset.fontInfo.LineHeight * m_lineHeight / 100;
                                break;
                        }
                        return true;
                    case -445573839: // </line-height>
                        m_lineHeight = 0;
                        return true;
                    case 15115642: // <noparse>
                        tag_NoParsing = true;
                        return true;
                }
            }
            return false;
        }
Beispiel #35
0
        /// <summary>
        /// This is the main function that is responsible for creating / displaying the text.
        /// </summary>
        void GenerateTextMesh()
        {
            //Debug.Log("***** GenerateTextMesh() ***** Frame: " + Time.frameCount); // + ". Point Size: " + m_fontSize + ". Margins are (W) " + m_marginWidth + "  (H) " + m_marginHeight); // ". Iteration Count: " + loopCountA + ".  Min: " + m_minFontSize + "  Max: " + m_maxFontSize + "  Delta: " + (m_maxFontSize - m_minFontSize) + "  Font size is " + m_fontSize); //called for Object with ID " + GetInstanceID()); // Assigned Material is " + m_uiRenderer.GetMaterial().name); // IncludeForMasking " + this.m_IncludeForMasking); // and text is " + m_text);
            //Debug.Log(this.defaultMaterial.GetInstanceID() + "  " + m_sharedMaterial.GetInstanceID() + "  " + m_uiRenderer.GetMaterial().GetInstanceID());
            
            // Early exit if no font asset was assigned. This should not be needed since Arial SDF will be assigned by default.
            if (m_fontAsset.characterDictionary == null)
            {
                Debug.Log("Can't Generate Mesh! No Font Asset has been assigned to Object ID: " + this.GetInstanceID());
                return;
            }

            // Reset TextInfo
            if (m_textInfo != null)
                m_textInfo.Clear();


            // Early exit if we don't have any Text to generate.
            if (m_char_buffer == null || m_char_buffer.Length == 0 || m_char_buffer[0] == (char)0)
            {
                //Debug.Log("Early Out! No Text has been set.");
                //Vector3[] vertices = m_textInfo.meshInfo.vertices;

                m_uiRenderer.SetMesh(null);

                if (m_inlineGraphics != null) m_inlineGraphics.ClearUIVertex();
                
                /*
                if (vertices != null)
                {
                    Array.Clear(vertices, 0, vertices.Length);
                    m_textInfo.meshInfo.mesh.vertices = vertices; 
                }
                */

                m_preferredWidth = 0;
                m_preferredHeight = 0;
                m_renderedWidth = 0;
                m_renderedHeight = 0;

                // This should only be called if there is a layout component attached
                LayoutRebuilder.MarkLayoutForRebuild(m_rectTransform);
                return;
            }

            m_currentFontAsset = m_fontAsset;
            m_currentMaterial = m_sharedMaterial;

            // Determine how many characters will be visible and make the necessary allocations (if needed).
            int totalCharacterCount = SetArraySizes(m_char_buffer);

            // Scale the font to approximately match the point size
            m_fontScale = (m_fontSize / m_currentFontAsset.fontInfo.PointSize);
            float baseScale = m_fontScale; // BaseScale keeps the character aligned vertically since <size=+000> results in font of different scale.
            m_maxFontScale = baseScale;
            float previousLineMaxScale = baseScale;
            float firstVisibleCharacterScale = 0;
            float spriteScale = 1;
            m_currentFontSize = m_fontSize;
            float fontSizeDelta = 0;

            int charCode = 0; // Holds the character code of the currently being processed character.
            //int prev_charCode = 0;
            bool isMissingCharacter; // Used to handle missing characters in the Font Atlas / Definition.

            m_style = m_fontStyle; // Set the default style.
            m_lineJustification = m_textAlignment; // Sets the line justification mode to match editor alignment.

            // GetPadding to adjust the size of the mesh due to border thickness, softness, glow, etc...
            if (checkPaddingRequired)
            {
                checkPaddingRequired = false;
                m_padding = ShaderUtilities.GetPadding(m_uiRenderer.GetMaterial(), m_enableExtraPadding, m_isUsingBold);
                //m_alignmentPadding = ShaderUtilities.GetFontExtent(m_sharedMaterial);
                m_isMaskingEnabled = ShaderUtilities.IsMaskingEnabled(m_sharedMaterial);
            }

            float style_padding = 0; // Extra padding required to accommodate Bold style.
            float xadvance_multiplier = 1; // Used to increase spacing between character when style is bold.

            m_baselineOffset = 0; // Used by subscript characters.

            // Underline
            bool beginUnderline = false;
            Vector3 underline_start = Vector3.zero; // Used to track where underline starts & ends.
            Vector3 underline_end = Vector3.zero;

            // Strike-through
            bool beginStrikethrough = false;
            Vector3 strikethrough_start = Vector3.zero;
            Vector3 strikethrough_end = Vector3.zero;

            m_fontColor32 = m_fontColor;
            Color32 vertexColor;
            m_htmlColor = m_fontColor32;
            m_colorStackIndex = 0;
            Array.Clear(m_colorStack, 0, m_colorStack.Length);

            m_styleStackIndex = 0;
            Array.Clear(m_styleStack, 0, m_styleStack.Length);

            m_lineOffset = 0; // Amount of space between lines (font line spacing + m_linespacing).
            m_lineHeight = 0;

            m_cSpacing = 0; // Amount of space added between characters as a result of the use of the <cspace> tag.
            m_monoSpacing = 0;
            float lineOffsetDelta = 0;
            m_xAdvance = 0; // Used to track the position of each character.
            m_maxXAdvance = 0;

            tag_LineIndent = 0; // Used for indentation of text.
            tag_Indent = 0;
            tag_NoParsing = false;
            m_isIgnoringAlignment = false;

            m_characterCount = 0; // Total characters in the char[]
            m_visibleCharacterCount = 0; // # of visible characters.
            m_visibleSpriteCount = 0;

            // Tracking of line information
            m_firstCharacterOfLine = 0;
            m_lastCharacterOfLine = 0;
            m_firstVisibleCharacterOfLine = 0;
            m_lastVisibleCharacterOfLine = 0;
            m_lineNumber = 0;
            bool isStartOfNewLine = true;

            m_pageNumber = 0;
            int pageToDisplay = Mathf.Clamp(m_pageToDisplay - 1, 0, m_textInfo.pageInfo.Length - 1);

            int ellipsisIndex = 0;

            m_rectTransform.GetLocalCorners(m_rectCorners);
            Vector4 margins = m_margin;
            float marginWidth = m_marginWidth;
            float marginHeight = m_marginHeight;
            m_marginLeft = 0;
            m_marginRight = 0;
            m_width = -1;
            
            // Used by Unity's Auto Layout system.
            m_renderedWidth = 0;
            m_renderedHeight = 0;

            // Initialize struct to track states of word wrapping
            bool isFirstWord = true;
            bool isLastBreakingChar = false;
            //bool isEastAsianLanguage = false;
            m_SavedLineState = new WordWrapState();
            m_SavedWordWrapState = new WordWrapState();
            int wrappingIndex = 0;

            // Need to initialize these Extents structures
            m_meshExtents = new Extents(k_InfinityVector, -k_InfinityVector);

            // Initialize lineInfo
            if (m_textInfo.lineInfo == null) m_textInfo.lineInfo = new TMP_LineInfo[2];
            for (int i = 0; i < m_textInfo.lineInfo.Length; i++)
            {
                m_textInfo.lineInfo[i] = new TMP_LineInfo();
                m_textInfo.lineInfo[i].lineExtents = new Extents(k_InfinityVector, -k_InfinityVector);
                m_textInfo.lineInfo[i].ascender = -k_InfinityVector.x;
                m_textInfo.lineInfo[i].descender = k_InfinityVector.x;
            }


            // Tracking of the highest Ascender
            m_maxAscender = 0;
            m_maxDescender = 0;
            float pageAscender = 0;
            float maxVisibleDescender = 0;
            bool isMaxVisibleDescenderSet = false;
            m_isNewPage = false;

            loopCountA += 1;

            int endTagIndex = 0;
            // Parse through Character buffer to read HTML tags and begin creating mesh.
            for (int i = 0; m_char_buffer[i] != 0; i++)
            {
                charCode = m_char_buffer[i];
                m_isSprite = false;
                spriteScale = 1;

                //Debug.Log("i:" + i + "  Character [" + (char)charCode + "] with ASCII of " + charCode);
                //if (m_characterCount >= m_maxVisibleCharacters || m_lineNumber >= m_maxVisibleLines)
                //    break;

                // Parse Rich Text Tag
                #region Parse Rich Text Tag
                if (m_isRichText && charCode == 60)  // '<'
                {
                    m_isParsingText = true;

                    // Check if Tag is valid. If valid, skip to the end of the validated tag.
                    if (ValidateHtmlTag(m_char_buffer, i + 1, out endTagIndex))
                    {
                        i = endTagIndex;

                        if (m_isRecalculateScaleRequired)
                        {
                            m_fontScale = m_currentFontSize / m_currentFontAsset.fontInfo.PointSize;
                            m_isRecalculateScaleRequired = false;
                        }

                        if (!m_isSprite)
                            continue;
                    }
                }
                #endregion End Parse Rich Text Tag

                m_isParsingText = false;
                isMissingCharacter = false;

                // Check if we should be using a different font asset
                //if (m_fontIndex != 0)
                //{
                //    // Check if we need to load the new font asset
                //    if (m_currentFontAsset == null)
                //    {
                //        Debug.Log("Loading secondary font asset.");
                //        m_currentFontAsset = Resources.Load("Fonts & Materials/Bangers SDF", typeof(TextMeshProFont)) as TextMeshProFont;
                //        //m_sharedMaterials.Add(m_currentFontAsset.material);
                //        //m_renderer.sharedMaterials = new Material[] { m_sharedMaterial, m_currentFontAsset.material }; // m_sharedMaterials.ToArray();
                //    }
                //}               
                //Debug.Log("Char [" + (char)charCode + "] is using FontIndex: " + m_fontIndex);



                // Handle Font Styles like LowerCase, UpperCase and SmallCaps.
                #region Handling of LowerCase, UpperCase and SmallCaps Font Styles
                if ((m_style & FontStyles.UpperCase) == FontStyles.UpperCase)
                {
                    // If this character is lowercase, switch to uppercase.
                    if (char.IsLower((char)charCode))
                        charCode = char.ToUpper((char)charCode);

                }
                else if ((m_style & FontStyles.LowerCase) == FontStyles.LowerCase)
                {
                    // If this character is uppercase, switch to lowercase.
                    if (char.IsUpper((char)charCode))
                        charCode = char.ToLower((char)charCode);
                }
                else if ((m_fontStyle & FontStyles.SmallCaps) == FontStyles.SmallCaps || (m_style & FontStyles.SmallCaps) == FontStyles.SmallCaps)
                {
                    if (char.IsLower((char)charCode))
                    {
                        m_fontScale = m_currentFontSize * 0.8f / m_currentFontAsset.fontInfo.PointSize;
                        charCode = char.ToUpper((char)charCode);
                    }
                    else
                        m_fontScale = m_currentFontSize / m_currentFontAsset.fontInfo.PointSize;

                }
                #endregion


                // Look up Character Data from Dictionary and cache it.
                #region Look up Character Data
                if (m_isSprite)
                {
                    SpriteInfo spriteInfo = m_inlineGraphics.GetSprite(m_spriteIndex);
                    if (spriteInfo == null) continue;

                    // Sprites are assigned in the E000 Private Area + sprite Index
                    charCode = 57344 + m_spriteIndex;

                    m_cached_GlyphInfo = new GlyphInfo(); // Generates 40 bytes

                    m_cached_GlyphInfo.x = spriteInfo.x;
                    m_cached_GlyphInfo.y = spriteInfo.y;
                    m_cached_GlyphInfo.width = spriteInfo.width;
                    m_cached_GlyphInfo.height = spriteInfo.height;
                    m_cached_GlyphInfo.xOffset = spriteInfo.pivot.x + spriteInfo.xOffset;
                    m_cached_GlyphInfo.yOffset = spriteInfo.pivot.y + spriteInfo.yOffset;

                    spriteScale = m_fontAsset.fontInfo.Ascender / spriteInfo.height * spriteInfo.scale;
                   
                    m_cached_GlyphInfo.xAdvance = spriteInfo.xAdvance * spriteScale;

                    m_textInfo.characterInfo[m_characterCount].type = TMP_CharacterType.Sprite;
                }
                else
                {
                    m_currentFontAsset.characterDictionary.TryGetValue(charCode, out m_cached_GlyphInfo);
                    if (m_cached_GlyphInfo == null)
                    {
                        // Character wasn't found in the Dictionary.

                        if (char.IsLower((char)charCode))
                        {
                            if (m_currentFontAsset.characterDictionary.TryGetValue(char.ToUpper((char)charCode), out m_cached_GlyphInfo))
                                charCode = char.ToUpper((char)charCode);
                        }
                        else if (char.IsUpper((char)charCode))
                        {
                            if (m_currentFontAsset.characterDictionary.TryGetValue(char.ToLower((char)charCode), out m_cached_GlyphInfo))
                                charCode = char.ToLower((char)charCode);
                        }

                        // Still don't have a replacement?
                        if (m_cached_GlyphInfo == null)
                        {
                            m_currentFontAsset.characterDictionary.TryGetValue(88, out m_cached_GlyphInfo);
                            if (m_cached_GlyphInfo != null)
                            {
                                Debug.LogWarning("Character with ASCII value of " + charCode + " was not found in the Font Asset Glyph Table.", this);
                                // Replace the missing character by X (if it is found)
                                charCode = 88;
                                isMissingCharacter = true;
                            }
                            else
                            {  // At this point the character isn't in the Dictionary, the replacement X isn't either so ...
                                Debug.LogWarning("Character with ASCII value of " + charCode + " was not found in the Font Asset Glyph Table.", this);
                                continue;
                            }
                        }
                    }

                    m_textInfo.characterInfo[m_characterCount].type = TMP_CharacterType.Character;
                }
                #endregion

                // Store some of the text object's information
                m_textInfo.characterInfo[m_characterCount].character = (char)charCode;
                m_textInfo.characterInfo[m_characterCount].pointSize = m_currentFontSize;
                m_textInfo.characterInfo[m_characterCount].color = m_htmlColor;
                m_textInfo.characterInfo[m_characterCount].style = m_style;
                m_textInfo.characterInfo[m_characterCount].index = (short)i;
                //m_textInfo.characterInfo[m_characterCount].isIgnoringAlignment = m_isIgnoringAlignment;


                // Handle Kerning if Enabled.
                #region Handle Kerning
                if (m_enableKerning && m_characterCount >= 1)
                {
                    int prev_charCode = m_textInfo.characterInfo[m_characterCount - 1].character;
                    KerningPairKey keyValue = new KerningPairKey(prev_charCode, charCode);

                    KerningPair pair;

                    m_currentFontAsset.kerningDictionary.TryGetValue(keyValue.key, out pair);
                    if (pair != null)
                    {
                        m_xAdvance += pair.XadvanceOffset * m_fontScale;
                    }
                }
                #endregion


                // Handle Mono Spacing
                #region Handle Mono Spacing
                float monoAdvance = 0;
                if (m_monoSpacing != 0)
                {
                    monoAdvance = (m_monoSpacing / 2 - (m_cached_GlyphInfo.width / 2 + m_cached_GlyphInfo.xOffset) * m_fontScale) * (1 - m_charWidthAdjDelta);
                    m_xAdvance += monoAdvance;
                }
                #endregion


                // Set Padding based on selected font style
                #region Handle Style Padding
                if ((m_style & FontStyles.Bold) == FontStyles.Bold || (m_fontStyle & FontStyles.Bold) == FontStyles.Bold) // Checks for any combination of Bold Style.
                {
                    style_padding = m_currentFontAsset.BoldStyle * 2;
                    xadvance_multiplier = 1 + m_currentFontAsset.boldSpacing * 0.01f;
                }
                else
                {
                    style_padding = m_currentFontAsset.NormalStyle * 2;
                    xadvance_multiplier = 1.0f;
                }
                #endregion Handle Style Padding


                // Set padding value if Character or Sprite
                float padding = m_isSprite ? 0 : m_padding;

                // Determine the position of the vertices of the Character or Sprite.
                Vector3 top_left = new Vector3(0 + m_xAdvance + ((m_cached_GlyphInfo.xOffset - padding - style_padding) * m_fontScale * spriteScale * (1 - m_charWidthAdjDelta)), (m_cached_GlyphInfo.yOffset + padding) * m_fontScale * spriteScale - m_lineOffset + m_baselineOffset, 0);
                Vector3 bottom_left = new Vector3(top_left.x, top_left.y - ((m_cached_GlyphInfo.height + padding * 2) * m_fontScale * spriteScale), 0);
                Vector3 top_right = new Vector3(bottom_left.x + ((m_cached_GlyphInfo.width + padding * 2 + style_padding * 2) * m_fontScale * spriteScale * (1 - m_charWidthAdjDelta)), top_left.y, 0);
                Vector3 bottom_right = new Vector3(top_right.x, bottom_left.y, 0);

                // Check if we need to Shear the rectangles for Italic styles
                #region Handle Italic & Shearing
                if ((m_style & FontStyles.Italic) == FontStyles.Italic || (m_fontStyle & FontStyles.Italic) == FontStyles.Italic)
                {
                    // Shift Top vertices forward by half (Shear Value * height of character) and Bottom vertices back by same amount. 
                    float shear_value = m_currentFontAsset.ItalicStyle * 0.01f;
                    Vector3 topShear = new Vector3(shear_value * ((m_cached_GlyphInfo.yOffset + padding + style_padding) * m_fontScale * spriteScale), 0, 0);
                    Vector3 bottomShear = new Vector3(shear_value * (((m_cached_GlyphInfo.yOffset - m_cached_GlyphInfo.height - padding - style_padding)) * m_fontScale * spriteScale), 0, 0);

                    top_left = top_left + topShear;
                    bottom_left = bottom_left + bottomShear;
                    top_right = top_right + topShear;
                    bottom_right = bottom_right + bottomShear;
                }
                #endregion Handle Italics & Shearing


                // Store position of the vertices for the Character or Sprite.
                m_textInfo.characterInfo[m_characterCount].bottomLeft = bottom_left;
                m_textInfo.characterInfo[m_characterCount].topLeft = top_left;
                m_textInfo.characterInfo[m_characterCount].topRight = top_right;
                m_textInfo.characterInfo[m_characterCount].bottomRight = bottom_right;
                m_textInfo.characterInfo[m_characterCount].baseLine = 0 - m_lineOffset + m_baselineOffset;
                m_textInfo.characterInfo[m_characterCount].scale = m_fontScale;


                // Compute MaxAscender & MaxDescender which is used for AutoScaling & other type layout options
                float ascender = m_fontAsset.fontInfo.Ascender * m_fontScale + m_baselineOffset;
                if ((charCode == 10 || charCode == 13) && m_characterCount > m_firstVisibleCharacterOfLine)
                    ascender = m_baselineOffset;

                float descender = m_fontAsset.fontInfo.Descender * m_fontScale - m_lineOffset + m_baselineOffset;

                // Check if Sprite exceeds the Ascender and Descender of the font and if so make the adjustment.
                if (m_isSprite)
                {
                    ascender = Mathf.Max(ascender, top_left.y - padding * m_fontScale * spriteScale);
                    descender = Mathf.Min(descender, bottom_right.y - padding * m_fontScale * spriteScale);
                }

                if (m_lineNumber == 0) m_maxAscender = m_maxAscender > ascender ? m_maxAscender : ascender;
                if (m_lineOffset == 0) pageAscender = pageAscender > ascender ? pageAscender : ascender;

                // Track Line Height
                //maxLineHeight = Mathf.Max(m_lineHeight, maxLineHeight);

                // Used to adjust line spacing when larger fonts or the size tag is used.
                if (m_baselineOffset == 0)
                    m_maxFontScale = Mathf.Max(m_maxFontScale, m_fontScale);

                // Set Characters to not visible by default.
                m_textInfo.characterInfo[m_characterCount].isVisible = false;


                // Setup Mesh for visible characters or sprites. ie. not a SPACE / LINEFEED / CARRIAGE RETURN.
                #region Handle Visible Characters
                if (charCode != 10 && charCode != 13 && charCode != 32 && charCode != 160 || m_isSprite)
                {
                    m_textInfo.characterInfo[m_characterCount].isVisible = true;
                    //if (isStartOfNewLine) { isStartOfNewLine = false; m_firstVisibleCharacterOfLine = m_characterCount; }

                    // Check if Character exceeds the width of the Text Container
                    #region Check for Characters Exceeding Width of Text Container
                    float width = m_width != -1 ? Mathf.Min(marginWidth + 0.0001f - m_marginLeft - m_marginRight, m_width) : marginWidth + 0.0001f - m_marginLeft - m_marginRight;

                    m_textInfo.lineInfo[m_lineNumber].width = width;
                    m_textInfo.lineInfo[m_lineNumber].marginLeft = m_marginLeft;

                    if (m_xAdvance + m_cached_GlyphInfo.xAdvance * (1 - m_charWidthAdjDelta) * m_fontScale > width)
                    {
                        ellipsisIndex = m_characterCount - 1; // Last safely rendered character

                        // Word Wrapping
                        #region Handle Word Wrapping
                        if (enableWordWrapping && m_characterCount != m_firstCharacterOfLine)
                        {

                            if (wrappingIndex == m_SavedWordWrapState.previous_WordBreak || isFirstWord)
                            {
                                // Word wrapping is no longer possible. Shrink size of text if auto-sizing is enabled.
                                if (m_enableAutoSizing && m_fontSize > m_fontSizeMin)
                                {

                                    // Handle Character Width Adjustments
                                    #region Character Width Adjustments
                                    if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100)
                                    {
                                        loopCountA = 0;
                                        m_charWidthAdjDelta += 0.01f;
                                        GenerateTextMesh();
                                        return;
                                    }
                                    #endregion
 
                                    // Adjust Point Size 
                                    m_maxFontSize = m_fontSize;

                                    m_fontSize -= Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f);
                                    m_fontSize = (int)(Mathf.Max(m_fontSize, m_fontSizeMin) * 20 + 0.5f) / 20f;

                                    if (loopCountA > 20) return; // Added to debug
                                    GenerateTextMesh();
                                    return;
                                }

                                // Word wrapping is no longer possible, now breaking up individual words.
                                if (m_isCharacterWrappingEnabled == false)
                                {
                                    m_isCharacterWrappingEnabled = true;
                                }
                                else
                                    isLastBreakingChar = true;

                                //Debug.Log("Wrapping Index " + wrappingIndex + ". Recursive Count: " + m_recursiveCount);

                                m_recursiveCount += 1;
                                if (m_recursiveCount > 20)
                                {
                                    //Debug.Log("Recursive count exceeded!");
                                    continue;
                                }

                                //Debug.Log("Line #" + m_lineNumber + " Character [" + (char)charCode + "] cannot be wrapped.  WrappingIndex: " + wrappingIndex + "  Saved Index: " + m_SavedWordWrapState.previous_WordBreak + ". Character Count is " + m_characterCount);
                            }


                            // Restore to previously stored state of last valid (space character or linefeed)
                            i = RestoreWordWrappingState(ref m_SavedWordWrapState);
                            wrappingIndex = i;  // Used to detect when line length can no longer be reduced.

                            //Debug.Log("Last Visible Character of line # " + m_lineNumber + " is [" + m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].character + " Character Count: " + m_characterCount + " Last visible: " + m_lastVisibleCharacterOfLine);

                            // Check if Line Spacing of previous line needs to be adjusted.
                            FaceInfo face = m_currentFontAsset.fontInfo;
                            float gap = m_lineHeight == 0 ? face.LineHeight - (face.Ascender - face.Descender) : m_lineHeight - (face.Ascender - face.Descender);
                            if (m_lineNumber > 0 && m_maxFontScale != 0 && m_lineHeight == 0 && firstVisibleCharacterScale != m_maxFontScale && !m_isNewPage)
                            {
                                float offsetDelta = 0 - face.Descender * previousLineMaxScale + (face.Ascender + gap + m_lineSpacing + m_paragraphSpacing + m_lineSpacingDelta) * m_maxFontScale;
                                m_lineOffset += offsetDelta - lineOffsetDelta;
                                AdjustLineOffset(m_firstCharacterOfLine, m_characterCount - 1, offsetDelta - lineOffsetDelta);
                                m_SavedWordWrapState.lineOffset = m_lineOffset;
                            }
                            m_isNewPage = false;


                            // Calculate lineAscender & make sure if last character is superscript or subscript that we check that as well.
                            float lineAscender = m_fontAsset.fontInfo.Ascender * m_maxFontScale - m_lineOffset;
                            float lineAscender2 = m_fontAsset.fontInfo.Ascender * m_fontScale - m_lineOffset + m_baselineOffset;
                            lineAscender = lineAscender > lineAscender2 ? lineAscender : lineAscender2;

                            // Calculate lineDescender & make sure if last character is superscript or subscript that we check that as well.
                            float lineDescender = m_fontAsset.fontInfo.Descender * m_maxFontScale - m_lineOffset;
                            float lineDescender2 = m_fontAsset.fontInfo.Descender * m_fontScale - m_lineOffset + m_baselineOffset;
                            lineDescender = lineDescender < lineDescender2 ? lineDescender : lineDescender2;

                            // Update maxDescender and maxVisibleDescender
                            m_maxDescender = m_maxDescender < lineDescender ? m_maxDescender : lineDescender;
                            if (!isMaxVisibleDescenderSet)
                                maxVisibleDescender = m_maxDescender;

                            if (m_characterCount >= m_maxVisibleCharacters || m_lineNumber >= m_maxVisibleLines)
                                isMaxVisibleDescenderSet = true;

                            // Track & Store lineInfo for the new line
                            m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex = m_firstCharacterOfLine;
                            m_textInfo.lineInfo[m_lineNumber].firstVisibleCharacterIndex = m_firstVisibleCharacterOfLine;
                            m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex = m_characterCount - 1 > 0 ? m_characterCount - 1 : 0;
                            m_textInfo.lineInfo[m_lineNumber].lastVisibleCharacterIndex = m_lastVisibleCharacterOfLine;
                            m_textInfo.lineInfo[m_lineNumber].characterCount = m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex - m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex + 1;

                            m_textInfo.lineInfo[m_lineNumber].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_firstVisibleCharacterOfLine].bottomLeft.x, lineDescender);
                            m_textInfo.lineInfo[m_lineNumber].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].topRight.x, lineAscender);
                            m_textInfo.lineInfo[m_lineNumber].lineLength = m_textInfo.lineInfo[m_lineNumber].lineExtents.max.x - padding * m_maxFontScale;
                            m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].xAdvance - m_characterSpacing * m_fontScale;
                            m_textInfo.lineInfo[m_lineNumber].maxScale = m_maxFontScale;

                            m_firstCharacterOfLine = m_characterCount; // Store first character of the next line.

                            // Compute Preferred Width & Height
                            m_renderedWidth += m_xAdvance;
                            if (m_enableWordWrapping)
                                m_renderedHeight = m_maxAscender - m_maxDescender;
                            else
                                m_renderedHeight = Mathf.Max(m_renderedHeight, lineAscender - lineDescender);

                            //Debug.Log("Line # " + m_lineNumber + "  Max Font Scale: " + m_maxFontScale + "  Current Font Scale: " + currentFontScale);
                            //Debug.Log("LineInfo for line # " + (m_lineNumber) + " First character [" + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex].character + "] at Index: " + m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex +
                            //                                                    " First visible character [" + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].firstVisibleCharacterIndex].character + "] at Index: " + m_textInfo.lineInfo[m_lineNumber].firstVisibleCharacterIndex +
                            //                                                    " Last character [" + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex].character + "] at index: " + m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex +
                            //                                                    " Last Visible character [" + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].lastVisibleCharacterIndex].character + "] at index: " + m_textInfo.lineInfo[m_lineNumber].lastVisibleCharacterIndex +
                            //                                                    " Character Count of " + m_textInfo.lineInfo[m_lineNumber].characterCount /* + " Line Length of " + m_textInfo.lineInfo[m_lineNumber].lineLength +
                            //                                                    "  MinX: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.min.x + "  MinY: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.min.y +
                            //                                                    "  MaxX: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.max.x + "  MaxY: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.max.y +
                            //                                                    "  Line Ascender: " + lineAscender + "  Line Descender: " + lineDescender */ );

                            // Store the state of the line before starting on the new line.
                            SaveWordWrappingState(ref m_SavedLineState, i, m_characterCount - 1);

                            m_lineNumber += 1;
                            isStartOfNewLine = true;

                            // Check to make sure Array is large enough to hold a new line.
                            if (m_lineNumber >= m_textInfo.lineInfo.Length)
                                ResizeLineExtents(m_lineNumber);

                            // Apply Line Spacing based on scale of the last character of the line.
                            FontStyles style = m_textInfo.characterInfo[m_characterCount].style;
                            float scale = (style & FontStyles.Subscript) == FontStyles.Subscript || (style & FontStyles.Superscript) == FontStyles.Superscript ? m_maxFontScale : m_textInfo.characterInfo[m_characterCount].scale;
                            lineOffsetDelta = 0 - face.Descender * m_maxFontScale + (face.Ascender + gap + m_lineSpacing + m_lineSpacingDelta) * scale;
                            m_lineOffset += lineOffsetDelta;


                            previousLineMaxScale = m_maxFontScale;
                            firstVisibleCharacterScale = scale;
                            m_maxFontScale = 0;
                            spriteScale = 1;
                            m_xAdvance = 0 + tag_Indent;

                            continue;
                        }
                        #endregion End Word Wrapping


                        // Text Auto-Sizing (text exceeding Width of container. 
                        #region Handle Text Auto-Sizing
                        if (m_enableAutoSizing && m_fontSize > m_fontSizeMin)
                        {
                            // Handle Character Width Adjustments
                            #region Character Width Adjustments
                            if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100)
                            {
                                loopCountA = 0;
                                m_charWidthAdjDelta += 0.01f;
                                GenerateTextMesh();
                                return;
                            }
                            #endregion

                            // Adjust Point Size
                            m_maxFontSize = m_fontSize;

                            m_fontSize -= Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f);
                            m_fontSize = (int)(Mathf.Max(m_fontSize, m_fontSizeMin) * 20 + 0.5f) / 20f;

                            m_recursiveCount = 0;
                            if (loopCountA > 20) return; // Added to debug 
                            GenerateTextMesh();
                            return;
                        }
                        #endregion End Text Auto-Sizing


                        // Handle Text Overflow
                        #region Handle Text Overflow
                        switch (m_overflowMode)
                        {
                            case TextOverflowModes.Overflow:
                                if (m_isMaskingEnabled)
                                    DisableMasking();

                                break;
                            case TextOverflowModes.Ellipsis:
                                if (m_isMaskingEnabled)
                                    DisableMasking();

                                m_isTextTruncated = true;

                                if (m_characterCount < 1)
                                {
                                    m_textInfo.characterInfo[m_characterCount].isVisible = false;
                                    m_visibleCharacterCount -= 1;
                                    break;
                                }

                                m_char_buffer[i - 1] = 8230;
                                m_char_buffer[i] = (char)0;

                                GenerateTextMesh();
                                return;
                            case TextOverflowModes.Masking:
                                if (!m_isMaskingEnabled)
                                    EnableMasking();
                                break;
                            case TextOverflowModes.ScrollRect:
                                if (!m_isMaskingEnabled)
                                    EnableMasking();
                                break;
                            case TextOverflowModes.Truncate:
                                if (m_isMaskingEnabled)
                                    DisableMasking();

                                m_textInfo.characterInfo[m_characterCount].isVisible = false;
                                break;
                        }
                        #endregion End Text Overflow

                    }
                    #endregion End Check for Characters Exceeding Width of Text Container

                    if (charCode != 9)
                    {
                        // Determine Vertex Color
                        if (isMissingCharacter)
                            vertexColor = Color.red;
                        else if (m_overrideHtmlColors)
                            vertexColor = m_fontColor32;
                        else
                            vertexColor = m_htmlColor;


                        // Store Character & Sprite Vertex Information
                        if (!m_isSprite)
                            SaveGlyphVertexInfo(style_padding, vertexColor);
                        else
                            SaveSpriteVertexInfo(vertexColor);
                    }
                    else // If character is Tab
                    {
                        m_textInfo.characterInfo[m_characterCount].isVisible = false;
                        m_lastVisibleCharacterOfLine = m_characterCount;
                        m_textInfo.lineInfo[m_lineNumber].spaceCount += 1;
                        m_textInfo.spaceCount += 1;
                    }

                    // Increase visible count for Characters.
                    if (m_textInfo.characterInfo[m_characterCount].isVisible)
                    {
                        if (m_isSprite)
                            m_visibleSpriteCount += 1;
                        else
                            m_visibleCharacterCount += 1;

                        if (isStartOfNewLine) { isStartOfNewLine = false; m_firstVisibleCharacterOfLine = m_characterCount; }
                        m_lastVisibleCharacterOfLine = m_characterCount;
                    }

                }
                else
                {   // This is a Space, Tab, LineFeed or Carriage Return

                    // Track # of spaces per line which is used for line justification.
                    if (charCode == 9 || charCode == 32 || charCode == 160)
                    {
                        m_textInfo.lineInfo[m_lineNumber].spaceCount += 1;
                        m_textInfo.spaceCount += 1;
                    }
                }
                #endregion Handle Visible Characters


                // Store Rectangle positions for each Character.
                #region Store Character Data
                m_textInfo.characterInfo[m_characterCount].lineNumber = (short)m_lineNumber;
                m_textInfo.characterInfo[m_characterCount].pageNumber = (short)m_pageNumber;

                if (charCode != 10 && charCode != 13 && charCode != 8230 || m_textInfo.lineInfo[m_lineNumber].characterCount == 1)
                    m_textInfo.lineInfo[m_lineNumber].alignment = m_lineJustification;
                #endregion Store Character Data


                // Check if text Exceeds the vertical bounds of the margin area.
                #region Check Vertical Bounds & Auto-Sizing
                if (m_maxAscender - descender > marginHeight + 0.0001f)
                {
                    //Debug.Log((m_maxAscender - descender + (m_alignmentPadding.w * 2 * m_fontScale)).ToString("f6") + "  " + marginHeight.ToString("f6"));
                    //Debug.Log("Character [" + (char)charCode + "] at Index: " + m_characterCount + " has exceeded the Height of the text container. Max Ascender: " + m_maxAscender + "  Max Descender: " + m_maxDescender + "  Margin Height: " + marginHeight + " Bottom Left: " + bottom_left.y);                                              

                    // Handle Line spacing adjustments
                    #region Line Spacing Adjustments
                    if (m_enableAutoSizing && m_lineSpacingDelta > m_lineSpacingMax && m_lineNumber > 0)
                    {
                        m_lineSpacingDelta -= 1;
                        GenerateTextMesh();
                        return;
                    }
                    #endregion


                    // Handle Text Auto-sizing resulting from text exceeding vertical bounds.
                    #region Text Auto-Sizing (Text greater than vertical bounds)
                    if (m_enableAutoSizing && m_fontSize > m_fontSizeMin)
                    {
                        m_maxFontSize = m_fontSize;

                        m_fontSize -= Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f);
                        m_fontSize = (int)(Mathf.Max(m_fontSize, m_fontSizeMin) * 20 + 0.5f) / 20f;

                        m_recursiveCount = 0;
                        if (loopCountA > 20) return; // Added to debug 
                        GenerateTextMesh();
                        return;
                    }
                    #endregion Text Auto-Sizing


                    // Handle Text Overflow
                    #region Text Overflow
                    switch (m_overflowMode)
                    {
                        case TextOverflowModes.Overflow:
                            if (m_isMaskingEnabled)
                                DisableMasking();

                            break;
                        case TextOverflowModes.Ellipsis:
                            if (m_isMaskingEnabled)
                                DisableMasking();

                            if (m_lineNumber > 0)
                            {
                                m_char_buffer[m_textInfo.characterInfo[ellipsisIndex].index] = 8230;
                                m_char_buffer[m_textInfo.characterInfo[ellipsisIndex].index + 1] = (char)0;
                                GenerateTextMesh();
                                m_isTextTruncated = true;
                                return;
                            }
                            else
                            {
                                m_char_buffer[0] = (char)0;
                                GenerateTextMesh();
                                m_isTextTruncated = true;
                                return;
                            }
                        case TextOverflowModes.Masking:
                            if (!m_isMaskingEnabled)
                                EnableMasking();
                            break;
                        case TextOverflowModes.ScrollRect:
                            if (!m_isMaskingEnabled)
                                EnableMasking();
                            break;
                        case TextOverflowModes.Truncate:
                         if (m_isMaskingEnabled)
                                DisableMasking();
                    
                            // Alternative Implementation 
                            //if (m_lineNumber > 0)
                            //{
                            //    if (!m_isTextTruncated && m_textInfo.characterInfo[ellipsisIndex + 1].character != 10)
                            //    {
                            //        Debug.Log("Char [" + (char)charCode + "] on line " + m_lineNumber + " exceeds the vertical bounds. Last safe character was " + (int)m_textInfo.characterInfo[ellipsisIndex + 1].character);
                            //        i = RestoreWordWrappingState(ref m_SavedWordWrapState);
                            //        m_lineNumber -= 1;
                            //        m_isTextTruncated = true;
                            //        m_isCharacterWrappingEnabled = true;
                            //        continue;
                            //    }
                            //    else
                            //    {
                            //        //Debug.Log("Char [" + (char)charCode + "] on line " + m_lineNumber + " set to invisible.");
                            //        m_textInfo.characterInfo[m_characterCount].isVisible = false;
                            //    }
                            ////    m_char_buffer[m_textInfo.characterInfo[ellipsisIndex].index + 1] = (char)0;
                            ////    m_isTextTruncated = true;
                            ////    i = RestoreWordWrappingState(ref m_SavedLineState);
                            ////    m_lineNumber -= 1;
                            
                            ////    continue;
                            //}
                            //break;

                            
                            // TODO : Optimize 
                            if (m_lineNumber > 0)
                            {
                                m_char_buffer[m_textInfo.characterInfo[ellipsisIndex].index + 1] = (char)0;
                                GenerateTextMesh();
                                m_isTextTruncated = true;
                                return;
                            }
                            else
                            {
                                m_char_buffer[0] = (char)0;
                                GenerateTextMesh();
                                m_isTextTruncated = true;
                                return;
                            }
                        case TextOverflowModes.Page:
                            if (m_isMaskingEnabled)
                                DisableMasking();

                            // Ignore Page Break, Linefeed or carriage return
                            if (charCode == 13 || charCode == 10)
                                break;

                            //Debug.Log("Character is [" + (char)charCode + "] with ASCII (" + charCode + ") on Page " + m_pageNumber + ". Ascender: " + m_textInfo.pageInfo[m_pageNumber].ascender + "  BaseLine: " + m_textInfo.pageInfo[m_pageNumber].baseLine + "  Descender: " + m_textInfo.pageInfo[m_pageNumber].descender);                          

                            // Go back to previous line and re-layout 
                            i = RestoreWordWrappingState(ref m_SavedLineState);
                            if (i == 0)
                            {
                                m_char_buffer[0] = (char)0;
                                GenerateTextMesh();
                                m_isTextTruncated = true;
                                return;
                            }

                            m_isNewPage = true;
                            m_xAdvance = 0 + tag_Indent;
                            m_lineOffset = 0;
                            m_lineNumber += 1;
                            m_pageNumber += 1;
                            continue;
                    }
                    #endregion End Text Overflow

                }
                #endregion Check Vertical Bounds


                // Handle xAdvance & Tabulation Stops. Tab stops at every 25% of Font Size.
                #region XAdvance, Tabulation & Stops
                if (charCode == 9)
                    m_xAdvance += m_fontAsset.fontInfo.TabWidth * m_fontScale;
                else if (m_monoSpacing != 0)
                    m_xAdvance += (m_monoSpacing - monoAdvance + (m_characterSpacing * m_fontScale) + m_cSpacing) * (1 - m_charWidthAdjDelta);
                else
                    m_xAdvance += ((m_cached_GlyphInfo.xAdvance * xadvance_multiplier + m_characterSpacing) * m_fontScale + m_cSpacing) * (1 - m_charWidthAdjDelta);


                // Store xAdvance information
                m_textInfo.characterInfo[m_characterCount].xAdvance = m_xAdvance;

                #endregion Tabulation & Stops


                // Handle Carriage Return
                #region Carriage Return
                if (charCode == 13)
                {
                    m_maxXAdvance = Mathf.Max(m_maxXAdvance, m_renderedWidth + m_xAdvance);
                    m_renderedWidth = 0;
                    m_xAdvance = 0 + tag_Indent;
                }
                #endregion Carriage Return


                // Handle Line Spacing Adjustments + Word Wrapping & special case for last line.
                #region Check for Line Feed and Last Character
                if (charCode == 10 || m_characterCount == totalCharacterCount - 1)
                {
                    // Check if Line Spacing of previous line needs to be adjusted.
                    FaceInfo face = m_currentFontAsset.fontInfo;
                    float gap = m_lineHeight == 0 ? face.LineHeight - (face.Ascender - face.Descender) : m_lineHeight - (face.Ascender - face.Descender);
                    if (m_lineNumber > 0 && m_maxFontScale != 0 && m_lineHeight == 0 && firstVisibleCharacterScale != m_maxFontScale && !m_isNewPage)
                    {
                        float offsetDelta = 0 - face.Descender * previousLineMaxScale + (face.Ascender + gap + m_lineSpacing + m_paragraphSpacing + m_lineSpacingDelta) * m_maxFontScale;
                        m_lineOffset += offsetDelta - lineOffsetDelta;
                        AdjustLineOffset(m_firstCharacterOfLine, m_characterCount, offsetDelta - lineOffsetDelta);
                    }
                    m_isNewPage = false;

                    // Calculate lineAscender & make sure if last character is superscript or subscript that we check that as well.
                    float lineAscender = m_fontAsset.fontInfo.Ascender * m_maxFontScale - m_lineOffset;
                    float lineAscender2 = m_fontAsset.fontInfo.Ascender * m_fontScale - m_lineOffset + m_baselineOffset;
                    lineAscender = lineAscender > lineAscender2 ? lineAscender : lineAscender2;

                    // Calculate lineDescender & make sure if last character is superscript or subscript that we check that as well.
                    float lineDescender = m_fontAsset.fontInfo.Descender * m_maxFontScale - m_lineOffset;
                    float lineDescender2 = m_fontAsset.fontInfo.Descender * m_fontScale - m_lineOffset + m_baselineOffset;
                    lineDescender = lineDescender < lineDescender2 ? lineDescender : lineDescender2;

                    // Update maxDescender and maxVisibleDescender
                    m_maxDescender = m_maxDescender < lineDescender ? m_maxDescender : lineDescender;
                    if (!isMaxVisibleDescenderSet)
                        maxVisibleDescender = m_maxDescender;

                    if (m_characterCount >= m_maxVisibleCharacters || m_lineNumber >= m_maxVisibleLines)
                        isMaxVisibleDescenderSet = true;

                    // Save Line Information
                    m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex = m_firstCharacterOfLine;
                    m_textInfo.lineInfo[m_lineNumber].firstVisibleCharacterIndex = m_firstVisibleCharacterOfLine;
                    m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex = m_characterCount;
                    m_textInfo.lineInfo[m_lineNumber].lastVisibleCharacterIndex = m_lastVisibleCharacterOfLine >= m_firstVisibleCharacterOfLine ? m_lastVisibleCharacterOfLine : m_firstVisibleCharacterOfLine;
                    m_textInfo.lineInfo[m_lineNumber].characterCount = m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex - m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex + 1;

                    m_textInfo.lineInfo[m_lineNumber].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_firstVisibleCharacterOfLine].bottomLeft.x, lineDescender);
                    m_textInfo.lineInfo[m_lineNumber].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].topRight.x, lineAscender);
                    m_textInfo.lineInfo[m_lineNumber].lineLength = m_textInfo.lineInfo[m_lineNumber].lineExtents.max.x - (padding * m_maxFontScale);
                    m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].xAdvance - m_characterSpacing * m_fontScale;
                    m_textInfo.lineInfo[m_lineNumber].maxScale = m_maxFontScale;

                    m_firstCharacterOfLine = m_characterCount + 1;

                    // Store PreferredWidth paying attention to linefeed and last character of text.
                    if (charCode == 10 && m_characterCount != totalCharacterCount - 1)
                    {
                        m_maxXAdvance = Mathf.Max(m_maxXAdvance, m_renderedWidth + m_xAdvance);
                        m_renderedWidth = 0;
                    }
                    else
                        m_renderedWidth = Mathf.Max(m_maxXAdvance, m_renderedWidth + m_xAdvance);
               
                    m_renderedHeight = m_maxAscender - m_maxDescender;

                    //Debug.Log("Line # " + m_lineNumber + "  Max Font Scale: " + m_maxFontScale + "  Next line Scale: " + m_fontScale);
                    //Debug.Log("LineInfo for line # " + (m_lineNumber) + " First character [" + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex].character + "] at Index: " + m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex +
                    //                                                    " First visible character [" + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].firstVisibleCharacterIndex].character + "] at Index: " + m_textInfo.lineInfo[m_lineNumber].firstVisibleCharacterIndex +
                    //                                                    " Last character [" + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex].character + "] at index: " + m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex +
                    //                                                    " Last Visible character [" + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].lastVisibleCharacterIndex].character + "] at index: " + m_textInfo.lineInfo[m_lineNumber].lastVisibleCharacterIndex +
                    //                                                    " Character Count of " + m_textInfo.lineInfo[m_lineNumber].characterCount /* + " Line Length of " + m_textInfo.lineInfo[m_lineNumber].lineLength +
                    //                                                    "  MinX: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.min.x + "  MinY: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.min.y +
                    //                                                    "  MaxX: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.max.x + "  MaxY: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.max.y +
                    //                                                    "  Line Ascender: " + lineAscender + "  Line Descender: " + lineDescender */ );


                    // Add new line if not last lines or character.
                    if (charCode == 10)
                    {
                        // Store the state of the line before starting on the new line.
                        SaveWordWrappingState(ref m_SavedLineState, i, m_characterCount);
                        // Store the state of the last Character before the new line.
                        SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);

                        m_lineNumber += 1;
                        isStartOfNewLine = true;

                        // Check to make sure Array is large enough to hold a new line.
                        if (m_lineNumber >= m_textInfo.lineInfo.Length)
                            ResizeLineExtents(m_lineNumber);

                        // Apply Line Spacing
                        float scale = (m_style & FontStyles.Subscript) == FontStyles.Subscript || (m_style & FontStyles.Superscript) == FontStyles.Superscript ? m_maxFontScale : m_fontScale;
                        lineOffsetDelta = 0 - face.Descender * m_maxFontScale + (face.Ascender + gap + m_lineSpacing + m_paragraphSpacing + m_lineSpacingDelta) * scale;
                        m_lineOffset += lineOffsetDelta;


                        previousLineMaxScale = m_maxFontScale;
                        firstVisibleCharacterScale = scale;
                        m_maxFontScale = 0;
                        spriteScale = 1;
                        m_xAdvance = 0 + tag_LineIndent + tag_Indent;

                        ellipsisIndex = m_characterCount - 1;
                    }
                }
                #endregion Check for Linefeed or Last Character


                // Store Rectangle positions for each Character and Mesh Extents.
                #region Save CharacterInfo for the current character.
                m_textInfo.characterInfo[m_characterCount].topLine = m_textInfo.characterInfo[m_characterCount].baseLine + m_currentFontAsset.fontInfo.Ascender * m_fontScale; // Ascender
                m_textInfo.characterInfo[m_characterCount].bottomLine = m_textInfo.characterInfo[m_characterCount].baseLine + m_currentFontAsset.fontInfo.Descender * m_fontScale; // Descender
                m_textInfo.characterInfo[m_characterCount].padding = padding * m_fontScale;
                m_textInfo.characterInfo[m_characterCount].aspectRatio = m_cached_GlyphInfo.width / m_cached_GlyphInfo.height;
                //m_textInfo.characterInfo[m_characterCount].scale = m_fontScale;


                // Determine the bounds of the Mesh.
                if (m_textInfo.characterInfo[m_characterCount].isVisible)
                {
                    m_meshExtents.min = new Vector2(Mathf.Min(m_meshExtents.min.x, m_textInfo.characterInfo[m_characterCount].vertex_BL.position.x), Mathf.Min(m_meshExtents.min.y, m_textInfo.characterInfo[m_characterCount].vertex_BL.position.y));
                    m_meshExtents.max = new Vector2(Mathf.Max(m_meshExtents.max.x, m_textInfo.characterInfo[m_characterCount].vertex_TR.position.x), Mathf.Max(m_meshExtents.max.y, m_textInfo.characterInfo[m_characterCount].vertex_TL.position.y));
                }


                // Save pageInfo Data
                if (charCode != 13 && charCode != 10 && m_pageNumber < 16)
                {
                    m_textInfo.pageInfo[m_pageNumber].ascender = pageAscender;
                    m_textInfo.pageInfo[m_pageNumber].descender = descender < m_textInfo.pageInfo[m_pageNumber].descender ? descender : m_textInfo.pageInfo[m_pageNumber].descender;
                    //Debug.Log("Char [" + (char)charCode + "] with ASCII (" + charCode + ") on Page # " + m_pageNumber + " with Ascender: " + m_textInfo.pageInfo[m_pageNumber].ascender + ". Descender: " + m_textInfo.pageInfo[m_pageNumber].descender);

                    if (m_pageNumber == 0 && m_characterCount == 0)
                        m_textInfo.pageInfo[m_pageNumber].firstCharacterIndex = m_characterCount;
                    else if (m_characterCount > 0 && m_pageNumber != m_textInfo.characterInfo[m_characterCount - 1].pageNumber)
                    {
                        m_textInfo.pageInfo[m_pageNumber - 1].lastCharacterIndex = m_characterCount - 1;
                        m_textInfo.pageInfo[m_pageNumber].firstCharacterIndex = m_characterCount;
                    }
                    else if (m_characterCount == totalCharacterCount - 1)
                        m_textInfo.pageInfo[m_pageNumber].lastCharacterIndex = m_characterCount;
                }
                #endregion Saving CharacterInfo


                // Save State of Mesh Creation for handling of Word Wrapping
                #region Save Word Wrapping State
                if (m_enableWordWrapping || m_overflowMode == TextOverflowModes.Truncate || m_overflowMode == TextOverflowModes.Ellipsis)
                {
                    if ((charCode == 9 || charCode == 32) && !m_isNonBreakingSpace)
                    {
                        // We store the state of numerous variables for the most recent Space, LineFeed or Carriage Return to enable them to be restored 
                        // for Word Wrapping.
                        SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);
                        m_isCharacterWrappingEnabled = false;
                        isFirstWord = false;
                    }
                    else if (charCode > 0x2e80 && charCode < 0x9fff || m_fontAsset.lineBreakingInfo.leadingCharacters.ContainsKey(charCode) || m_fontAsset.lineBreakingInfo.followingCharacters.ContainsKey(charCode))
                    {
                        if (m_characterCount < totalCharacterCount - 1
                                && m_fontAsset.lineBreakingInfo.leadingCharacters.ContainsKey(charCode) == false
                                && m_fontAsset.lineBreakingInfo.followingCharacters.ContainsKey(m_VisibleCharacters[m_characterCount + 1]) == false)
                        {
                            SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);
                            m_isCharacterWrappingEnabled = false;
                            isFirstWord = false;
                        }
                    }
                    else if ((isFirstWord || m_isCharacterWrappingEnabled == true || isLastBreakingChar))
                        SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);
                }
                #endregion Save Word Wrapping State

                m_characterCount += 1;
            }


            // Check Auto Sizing and increase font size to fill text container.
            #region Check Auto-Sizing (Upper Font Size Bounds)
            fontSizeDelta = m_maxFontSize - m_minFontSize;
            if (!m_isCharacterWrappingEnabled && m_enableAutoSizing && fontSizeDelta > 0.051f && m_fontSize < m_fontSizeMax)
            {
                m_minFontSize = m_fontSize;
                m_fontSize += Mathf.Max((m_maxFontSize - m_fontSize) / 2, 0.05f);
                m_fontSize = (int)(Mathf.Min(m_fontSize, m_fontSizeMax) * 20 + 0.5f) / 20f;

                if (loopCountA > 20) return; // Added to debug
                GenerateTextMesh();
                return;
            }
            #endregion End Auto-sizing Check


            m_isCharacterWrappingEnabled = false;

            // Adjust Preferred Height to account for Margins.
            m_renderedHeight += m_margin.y > 0 ? m_margin.y : 0;
            
            if (m_renderMode == TextRenderFlags.GetPreferredSizes)
                return;

            if (!IsRectTransformDriven) { m_preferredWidth = m_renderedWidth; m_preferredHeight = m_renderedHeight; }

            // DEBUG & PERFORMANCE CHECKS (0.006ms)
            //Debug.Log("Iteration Count: " + loopCountA + ". Final Point Size: " + m_fontSize); // + "  B: " + loopCountB + "  C: " + loopCountC + "  D: " + loopCountD);

            // If there are no visible characters... no need to continue
            if (m_visibleCharacterCount == 0 && m_visibleSpriteCount == 0)
            {
                m_uiRenderer.SetMesh(null);

                //Vector3[] vertices = m_textInfo.meshInfo.vertices;

                //if (vertices != null)
                //{
                //    Array.Clear(vertices, 0, vertices.Length);
                //    m_mesh.vertices = vertices;
                //}
                return;
            }


            int last_vert_index = m_visibleCharacterCount * 4;
            // Partial clear of the vertices array to mark unused vertices as degenerate.
            Array.Clear(m_textInfo.meshInfo.vertices, last_vert_index, m_textInfo.meshInfo.vertices.Length - last_vert_index);
            // Do we want to clear the sprite array?

            // Handle Text Alignment
            #region Text Alignment
            switch (m_textAlignment)
            {
                // Top Vertically
                case TextAlignmentOptions.Top:
                case TextAlignmentOptions.TopLeft:
                case TextAlignmentOptions.TopJustified:
                case TextAlignmentOptions.TopRight:
                    if (m_overflowMode != TextOverflowModes.Page)
                        m_anchorOffset = m_rectCorners[1] + new Vector3(0 + margins.x, 0 - m_maxAscender - margins.y, 0);
                    else
                        m_anchorOffset = m_rectCorners[1] + new Vector3(0 + margins.x, 0 - m_textInfo.pageInfo[pageToDisplay].ascender - margins.y, 0);
                    break;

                // Middle Vertically
                case TextAlignmentOptions.Left:
                case TextAlignmentOptions.Right:
                case TextAlignmentOptions.Center:
                case TextAlignmentOptions.Justified:
                    if (m_overflowMode != TextOverflowModes.Page)
                        m_anchorOffset = (m_rectCorners[0] + m_rectCorners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_maxAscender + margins.y + maxVisibleDescender - margins.w) / 2, 0);
                    else
                        m_anchorOffset = (m_rectCorners[0] + m_rectCorners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_textInfo.pageInfo[pageToDisplay].ascender + margins.y + m_textInfo.pageInfo[pageToDisplay].descender - margins.w) / 2, 0);
                    break;

                // Bottom Vertically
                case TextAlignmentOptions.Bottom:
                case TextAlignmentOptions.BottomLeft:
                case TextAlignmentOptions.BottomRight:
                case TextAlignmentOptions.BottomJustified:
                    if (m_overflowMode != TextOverflowModes.Page)
                        m_anchorOffset = m_rectCorners[0] + new Vector3(0 + margins.x, 0 - maxVisibleDescender + margins.w, 0);
                    else
                        m_anchorOffset = m_rectCorners[0] + new Vector3(0 + margins.x, 0 - m_textInfo.pageInfo[pageToDisplay].descender + margins.w, 0);
                    break;
                    
                // Baseline Vertically
                case TextAlignmentOptions.Baseline:
                case TextAlignmentOptions.BaselineLeft:
                case TextAlignmentOptions.BaselineRight:
                case TextAlignmentOptions.BaselineJustified:
                    m_anchorOffset = (m_rectCorners[0] + m_rectCorners[1]) / 2 + new Vector3(0 + margins.x, 0, 0);
                    break;

                // Midline Vertically 
                case TextAlignmentOptions.MidlineLeft:
                case TextAlignmentOptions.Midline:
                case TextAlignmentOptions.MidlineRight:
                case TextAlignmentOptions.MidlineJustified:
                    m_anchorOffset = (m_rectCorners[0] + m_rectCorners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_meshExtents.max.y + margins.y + m_meshExtents.min.y - margins.w) / 2, 0);
                    break;
            }
            #endregion Text Alignment


            // Initialization for Second Pass
            Vector3 justificationOffset = Vector3.zero;
            Vector3 offset = Vector3.zero;
            int vert_index_X4 = 0;
            int sprite_index_X4 = 0;
            //Array.Clear(m_meshAllocCount, 0, 17);

            int wordCount = 0;
            int lineCount = 0;
            int lastLine = 0;

            bool isStartOfWord = false;
            int wordFirstChar = 0;
            int wordLastChar = 0;

            // Second Pass : Line Justification, UV Mapping, Character & Line Visibility & more.
            #region Handle Line Justification & UV Mapping & Character Visibility & More
            
            // Variables used to handle Canvas Render Modes and SDF Scaling
            bool isCameraAssigned = m_canvas.worldCamera == null ? false : true;
            float lossyScale = m_rectTransform.lossyScale.z;
            RenderMode canvasRenderMode = m_canvas.renderMode;
            float canvasScaleFactor = m_canvas.scaleFactor;

            int underlineSegmentCount = 0;
            Color32 underlineColor = Color.white;
            Color32 strikethroughColor = Color.white;
            float underlineStartScale = 0;
            float underlineEndScale = 0;
            float underlineMaxScale = 0;
            float underlineBaseLine = Mathf.Infinity;
            int lastPage = 0;

            float strikethroughPointSize = 0;
            float strikethroughScale = 0;
            float strikethroughBaseline = 0;

            TMP_CharacterInfo[] characterInfos = m_textInfo.characterInfo;
            for (int i = 0; i < m_characterCount; i++)
            {
                int currentLine = characterInfos[i].lineNumber;
                char currentCharacter = characterInfos[i].character;
                TMP_LineInfo lineInfo = m_textInfo.lineInfo[currentLine];
                
                TextAlignmentOptions lineAlignment = lineInfo.alignment;
                lineCount = currentLine + 1;

                // Process Line Justification
                #region Handle Line Justification
                //if (!characterInfos[i].isIgnoringAlignment)
                //{
                switch (lineAlignment)
                {
                    case TextAlignmentOptions.TopLeft:
                    case TextAlignmentOptions.Left:
                    case TextAlignmentOptions.BottomLeft:
                    case TextAlignmentOptions.BaselineLeft:
                    case TextAlignmentOptions.MidlineLeft:
                        justificationOffset = new Vector3 (0 + lineInfo.marginLeft, 0, 0);
                        break;

                    case TextAlignmentOptions.Top:
                    case TextAlignmentOptions.Center:
                    case TextAlignmentOptions.Bottom:
                    case TextAlignmentOptions.Baseline:
                    case TextAlignmentOptions.Midline:
                        justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width / 2 - lineInfo.maxAdvance / 2, 0, 0);
                        break;

                    case TextAlignmentOptions.TopRight:
                    case TextAlignmentOptions.Right:
                    case TextAlignmentOptions.BottomRight:
                    case TextAlignmentOptions.BaselineRight:
                    case TextAlignmentOptions.MidlineRight:
                        justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width - lineInfo.maxAdvance, 0, 0);
                        break;

                    case TextAlignmentOptions.TopJustified:
                    case TextAlignmentOptions.Justified:
                    case TextAlignmentOptions.BottomJustified:
                    case TextAlignmentOptions.BaselineJustified:
                    case TextAlignmentOptions.MidlineJustified:
                        charCode = m_textInfo.characterInfo[i].character;
                        char lastCharOfCurrentLine = m_textInfo.characterInfo[lineInfo.lastCharacterIndex].character;

                        if (/*char.IsWhiteSpace(lastCharOfCurrentLine) &&*/ !char.IsControl(lastCharOfCurrentLine) && currentLine < m_lineNumber)
                        {
                            // All lines are justified accept the last one.
                            float gap = lineInfo.width - lineInfo.maxAdvance;

                            if (currentLine != lastLine || i == 0)
                                justificationOffset = new Vector3(lineInfo.marginLeft, 0, 0);
                            else
                            {
                                if (charCode == 9 || charCode == 32 || charCode == 160)
                                {
                                    int spaces = lineInfo.spaceCount - 1 > 0 ? lineInfo.spaceCount - 1 : 1;
                                    justificationOffset += new Vector3(gap * (1 - m_wordWrappingRatios) / (spaces), 0, 0);
                                }
                                else
                                {
                                    justificationOffset += new Vector3(gap * m_wordWrappingRatios / (lineInfo.characterCount - lineInfo.spaceCount - 1), 0, 0);
                                }
                            }
                        }
                        else
                            justificationOffset = new Vector3(lineInfo.marginLeft, 0, 0); // Keep last line left justified.

                        //Debug.Log("Char [" + (char)charCode + "] Code:" + charCode + "  Line # " + currentLine + "  Offset:" + justificationOffset + "  # Spaces:" + lineInfo.spaceCount + "  # Characters:" + lineInfo.characterCount);
                        break;
                }
                //}
                #endregion End Text Justification

                offset = m_anchorOffset + justificationOffset;

                // Handle Visible Characters
                #region Handle Visible Characters
                if (characterInfos[i].isVisible)
                {
                    TMP_CharacterType type = characterInfos[i].type;
                    switch (type)
                    {
                        // CHARACTERS
                        case TMP_CharacterType.Character:

                            Extents lineExtents = lineInfo.lineExtents;
                            float uvOffset = (m_uvLineOffset * currentLine) % 1 + m_uvOffset.x;

                            // Setup UV2 based on Character Mapping Options Selected
                            #region Handle UV Mapping Options
                            switch (m_horizontalMapping)
                            {
                                case TextureMappingOptions.Character:
                                    characterInfos[i].vertex_BL.uv2.x = 0 + m_uvOffset.x;
                                    characterInfos[i].vertex_TL.uv2.x = 0 + m_uvOffset.x;
                                    characterInfos[i].vertex_TR.uv2.x = 1 + m_uvOffset.x;
                                    characterInfos[i].vertex_BR.uv2.x = 1 + m_uvOffset.x;
                                    break;

                                case TextureMappingOptions.Line:
                                    if (m_textAlignment != TextAlignmentOptions.Justified)
                                    {
                                        characterInfos[i].vertex_BL.uv2.x = (characterInfos[i].vertex_BL.position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
                                        characterInfos[i].vertex_TL.uv2.x = (characterInfos[i].vertex_TL.position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
                                        characterInfos[i].vertex_TR.uv2.x = (characterInfos[i].vertex_TR.position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
                                        characterInfos[i].vertex_BR.uv2.x = (characterInfos[i].vertex_BR.position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
                                        break;
                                    }
                                    else // Special Case if Justified is used in Line Mode.
                                    {
                                        characterInfos[i].vertex_BL.uv2.x = (characterInfos[i].vertex_BL.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                                        characterInfos[i].vertex_TL.uv2.x = (characterInfos[i].vertex_TL.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                                        characterInfos[i].vertex_TR.uv2.x = (characterInfos[i].vertex_TR.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                                        characterInfos[i].vertex_BR.uv2.x = (characterInfos[i].vertex_BR.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                                        break;
                                    }

                                case TextureMappingOptions.Paragraph:
                                    characterInfos[i].vertex_BL.uv2.x = (characterInfos[i].vertex_BL.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                                    characterInfos[i].vertex_TL.uv2.x = (characterInfos[i].vertex_TL.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                                    characterInfos[i].vertex_TR.uv2.x = (characterInfos[i].vertex_TR.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                                    characterInfos[i].vertex_BR.uv2.x = (characterInfos[i].vertex_BR.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                                    break;

                                case TextureMappingOptions.MatchAspect:

                                    switch (m_verticalMapping)
                                    {
                                        case TextureMappingOptions.Character:
                                            characterInfos[i].vertex_BL.uv2.y = 0 + m_uvOffset.y;
                                            characterInfos[i].vertex_TL.uv2.y = 1 + m_uvOffset.y;
                                            characterInfos[i].vertex_TR.uv2.y = 0 + m_uvOffset.y;
                                            characterInfos[i].vertex_BR.uv2.y = 1 + m_uvOffset.y;
                                            break;

                                        case TextureMappingOptions.Line:
                                            characterInfos[i].vertex_BL.uv2.y = (characterInfos[i].vertex_BL.position.y - lineExtents.min.y) / (lineExtents.max.y - lineExtents.min.y) + uvOffset;
                                            characterInfos[i].vertex_TL.uv2.y = (characterInfos[i].vertex_TL.position.y - lineExtents.min.y) / (lineExtents.max.y - lineExtents.min.y) + uvOffset;
                                            characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
                                            characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
                                            break;

                                        case TextureMappingOptions.Paragraph:
                                            characterInfos[i].vertex_BL.uv2.y = (characterInfos[i].vertex_BL.position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y) + uvOffset;
                                            characterInfos[i].vertex_TL.uv2.y = (characterInfos[i].vertex_TL.position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y) + uvOffset;
                                            characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
                                            characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
                                            break;

                                        case TextureMappingOptions.MatchAspect:
                                            Debug.Log("ERROR: Cannot Match both Vertical & Horizontal.");
                                            break;
                                    }

                                    //float xDelta = 1 - (_uv2s[vert_index + 0].y * textMeshCharacterInfo[i].AspectRatio); // Left aligned
                                    float xDelta = (1 - ((characterInfos[i].vertex_BL.uv2.y +  characterInfos[i].vertex_TL.uv2.y) * characterInfos[i].aspectRatio)) / 2; // Center of Rectangle

                                    characterInfos[i].vertex_BL.uv2.x = (characterInfos[i].vertex_BL.uv2.y * characterInfos[i].aspectRatio) + xDelta + uvOffset;
                                    characterInfos[i].vertex_TL.uv2.x = characterInfos[i].vertex_BL.uv2.x;
                                    characterInfos[i].vertex_TR.uv2.x = (characterInfos[i].vertex_TL.uv2.y * characterInfos[i].aspectRatio) + xDelta + uvOffset;
                                    characterInfos[i].vertex_BR.uv2.x = characterInfos[i].vertex_TR.uv2.x;
                                    break;
                            }

                            switch (m_verticalMapping)
                            {
                                case TextureMappingOptions.Character:
                                    characterInfos[i].vertex_BL.uv2.y = 0 + m_uvOffset.y;
                                    characterInfos[i].vertex_TL.uv2.y = 1 + m_uvOffset.y;
                                    characterInfos[i].vertex_TR.uv2.y = 1 + m_uvOffset.y;
                                    characterInfos[i].vertex_BR.uv2.y = 0 + m_uvOffset.y;
                                    break;

                                case TextureMappingOptions.Line:
                                    characterInfos[i].vertex_BL.uv2.y = (characterInfos[i].vertex_BL.position.y - lineExtents.min.y) / (lineExtents.max.y - lineExtents.min.y) + m_uvOffset.y;
                                    characterInfos[i].vertex_TL.uv2.y = (characterInfos[i].vertex_TL.position.y - lineExtents.min.y) / (lineExtents.max.y - lineExtents.min.y) + m_uvOffset.y;
                                    characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
                                    characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
                                    break;

                                case TextureMappingOptions.Paragraph:
                                    characterInfos[i].vertex_BL.uv2.y = (characterInfos[i].vertex_BL.position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y) + m_uvOffset.y;
                                    characterInfos[i].vertex_TL.uv2.y = (characterInfos[i].vertex_TL.position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y) + m_uvOffset.y;
                                    characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
                                    characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
                                    break;

                                case TextureMappingOptions.MatchAspect:
                                    //float yDelta = 1 - (_uv2s[vert_index + 2].x / textMeshCharacterInfo[i].AspectRatio); // Top Corner
                                    float yDelta = (1 - ((characterInfos[i].vertex_BL.uv2.x + characterInfos[i].vertex_TR.uv2.x) / characterInfos[i].aspectRatio)) / 2; // Center of Rectangle
                                    //float yDelta = 0;

                                    characterInfos[i].vertex_BL.uv2.y = yDelta + (characterInfos[i].vertex_BL.uv2.x / characterInfos[i].aspectRatio) + m_uvOffset.y;
                                    characterInfos[i].vertex_TL.uv2.y = yDelta + (characterInfos[i].vertex_TR.uv2.x / characterInfos[i].aspectRatio) + m_uvOffset.y;
                                    characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
                                    characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
                                    break;
                            }
                            #endregion End UV Mapping Options


                            // Pack UV's so that we can pass Xscale needed for Shader to maintain 1:1 ratio.
                            #region Pack Scale into UV2
                            float xScale = characterInfos[i].scale * (1 - m_charWidthAdjDelta);
                            if ((characterInfos[i].style & FontStyles.Bold) == FontStyles.Bold) xScale *= -1;
                        
                            switch (canvasRenderMode)
                            {
                                case RenderMode.ScreenSpaceOverlay:
                                    xScale *= lossyScale / canvasScaleFactor;
                                    break;
                                case RenderMode.ScreenSpaceCamera:
                                    xScale *= isCameraAssigned ? lossyScale : 1;
                                    break;
                                case RenderMode.WorldSpace:
                                    xScale *= lossyScale;
                                    break;
                            }

                            float x0 = characterInfos[i].vertex_BL.uv2.x;
                            float y0 = characterInfos[i].vertex_BL.uv2.y;
                            float x1 = characterInfos[i].vertex_TR.uv2.x;
                            float y1 = characterInfos[i].vertex_TR.uv2.y; 

                            float dx = Mathf.Floor(x0);
                            float dy = Mathf.Floor(y0);

                            x0 = x0 - dx;
                            x1 = x1 - dx;
                            y0 = y0 - dy;
                            y1 = y1 - dy;

                            characterInfos[i].vertex_BL.uv2 = PackUV(x0, y0, xScale);
                            characterInfos[i].vertex_TL.uv2 = PackUV(x0, y1, xScale);
                            characterInfos[i].vertex_TR.uv2 = PackUV(x1, y1, xScale);
                            characterInfos[i].vertex_BR.uv2 = PackUV(x1, y0, xScale);
                            #endregion
                            
                            break;
                        
                        // SPRITES
                        case TMP_CharacterType.Sprite:
                            // Nothing right now
                            break;
                    }


                    // Handle maxVisibleCharacters, maxVisibleLines and Overflow Page Mode.
                    #region Handle maxVisibleCharacters / maxVisibleLines / Page Mode
                    if (i < m_maxVisibleCharacters && currentLine < m_maxVisibleLines && m_overflowMode != TextOverflowModes.Page)
                    {
                        characterInfos[i].vertex_BL.position += offset;
                        characterInfos[i].vertex_TL.position += offset;
                        characterInfos[i].vertex_TR.position += offset;
                        characterInfos[i].vertex_BR.position += offset;
                    }
                    else if (i < m_maxVisibleCharacters && currentLine < m_maxVisibleLines && m_overflowMode == TextOverflowModes.Page && characterInfos[i].pageNumber == pageToDisplay)
                    {
                        characterInfos[i].vertex_BL.position += offset;
                        characterInfos[i].vertex_TL.position += offset;
                        characterInfos[i].vertex_TR.position += offset;
                        characterInfos[i].vertex_BR.position += offset;
                    }
                    else
                    {
                        characterInfos[i].vertex_BL.position *= 0;
                        characterInfos[i].vertex_TL.position *= 0;
                        characterInfos[i].vertex_TR.position *= 0;
                        characterInfos[i].vertex_BR.position *= 0;
                    }
                    #endregion


                    // Fill Vertex Buffers for the various types of element
                    if (type == TMP_CharacterType.Character)
                    {
                        FillCharacterVertexBuffers(i, vert_index_X4);
                        vert_index_X4 += 4;
                    }
                    else if (type == TMP_CharacterType.Sprite)
                    {
                        FillSpriteVertexBuffers(i, sprite_index_X4);
                        sprite_index_X4 += 4;
                    }

                }
                #endregion


                // Apply Alignment and Justification Offset
                m_textInfo.characterInfo[i].bottomLeft += offset;
                m_textInfo.characterInfo[i].topLeft += offset;
                m_textInfo.characterInfo[i].topRight += offset;
                m_textInfo.characterInfo[i].bottomRight += offset;

                // Need to add top left and bottom right.
                m_textInfo.characterInfo[i].topLine += offset.y;
                m_textInfo.characterInfo[i].bottomLine += offset.y;
                m_textInfo.characterInfo[i].baseLine += offset.y;


                // Store Max Ascender & Descender
                if (currentCharacter != 10 && currentCharacter != 13)
                {
                    m_textInfo.lineInfo[currentLine].ascender = m_textInfo.characterInfo[i].topLine > m_textInfo.lineInfo[currentLine].ascender ? m_textInfo.characterInfo[i].topLine : m_textInfo.lineInfo[currentLine].ascender;
                    m_textInfo.lineInfo[currentLine].descender = m_textInfo.characterInfo[i].bottomLine < m_textInfo.lineInfo[currentLine].descender ? m_textInfo.characterInfo[i].bottomLine : m_textInfo.lineInfo[currentLine].descender;
                }


                // Need to recompute lineExtent to account for the offset from justification.
                #region Adjust lineExtents resulting from alignment offset
                if (currentLine != lastLine || i == m_characterCount - 1)
                {
                    // Update the previous line's extents
                    if (currentLine != lastLine)
                    {
                        m_textInfo.lineInfo[lastLine].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[lastLine].firstCharacterIndex].bottomLeft.x, m_textInfo.lineInfo[lastLine].descender);
                        m_textInfo.lineInfo[lastLine].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[lastLine].lastVisibleCharacterIndex].topRight.x, m_textInfo.lineInfo[lastLine].ascender);
                    }

                    // Update the current line's extents
                    if (i == m_characterCount - 1)
                    {
                        m_textInfo.lineInfo[currentLine].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[currentLine].firstCharacterIndex].bottomLeft.x, m_textInfo.lineInfo[currentLine].descender);
                        m_textInfo.lineInfo[currentLine].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[currentLine].lastVisibleCharacterIndex].topRight.x, m_textInfo.lineInfo[currentLine].ascender);
                    }
                }
                #endregion


                // Track Word Count per line and for the object
                #region Track Word Count
                if (char.IsLetterOrDigit(currentCharacter) || currentCharacter == 39 || currentCharacter == 8217)
                {
                    if (isStartOfWord == false)
                    {
                        isStartOfWord = true;
                        wordFirstChar = i;
                    }

                    // If last character is a word
                    if (isStartOfWord && i == m_characterCount - 1)
                    {
                        wordLastChar = i;
                        wordCount += 1;
                        m_textInfo.lineInfo[currentLine].wordCount += 1;

                        TMP_WordInfo wordInfo = new TMP_WordInfo();
                        wordInfo.firstCharacterIndex = wordFirstChar;
                        wordInfo.lastCharacterIndex = wordLastChar;
                        wordInfo.characterCount = wordLastChar - wordFirstChar + 1;
                        m_textInfo.wordInfo.Add(wordInfo);
                    }
                }
                else if (isStartOfWord || i == 0 && (char.IsPunctuation(currentCharacter) || char.IsWhiteSpace(currentCharacter) || i == m_characterCount - 1))
                {
                    wordLastChar = i == m_characterCount - 1 && char.IsLetterOrDigit(currentCharacter) ? i : i - 1;
                    isStartOfWord = false;

                    wordCount += 1;
                    m_textInfo.lineInfo[currentLine].wordCount += 1;

                    TMP_WordInfo wordInfo = new TMP_WordInfo();
                    wordInfo.firstCharacterIndex = wordFirstChar;
                    wordInfo.lastCharacterIndex = wordLastChar;
                    wordInfo.characterCount = wordLastChar - wordFirstChar + 1;
                    m_textInfo.wordInfo.Add(wordInfo);
                }
                #endregion


                // Setup & Handle Underline
                #region Underline
                // NOTE: Need to figure out how underline will be handled with multiple fonts and which font will be used for the underline.
                bool isUnderline = (m_textInfo.characterInfo[i].style & FontStyles.Underline) == FontStyles.Underline;
                if (isUnderline)
                {
                    bool isUnderlineVisible = true;
                    int currentPage = m_textInfo.characterInfo[i].pageNumber;

                    if (i > m_maxVisibleCharacters || currentLine > m_maxVisibleLines || (m_overflowMode == TextOverflowModes.Page && currentPage + 1 != m_pageToDisplay))
                        isUnderlineVisible = false;

                    // We only use the scale of visible characters.
                    if (currentCharacter != 10 && currentCharacter != 13 && currentCharacter != 32 && currentCharacter != 160)
                    {
                        underlineMaxScale = Mathf.Max(underlineMaxScale, m_textInfo.characterInfo[i].scale);
                        underlineBaseLine = Mathf.Min(currentPage == lastPage ? underlineBaseLine : Mathf.Infinity, m_textInfo.characterInfo[i].baseLine + font.fontInfo.Underline * underlineMaxScale);
                        lastPage = currentPage; // Need to track pages to ensure we reset baseline for the new pages.
                    }

                    if (beginUnderline == false && isUnderlineVisible == true && i <= lineInfo.lastVisibleCharacterIndex && currentCharacter != 10 && currentCharacter != 13)
                    {
                        if (i == lineInfo.lastVisibleCharacterIndex && (currentCharacter == 32 || currentCharacter == 160))
                        { }
                        else
                        {
                            beginUnderline = true;
                            underlineStartScale = m_textInfo.characterInfo[i].scale;
                            if (underlineMaxScale == 0) underlineMaxScale = underlineStartScale;
                            underline_start = new Vector3(m_textInfo.characterInfo[i].bottomLeft.x, underlineBaseLine, 0);
                            underlineColor = m_textInfo.characterInfo[i].color;
                        }
                    }

                    // End Underline if text only contains one character.
                    if (beginUnderline && m_characterCount == 1)
                    {
                        beginUnderline = false;
                        underline_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, underlineBaseLine, 0);
                        underlineEndScale = m_textInfo.characterInfo[i].scale;

                        DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, underlineColor);
                        underlineSegmentCount += 1;
                        underlineMaxScale = 0;
                        underlineBaseLine = Mathf.Infinity;
                    }
                    else if (beginUnderline && (i == lineInfo.lastCharacterIndex || i >= lineInfo.lastVisibleCharacterIndex))
                    {
                        // Terminate underline at previous visible character if space or carriage return.
                        if (currentCharacter == 10 || currentCharacter == 13 || currentCharacter == 32 || currentCharacter == 160)
                        {
                            int lastVisibleCharacterIndex = lineInfo.lastVisibleCharacterIndex;
                            underline_end = new Vector3(m_textInfo.characterInfo[lastVisibleCharacterIndex].topRight.x, underlineBaseLine, 0);
                            underlineEndScale = m_textInfo.characterInfo[lastVisibleCharacterIndex].scale;
                        }
                        else
                        {   // End underline if last character of the line.
                            underline_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, underlineBaseLine, 0);
                            underlineEndScale = m_textInfo.characterInfo[i].scale;
                        }

                        beginUnderline = false;
                        DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, underlineColor);
                        underlineSegmentCount += 1;
                        underlineMaxScale = 0;
                        underlineBaseLine = Mathf.Infinity;
                    }
                    else if (beginUnderline && !isUnderlineVisible)
                    {
                        beginUnderline = false;
                        underline_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, underlineBaseLine, 0);
                        underlineEndScale = m_textInfo.characterInfo[i - 1].scale;

                        DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, underlineColor);
                        underlineSegmentCount += 1;
                        underlineMaxScale = 0;
                        underlineBaseLine = Mathf.Infinity;
                    }
                }
                else
                {
                    // End Underline
                    if (beginUnderline == true)
                    {
                        beginUnderline = false;
                        underline_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, underlineBaseLine, 0);
                        underlineEndScale = m_textInfo.characterInfo[i - 1].scale;

                        DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, underlineColor);
                        underlineSegmentCount += 1;
                        underlineMaxScale = 0;
                        underlineBaseLine = Mathf.Infinity;
                    }
                }
                #endregion


                // Setup & Handle Strikethrough
                #region Strikethrough
                // NOTE: Need to figure out how underline will be handled with multiple fonts and which font will be used for the underline.
                bool isStrikethrough = (m_textInfo.characterInfo[i].style & FontStyles.Strikethrough) == FontStyles.Strikethrough;
                if (isStrikethrough)
                {
                    bool isStrikeThroughVisible = true;

                    if (i > m_maxVisibleCharacters || currentLine > m_maxVisibleLines || (m_overflowMode == TextOverflowModes.Page && m_textInfo.characterInfo[i].pageNumber + 1 != m_pageToDisplay))
                        isStrikeThroughVisible = false;

                    if (beginStrikethrough == false && isStrikeThroughVisible && i <= lineInfo.lastVisibleCharacterIndex && currentCharacter != 10 && currentCharacter != 13)
                    {
                        if (i == lineInfo.lastVisibleCharacterIndex && (currentCharacter == 32 || currentCharacter == 160))
                        { }
                        else
                        {
                            beginStrikethrough = true;
                            strikethroughPointSize = m_textInfo.characterInfo[i].pointSize;
                            strikethroughScale = m_textInfo.characterInfo[i].scale;
                            strikethrough_start = new Vector3(m_textInfo.characterInfo[i].bottomLeft.x, m_textInfo.characterInfo[i].baseLine + (font.fontInfo.Ascender + font.fontInfo.Descender) / 2.75f * strikethroughScale, 0);
                            strikethroughColor = m_textInfo.characterInfo[i].color;
                            strikethroughBaseline = m_textInfo.characterInfo[i].baseLine;
                            //Debug.Log("Char [" + currentCharacter + "] Start Strikethrough POS: " + strikethrough_start);
                        }
                    }

                    // End Strikethrough if text only contains one character.
                    if (beginStrikethrough && m_characterCount == 1)
                    {
                        beginStrikethrough = false;
                        strikethrough_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + (font.fontInfo.Ascender + font.fontInfo.Descender) / 2 * strikethroughScale, 0);

                        DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, strikethroughColor);
                        underlineSegmentCount += 1;
                    }
                    else if (beginStrikethrough && i == lineInfo.lastCharacterIndex)
                    {
                        // Terminate Strikethrough at previous visible character if space or carriage return.
                        if (currentCharacter == 10 || currentCharacter == 13 || currentCharacter == 32 || currentCharacter == 160)
                        {
                            int lastVisibleCharacterIndex = lineInfo.lastVisibleCharacterIndex;
                            strikethrough_end = new Vector3(m_textInfo.characterInfo[lastVisibleCharacterIndex].topRight.x, m_textInfo.characterInfo[lastVisibleCharacterIndex].baseLine + (font.fontInfo.Ascender + font.fontInfo.Descender) / 2 * strikethroughScale, 0);
                        }
                        else
                        {
                            // Terminate Strikethrough at last character of line.
                            strikethrough_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + (font.fontInfo.Ascender + font.fontInfo.Descender) / 2 * strikethroughScale, 0);
                        }

                        beginStrikethrough = false;
                        DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, strikethroughColor);
                        underlineSegmentCount += 1;
                    }
                    else if (beginStrikethrough && i < m_characterCount && (m_textInfo.characterInfo[i + 1].pointSize != strikethroughPointSize || !TMP_Math.Equals(m_textInfo.characterInfo[i + 1].baseLine + offset.y, strikethroughBaseline)))
                    {
                        // Terminate Strikethrough if scale changes.
                        beginStrikethrough = false;

                        int lastVisibleCharacterIndex = lineInfo.lastVisibleCharacterIndex;
                        if (i > lastVisibleCharacterIndex)
                            strikethrough_end = new Vector3(m_textInfo.characterInfo[lastVisibleCharacterIndex].topRight.x, m_textInfo.characterInfo[lastVisibleCharacterIndex].baseLine + (font.fontInfo.Ascender + font.fontInfo.Descender) / 2 * strikethroughScale, 0);
                        else
                            strikethrough_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + (font.fontInfo.Ascender + font.fontInfo.Descender) / 2 * strikethroughScale, 0);

                        DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, strikethroughColor);
                        underlineSegmentCount += 1;
                        //Debug.Log("Char [" + currentCharacter + "] at Index: " + i + "  End Strikethrough POS: " + strikethrough_end + "  Baseline: " + m_textInfo.characterInfo[i].baseLine.ToString("f3"));
                    }
                    else if (beginStrikethrough && !isStrikeThroughVisible)
                    {
                        // Terminate Strikethrough if character is not visible.
                        beginStrikethrough = false;
                        strikethrough_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, m_textInfo.characterInfo[i - 1].baseLine + (font.fontInfo.Ascender + font.fontInfo.Descender) / 2 * strikethroughScale, 0);

                        DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, strikethroughColor);
                        underlineSegmentCount += 1;
                    }
                }
                else
                {
                    // End Underline
                    if (beginStrikethrough == true)
                    {
                        beginStrikethrough = false;
                        strikethrough_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, m_textInfo.characterInfo[i - 1].baseLine + (font.fontInfo.Ascender + font.fontInfo.Descender) / 2 * m_fontScale, 0);

                        DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, strikethroughColor);
                        underlineSegmentCount += 1;
                    }
                }
                #endregion


                lastLine = currentLine;
            }
            #endregion


            // METRICS ABOUT THE TEXT OBJECT
            m_textInfo.characterCount = (short)m_characterCount;
            m_textInfo.spriteCount = m_spriteCount;
            m_textInfo.lineCount = (short)lineCount;
            m_textInfo.wordCount = wordCount != 0 && m_characterCount > 0 ? (short)wordCount : (short)1;
            m_textInfo.pageCount = m_pageNumber + 1;


            // If Advanced Layout Component is present, don't upload the mesh.
            if (m_renderMode == TextRenderFlags.Render) // m_isAdvanceLayoutComponentPresent == false || m_advancedLayoutComponent.isEnabled == false)
            {
                //Debug.Log("Uploading Mesh normally.");

                // Upload Mesh Data
                m_mesh.vertices = m_textInfo.meshInfo.vertices;
                m_mesh.uv = m_textInfo.meshInfo.uvs0;
                m_mesh.uv2 = m_textInfo.meshInfo.uvs2;
                m_mesh.colors32 = m_textInfo.meshInfo.colors32;

                m_mesh.RecalculateBounds(); // Replace by manual bound calculation to improve performance.

                m_uiRenderer.SetMesh(m_mesh);


                if (m_inlineGraphics != null)
                    m_inlineGraphics.DrawSprite(m_inlineGraphics.uiVertex, m_visibleSpriteCount);

            }

            // Compute Bounds for the mesh. Manual computation is more efficient then using Mesh.recalcualteBounds.
            m_bounds = new Bounds(new Vector3((m_meshExtents.max.x + m_meshExtents.min.x) / 2, (m_meshExtents.max.y + m_meshExtents.min.y) / 2, 0) + offset, new Vector3(m_meshExtents.max.x - m_meshExtents.min.x, m_meshExtents.max.y - m_meshExtents.min.y, 0));

            // Has Text Container's Width or Height been specified by the user?
            /*
            if (m_rectTransform.sizeDelta.x == 0 || m_rectTransform.sizeDelta.y == 0)
            {
                //Debug.Log("Auto-fitting Text. Default Width:" + m_textContainer.isDefaultWidth + "  Default Height:" + m_textContainer.isDefaultHeight);
                if (marginWidth == 0)
                    m_rectTransform.sizeDelta = new Vector2(m_preferredWidth + margins.x + margins.z, m_rectTransform.sizeDelta.y);

                if (marginHeight == 0)
                    m_rectTransform.sizeDelta = new Vector2(m_rectTransform.sizeDelta.x,  m_preferredHeight + margins.y + margins.w);

                
                Debug.Log("Auto-fitting Text. Default Width:" + m_preferredWidth + "  Default Height:" + m_preferredHeight);
                GenerateTextMesh();
                return;
            }
            */

            //for (int i = 0; i < m_lineNumber + 1; i++)
            //{
            //    Debug.Log("Line: " + (i + 1) + "  Character Count: " + m_textInfo.lineInfo[i].characterCount
            //                                 + "  Word Count: " + m_textInfo.lineInfo[i].wordCount
            //                                 + "  Space Count: " + m_textInfo.lineInfo[i].spaceCount
            //                                 + "  First: [" + m_textInfo.characterInfo[m_textInfo.lineInfo[i].firstCharacterIndex].character + "] at Index: " + m_textInfo.lineInfo[i].firstCharacterIndex
            //                                 + "  First Visible: [" + m_textInfo.characterInfo[m_textInfo.lineInfo[i].firstVisibleCharacterIndex].character + "] at Index: " + m_textInfo.lineInfo[i].firstVisibleCharacterIndex
            //                                 + "  Last [" + m_textInfo.characterInfo[m_textInfo.lineInfo[i].lastCharacterIndex].character + "] at Index: " + m_textInfo.lineInfo[i].lastCharacterIndex
            //                                 + "  Last visible [" + m_textInfo.characterInfo[m_textInfo.lineInfo[i].lastVisibleCharacterIndex].character + "] at Index: " + m_textInfo.lineInfo[i].lastVisibleCharacterIndex
            //                                 + "  Length: " + m_textInfo.lineInfo[i].lineLength
            //                                 + "  Line Extents: " + m_textInfo.lineInfo[i].lineExtents);
            //}

            //Debug.Log("Done rendering text. Character Count is " + m_textInfo.characterCount);
            //Debug.Log("Done rendering text. Preferred Width:" + m_preferredWidth + "  Preferred Height:" + m_preferredHeight);

            // Event indicating the text has been regenerated.
            TMPro_EventManager.ON_TEXT_CHANGED(this);

            //Debug.Log(m_minWidth);
            //Profiler.EndSample();
            //m_StopWatch.Stop();
            //Debug.Log("Done Rendering Text.");

            //Debug.Log("TimeElapsed is:" + (m_StopWatch.ElapsedTicks / 10000f).ToString("f4"));
            //m_StopWatch.Reset();
        }
        // Function to identify and validate the rich tag. Returns the position of the > if the tag was valid.
        bool ValidateHtmlTag(int[] chars, int startIndex, out int endIndex)
        {
            Array.Clear(m_htmlTag, 0, 16);
            int tagCharCount = 0;
            int tagCode = 0;
            int colorCode = 0;
            int numSequenceStart = 0;
            int numSequenceEnd = 0;
            int numSequenceDecimalPos = 0;

            endIndex = startIndex;

            bool isValidHtmlTag = false;
            int equalSignValue = 1;

            for (int i = startIndex; chars[i] != 0 && tagCharCount < 16 && chars[i] != 60; i++)
            {
                if (chars[i] == 62) // ASC Code of End Html tag '>'
                {
                    isValidHtmlTag = true;
                    endIndex = i;
                    m_htmlTag[tagCharCount] = (char)0;
                    break;
                }

                m_htmlTag[tagCharCount] = (char)chars[i];
                tagCharCount += 1;

                if (chars[i] == 61) equalSignValue = 0; // Once we encounter the equal sign, we stop adding the tagCode.

                tagCode += chars[i] * tagCharCount * equalSignValue;
                colorCode += chars[i] * tagCharCount * (1 - equalSignValue);
                // Get possible positions of numerical values
                switch ((int)chars[i])
                {
                    case 61: // '='
                        numSequenceStart = tagCharCount;
                        break;
                    case 46: // '.'
                        numSequenceDecimalPos = tagCharCount - 1;
                        break;
                }
            }

            if (!isValidHtmlTag)
            {
                return false;
            }

            //Debug.Log("Tag Code:" + tagCode + "  Color Code: " + colorCode);

            if (m_htmlTag[0] == 35 && tagCharCount == 7) // if Tag begins with # and contains 7 characters.
            {
                m_htmlColor = HexCharsToColor(m_htmlTag);
                return true;
            }
            else if (m_htmlTag[0] == 35 && tagCharCount == 9) // if Tag begins with # and contains 9 characters.
            {
                m_htmlColor = HexCharsToColor(m_htmlTag);
                return true;
            }
            else
            {
                switch (tagCode)
                {
                    case 98: // <b>
                        m_style |= FontStyles.Bold;
                        return true;
                    case 105: // <i>
                        m_style |= FontStyles.Italic;
                        return true;
                    case 117: // <u>
                        m_style |= FontStyles.Underline;
                        return true;
                    case 243: // </b>
                        m_style &= ~FontStyles.Bold;
                        return true;
                    case 257: // </i>
                        m_style &= ~FontStyles.Italic;
                        return true;
                    case 281: // </u>
                        m_style &= ~FontStyles.Underline;
                        return true;
                    case 643: // <sub>
                        m_currentFontSize *= m_fontAsset.fontInfo.SubSize > 0 ? m_fontAsset.fontInfo.SubSize : 1; // Subscript characters are half size.
                        //m_xAdvance += 10 * m_fontScale;
                        m_baselineOffset = m_fontAsset.fontInfo.SubscriptOffset;
                        m_isRecalculateScaleRequired = true;
                        return true;
                    case 679: // <pos=000.00>
                        m_tabSpacing = ConvertToFloat(m_htmlTag, numSequenceStart, tagCharCount - 1, numSequenceDecimalPos);
                        return true;
                    case 685: // <sup>
                        m_currentFontSize *= m_fontAsset.fontInfo.SubSize > 0 ? m_fontAsset.fontInfo.SubSize : 1;
                        //m_xAdvance += 10 * m_fontScale;
                        m_baselineOffset = m_fontAsset.fontInfo.SuperscriptOffset;
                        m_isRecalculateScaleRequired = true;
                        return true;
                    case 1020: // </sub>
                        m_currentFontSize /= m_fontAsset.fontInfo.SubSize > 0 ? m_fontAsset.fontInfo.SubSize : 1; //m_fontSize / m_fontAsset.FontInfo.PointSize * .1f;
                        m_baselineOffset = 0;
                        m_isRecalculateScaleRequired = true;
                        return true;
                    case 1076: // </sup>
                        m_currentFontSize /= m_fontAsset.fontInfo.SubSize > 0 ? m_fontAsset.fontInfo.SubSize : 1; //m_fontSize / m_fontAsset.FontInfo.PointSize * .1f;
                        m_baselineOffset = 0;
                        m_isRecalculateScaleRequired = true;
                        return true;
                    case 1095: // <size=>
                        numSequenceEnd = tagCharCount - 1;
                        float val = 0;

                        if (m_htmlTag[5] == 37) // <size=%00>
                        {
                            val = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                            m_currentFontSize = m_fontSize * val / 100;
                            m_isRecalculateScaleRequired = true;
                            return true;
                        }
                        else if (m_htmlTag[5] == 43) // <size=+00>
                        {
                            val = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                            m_currentFontSize = m_fontSize + val;
                            m_isRecalculateScaleRequired = true;
                            return true;
                        }
                        else if (m_htmlTag[5] == 45) // <size=-00>
                        {
                            val = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                            m_currentFontSize = m_fontSize + val;
                            m_isRecalculateScaleRequired = true;
                            return true;
                        }
                        else // <size=0000.00>
                        {
                            val = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                            if (val == 73493) return false; // if tag is <size> with no values.
                            m_currentFontSize = val;
                            m_isRecalculateScaleRequired = true;
                            return true;
                        }
                    case 1118: // <font=xx>
                        Debug.Log("Font Tag used.");
                        //m_fontIndex = (int)ConvertToFloat(m_htmlTag, numSequenceStart, tagCharCount - 1, numSequenceDecimalPos);

                        //if(m_fontAssetArray[m_fontIndex] == null)
                        //{
                        //    // Load new font asset into index
                        //    m_fontAssetArray[m_fontIndex] = Resources.Load("Fonts & Materials/Bangers SDF", typeof(TextMeshProFont)) as TextMeshProFont; // Hard coded right now to a specific font
                        //}

                        //m_fontScale = (m_fontSize / m_fontAssetArray[m_fontIndex].fontInfo.PointSize * (m_isOrthographic ? 1 : 0.1f));
                        //Debug.Log("Font Index = " + m_fontIndex);
                        return true;
                    case 1531: // <space=000.00>
                        m_spacing = ConvertToFloat(m_htmlTag, numSequenceStart, tagCharCount - 1, numSequenceDecimalPos);
                        return true;
                    case 1585: // </size>
                        m_currentFontSize = m_fontSize;
                        m_isRecalculateScaleRequired = true;
                        //m_fontScale = m_fontSize / m_fontAsset.fontInfo.PointSize * .1f;
                        return true;
                    case 1590: // <align=>
                        //Debug.Log("Align " + colorCode);
                        switch (colorCode)
                        {
                            case 4008: // <align=left>
                                m_lineJustification = TextAlignmentOptions.Left;
                                return true;
                            case 5247: // <align=right>
                                m_lineJustification = TextAlignmentOptions.Right;
                                return true;
                            case 6496: // <align=center>
                                m_lineJustification = TextAlignmentOptions.Center;
                                return true;
                            case 10897: // <align=justified>
                                m_lineJustification = TextAlignmentOptions.Justified;
                                return true;
                        }
                        return false;
                    case 1659: // <color=>
                        switch (colorCode)
                        {
                            case 2872: // <color=red>
                                m_htmlColor = Color.red;
                                return true;
                            case 3979: // <color=blue>
                                m_htmlColor = Color.blue;
                                return true;
                            case 4956: // <color=black>
                                m_htmlColor = Color.black;
                                return true;
                            case 5128: // <color=green>
                                m_htmlColor = Color.green;
                                return true;
                            case 5247: // <color=white>
                                m_htmlColor = Color.white;
                                return true;
                            case 6373: // <color=orange>
                                m_htmlColor = new Color32(255, 128, 0, 255);
                                return true;
                            case 6632: // <color=purple>
                                m_htmlColor = new Color32(160, 32, 240, 255);
                                return true;
                            case 6722: // <color=yellow>
                                m_htmlColor = Color.yellow;
                                return true;
                        }
                        return false;
                    case 2154: // <cspace=xx.x>
                        m_cSpacing = ConvertToFloat(m_htmlTag, numSequenceStart, tagCharCount - 1, numSequenceDecimalPos);
                        return true;
                    case 2160: // </align>
                        m_lineJustification = m_textAlignment;
                        return true;
                    case 2824: // </cspace>
                        m_cSpacing = 0;
                        return true;
                    case 2249: // </color>
                        m_htmlColor = m_fontColor32;
                        return true;
                    case 2287: // <sprite=x>
                        Debug.Log("Sprite Tag used.");
                        return true;
                    case 2995: // <allcaps>
                        m_style |= FontStyles.UpperCase;
                        return true;
                    case 3778: // </allcaps>
                        m_style &= ~FontStyles.UpperCase;
                        return true;
                    case 4800: // <smallcaps>
                        m_style |= FontStyles.SmallCaps;
                        return true;
                    case 5807: // </smallcaps>
                        m_currentFontSize = m_fontSize;
                        m_style &= ~FontStyles.SmallCaps;
                        m_isRecalculateScaleRequired = true;
                        return true;
                }
            }

            return false;
        }
        /// <summary>
        /// This is the main function that is responsible for creating / displaying the text.
        /// </summary>
        void GenerateTextMesh()
        {
            //Debug.Log("GenerateTextMesh() called."); // Assigned Material is " + m_uiRenderer.GetMaterial().name); // IncludeForMasking " + this.m_IncludeForMasking); // and text is " + m_text);
            //Debug.Log(this.defaultMaterial.GetInstanceID() + "  " + m_sharedMaterial.GetInstanceID() + "  " + m_uiRenderer.GetMaterial().GetInstanceID());
            // Early exit if no font asset was assigned. This should not be needed since Arial SDF will be assigned by default.
            if (m_fontAsset.characterDictionary == null)
            {
                Debug.Log("Can't Generate Mesh! No Font Asset has been assigned to Object ID: " + this.GetInstanceID());
                return;
            }

            // Reset TextInfo
            if (m_textInfo != null)
            {
                m_textInfo.characterCount = 0;
                m_textInfo.lineCount = 0;
                m_textInfo.spaceCount = 0;
                m_textInfo.wordCount = 0;
                m_textInfo.minWidth = 0;
            }

            // Early exit if we don't have any Text to generate.
            if (m_char_buffer == null || m_char_buffer.Length == 0 || m_char_buffer[0] == (char)0)
            {
                //Debug.Log("Early Out! No Text has been set.");
                if (m_uiVertices != null)
                {
                    m_uiRenderer.SetVertices(m_uiVertices, 0);
                }

                m_preferredWidth = 0;
                m_preferredHeight = 0;

                // This should only be called if there is a layout component attached
                if (IsRectTransformDriven) LayoutRebuilder.MarkLayoutForRebuild(m_rectTransform);
                return;
            }

            // Determine how many characters will be visible and make the necessary allocations (if needed).
            int totalCharacterCount = SetArraySizes(m_char_buffer);

            m_fontIndex = 0; // Will be used when support for using different font assets or sprites withint the same object will be added.
            m_fontAssetArray[m_fontIndex] = m_fontAsset;

            // Scale the font to approximately match the point size
            m_fontScale = (m_fontSize / m_fontAssetArray[m_fontIndex].fontInfo.PointSize);
            //float baseScale = m_fontScale; // BaseScale keeps the character aligned vertically since <size=+000> results in font of different scale.
            m_maxFontScale = 0;
            float previousFontScale = 0;
            m_currentFontSize = m_fontSize;
            float fontSizeDelta = 0;

            int charCode = 0; // Holds the character code of the currently being processed character.
            //int prev_charCode = 0;
            bool isMissingCharacter; // Used to handle missing characters in the Font Atlas / Definition.

            //bool isLineTruncated = false;

            m_style = m_fontStyle; // Set the default style.
            m_lineJustification = m_textAlignment; // Sets the line justification mode to match editor alignment.

            // GetPadding to adjust the size of the mesh due to border thickness, softness, glow, etc...
            if (checkPaddingRequired)
            {
                checkPaddingRequired = false;
                m_padding = ShaderUtilities.GetPadding(m_uiRenderer.GetMaterial(), m_enableExtraPadding, m_isUsingBold);
                m_alignmentPadding = ShaderUtilities.GetFontExtent(m_sharedMaterial);
                m_isMaskingEnabled = ShaderUtilities.IsMaskingEnabled(m_sharedMaterial);
            }

            float style_padding = 0; // Extra padding required to accomodate Bold style.
            float xadvance_multiplier = 1; // Used to increase spacing between character when style is bold.

            m_baselineOffset = 0; // Used by subscript characters.

            bool beginUnderline = false;
            Vector3 underline_start = Vector3.zero; // Used to track where underline starts & ends.
            Vector3 underline_end = Vector3.zero;

            m_fontColor32 = m_fontColor;
            Color32 vertexColor;
            m_htmlColor = m_fontColor32;

            m_lineOffset = 0; // Amount of space between lines (font line spacing + m_linespacing).
            m_cSpacing = 0; // Amount of space added between characters as a result of the use of the <cspace> tag.
            float lineOffsetDelta = 0;
            m_xAdvance = 0; // Used to track the position of each character.
            m_maxXAdvance = 0;

            m_lineNumber = 0;
            m_characterCount = 0; // Total characters in the char[]
            m_visibleCharacterCount = 0; // # of visible characters.

            // Limit Line Length to whatever size fits all characters on a single line.
            //m_lineLength = m_lineLength > max_LineWrapLength ? max_LineWrapLength : m_lineLength;
            int firstCharacterOfLine = 0;
            int lastCharacterOfLine = 0;

            int ellipsisIndex = 0;
            //int truncateIndex = -1;
            //bool isLineTruncated = false;
            //int truncatedLine = 0;
            //m_isTextTruncated = false;

            m_rectTransform.GetLocalCorners(m_rectCorners); // m_textContainer.corners;
            //Debug.Log (corners [0] + "  " + corners [2]);
            Vector4 margins = m_margin; // _textContainer.margins;
            float marginWidth = m_marginWidth; // m_rectTransform.rect.width - margins.z - margins.x;
            float marginHeight = m_marginHeight; // m_rectTransform.rect.height - margins.y - margins.w;

            m_preferredWidth = 0;
            m_preferredHeight = 0;
            //m_layoutWidth = 0;
            //m_layoutHeight = 0;

            // Initialize struct to track states of word wrapping
            m_SavedWordWrapState = new WordWrapState();
            m_SavedLineState = new WordWrapState();
            int wrappingIndex = 0;

            // Need to initialize these Extents Structs
            m_meshExtents = new Extents(k_InfinityVector, -k_InfinityVector);
            if (m_textInfo.wordInfo == null)
                m_textInfo.wordInfo = new List<WordInfo>();
            else
                m_textInfo.wordInfo.Clear();

            if (m_textInfo.lineInfo == null) m_textInfo.lineInfo = new LineInfo[2];
            for (int i = 0; i < m_textInfo.lineInfo.Length; i++)
            {
                m_textInfo.lineInfo[i] = new LineInfo();
                m_textInfo.lineInfo[i].lineExtents = new Extents(k_InfinityVector, -k_InfinityVector);
                m_textInfo.lineInfo[i].ascender = -k_InfinityVector.x;
                m_textInfo.lineInfo[i].descender = k_InfinityVector.x;
            }

            // Tracking of the highest Ascender
            m_maxAscender = 0;
            m_maxDescender = 0;

            bool isLineOffsetAdjusted = false;

            int endTagIndex = 0;
            // Parse through Character buffer to read html tags and begin creating mesh.
            for (int i = 0; m_char_buffer[i] != 0; i++)
            {
                m_tabSpacing = -999;
                m_spacing = -999;
                charCode = m_char_buffer[i];

                //Debug.Log("i:" + i + "  Character [" + (char)charCode + "]");
                //loopCountE += 1;

                if (m_isRichText && charCode == 60)  // '<'
                {
                    // Check if Tag is valid. If valid, skip to the end of the validated tag.
                    if (ValidateHtmlTag(m_char_buffer, i + 1, out endTagIndex))
                    {
                        i = endTagIndex;

                        if (m_isRecalculateScaleRequired)
                        {
                            m_fontScale = m_currentFontSize / m_fontAssetArray[m_fontIndex].fontInfo.PointSize;
                            //isAffectingWordWrapping = true;
                            m_isRecalculateScaleRequired = false;
                        }

                        if (m_tabSpacing != -999)
                        {
                            // Move character to a fix position. Position expresses in characters (approximation).
                            m_xAdvance = m_tabSpacing * m_cached_Underline_GlyphInfo.width * m_fontScale;
                        }

                        if (m_spacing != -999)
                        {
                            m_xAdvance += m_spacing * m_fontScale * m_cached_Underline_GlyphInfo.width;
                        }

                        continue;
                    }
                }

                isMissingCharacter = false;

                // Check if we should be using a different font asset
                //if (m_fontIndex != 0)
                //{
                //    // Check if we need to load the new font asset
                //    if (m_fontAssetArray[m_fontIndex] == null)
                //    {
                //        Debug.Log("Loading secondary font asset.");
                //        m_fontAssetArray[m_fontIndex] = Resources.Load("Fonts & Materials/Bangers SDF", typeof(TextMeshProFont)) as TextMeshProFont;
                //        //m_sharedMaterials.Add(m_fontAssetArray[m_fontIndex].material);
                //        //m_renderer.sharedMaterials = new Material[] { m_sharedMaterial, m_fontAssetArray[m_fontIndex].material }; // m_sharedMaterials.ToArray();
                //    }
                //}
                //Debug.Log("Char [" + (char)charCode + "] is using FontIndex: " + m_fontIndex);

                // Handle Font Styles like LowerCase, UpperCase and SmallCaps.
                #region Handling of LowerCase, UpperCase and SmallCaps Font Styles
                if ((m_style & FontStyles.UpperCase) == FontStyles.UpperCase)
                {
                    // If this character is lowercase, switch to uppercase.
                    if (char.IsLower((char)charCode))
                        charCode -= 32;

                }
                else if ((m_style & FontStyles.LowerCase) == FontStyles.LowerCase)
                {
                    // If this character is uppercase, switch to lowercase.
                    if (char.IsUpper((char)charCode))
                        charCode += 32;
                }
                else if ((m_fontStyle & FontStyles.SmallCaps) == FontStyles.SmallCaps || (m_style & FontStyles.SmallCaps) == FontStyles.SmallCaps)
                {
                    if (char.IsLower((char)charCode))
                    {
                        m_fontScale = m_currentFontSize * 0.8f / m_fontAssetArray[m_fontIndex].fontInfo.PointSize;
                        charCode -= 32;
                    }
                    else
                        m_fontScale = m_currentFontSize / m_fontAssetArray[m_fontIndex].fontInfo.PointSize;

                }
                #endregion

                // Look up Character Data from Dictionary and cache it.
                #region Look up Character Data
                m_fontAssetArray[m_fontIndex].characterDictionary.TryGetValue(charCode, out m_cached_GlyphInfo);
                if (m_cached_GlyphInfo == null)
                {
                    // Character wasn't found in the Dictionary.

                    // Check if Lowercase & Replace by Uppercase if possible
                    if (char.IsLower((char)charCode))
                    {
                        if (m_fontAssetArray[m_fontIndex].characterDictionary.TryGetValue(charCode - 32, out m_cached_GlyphInfo))
                            charCode -= 32;
                    }
                    else if (char.IsUpper((char)charCode))
                    {
                        if (m_fontAssetArray[m_fontIndex].characterDictionary.TryGetValue(charCode + 32, out m_cached_GlyphInfo))
                            charCode += 32;
                    }

                    // Still don't have a replacement?
                    if (m_cached_GlyphInfo == null)
                    {
                        m_fontAssetArray[m_fontIndex].characterDictionary.TryGetValue(88, out m_cached_GlyphInfo);
                        if (m_cached_GlyphInfo != null)
                        {
                            Debug.LogWarning("Character with ASCII value of " + charCode + " was not found in the Font Asset Glyph Table.");
                            // Replace the missing character by X (if it is found)
                            charCode = 88;
                            isMissingCharacter = true;
                        }
                        else
                        {  // At this point the character isn't in the Dictionary, the replacement X isn't either so ...
                            Debug.LogWarning("Character with ASCII value of " + charCode + " was not found in the Font Asset Glyph Table.");
                            continue;
                        }
                    }
                }
                #endregion

                // Store some of the text object's information
                m_textInfo.characterInfo[m_characterCount].character = (char)charCode;
                m_textInfo.characterInfo[m_characterCount].color = m_htmlColor;
                m_textInfo.characterInfo[m_characterCount].style = m_style;
                m_textInfo.characterInfo[m_characterCount].index = (short)i;

                // Handle Kerning if Enabled.
                #region Handle Kerning
                if (m_enableKerning && m_characterCount >= 1)
                {
                    int prev_charCode = m_textInfo.characterInfo[m_characterCount - 1].character;
                    KerningPairKey keyValue = new KerningPairKey(prev_charCode, charCode);

                    KerningPair pair;

                    m_fontAssetArray[m_fontIndex].kerningDictionary.TryGetValue(keyValue.key, out pair);
                    if (pair != null)
                    {
                        m_xAdvance += pair.XadvanceOffset * m_fontScale;
                    }
                }
                #endregion

                // Set Padding based on selected font style
                #region Handle Style Padding
                if ((m_style & FontStyles.Bold) == FontStyles.Bold || (m_fontStyle & FontStyles.Bold) == FontStyles.Bold) // Checks for any combination of Bold Style.
                {
                    style_padding = m_fontAssetArray[m_fontIndex].BoldStyle * 2;
                    xadvance_multiplier = 1.07f; // Increase xAdvance for bold characters.
                }
                else
                {
                    style_padding = m_fontAssetArray[m_fontIndex].NormalStyle * 2;
                    xadvance_multiplier = 1.0f;
                }
                #endregion Handle Style Padding

                // Setup Vertices for each character
                Vector3 top_left = new Vector3(0 + m_xAdvance + ((m_cached_GlyphInfo.xOffset - m_padding - style_padding) * m_fontScale), (m_cached_GlyphInfo.yOffset + m_baselineOffset + m_padding) * m_fontScale - m_lineOffset, 0);
                Vector3 bottom_left = new Vector3(top_left.x, top_left.y - ((m_cached_GlyphInfo.height + m_padding * 2) * m_fontScale), 0);
                Vector3 top_right = new Vector3(bottom_left.x + ((m_cached_GlyphInfo.width + m_padding * 2 + style_padding * 2) * m_fontScale), top_left.y, 0);
                Vector3 bottom_right = new Vector3(top_right.x, bottom_left.y, 0);

                // Check if we need to Shear the rectangles for Italic styles
                #region Handle Italic & Shearing
                if ((m_style & FontStyles.Italic) == FontStyles.Italic || (m_fontStyle & FontStyles.Italic) == FontStyles.Italic)
                {
                    // Shift Top vertices forward by half (Shear Value * height of character) and Bottom vertices back by same amount.
                    float shear_value = m_fontAssetArray[m_fontIndex].ItalicStyle * 0.01f;
                    Vector3 topShear = new Vector3(shear_value * ((m_cached_GlyphInfo.yOffset + m_padding + style_padding) * m_fontScale), 0, 0);
                    Vector3 bottomShear = new Vector3(shear_value * (((m_cached_GlyphInfo.yOffset - m_cached_GlyphInfo.height - m_padding - style_padding)) * m_fontScale), 0, 0);

                    top_left = top_left + topShear;
                    bottom_left = bottom_left + bottomShear;
                    top_right = top_right + topShear;
                    bottom_right = bottom_right + bottomShear;
                }
                #endregion Handle Italics & Shearing

                // Store postion of vertices for each character
                m_textInfo.characterInfo[m_characterCount].topLeft = top_left;
                m_textInfo.characterInfo[m_characterCount].bottomLeft = bottom_left;
                m_textInfo.characterInfo[m_characterCount].topRight = top_right;
                m_textInfo.characterInfo[m_characterCount].bottomRight = bottom_right;

                // Compute MaxAscender & MaxDescender which is used for AutoScaling & other type layout options
                float ascender = (m_fontAsset.fontInfo.Ascender + m_baselineOffset + m_alignmentPadding.y) * m_fontScale;
                if (m_lineNumber == 0) m_maxAscender = m_maxAscender > ascender ? m_maxAscender : ascender;

                //float descender = (m_fontAsset.fontInfo.Descender + m_baselineOffset + m_alignmentPadding.w) * m_fontScale - m_lineOffset;
                //m_maxDescender = m_maxDescender < descender ? m_maxDescender : descender;

                // Set Characters to not visible by default.
                m_textInfo.characterInfo[m_characterCount].isVisible = false;

                // Setup Mesh for visible characters. ie. not a SPACE / LINEFEED / CARRIAGE RETURN.
                #region Handle Visible Characters
                if (charCode != 32 && charCode != 9 && charCode != 10 && charCode != 13)
                {
                    int index_X4 = m_visibleCharacterCount * 4;

                    m_textInfo.characterInfo[m_characterCount].isVisible = true;
                    m_textInfo.characterInfo[m_characterCount].vertexIndex = (short)(0 + index_X4);

                    // Vertices
                    m_uiVertices[0 + index_X4].position = m_textInfo.characterInfo[m_characterCount].bottomLeft;
                    m_uiVertices[1 + index_X4].position = m_textInfo.characterInfo[m_characterCount].topLeft;
                    m_uiVertices[2 + index_X4].position = m_textInfo.characterInfo[m_characterCount].topRight;
                    m_uiVertices[3 + index_X4].position = m_textInfo.characterInfo[m_characterCount].bottomRight;

                    //m_textInfo.characterInfo[character_Count].charNumber = (short)m_lineExtents[lineNumber].characterCount;

                    // Used to adjust line spacing when larger fonts or the size tag is used.
                    if (m_baselineOffset == 0)
                        m_maxFontScale = Mathf.Max(m_maxFontScale, m_fontScale);

                    //Debug.Log("Char [" + (char)charCode + "] Width is " + (m_textInfo.characterInfo[m_characterCount].topRight.x - (m_padding - m_alignmentPadding.z) * m_fontScale) + "  Margin Width is " + marginWidth +
                    //    "  Vertex Padding: " + (m_padding * m_fontScale) + "  Alignment Padding: " + (m_alignmentPadding.z * m_fontScale) + "  Alignment Padding: " + (m_alignmentPadding.x * m_fontScale));

                    // Check if Character exceeds the width of the Text Container
                    #region Check for Characters Exceeding Width of Text Container
                    if (m_textInfo.characterInfo[m_characterCount].topRight.x - (m_padding - m_alignmentPadding.z) * m_fontScale > marginWidth)
                    {

                        // Word Wrapping
                        #region Handle Word Wrapping
                        if (enableWordWrapping)
                        {

                            ellipsisIndex = m_characterCount - 1;

                            if (wrappingIndex == m_SavedWordWrapState.previous_WordBreak) // && m_isCharacterWrappingEnabled == false)
                            {
                                // Word wrapping is no longer possible. Shrink size of text if auto-sizing is enabled.
                                if (m_enableAutoSizing && m_fontSize > m_fontSizeMin)
                                {
                                    //Debug.Log("Reducing Font Size.");
                                    m_maxFontSize = m_fontSize;

                                    float delta = Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.01f);
                                    m_fontSize -= delta;
                                    //Debug.Log("Delta = " + delta);
                                    m_fontSize = Mathf.Max(m_fontSize, m_fontSizeMin);

                                    //loopCountC += 1;
                                    //Debug.Log("Count C: " + loopCountC + " Min: " + m_minFontSize + "  Max: " + m_maxFontSize + "  Size: " + m_fontSize + " Delta: " + fontSizeDelta);
                                    //m_fontSize -= 1f; // 0.25f;
                                    //m_maxFontSize = m_fontSize;
                                    //Debug.Log("Decreasing Width to " + m_fontSize);

                                    GenerateTextMesh();
                                    return;
                                }

                                // Word wrapping is no longer possible, now breaking up individual words.
                                if (m_isCharacterWrappingEnabled == false)
                                {
                                    m_isCharacterWrappingEnabled = true; // Should add a check to make sure this mode is available.
                                    //Debug.Log("Enabling Character Wrapping.");

                                    GenerateTextMesh();
                                    return;
                                }

                                /*
                                if (isAffectingWordWrapping)
                                {
                                    m_textContainer.size = new Vector2(Mathf.Round((top_right.x + margins.x + margins.z) * 100 + 0.5f) / 100f, m_textContainer.rect.height);
                                    GenerateTextMesh();
                                    isAffectingWordWrapping = false;
                                }

                                else
                                {
                                    //Debug.Log("Text can no longer be reduced in size. Min font size reached.");

                                    //m_textContainer.size = new Vector2(Mathf.Round((top_right.x + margins.x + margins.z) * 100 + 0.5f) / 100f, m_textContainer.rect.height);
                                    //GenerateTextMesh();
                                }
                                */
                                //m_isCharacterWrappingEnabled = true;
                                //Debug.Log("Line #" + lineNumber + " Character [" + (char)charCode + "] cannot be wrapped."); // WrappingIndex: " + wrappingIndex + "  Saved Index: " + m_SaveWordWrapState.previous_WordBreak);
                                return;
                            }

                            // Restore to previously stored state of last valid (space character or linefeed)
                            i = RestoreWordWrappingState(ref m_SavedWordWrapState);
                            wrappingIndex = i;  // Used to dectect when line length can no longer be reduced.

                            // Check if we need to Adjust LineOffset & Restore State to the start of the line.
                            if (m_lineNumber > 0 && m_maxFontScale != 0 && m_maxFontScale != previousFontScale && !isLineOffsetAdjusted)
                            {
                                // Compute Offset
                                float gap = m_fontAssetArray[m_fontIndex].fontInfo.LineHeight - (m_fontAssetArray[m_fontIndex].fontInfo.Ascender - m_fontAssetArray[m_fontIndex].fontInfo.Descender);
                                float offsetDelta = (m_fontAssetArray[m_fontIndex].fontInfo.Ascender + m_lineSpacing + m_paragraphSpacing + gap + m_lineSpacingDelta) * m_maxFontScale - (m_fontAssetArray[m_fontIndex].fontInfo.Descender - gap) * previousFontScale;
                                m_lineOffset += offsetDelta - lineOffsetDelta;
                                AdjustLineOffset(firstCharacterOfLine, lastCharacterOfLine, offsetDelta - lineOffsetDelta);
                            }

                            // Calculate lineAscender & make sure if last character is superscript or subscript that we check that as well.
                            float lineAscender = (m_fontAsset.fontInfo.Ascender + m_alignmentPadding.y) * m_maxFontScale - m_lineOffset;
                            float lineAscender2 = (m_fontAsset.fontInfo.Ascender + m_baselineOffset + m_alignmentPadding.y) * m_fontScale - m_lineOffset;
                            lineAscender = lineAscender > lineAscender2 ? lineAscender : lineAscender2;

                            // Calculate lineDescender & make sure if last character is superscript or subscript that we check that as well.
                            float lineDescender = (m_fontAsset.fontInfo.Descender + m_alignmentPadding.w) * m_maxFontScale - m_lineOffset;
                            float lineDescender2 = (m_fontAsset.fontInfo.Descender + m_baselineOffset + m_alignmentPadding.w) * m_fontScale - m_lineOffset;
                            lineDescender = lineDescender < lineDescender2 ? lineDescender : lineDescender2;

                            m_maxDescender = m_maxDescender < lineDescender ? m_maxDescender : lineDescender;

                            // Track & Store lineInfo for the new line
                            m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex = firstCharacterOfLine; // Need new variable to track this
                            m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex = m_characterCount - 1 > 0 ? m_characterCount - 1 : 1;
                            firstCharacterOfLine = m_characterCount; // Store first character for the next line.

                            m_textInfo.lineInfo[m_lineNumber].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex].bottomLeft.x, lineDescender);
                            m_textInfo.lineInfo[m_lineNumber].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex - 1].topRight.x, lineAscender);
                            m_textInfo.lineInfo[m_lineNumber].lineLength = m_textInfo.lineInfo[m_lineNumber].lineExtents.max.x - m_padding * m_maxFontScale;

                            // Compute Preferred Width & Height
                            m_preferredWidth += m_xAdvance; // m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex].topRight.x - m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex].bottomLeft.x;
                            if (m_enableWordWrapping)
                                m_preferredHeight = m_maxAscender - m_maxDescender;
                            else
                                m_preferredHeight = Mathf.Max(m_preferredHeight, lineAscender - lineDescender);

                            //Debug.Log("LineInfo for line # " + (m_lineNumber) + " First character [" + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex].character + "] at Index: " + m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex +
                            //                                                    " Last character [" + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex].character + "] at index: " + m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex +
                            //                                                    " Character Count of " + m_textInfo.lineInfo[m_lineNumber].characterCount + " Line Lenght of " + m_textInfo.lineInfo[m_lineNumber].lineLength +
                            //                                                    "  MinX: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.min.x + "  MinY: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.min.y +
                            //                                                    "  MaxX: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.max.x + "  MaxY: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.max.y +
                            //                                                    "  Line Ascender: " + lineAscender + "  Line Descender: " + lineDescender);

                            // Store the state of the line before starting on the new line.
                            SaveWordWrappingState(ref m_SavedLineState, i);

                            m_lineNumber += 1;
                            // Check to make sure Array is large enough to hold a new line.
                            if (m_lineNumber >= m_textInfo.lineInfo.Length)
                                ResizeLineExtents(m_lineNumber);

                            // Apply Line Spacing based on scale of the last character of the line.
                            lineOffsetDelta = (m_fontAssetArray[m_fontIndex].fontInfo.LineHeight + m_lineSpacing + m_lineSpacingDelta) * m_fontScale;
                            m_lineOffset += lineOffsetDelta;

                            previousFontScale = m_fontScale;
                            m_xAdvance = 0;
                            m_maxFontScale = 0;

                            // Handle Page #
                            //if (m_lineNumber % 5 == 0)
                            //    m_lineOffset = 0;

                            continue;
                        }
                        #endregion End Word Wrapping

                        // Text Auto-Sizing (text exceeding Width of container.
                        #region Handle Text Auto-Sizing
                        if (m_enableAutoSizing && m_fontSize > m_fontSizeMin)
                        {
                            m_maxFontSize = m_fontSize;

                            float delta = Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.01f);
                            m_fontSize -= delta;

                            m_fontSize = Mathf.Max(m_fontSize, m_fontSizeMin);

                            //Debug.Log("Decreasing Width to " + m_fontSize);
                            //loopCountA += 1;
                            //Debug.Log("Count A: " + loopCountA + " Min: " + m_minFontSize + "  Max: " + m_maxFontSize + "  Size: " + m_fontSize + " Delta: " + fontSizeDelta);

                            GenerateTextMesh();
                            return;
                        }
                        #endregion End Text Auto-Sizing

                        // Handle Text Overflow
                        #region Handle Text Overflow
                        switch (m_overflowMode)
                        {
                            case TextOverflowModes.Overflow:
                                if (m_isMaskingEnabled)
                                    DisableMasking();

                                break;
                            case TextOverflowModes.Ellipsis:
                                if (m_isMaskingEnabled)
                                    DisableMasking();

                                m_isTextTruncated = true;

                                if (i < 1) break;

                                m_char_buffer[i - 1] = 8230;
                                m_char_buffer[i] = (char)0;

                                GenerateTextMesh();
                                return;
                            case TextOverflowModes.Masking:
                                if (!m_isMaskingEnabled)
                                    EnableMasking();
                                break;
                            case TextOverflowModes.ScrollRect:
                                if (!m_isMaskingEnabled)
                                    EnableMasking();
                                break;
                            case TextOverflowModes.Truncate:
                                if (m_isMaskingEnabled)
                                    DisableMasking();

                                m_textInfo.characterInfo[m_characterCount].isVisible = false;
                                m_visibleCharacterCount -= 1;
                                break;
                        }
                        #endregion End Text Overflow

                    }
                    #endregion End Check for Characters Exceeding Width of Text Container

                    // Determine what color gets assigned to vertex.
                    #region Handle Vertex Colors
                    if (isMissingCharacter)
                        vertexColor = Color.red;
                    else if (m_overrideHtmlColors)
                        vertexColor = m_fontColor32;
                    else
                        vertexColor = m_htmlColor;

                    // Set Alpha for Shader to render font as normal or bold. (Alpha channel is being used to let the shader know if the character is bold or normal).
                    if ((m_style & FontStyles.Bold) == FontStyles.Bold || (m_fontStyle & FontStyles.Bold) == FontStyles.Bold)
                    {
                        vertexColor.a = m_fontColor32.a < vertexColor.a ? (byte)(m_fontColor32.a >> 1) : (byte)(vertexColor.a >> 1);
                        vertexColor.a += 128;
                    }
                    else
                    {
                        vertexColor.a = m_fontColor32.a < vertexColor.a ? (byte)(m_fontColor32.a >> 1) : (byte)(vertexColor.a >> 1);
                    }

                    // Vertex Colors
                    if (!m_enableVertexGradient)
                    {
                        m_uiVertices[0 + index_X4].color = vertexColor;
                        m_uiVertices[1 + index_X4].color = vertexColor;
                        m_uiVertices[2 + index_X4].color = vertexColor;
                        m_uiVertices[3 + index_X4].color = vertexColor;
                    }
                    else
                    {
                        if (!m_overrideHtmlColors && !m_htmlColor.CompareRGB(m_fontColor32))
                        {
                            m_uiVertices[0 + index_X4].color = vertexColor;
                            m_uiVertices[1 + index_X4].color = vertexColor;
                            m_uiVertices[2 + index_X4].color = vertexColor;
                            m_uiVertices[3 + index_X4].color = vertexColor;
                        }
                        else
                        {
                            m_uiVertices[0 + index_X4].color = m_fontColorGradient.bottomLeft;
                            m_uiVertices[1 + index_X4].color = m_fontColorGradient.topLeft;
                            m_uiVertices[2 + index_X4].color = m_fontColorGradient.topRight;
                            m_uiVertices[3 + index_X4].color = m_fontColorGradient.bottomRight;
                        }

                        m_uiVertices[0 + index_X4].color.a = vertexColor.a;
                        m_uiVertices[1 + index_X4].color.a = vertexColor.a;
                        m_uiVertices[2 + index_X4].color.a = vertexColor.a;
                        m_uiVertices[3 + index_X4].color.a = vertexColor.a;
                    }
                    #endregion Handle Vertex Colors

                    // Apply style_padding only if this is a SDF Shader.
                    if (!m_sharedMaterial.HasProperty(ShaderUtilities.ID_WeightNormal))
                        style_padding = 0;

                    // Setup UVs for the Mesh
                    #region Setup UVs
                    Vector2 uv0 = new Vector2((m_cached_GlyphInfo.x - m_padding - style_padding) / m_fontAssetArray[m_fontIndex].fontInfo.AtlasWidth, 1 - (m_cached_GlyphInfo.y + m_padding + style_padding + m_cached_GlyphInfo.height) / m_fontAssetArray[m_fontIndex].fontInfo.AtlasHeight);  // bottom left
                    Vector2 uv1 = new Vector2(uv0.x, 1 - (m_cached_GlyphInfo.y - m_padding - style_padding) / m_fontAssetArray[m_fontIndex].fontInfo.AtlasHeight);  // top left
                    Vector2 uv2 = new Vector2((m_cached_GlyphInfo.x + m_padding + style_padding + m_cached_GlyphInfo.width) / m_fontAssetArray[m_fontIndex].fontInfo.AtlasWidth, uv0.y); // bottom right
                    Vector2 uv3 = new Vector2(uv2.x, uv1.y); // top right

                    // UV
                    m_uiVertices[0 + index_X4].uv0 = uv0; // BL
                    m_uiVertices[1 + index_X4].uv0 = uv1; // TL
                    m_uiVertices[2 + index_X4].uv0 = uv3; // TR
                    m_uiVertices[3 + index_X4].uv0 = uv2; // BR
                    #endregion Setup UVs

                    // Normal
                    #region Setup Normals & Tangents
                    Vector3 normal = new Vector3(0, 0, -1);
                    m_uiVertices[0 + index_X4].normal = normal;
                    m_uiVertices[1 + index_X4].normal = normal;
                    m_uiVertices[2 + index_X4].normal = normal;
                    m_uiVertices[3 + index_X4].normal = normal;

                    // Tangents
                    Vector4 tangent = new Vector4(-1, 0, 0, 1);
                    m_uiVertices[0 + index_X4].tangent = tangent;
                    m_uiVertices[1 + index_X4].tangent = tangent;
                    m_uiVertices[2 + index_X4].tangent = tangent;
                    m_uiVertices[3 + index_X4].tangent = tangent;
                    #endregion end Normals & Tangents

                    // Determine the bounds of the Mesh.
                    m_meshExtents.min = new Vector2(Mathf.Min(m_meshExtents.min.x, m_textInfo.characterInfo[m_characterCount].bottomLeft.x), Mathf.Min(m_meshExtents.min.y, m_textInfo.characterInfo[m_characterCount].bottomLeft.y));
                    m_meshExtents.max = new Vector2(Mathf.Max(m_meshExtents.max.x, m_textInfo.characterInfo[m_characterCount].topRight.x), Mathf.Max(m_meshExtents.max.y, m_textInfo.characterInfo[m_characterCount].topLeft.y));

                    m_visibleCharacterCount += 1;
                    lastCharacterOfLine = m_characterCount;
                }
                else
                {   // This is a Space, Tab, LineFeed or Carriage Return

                    // Track # of spaces per line which is used for line justification.
                    if (charCode == 9 || charCode == 32)
                    {
                        m_textInfo.lineInfo[m_lineNumber].spaceCount += 1;
                        m_textInfo.spaceCount += 1;
                    }
                }
                #endregion Handle Visible Characters

                // Store Rectangle positions for each Character.
                #region Store Character Data
                m_textInfo.characterInfo[m_characterCount].lineNumber = (short)m_lineNumber;
                m_textInfo.lineInfo[m_lineNumber].characterCount += 1;
                if (charCode != 10 && charCode != 13)
                    m_textInfo.lineInfo[m_lineNumber].alignment = m_lineJustification;
                #endregion Store Character Data

                // Handle Tabulation Stops. Tab stops at every 25% of Font Size.
                #region xAdvance & Tabulation
                if (charCode == 9)
                {
                    m_xAdvance = (int)(m_xAdvance / (m_fontSize * 0.25f) + 1) * (m_fontSize * 0.25f);
                }
                else
                    m_xAdvance += (m_cached_GlyphInfo.xAdvance * xadvance_multiplier * m_fontScale) + m_characterSpacing + m_cSpacing;
                #endregion Tabulation & Stops

                // Handle Carriage Return
                #region Carriage Return
                if (charCode == 13)
                {
                    m_maxXAdvance = Mathf.Max(m_maxXAdvance, m_preferredWidth + m_xAdvance + (m_alignmentPadding.z * m_fontScale));
                    m_preferredWidth = 0;
                    m_xAdvance = 0;
                }
                #endregion Carriage Return

                //Debug.Log("Char [" + (char)charCode + "] with ASCII (" + charCode + ") cummulative xAdvance: " + m_xAdvance);

                // Handle Line Spacing Adjustments + Word Wrapping & special case for last line.
                #region Check for Line Feed and Last Character
                if (charCode == 10 || m_characterCount == totalCharacterCount - 1)
                {
                    //Debug.Log("Line # " + m_lineNumber + "  Current Character is [" + (char)charCode + "] with ASC value of " + charCode);

                    // Handle Line Spacing Changes
                    if (m_lineNumber > 0 && m_maxFontScale != 0 && m_maxFontScale != previousFontScale && !isLineOffsetAdjusted)
                    {
                        float gap = m_fontAssetArray[m_fontIndex].fontInfo.LineHeight - (m_fontAssetArray[m_fontIndex].fontInfo.Ascender - m_fontAssetArray[m_fontIndex].fontInfo.Descender);
                        float offsetDelta = (m_fontAssetArray[m_fontIndex].fontInfo.Ascender + m_lineSpacing + m_paragraphSpacing + gap + m_lineSpacingDelta) * m_maxFontScale - (m_fontAssetArray[m_fontIndex].fontInfo.Descender - gap) * previousFontScale;
                        m_lineOffset += offsetDelta - lineOffsetDelta;
                        AdjustLineOffset(firstCharacterOfLine, lastCharacterOfLine, offsetDelta - lineOffsetDelta);
                    }

                    // Calculate lineAscender & make sure if last character is superscript or subscript that we check that as well.
                    float lineAscender = (m_fontAsset.fontInfo.Ascender + m_alignmentPadding.y) * m_maxFontScale - m_lineOffset;
                    float lineAscender2 = (m_fontAsset.fontInfo.Ascender + m_baselineOffset + m_alignmentPadding.y) * m_fontScale - m_lineOffset;
                    lineAscender = lineAscender > lineAscender2 ? lineAscender : lineAscender2;

                    // Calculate lineDescender & make sure if last character is superscript or subscript that we check that as well.
                    float lineDescender = (m_fontAsset.fontInfo.Descender + m_alignmentPadding.w) * m_maxFontScale - m_lineOffset;
                    float lineDescender2 = (m_fontAsset.fontInfo.Descender + m_baselineOffset + m_alignmentPadding.w) * m_fontScale - m_lineOffset;
                    lineDescender = lineDescender < lineDescender2 ? lineDescender : lineDescender2;

                    m_maxDescender = m_maxDescender < lineDescender ? m_maxDescender : lineDescender;

                    // Save Line Information
                    m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex = firstCharacterOfLine; // Need new variable to track this
                    m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex = charCode == 10 ? lastCharacterOfLine + 1 : lastCharacterOfLine;
                    firstCharacterOfLine = m_characterCount + 1;

                    m_textInfo.lineInfo[m_lineNumber].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex].bottomLeft.x, lineDescender);
                    m_textInfo.lineInfo[m_lineNumber].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex - (charCode == 10 ? 1 : 0)].topRight.x, lineAscender);
                    m_textInfo.lineInfo[m_lineNumber].lineLength = m_textInfo.lineInfo[m_lineNumber].lineExtents.max.x - (m_padding * m_maxFontScale);

                    // Store PreferredWidth paying attention to linefeed and last character of text.
                    if (charCode == 10 && m_characterCount != totalCharacterCount - 1)
                    {
                        m_maxXAdvance = Mathf.Max(m_maxXAdvance, m_preferredWidth + m_xAdvance + (m_alignmentPadding.z * m_fontScale));
                        m_preferredWidth = 0;
                    }
                    else
                        m_preferredWidth = Mathf.Max(m_maxXAdvance, m_preferredWidth + m_xAdvance + (m_alignmentPadding.z * m_fontScale));

                    //Debug.Log("Line # " + m_lineNumber + " XAdance is " +  (m_preferredWidth + m_xAdvance + (m_alignmentPadding.z * m_fontScale)) + "  Max XAdvance: " + m_maxXAdvance);

                    //m_preferredWidth += m_xAdvance + (m_alignmentPadding.z * m_fontScale);
                    if (m_enableWordWrapping)
                        m_preferredHeight = m_maxAscender - m_maxDescender;
                    else
                        m_preferredHeight = Mathf.Max(m_preferredHeight, lineAscender - lineDescender);

                    //Debug.Log("LineInfo for line # " + (m_lineNumber) + " First character [" + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex].character + "] at Index: " + m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex +
                    //                                                    " Last character [" + m_textInfo.characterInfo[m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex].character + "] at index: " + m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex +
                    //                                                    " Character Count of " + m_textInfo.lineInfo[m_lineNumber].characterCount + " Line Lenght of " + m_textInfo.lineInfo[m_lineNumber].lineLength +
                    //                                                    "  MinX: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.min.x + "  MinY: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.min.y +
                    //                                                    "  MaxX: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.max.x + "  MaxY: " + m_textInfo.lineInfo[m_lineNumber].lineExtents.max.y +
                    //                                                    "  Line Ascender: " + lineAscender + "  Line Descender: " + lineDescender);

                    // Add new line if not last lines or character.
                    if (charCode == 10)
                    {
                        // Store the state of the line before starting on the new line.
                        SaveWordWrappingState(ref m_SavedLineState, i);

                        m_lineNumber += 1;
                        // Check to make sure Array is large enough to hold a new line.
                        if (m_lineNumber >= m_textInfo.lineInfo.Length)
                            ResizeLineExtents(m_lineNumber);

                        // Apply Line Spacing based on scale of the last character of the line.
                        lineOffsetDelta = (m_fontAssetArray[m_fontIndex].fontInfo.LineHeight + m_paragraphSpacing + m_lineSpacing + m_lineSpacingDelta) * m_fontScale;
                        m_lineOffset += lineOffsetDelta;

                        previousFontScale = m_fontScale;
                        m_maxFontScale = 0;
                        m_xAdvance = 0;

                        // Check for page #
                        //if (m_lineNumber % 5 == 0)
                        //    m_lineOffset = 0;
                    }
                }
                #endregion Check for Linefeed or Last Character

                // Check if text Exceeds the vertical bounds of the margin area.
                #region Check Vertical Bounds & Auto-Sizing
                if (m_maxAscender - m_maxDescender + (m_alignmentPadding.w * 2 * m_fontScale) > marginHeight)
                {
                    //Debug.Log((m_maxAscender - m_maxDescender) + "  " + marginHeight);
                    //Debug.Log("Character [" + (char)charCode + "] at Index: " + m_characterCount + " has exceeded the Height of the text container. Max Ascender: " + m_maxAscender + "  Max Descender: " + m_maxDescender + "  Margin Height: " + marginHeight + " Bottom Left: " + bottom_left.y);

                    // Handle Linespacing adjustments
                    #region Line Spacing Adjustments
                    if (m_enableAutoSizing && m_lineSpacingDelta > m_lineSpacingMax)
                    {
                        m_lineSpacingDelta -= 1;
                        GenerateTextMesh();
                        return;
                    }
                    #endregion

                    // Handle Text Auto-sizing resulting from text exceeding vertical bounds.
                    #region Text Auto-Sizing (Text greater than verical bounds)
                    if (m_enableAutoSizing && m_fontSize > m_fontSizeMin)
                    {
                        m_maxFontSize = m_fontSize;

                        float delta = Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.01f);
                        //if (delta == 0.01f) return;

                        m_fontSize -= delta;

                        m_fontSize = Mathf.Max(m_fontSize, m_fontSizeMin);
                        //Debug.Log("Decreasing Height to " + m_fontSize);
                        //loopCountB += 1;
                        //Debug.Log("Count B: " + loopCountB + " Min: " + m_minFontSize + "  Max: " + m_maxFontSize + "  Size: " + m_fontSize + " Delta: " + (m_maxFontSize - m_minFontSize).ToString("f4"));

                        GenerateTextMesh();
                        return;
                    }
                    #endregion Text Auto-Sizing

                    // Handle Text Overflow
                    #region Text Overflow
                    switch (m_overflowMode)
                    {
                        case TextOverflowModes.Overflow:
                            if (m_isMaskingEnabled)
                                DisableMasking();

                            break;
                        case TextOverflowModes.Ellipsis:
                            if (m_isMaskingEnabled)
                                DisableMasking();

                            if (m_lineNumber > 0)
                            {
                                m_char_buffer[m_textInfo.characterInfo[ellipsisIndex].index] = 8230;
                                m_char_buffer[m_textInfo.characterInfo[ellipsisIndex].index + 1] = (char)0;
                                GenerateTextMesh();
                                m_isTextTruncated = true;
                                return;
                            }
                            else
                            {
                                m_char_buffer[0] = (char)0;
                                GenerateTextMesh();
                                m_isTextTruncated = true;
                                return;
                            }
                        case TextOverflowModes.Masking:
                            if (!m_isMaskingEnabled)
                                EnableMasking();
                            break;
                        case TextOverflowModes.ScrollRect:
                            if (!m_isMaskingEnabled)
                                EnableMasking();
                            break;
                        case TextOverflowModes.Truncate:
                            if (m_isMaskingEnabled)
                                DisableMasking();

                            if (m_lineNumber > 0)
                            {
                                m_char_buffer[m_textInfo.characterInfo[ellipsisIndex].index + 1] = (char)0;
                                GenerateTextMesh();
                                m_isTextTruncated = true;
                                return;
                            }
                            else
                            {
                                m_char_buffer[0] = (char)0;
                                GenerateTextMesh();
                                m_isTextTruncated = true;
                                return;
                            }
                        //case TextOverflowModes.Pages:
                        //    if (m_isMaskingEnabled)
                        //        DisableMasking();

                        //    // Go back to previous line and re-layout
                        //    i = RestoreWordWrappingState(ref m_SavedLineState);
                        //    m_xAdvance = 0;
                        //    m_lineOffset = 0;
                        //    continue;

                        //    //break;

                    }
                    #endregion End Text Overflow

                }
                #endregion Check Vertical Bounds

                //// Store Rectangle positions for each Character.
                #region Save CharacterInfo for the current character.
                m_textInfo.characterInfo[m_characterCount].baseLine = m_textInfo.characterInfo[m_characterCount].topRight.y - (m_cached_GlyphInfo.yOffset + m_padding) * m_fontScale;
                m_textInfo.characterInfo[m_characterCount].topLine = m_textInfo.characterInfo[m_characterCount].baseLine + (m_fontAssetArray[m_fontIndex].fontInfo.Ascender + m_alignmentPadding.y) * m_fontScale; // Ascender
                m_textInfo.characterInfo[m_characterCount].bottomLine = m_textInfo.characterInfo[m_characterCount].baseLine + (m_fontAssetArray[m_fontIndex].fontInfo.Descender - m_alignmentPadding.w) * m_fontScale; // Descender
                m_textInfo.characterInfo[m_characterCount].padding = m_padding * m_fontScale;
                m_textInfo.characterInfo[m_characterCount].aspectRatio = m_cached_GlyphInfo.width / m_cached_GlyphInfo.height;
                m_textInfo.characterInfo[m_characterCount].scale = m_fontScale;
                #endregion Saving CharacterInfo

                // Save State of Mesh Creation forhandling of Word Wrapping
                #region Save Word Wrapping State
                if (m_enableWordWrapping)
                {
                    //char c;
                    //m_fontAsset.lineBreakingInfo.leadingCharacters.ContainsKey(charCode);

                    //Debug.Log((char)charCode + "  " +  m_fontAsset.lineBreakingInfo.leadingCharacters.ContainsKey(charCode));

                    if (m_isCharacterWrappingEnabled == false && (charCode == 9 || charCode == 32))
                    {
                        // We store the state of numerous variables for the most recent Space, LineFeed or Carriage Return to enable them to be restored
                        // for Word Wrapping.
                        SaveWordWrappingState(ref m_SavedWordWrapState, i);
                        //Debug.Log("Storing Character [" + (char)charCode + "] at Index: " + i);
                    }
                    else if (m_isCharacterWrappingEnabled == true && m_characterCount < totalCharacterCount - 1
                           && m_fontAsset.lineBreakingInfo.leadingCharacters.ContainsKey(charCode) == false
                           && m_fontAsset.lineBreakingInfo.followingCharacters.ContainsKey(m_VisibleCharacters[m_characterCount + 1]) == false
                           && (charCode < 48 || charCode > 57) && charCode != 44)
                    {
                        //Debug.Log("Storing Character [" + (char)charCode + "] at Index: " + i);
                        SaveWordWrappingState(ref m_SavedWordWrapState, i);
                    }
                }
                #endregion Save Word Wrapping State

                m_characterCount += 1;
            }

            // Check Auto Sizing and increase font size to fill text container.
            #region Check Auto-Sizing (Upper Font Size Bounds)
            fontSizeDelta = m_maxFontSize - m_minFontSize;
            if (m_enableAutoSizing && fontSizeDelta > 0.25f && m_fontSize < m_fontSizeMax)
            {
                m_minFontSize = m_fontSize;
                m_fontSize = m_fontSize + (m_maxFontSize - m_fontSize) / 2;

                //loopCountD += 1;
                //Debug.Log("Count D: " + loopCountD + " Min: " + m_minFontSize + "  Max: " + m_maxFontSize + "  Size: " + m_fontSize + " Delta: " + fontSizeDelta);

                m_fontSize = Mathf.Min(m_fontSize, m_fontSizeMax);

                GenerateTextMesh();
                return;
            }
            #endregion End Auto-sizing Check

            // Add Termination Character to textMeshCharacterInfo which is used by the Advanced Layout Component.
            if (m_characterCount < m_textInfo.characterInfo.Length)
                m_textInfo.characterInfo[m_characterCount].character = (char)0;

            if (m_renderMode == TextRenderFlags.GetPreferredSizes)
                return;

            // DEBUG & PERFORMANCE CHECKS (0.006ms)
            //m_StopWatch.Stop();

            // If there are no visible characters... no need to continue
            if (m_visibleCharacterCount == 0)
            {
                if (m_uiVertices != null)
                {
                    m_uiRenderer.SetVertices(m_uiVertices, 0);
                }
                return;
            }

            int last_vert_index = m_visibleCharacterCount * 4;
            // Partial clear of the vertices array to mark unused vertices as degenerate.
            Array.Clear(m_uiVertices, last_vert_index, m_uiVertices.Length - last_vert_index);

            // Handle Text Alignment
            #region Text Alignment
            switch (m_textAlignment)
            {
                // Top Vertically
                case TextAlignmentOptions.Top:
                case TextAlignmentOptions.TopLeft:
                case TextAlignmentOptions.TopJustified:
                case TextAlignmentOptions.TopRight:
                    m_anchorOffset = m_rectCorners[1] + new Vector3(0 + margins.x, 0 - m_maxAscender - margins.y, 0);
                    break;

                // Middle Vertically
                case TextAlignmentOptions.Left:
                case TextAlignmentOptions.Right:
                case TextAlignmentOptions.Center:
                case TextAlignmentOptions.Justified:
                    m_anchorOffset = (m_rectCorners[0] + m_rectCorners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_maxAscender + margins.y + m_maxDescender - margins.w) / 2, 0);
                    break;

                // Bottom Vertically
                case TextAlignmentOptions.Bottom:
                case TextAlignmentOptions.BottomLeft:
                case TextAlignmentOptions.BottomRight:
                case TextAlignmentOptions.BottomJustified:
                    m_anchorOffset = m_rectCorners[0] + new Vector3(0 + margins.x, 0 - m_maxDescender + margins.w, 0);
                    break;

                // Baseline Vertically
                case TextAlignmentOptions.BaselineLeft:
                case TextAlignmentOptions.BaselineRight:
                case TextAlignmentOptions.Baseline:
                    m_anchorOffset = (m_rectCorners[0] + m_rectCorners[1]) / 2 + new Vector3(0 + margins.x, 0, 0);
                    break;
            }
            #endregion Text Alignment

            // Handling of Anchor Dampening. If mesh width changes by more than 1/3 of the underline character's wdith then adjust it.
            float currentMeshWidth = m_meshExtents.max.x - m_meshExtents.min.x;
            if (m_anchorDampening)
            {
                float delta = currentMeshWidth - m_baseDampeningWidth;
                if (m_baseDampeningWidth != 0 && Mathf.Abs(delta) < m_cached_Underline_GlyphInfo.width * m_fontScale * 0.6f)
                    m_anchorOffset.x += delta / 2;
                else
                    m_baseDampeningWidth = currentMeshWidth;
            }

            // Initialization for Second Pass
            Vector3 justificationOffset = Vector3.zero;
            Vector3 offset = Vector3.zero;
            int vert_index_X4 = 0;
            int underlineSegmentCount = 0;

            int wordCount = 0;
            int lineCount = 0;
            int lastLine = 0;

            bool isStartOfWord = false;
            int wordFirstChar = 0;
            int wordLastChar = 0;

            // Second Pass : Line Justification, UV Mapping, Character & Line Visibility & more.
            #region Handle Line Justification & UV Mapping & Character Visibility & More
            for (int i = 0; i < m_characterCount; i++)
            {
                int currentLine = m_textInfo.characterInfo[i].lineNumber;
                char currentCharacter = m_textInfo.characterInfo[i].character;
                LineInfo lineInfo = m_textInfo.lineInfo[currentLine];
                TextAlignmentOptions lineAlignment = lineInfo.alignment;
                lineCount = currentLine + 1;

                // Process Line Justification
                #region Handle Line Justification
                switch (lineAlignment)
                {
                    case TextAlignmentOptions.TopLeft:
                    case TextAlignmentOptions.Left:
                    case TextAlignmentOptions.BottomLeft:
                    case TextAlignmentOptions.BaselineLeft:
                        justificationOffset = Vector3.zero;
                        break;

                    case TextAlignmentOptions.Top:
                    case TextAlignmentOptions.Center:
                    case TextAlignmentOptions.Bottom:
                    case TextAlignmentOptions.Baseline:
                        justificationOffset = new Vector3(marginWidth / 2 - (lineInfo.lineExtents.min.x + lineInfo.lineExtents.max.x) / 2, 0, 0);
                        break;

                    case TextAlignmentOptions.TopRight:
                    case TextAlignmentOptions.Right:
                    case TextAlignmentOptions.BottomRight:
                    case TextAlignmentOptions.BaselineRight:
                        justificationOffset = new Vector3(marginWidth - lineInfo.lineExtents.max.x, 0, 0);
                        break;

                    case TextAlignmentOptions.TopJustified:
                    case TextAlignmentOptions.Justified:
                    case TextAlignmentOptions.BottomJustified:
                        charCode = m_textInfo.characterInfo[i].character;
                        char lastCharOfCurrentLine = m_textInfo.characterInfo[lineInfo.lastCharacterIndex].character;

                        if (char.IsWhiteSpace(lastCharOfCurrentLine) && !char.IsControl(lastCharOfCurrentLine) && currentLine < m_lineNumber)
                        {   // All lines are justified accept the last one.
                            float gap = (m_rectCorners[3].x - margins.z) - (m_rectCorners[0].x + margins.x) - (lineInfo.lineExtents.max.x);
                            if (currentLine != lastLine || i == 0)
                                justificationOffset = Vector3.zero;
                            else
                            {
                                if (charCode == 9 || charCode == 32)
                                {
                                    justificationOffset += new Vector3(gap * (1 - m_wordWrappingRatios) / (lineInfo.spaceCount - 1), 0, 0);
                                }
                                else
                                {
                                    //Debug.Log("LineInfo Character Count: " + lineInfo.characterCount);
                                    justificationOffset += new Vector3(gap * m_wordWrappingRatios / (lineInfo.characterCount - lineInfo.spaceCount - 1), 0, 0);
                                }
                            }
                        }
                        else
                            justificationOffset = Vector3.zero; // Keep last line left justified.

                        //Debug.Log("Char [" + (char)charCode + "] Code:" + charCode + "  Offset:" + justificationOffset + "  # Spaces:" + m_lineExtents[currentLine].NumberOfSpaces + "  # Characters:" + m_lineExtents[currentLine].NumberOfChars);
                        break;
                }
                #endregion End Text Justification

                offset = m_anchorOffset + justificationOffset;

                if (m_textInfo.characterInfo[i].isVisible)
                {
                    Extents lineExtents = lineInfo.lineExtents;
                    float uvOffset = (m_uvLineOffset * currentLine) % 1 + m_uvOffset.x;

                    // Setup UV2 based on Character Mapping Options Selected
                    #region Handle UV Mapping Options
                    switch (m_horizontalMapping)
                    {
                        case TextureMappingOptions.Character:
                            m_uiVertices[vert_index_X4 + 0].uv1.x = 0 + m_uvOffset.x;
                            m_uiVertices[vert_index_X4 + 1].uv1.x = 0 + m_uvOffset.x;
                            m_uiVertices[vert_index_X4 + 2].uv1.x = 1 + m_uvOffset.x;
                            m_uiVertices[vert_index_X4 + 3].uv1.x = 1 + m_uvOffset.x;
                            break;

                        case TextureMappingOptions.Line:
                            if (m_textAlignment != TextAlignmentOptions.Justified)
                            {
                                m_uiVertices[vert_index_X4 + 0].uv1.x = (m_uiVertices[vert_index_X4 + 0].position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
                                m_uiVertices[vert_index_X4 + 1].uv1.x = (m_uiVertices[vert_index_X4 + 1].position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
                                m_uiVertices[vert_index_X4 + 2].uv1.x = (m_uiVertices[vert_index_X4 + 2].position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
                                m_uiVertices[vert_index_X4 + 3].uv1.x = (m_uiVertices[vert_index_X4 + 3].position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
                                break;
                            }
                            else // Special Case if Justified is used in Line Mode.
                            {
                                m_uiVertices[vert_index_X4 + 0].uv1.x = (m_uiVertices[vert_index_X4 + 0].position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                                m_uiVertices[vert_index_X4 + 1].uv1.x = (m_uiVertices[vert_index_X4 + 1].position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                                m_uiVertices[vert_index_X4 + 2].uv1.x = (m_uiVertices[vert_index_X4 + 2].position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                                m_uiVertices[vert_index_X4 + 3].uv1.x = (m_uiVertices[vert_index_X4 + 3].position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                                break;
                            }

                        case TextureMappingOptions.Paragraph:
                            m_uiVertices[vert_index_X4 + 0].uv1.x = (m_uiVertices[vert_index_X4 + 0].position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                            m_uiVertices[vert_index_X4 + 1].uv1.x = (m_uiVertices[vert_index_X4 + 1].position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                            m_uiVertices[vert_index_X4 + 2].uv1.x = (m_uiVertices[vert_index_X4 + 2].position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                            m_uiVertices[vert_index_X4 + 3].uv1.x = (m_uiVertices[vert_index_X4 + 3].position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
                            break;

                        case TextureMappingOptions.MatchAspect:

                            switch (m_verticalMapping)
                            {
                                case TextureMappingOptions.Character:
                                    m_uiVertices[vert_index_X4 + 0].uv1.y = 0 + m_uvOffset.y;
                                    m_uiVertices[vert_index_X4 + 1].uv1.y = 1 + m_uvOffset.y;
                                    m_uiVertices[vert_index_X4 + 2].uv1.y = 0 + m_uvOffset.y;
                                    m_uiVertices[vert_index_X4 + 3].uv1.y = 1 + m_uvOffset.y;
                                    break;

                                case TextureMappingOptions.Line:
                                    m_uiVertices[vert_index_X4 + 0].uv1.y = (m_uiVertices[vert_index_X4].position.y - lineExtents.min.y) / (lineExtents.max.y - lineExtents.min.y) + uvOffset;
                                    m_uiVertices[vert_index_X4 + 1].uv1.y = (m_uiVertices[vert_index_X4 + 1].position.y - lineExtents.min.y) / (lineExtents.max.y - lineExtents.min.y) + uvOffset;
                                    m_uiVertices[vert_index_X4 + 2].uv1.y = m_uiVertices[vert_index_X4].uv1.y;
                                    m_uiVertices[vert_index_X4 + 3].uv1.y = m_uiVertices[vert_index_X4 + 1].uv1.y;
                                    break;

                                case TextureMappingOptions.Paragraph:
                                    m_uiVertices[vert_index_X4 + 0].uv1.y = (m_uiVertices[vert_index_X4].position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y) + uvOffset;
                                    m_uiVertices[vert_index_X4 + 1].uv1.y = (m_uiVertices[vert_index_X4 + 1].position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y) + uvOffset;
                                    m_uiVertices[vert_index_X4 + 2].uv1.y = m_uiVertices[vert_index_X4].uv1.y;
                                    m_uiVertices[vert_index_X4 + 3].uv1.y = m_uiVertices[vert_index_X4 + 1].uv1.y;
                                    break;

                                case TextureMappingOptions.MatchAspect:
                                    Debug.Log("ERROR: Cannot Match both Vertical & Horizontal.");
                                    break;
                            }

                            //float xDelta = 1 - (_uv2s[vert_index + 0].y * textMeshCharacterInfo[i].AspectRatio); // Left aligned
                            float xDelta = (1 - ((m_uiVertices[vert_index_X4 + 0].uv1.y + m_uiVertices[vert_index_X4 + 1].uv1.y) * m_textInfo.characterInfo[i].aspectRatio)) / 2; // Center of Rectangle
                            //float xDelta = 0;

                            m_uiVertices[vert_index_X4 + 0].uv1.x = (m_uiVertices[vert_index_X4 + 0].uv1.y * m_textInfo.characterInfo[i].aspectRatio) + xDelta + uvOffset;
                            m_uiVertices[vert_index_X4 + 1].uv1.x = m_uiVertices[vert_index_X4 + 0].uv1.x;
                            m_uiVertices[vert_index_X4 + 2].uv1.x = (m_uiVertices[vert_index_X4 + 1].uv1.y * m_textInfo.characterInfo[i].aspectRatio) + xDelta + uvOffset;
                            m_uiVertices[vert_index_X4 + 3].uv1.x = m_uiVertices[vert_index_X4 + 2].uv1.x;
                            break;
                    }

                    switch (m_verticalMapping)
                    {
                        case TextureMappingOptions.Character:
                            m_uiVertices[vert_index_X4 + 0].uv1.y = 0 + m_uvOffset.y;
                            m_uiVertices[vert_index_X4 + 1].uv1.y = 1 + m_uvOffset.y;
                            m_uiVertices[vert_index_X4 + 2].uv1.y = 1 + m_uvOffset.y;
                            m_uiVertices[vert_index_X4 + 3].uv1.y = 0 + m_uvOffset.y;
                            break;

                        case TextureMappingOptions.Line:
                            m_uiVertices[vert_index_X4 + 0].uv1.y = (m_uiVertices[vert_index_X4].position.y - lineExtents.min.y) / (lineExtents.max.y - lineExtents.min.y) + m_uvOffset.y;
                            m_uiVertices[vert_index_X4 + 1].uv1.y = (m_uiVertices[vert_index_X4 + 1].position.y - lineExtents.min.y) / (lineExtents.max.y - lineExtents.min.y) + m_uvOffset.y;
                            m_uiVertices[vert_index_X4 + 3].uv1.y = m_uiVertices[vert_index_X4].uv1.y;
                            m_uiVertices[vert_index_X4 + 2].uv1.y = m_uiVertices[vert_index_X4 + 1].uv1.y;
                            break;

                        case TextureMappingOptions.Paragraph:
                            m_uiVertices[vert_index_X4 + 0].uv1.y = (m_uiVertices[vert_index_X4].position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y) + m_uvOffset.y;
                            m_uiVertices[vert_index_X4 + 1].uv1.y = (m_uiVertices[vert_index_X4 + 1].position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y) + m_uvOffset.y;
                            m_uiVertices[vert_index_X4 + 3].uv1.y = m_uiVertices[vert_index_X4].uv1.y;
                            m_uiVertices[vert_index_X4 + 2].uv1.y = m_uiVertices[vert_index_X4 + 1].uv1.y;
                            break;

                        case TextureMappingOptions.MatchAspect:
                            //float yDelta = 1 - (_uv2s[vert_index + 2].x / textMeshCharacterInfo[i].AspectRatio); // Top Corner
                            float yDelta = (1 - ((m_uiVertices[vert_index_X4 + 0].uv1.x + m_uiVertices[vert_index_X4 + 2].uv1.x) / m_textInfo.characterInfo[i].aspectRatio)) / 2; // Center of Rectangle
                            //float yDelta = 0;

                            m_uiVertices[vert_index_X4 + 0].uv1.y = yDelta + (m_uiVertices[vert_index_X4 + 0].uv1.x / m_textInfo.characterInfo[i].aspectRatio) + m_uvOffset.y;
                            m_uiVertices[vert_index_X4 + 1].uv1.y = yDelta + (m_uiVertices[vert_index_X4 + 2].uv1.x / m_textInfo.characterInfo[i].aspectRatio) + m_uvOffset.y;
                            m_uiVertices[vert_index_X4 + 2].uv1.y = m_uiVertices[vert_index_X4 + 0].uv1.y;
                            m_uiVertices[vert_index_X4 + 3].uv1.y = m_uiVertices[vert_index_X4 + 1].uv1.y;
                            break;
                    }
                    #endregion End UV Mapping Options

                    // Pack UV's so that we can pass Xscale needed for Shader to maintain 1:1 ratio.
                    float xScale = m_textInfo.characterInfo[i].scale * m_rectTransform.lossyScale.z;

                    float x0 = m_uiVertices[vert_index_X4 + 0].uv1.x;
                    float y0 = m_uiVertices[vert_index_X4 + 0].uv1.y;
                    float x1 = m_uiVertices[vert_index_X4 + 2].uv1.x;
                    float y1 = m_uiVertices[vert_index_X4 + 2].uv1.y;

                    float dx = Mathf.Floor(x0);
                    float dy = Mathf.Floor(y0);

                    x0 = x0 - dx;
                    x1 = x1 - dx;
                    y0 = y0 - dy;
                    y1 = y1 - dy;

                    m_uiVertices[vert_index_X4 + 0].uv1 = PackUV(x0, y0, xScale);
                    m_uiVertices[vert_index_X4 + 1].uv1 = PackUV(x0, y1, xScale);
                    m_uiVertices[vert_index_X4 + 2].uv1 = PackUV(x1, y1, xScale);
                    m_uiVertices[vert_index_X4 + 3].uv1 = PackUV(x1, y0, xScale);

                    // Enables control of the visibility of characters && lines.
                    if (m_maxVisibleCharacters != -1 && i >= m_maxVisibleCharacters || m_maxVisibleLines != -1 && currentLine >= m_maxVisibleLines) // || pages != AllPages &&
                    {
                        m_uiVertices[vert_index_X4 + 0].position *= 0;
                        m_uiVertices[vert_index_X4 + 1].position *= 0;
                        m_uiVertices[vert_index_X4 + 2].position *= 0;
                        m_uiVertices[vert_index_X4 + 3].position *= 0;
                    }
                    else
                    {
                        m_uiVertices[vert_index_X4 + 0].position += offset;
                        m_uiVertices[vert_index_X4 + 1].position += offset;
                        m_uiVertices[vert_index_X4 + 2].position += offset;
                        m_uiVertices[vert_index_X4 + 3].position += offset;
                    }

                    vert_index_X4 += 4;
                }

                m_textInfo.characterInfo[i].bottomLeft += offset;
                m_textInfo.characterInfo[i].topRight += offset;
                m_textInfo.characterInfo[i].topLine += offset.y;
                m_textInfo.characterInfo[i].bottomLine += offset.y;
                m_textInfo.characterInfo[i].baseLine += offset.y;

                // Store Max Ascender & Descender
                m_textInfo.lineInfo[currentLine].ascender = m_textInfo.characterInfo[i].topLine > m_textInfo.lineInfo[currentLine].ascender ? m_textInfo.characterInfo[i].topLine : m_textInfo.lineInfo[currentLine].ascender;
                m_textInfo.lineInfo[currentLine].descender = m_textInfo.characterInfo[i].bottomLine < m_textInfo.lineInfo[currentLine].descender ? m_textInfo.characterInfo[i].bottomLine : m_textInfo.lineInfo[currentLine].descender;

                // Need to recompute lineExtent to account for the offset from justification.
                if (currentLine != lastLine || i == m_characterCount - 1)
                {
                    m_textInfo.lineInfo[lastLine].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[lastLine].firstCharacterIndex].bottomLeft.x, m_textInfo.lineInfo[lastLine].descender);
                    m_textInfo.lineInfo[lastLine].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[lastLine].lastCharacterIndex].topRight.x, m_textInfo.lineInfo[lastLine].ascender);
                }

                // Track Word Count per line and for the object
                if (char.IsLetterOrDigit(currentCharacter) && i < m_characterCount - 1)
                {
                    if (isStartOfWord == false)
                    {
                        isStartOfWord = true;
                        wordFirstChar = i;
                    }
                }
                else if ((char.IsPunctuation(currentCharacter) || char.IsWhiteSpace(currentCharacter) || i == m_characterCount - 1) && isStartOfWord || i == 0)
                {
                    wordLastChar = i == m_characterCount - 1 && char.IsLetterOrDigit(currentCharacter) ? i : i - 1;
                    isStartOfWord = false;

                    wordCount += 1;
                    m_textInfo.lineInfo[currentLine].wordCount += 1;

                    WordInfo wordInfo = new WordInfo();
                    wordInfo.firstCharacterIndex = wordFirstChar;
                    wordInfo.lastCharacterIndex = wordLastChar;
                    wordInfo.characterCount = wordLastChar - wordFirstChar + 1;
                    m_textInfo.wordInfo.Add(wordInfo);
                    //Debug.Log("Word #" + wordCount + " is [" + wordInfo.word + "] Start Index: " + wordInfo.firstCharacterIndex + "  End Index: " + wordInfo.lastCharacterIndex);
                }

                // Handle Underline
                #region Underline Tracking
                // TODO : Address underline and which font to use in the list
                if ((m_textInfo.characterInfo[i].style & FontStyles.Underline) == FontStyles.Underline && i != m_textInfo.lineInfo[currentLine].lastCharacterIndex) // m_textInfo.characterInfo[i].character != 10 && m_textInfo.characterInfo[i].character != 13)
                {
                    if (beginUnderline == false)
                    {
                        beginUnderline = true;
                        underline_start = new Vector3(m_textInfo.characterInfo[i].bottomLeft.x, m_textInfo.characterInfo[i].baseLine + font.fontInfo.Underline * m_fontScale, 0);
                        //Debug.Log("Underline Start Char [" + m_textInfo.characterInfo[i].character + "].");
                    }
                }
                else
                {
                    if (beginUnderline == true)
                    {
                        beginUnderline = false;
                        if (i != m_characterCount - 1 && (m_textInfo.characterInfo[i].character == 32 || m_textInfo.characterInfo[i].character == 10))
                        {
                            underline_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, m_textInfo.characterInfo[i - 1].baseLine + font.fontInfo.Underline * m_fontScale, 0);
                            //Debug.Log("Underline End Char [" + m_textInfo.characterInfo[i - 1].character + "].");
                        }
                        else
                        {
                            underline_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + font.fontInfo.Underline * m_fontScale, 0);
                            //Debug.Log("Underline End Char [" + m_textInfo.characterInfo[i].character + "].");
                        }

                        DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index);
                        underlineSegmentCount += 1;
                    }
                }
                #endregion

                lastLine = currentLine;
            }
            #endregion

            // METRICS ABOUT THE TEXT OBJECT
            m_textInfo.characterCount = (short)m_characterCount;
            m_textInfo.lineCount = (short)lineCount;
            m_textInfo.wordCount = wordCount != 0 && m_characterCount > 0 ? (short)wordCount : (short)1;

            // Need to store UI Vertex
            m_textInfo.meshInfo.uiVertices = m_uiVertices;

            // If Advanced Layout Component is present, don't upload the mesh.
            if (m_renderMode == TextRenderFlags.Render) // m_isAdvanceLayoutComponentPresent == false || m_advancedLayoutComponent.isEnabled == false)
            {
                //Debug.Log("Uploading Mesh normally.");
                // Upload Mesh Data
                m_uiRenderer.SetVertices(m_uiVertices, vert_index_X4 + underlineSegmentCount * 12);

                // Setting Mesh Bounds manually is more efficient.
                m_bounds = new Bounds(new Vector3((m_meshExtents.max.x + m_meshExtents.min.x) / 2, (m_meshExtents.max.y + m_meshExtents.min.y) / 2, 0) + m_anchorOffset, new Vector3(m_meshExtents.max.x - m_meshExtents.min.x, m_meshExtents.max.y - m_meshExtents.min.y, 0));

                //m_maskOffset = new Vector4(m_mesh.bounds.center.x, m_mesh.bounds.center.y, m_mesh.bounds.size.x, m_mesh.bounds.size.y);
            }

            m_bounds = new Bounds(new Vector3((m_meshExtents.max.x + m_meshExtents.min.x) / 2, (m_meshExtents.max.y + m_meshExtents.min.y) / 2, 0) + m_anchorOffset, new Vector3(m_meshExtents.max.x - m_meshExtents.min.x, m_meshExtents.max.y - m_meshExtents.min.y, 0));

            m_isCharacterWrappingEnabled = false;

            // Has Text Container's Width or Height been specified by the user?
            /*
            if (m_rectTransform.sizeDelta.x == 0 || m_rectTransform.sizeDelta.y == 0)
            {
                //Debug.Log("Auto-fitting Text. Default Width:" + m_textContainer.isDefaultWidth + "  Default Height:" + m_textContainer.isDefaultHeight);
                if (marginWidth == 0)
                    m_rectTransform.sizeDelta = new Vector2(m_preferredWidth + margins.x + margins.z, m_rectTransform.sizeDelta.y);

                if (marginHeight == 0)
                    m_rectTransform.sizeDelta = new Vector2(m_rectTransform.sizeDelta.x,  m_preferredHeight + margins.y + margins.w);

                Debug.Log("Auto-fitting Text. Default Width:" + m_preferredWidth + "  Default Height:" + m_preferredHeight);
                GenerateTextMesh();
                return;
            }
            */

            //Debug.Log("Done rendering text. Margin Width was " + marginWidth +  " and Margin Height was " + marginHeight + ". Preferred Width: " + m_preferredWidth + " and Height: " + m_preferredHeight);

            //Debug.Log(m_minWidth);
            //Profiler.EndSample();
            //m_StopWatch.Stop();
            //Debug.Log("Done Rendering Text.");
            //Debug.Log("TimeElapsed is:" + (m_StopWatch.ElapsedTicks / 10000f).ToString("f4"));
            //m_StopWatch.Reset();
        }
        /// <summary>
        /// Function to identify and validate the rich tag. Returns the position of the > if the tag was valid.
        /// </summary>
        /// <param name="chars"></param>
        /// <param name="startIndex"></param>
        /// <param name="endIndex"></param>
        /// <returns></returns>
        protected bool ValidateHtmlTag(int[] chars, int startIndex, out int endIndex)
        {
            int tagCharCount = 0;
            byte attributeFlag = 0;

            TagUnits tagUnits = TagUnits.Pixels;
            TagType tagType = TagType.None;

            int attributeIndex = 0;
            m_xmlAttribute[attributeIndex].nameHashCode = 0;
            m_xmlAttribute[attributeIndex].valueType = TagType.None;
            m_xmlAttribute[attributeIndex].valueHashCode = 0;
            m_xmlAttribute[attributeIndex].valueStartIndex = 0;
            m_xmlAttribute[attributeIndex].valueLength = 0;
            m_xmlAttribute[attributeIndex].valueDecimalIndex = 0;

            endIndex = startIndex;
            bool isTagSet = false;
            bool isValidHtmlTag = false;

            for (int i = startIndex; i < chars.Length && chars[i] != 0 && tagCharCount < m_htmlTag.Length && chars[i] != 60; i++)
            {
                if (chars[i] == 62) // ASCII Code of End HTML tag '>'
                {
                    isValidHtmlTag = true;
                    endIndex = i;
                    m_htmlTag[tagCharCount] = (char)0;
                    break;
                }

                m_htmlTag[tagCharCount] = (char)chars[i];
                tagCharCount += 1;

                if (attributeFlag == 1)
                {
                    if (m_xmlAttribute[attributeIndex].valueStartIndex == 0)
                    {
                        // Check for attribute type
                        if (chars[i] == 43 || chars[i] == 45 || char.IsDigit((char)chars[i]))
                        {
                            tagType = TagType.NumericalValue;
                            m_xmlAttribute[attributeIndex].valueType = TagType.NumericalValue;
                            m_xmlAttribute[attributeIndex].valueStartIndex = tagCharCount - 1;
                            m_xmlAttribute[attributeIndex].valueLength += 1;
                        }
                        else if (chars[i] == 35)
                        {
                            tagType = TagType.ColorValue;
                            m_xmlAttribute[attributeIndex].valueType = TagType.ColorValue;
                            m_xmlAttribute[attributeIndex].valueStartIndex = tagCharCount - 1;
                            m_xmlAttribute[attributeIndex].valueLength += 1;
                        }
                        else if (chars[i] != 34)
                        {
                            tagType = TagType.StringValue;
                            m_xmlAttribute[attributeIndex].valueType = TagType.StringValue;
                            m_xmlAttribute[attributeIndex].valueStartIndex = tagCharCount - 1;
                            m_xmlAttribute[attributeIndex].valueHashCode = (m_xmlAttribute[attributeIndex].valueHashCode << 5) + m_xmlAttribute[attributeIndex].valueHashCode ^ chars[i];
                            m_xmlAttribute[attributeIndex].valueLength += 1;
                        }
                    }
                    else
                    {
                        if (tagType == TagType.NumericalValue)
                        {
                            if (chars[i] == 46) // '.' Decimal Point Index
                                m_xmlAttribute[attributeIndex].valueDecimalIndex = tagCharCount - 1;

                            // Check for termination of numerical value.
                            if (chars[i] == 112 || chars[i] == 101 || chars[i] == 37 || chars[i] == 32)
                            {
                                attributeFlag = 2;
                                tagType = TagType.None;
                                attributeIndex += 1;
                                m_xmlAttribute[attributeIndex].nameHashCode = 0;
                                m_xmlAttribute[attributeIndex].valueType = TagType.None;
                                m_xmlAttribute[attributeIndex].valueHashCode = 0;
                                m_xmlAttribute[attributeIndex].valueStartIndex = 0;
                                m_xmlAttribute[attributeIndex].valueLength = 0;
                                m_xmlAttribute[attributeIndex].valueDecimalIndex = 0;

                                if (chars[i] == 101)
                                    tagUnits = TagUnits.FontUnits;
                                else if (chars[i] == 37)
                                    tagUnits = TagUnits.Percentage;
                            }
                            else if (attributeFlag != 2)
                            {
                                m_xmlAttribute[attributeIndex].valueLength += 1;
                            }
                        }
                        else if (tagType == TagType.ColorValue)
                        {
                            if (chars[i] != 32)
                            {
                                m_xmlAttribute[attributeIndex].valueLength += 1;
                            }
                            else
                            {
                                attributeFlag = 2;
                                tagType = TagType.None;
                                attributeIndex += 1;
                                m_xmlAttribute[attributeIndex].nameHashCode = 0;
                                m_xmlAttribute[attributeIndex].valueType = TagType.None;
                                m_xmlAttribute[attributeIndex].valueHashCode = 0;
                                m_xmlAttribute[attributeIndex].valueStartIndex = 0;
                                m_xmlAttribute[attributeIndex].valueLength = 0;
                                m_xmlAttribute[attributeIndex].valueDecimalIndex = 0;
                            }
                        }
                        else if (tagType == TagType.StringValue)
                        {
                            // Compute HashCode value for the named tag.
                            if (chars[i] != 34)
                            {
                                m_xmlAttribute[attributeIndex].valueHashCode = (m_xmlAttribute[attributeIndex].valueHashCode << 5) + m_xmlAttribute[attributeIndex].valueHashCode ^ chars[i];
                                m_xmlAttribute[attributeIndex].valueLength += 1;
                            }
                            else
                            {
                                //m_xmlAttribute[attributeIndex].valueHashCode = -1;
                                attributeFlag = 2;
                                tagType = TagType.None;
                                attributeIndex += 1;
                                m_xmlAttribute[attributeIndex].nameHashCode = 0;
                                m_xmlAttribute[attributeIndex].valueType = TagType.None;
                                m_xmlAttribute[attributeIndex].valueHashCode = 0;
                                m_xmlAttribute[attributeIndex].valueStartIndex = 0;
                                m_xmlAttribute[attributeIndex].valueLength = 0;
                                m_xmlAttribute[attributeIndex].valueDecimalIndex = 0;
                            }
                        }
                    }
                }

                if (chars[i] == 61) // '='
                    attributeFlag = 1;

                // Compute HashCode for the name of the attribute
                if (attributeFlag == 0 && chars[i] == 32)
                {
                    if (isTagSet) return false;

                    isTagSet = true;
                    attributeFlag = 2;

                    tagType = TagType.None;
                    attributeIndex += 1;
                    m_xmlAttribute[attributeIndex].nameHashCode = 0;
                    m_xmlAttribute[attributeIndex].valueType = TagType.None;
                    m_xmlAttribute[attributeIndex].valueHashCode = 0;
                    m_xmlAttribute[attributeIndex].valueStartIndex = 0;
                    m_xmlAttribute[attributeIndex].valueLength = 0;
                    m_xmlAttribute[attributeIndex].valueDecimalIndex = 0;
                }

                if (attributeFlag == 0)
                    m_xmlAttribute[attributeIndex].nameHashCode = (m_xmlAttribute[attributeIndex].nameHashCode << 3) - m_xmlAttribute[attributeIndex].nameHashCode + chars[i];

                if (attributeFlag == 2 && chars[i] == 32)
                    attributeFlag = 0;

            }

            if (!isValidHtmlTag)
            {
                return false;
            }

            //Debug.Log("Tag is [" + m_htmlTag.ArrayToString() + "].  Tag HashCode: " + m_xmlAttribute[0].nameHashCode + "  Tag Value HashCode: " + m_xmlAttribute[0].valueHashCode + "  Attribute 1 HashCode: " + m_xmlAttribute[1].nameHashCode + " Value HashCode: " + m_xmlAttribute[1].valueHashCode);
            //for (int i = 0; i < attributeIndex + 1; i++)
            //    Debug.Log("Tag [" + i + "] with HashCode: " + m_xmlAttribute[i].nameHashCode + " has value of [" + new string(m_htmlTag, m_xmlAttribute[i].valueStartIndex, m_xmlAttribute[i].valueLength) + "] Numerical Value: " + ConvertToFloat(m_htmlTag, m_xmlAttribute[i].valueStartIndex, m_xmlAttribute[i].valueLength, m_xmlAttribute[i].valueDecimalIndex));

            // Special handling of the NoParsing tag
            if (tag_NoParsing && m_xmlAttribute[0].nameHashCode != 53822163)
                return false;
            else if (m_xmlAttribute[0].nameHashCode == 53822163)
            {
                tag_NoParsing = false;
                return true;
            }

            // Color <#FF00FF>
            if (m_htmlTag[0] == 35 && tagCharCount == 7) // if Tag begins with # and contains 7 characters.
            {
                m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                m_colorStack.Add(m_htmlColor);
                return true;
            }
            // Color <#FF00FF00> with alpha
            else if (m_htmlTag[0] == 35 && tagCharCount == 9) // if Tag begins with # and contains 9 characters.
            {
                m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                m_colorStack.Add(m_htmlColor);
                return true;
            }
            else
            {
                float value = 0;

                switch (m_xmlAttribute[0].nameHashCode)
                {
                    case 98: // <b>
                        m_style |= FontStyles.Bold;
                        m_fontWeightInternal = 700;
                        m_fontWeightStack.Add(700);
                        return true;
                    case 427: // </b>
                        if ((m_fontStyle & FontStyles.Bold) != FontStyles.Bold)
                        {
                            m_style &= ~FontStyles.Bold;
                            m_fontWeightInternal = m_fontWeightStack.Remove();
                        }
                        return true;
                    case 105: // <i>
                        m_style |= FontStyles.Italic;
                        return true;
                    case 434: // </i>
                        m_style &= ~FontStyles.Italic;
                        return true;
                    case 115: // <s>
                        m_style |= FontStyles.Strikethrough;
                        return true;
                    case 444: // </s>
                        if ((m_fontStyle & FontStyles.Strikethrough) != FontStyles.Strikethrough)
                            m_style &= ~FontStyles.Strikethrough;
                        return true;
                    case 117: // <u>
                        m_style |= FontStyles.Underline;
                        return true;
                    case 446: // </u>
                        if ((m_fontStyle & FontStyles.Underline) != FontStyles.Underline)
                            m_style &= ~FontStyles.Underline;
                        return true;

                    case 6552: // <sub>
                        m_fontScaleMultiplier = m_currentFontAsset.fontInfo.SubSize > 0 ? m_currentFontAsset.fontInfo.SubSize : 1;
                        m_baselineOffset = m_currentFontAsset.fontInfo.SubscriptOffset * m_fontScale * m_fontScaleMultiplier;
                        m_style |= FontStyles.Subscript;
                        return true;
                    case 22673: // </sub>
                        if ((m_style & FontStyles.Subscript) == FontStyles.Subscript)
                        {
                            // Check to make sure we are not also using Superscript
                            if ((m_style & FontStyles.Superscript) == FontStyles.Superscript)
                            {
                                m_fontScaleMultiplier = m_currentFontAsset.fontInfo.SubSize > 0 ? m_currentFontAsset.fontInfo.SubSize : 1;
                                m_baselineOffset = m_currentFontAsset.fontInfo.SuperscriptOffset * m_fontScale * m_fontScaleMultiplier;
                            }
                            else
                            {
                                m_baselineOffset = 0;
                                m_fontScaleMultiplier = 1;
                            }

                            m_style &= ~FontStyles.Subscript;
                        }
                        return true;
                    case 6566: // <sup>
                        m_fontScaleMultiplier = m_currentFontAsset.fontInfo.SubSize > 0 ? m_currentFontAsset.fontInfo.SubSize : 1;
                        m_baselineOffset = m_currentFontAsset.fontInfo.SuperscriptOffset * m_fontScale * m_fontScaleMultiplier;
                        m_style |= FontStyles.Superscript;
                        return true;
                    case 22687: // </sup>
                        if ((m_style & FontStyles.Superscript) == FontStyles.Superscript)
                        {
                            // Check to make sure we are not also using Superscript
                            if ((m_style & FontStyles.Subscript) == FontStyles.Subscript)
                            {
                                m_fontScaleMultiplier = m_currentFontAsset.fontInfo.SubSize > 0 ? m_currentFontAsset.fontInfo.SubSize : 1;
                                m_baselineOffset = m_currentFontAsset.fontInfo.SubscriptOffset * m_fontScale * m_fontScaleMultiplier;
                            }
                            else
                            {
                                m_baselineOffset = 0;
                                m_fontScaleMultiplier = 1;
                            }

                            m_style &= ~FontStyles.Superscript;
                        }
                        return true;
                    case -330774850: // <font-weight>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        if ((m_fontStyle & FontStyles.Bold) == FontStyles.Bold)
                        {
                            // Nothing happens since Bold is forced on the text.
                            //m_fontWeight = 700;
                            return true;
                        }

                        // Remove bold style
                        m_style &= ~FontStyles.Bold;

                        switch ((int)value)
                        {
                            case 100:
                                m_fontWeightInternal = 100;
                                break;
                            case 200:
                                m_fontWeightInternal = 200;
                                break;
                            case 300:
                                m_fontWeightInternal = 300;
                                break;
                            case 400:
                                m_fontWeightInternal = 400;

                                break;
                            case 500:
                                m_fontWeightInternal = 500;
                                break;
                            case 600:
                                m_fontWeightInternal = 600;
                                break;
                            case 700:
                                m_fontWeightInternal = 700;
                                m_style |= FontStyles.Bold;
                                break;
                            case 800:
                                m_fontWeightInternal = 800;
                                break;
                            case 900:
                                m_fontWeightInternal = 900;
                                break;
                        }

                        m_fontWeightStack.Add(m_fontWeightInternal);

                        return true;
                    case -1885698441: // </font-weight>
                        m_fontWeightInternal = m_fontWeightStack.Remove();
                        return true;
                    case 6380: // <pos=000.00px> <pos=0em> <pos=50%>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_xAdvance = value;
                                //m_isIgnoringAlignment = true;
                                return true;
                            case TagUnits.FontUnits:
                                m_xAdvance = value * m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
                                //m_isIgnoringAlignment = true;
                                return true;
                            case TagUnits.Percentage:
                                m_xAdvance = m_marginWidth * value / 100;
                                //m_isIgnoringAlignment = true;
                                return true;
                        }
                        return false;
                    case 22501: // </pos>
                        m_isIgnoringAlignment = false;
                        return true;
                    case 16034505: // <voffset>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_baselineOffset = value;
                                return true;
                            case TagUnits.FontUnits:
                                m_baselineOffset = value * m_fontScale * m_fontAsset.fontInfo.Ascender;
                                return true;
                            case TagUnits.Percentage:
                                //m_baselineOffset = m_marginHeight * val / 100;
                                return false;
                        }
                        return false;
                    case 54741026: // </voffset>
                        m_baselineOffset = 0;
                        return true;
                    case 43991: // <page>
                        // This tag only works when Overflow - Page mode is used.
                        if (m_overflowMode == TextOverflowModes.Page)
                        {
                            m_xAdvance = 0 + tag_LineIndent + tag_Indent;
                            //m_textInfo.lineInfo[m_lineNumber].marginLeft = m_xAdvance;
                            m_lineOffset = 0;
                            m_pageNumber += 1;
                            m_isNewPage = true;
                        }
                        return true;

                    case 43969: // <nobr>
                        m_isNonBreakingSpace = true;
                        return true;
                    case 156816: // </nobr>
                        m_isNonBreakingSpace = false;
                        return true;
                    case 45545: // <size=>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                if (m_htmlTag[5] == 43) // <size=+00>
                                {
                                    m_currentFontSize = m_fontSize + value;
                                    m_sizeStack.Add(m_currentFontSize);
                                    m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
                                    return true;
                                }
                                else if (m_htmlTag[5] == 45) // <size=-00>
                                {
                                    m_currentFontSize = m_fontSize + value;
                                    m_sizeStack.Add(m_currentFontSize);
                                    m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
                                    return true;
                                }
                                else // <size=00.0>
                                {
                                    m_currentFontSize = value;
                                    m_sizeStack.Add(m_currentFontSize);
                                    m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
                                    return true;
                                }
                            case TagUnits.FontUnits:
                                m_currentFontSize = m_fontSize * value;
                                m_sizeStack.Add(m_currentFontSize);
                                m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
                                return true;
                            case TagUnits.Percentage:
                                m_currentFontSize = m_fontSize * value / 100;
                                m_sizeStack.Add(m_currentFontSize);
                                m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
                                return true;
                        }
                        return false;
                    case 158392: // </size>
                        m_currentFontSize = m_sizeStack.Remove();
                        m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
                        return true;
                    case 41311: // <font=xx>
                        //Debug.Log("Font name: \"" + new string(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength) + "\"   HashCode: " + m_xmlAttribute[0].valueHashCode + "   Material Name: \"" + new string(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength) + "\"   Hashcode: " + m_xmlAttribute[1].valueHashCode);

                        int fontHashCode = m_xmlAttribute[0].valueHashCode;
                        int materialAttributeHashCode = m_xmlAttribute[1].nameHashCode;
                        int materialHashCode = m_xmlAttribute[1].valueHashCode;

                        // Special handling for <font=default> or <font=Default>
                        if (fontHashCode == 764638571 || fontHashCode == 523367755)
                        {
                            m_currentFontAsset = m_materialReferences[0].fontAsset;
                            m_currentMaterial = m_materialReferences[0].material;
                            m_currentMaterialIndex = 0;
                            //Debug.Log("<font=Default> assigning Font Asset [" + m_currentFontAsset.name + "] with Material [" + m_currentMaterial.name + "].");

                            m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));

                            m_materialReferenceStack.Add(m_materialReferences[0]);

                            return true;
                        }

                        TMP_FontAsset tempFont;
                        Material tempMaterial;

                        // HANDLE NEW FONT ASSET
                        if (MaterialReferenceManager.TryGetFontAsset(fontHashCode, out tempFont))
                        {
                            //if (tempFont != m_currentFontAsset)
                            //{
                            //    //Debug.Log("Assigning Font Asset: " + tempFont.name);
                            //    m_currentFontAsset = tempFont;
                            //    m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
                            //}
                        }
                        else
                        {
                            // Load Font Asset
                            tempFont = Resources.Load<TMP_FontAsset>("Fonts & Materials/" + new string(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength));

                            if (tempFont == null)
                                return false;

                            // Add new reference to the font asset as well as default material to the MaterialReferenceManager
                            MaterialReferenceManager.AddFontAsset(tempFont);
                        }

                        // HANDLE NEW MATERIAL
                        if (materialAttributeHashCode == 0 && materialHashCode == 0)
                        {
                            // No material specified then use default font asset material.
                            m_currentMaterial = tempFont.material;

                            m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFont, m_materialReferences, m_materialReferenceIndexLookup);

                            m_materialReferenceStack.Add(m_materialReferences[m_currentMaterialIndex]);
                        }
                        else if (materialAttributeHashCode == 103415287) // using material attribute
                        {
                            if (MaterialReferenceManager.TryGetMaterial(materialHashCode, out tempMaterial))
                            {
                                m_currentMaterial = tempMaterial;

                                m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFont, m_materialReferences, m_materialReferenceIndexLookup);

                                m_materialReferenceStack.Add(m_materialReferences[m_currentMaterialIndex]);
                            }
                            else
                            {
                                // Load new material
                                tempMaterial = Resources.Load<Material>("Fonts & Materials/" + new string(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength));

                                if (tempMaterial == null)
                                    return false;

                                // Add new reference to this material in the MaterialReferenceManager
                                MaterialReferenceManager.AddFontMaterial(materialHashCode, tempMaterial);

                                m_currentMaterial = tempMaterial;

                                m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFont, m_materialReferences, m_materialReferenceIndexLookup);

                                m_materialReferenceStack.Add(m_materialReferences[m_currentMaterialIndex]);
                            }
                        }
                        else
                            return false;

                        m_currentFontAsset = tempFont;
                        m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));

                        return true;
                    case 154158: // </font>
                        MaterialReference materialReference = m_materialReferenceStack.Remove();

                        m_currentFontAsset = materialReference.fontAsset;
                        m_currentMaterial = materialReference.material;
                        m_currentMaterialIndex = materialReference.index;

                        m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));

                        return true;
                    case 320078: // <space=000.00>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_xAdvance += value;
                                return true;
                            case TagUnits.FontUnits:
                                m_xAdvance += value * m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
                                return true;
                            case TagUnits.Percentage:
                                // Not applicable
                                return false;
                        }
                        return false;
                    case 276254: // <alpha=#FF>
                        if (m_xmlAttribute[0].valueLength != 3) return false;

                        m_htmlColor.a = (byte)(HexToInt(m_htmlTag[7]) * 16 + HexToInt(m_htmlTag[8]));
                        return true;

                    case 1750458: // <a name=" ">
                        return false;
                    case 426: // </a>
                        return true;
                    case 43066: // <link="name">
                        if (m_isParsingText)
                        {
                            tag_LinkInfo.textComponent = this;
                            tag_LinkInfo.hashCode = m_xmlAttribute[0].valueHashCode;
                            tag_LinkInfo.linkTextfirstCharacterIndex = m_characterCount;

                            tag_LinkInfo.linkIdFirstCharacterIndex = startIndex + m_xmlAttribute[0].valueStartIndex;
                            tag_LinkInfo.linkIdLength = m_xmlAttribute[0].valueLength;

                        }
                        return true;
                    case 155913: // </link>
                        if (m_isParsingText)
                        {
                            tag_LinkInfo.linkTextLength = m_characterCount - tag_LinkInfo.linkTextfirstCharacterIndex;

                            int size = m_textInfo.linkInfo.Length;

                            if (m_textInfo.linkCount + 1 > size)
                                TMP_TextInfo.Resize(ref m_textInfo.linkInfo, size + 1);

                            m_textInfo.linkInfo[m_textInfo.linkCount] = tag_LinkInfo;

                            m_textInfo.linkCount += 1;

                        }
                        return true;
                    case 275917: // <align=>
                        switch (m_xmlAttribute[0].valueHashCode)
                        {
                            case 3774683: // <align=left>
                                m_lineJustification = TextAlignmentOptions.Left;
                                return true;
                            case 136703040: // <align=right>
                                m_lineJustification = TextAlignmentOptions.Right;
                                return true;
                            case -458210101: // <align=center>
                                m_lineJustification = TextAlignmentOptions.Center;
                                return true;
                            case -523808257: // <align=justified>
                                m_lineJustification = TextAlignmentOptions.Justified;
                                return true;
                        }
                        return false;
                    case 1065846: // </align>
                        m_lineJustification = m_textAlignment;
                        return true;
                    case 327550: // <width=xx>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_width = value;
                                break;
                            case TagUnits.FontUnits:
                                return false;
                            //break;
                            case TagUnits.Percentage:
                                m_width = m_marginWidth * value / 100;
                                break;
                        }
                        return true;
                    case 1117479: // </width>
                        m_width = -1;
                        return true;
                    case 322689: // <style="name">
                        TMP_Style style = TMP_StyleSheet.Instance.GetStyle(m_xmlAttribute[0].valueHashCode);

                        if (style == null) return false;

                        m_styleStack.Add(style.hashCode);

                        //// Parse Style Macro
                        for (int i = 0; i < style.styleOpeningTagArray.Length; i++)
                        {
                            if (style.styleOpeningTagArray[i] == 60)
                                ValidateHtmlTag(style.styleOpeningTagArray, i + 1, out i);
                        }
                        return true;
                    case 1112618: // </style>
                        style = TMP_StyleSheet.Instance.GetStyle(m_xmlAttribute[0].valueHashCode);

                        if (style == null)
                        {
                            // Get style from the Style Stack
                            int styleHashCode = m_styleStack.Remove();
                            style = TMP_StyleSheet.Instance.GetStyle(styleHashCode);
                        }

                        if (style == null) return false;
                        //// Parse Style Macro
                        for (int i = 0; i < style.styleClosingTagArray.Length; i++)
                        {
                            if (style.styleClosingTagArray[i] == 60)
                                ValidateHtmlTag(style.styleClosingTagArray, i + 1, out i);
                        }
                        return true;
                    case 281955: // <color=#FF00FF> or <color=#FF00FF00>
                        // <color=#FF00FF> 3 Hex pairs
                        if (m_htmlTag[6] == 35 && tagCharCount == 13)
                        {
                            m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                            m_colorStack.Add(m_htmlColor);
                            return true;
                        }
                        // <color=#FF00FF00> 4 Hex pairs
                        else if (m_htmlTag[6] == 35 && tagCharCount == 15)
                        {
                            m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                            m_colorStack.Add(m_htmlColor);
                            return true;
                        }

                        // <color=name>
                        switch (m_xmlAttribute[0].valueHashCode)
                        {
                            case 125395: // <color=red>
                                m_htmlColor = Color.red;
                                m_colorStack.Add(m_htmlColor);
                                return true;
                            case 3573310: // <color=blue>
                                m_htmlColor = Color.blue;
                                m_colorStack.Add(m_htmlColor);
                                return true;
                            case 117905991: // <color=black>
                                m_htmlColor = Color.black;
                                m_colorStack.Add(m_htmlColor);
                                return true;
                            case 121463835: // <color=green>
                                m_htmlColor = Color.green;
                                m_colorStack.Add(m_htmlColor);
                                return true;
                            case 140357351: // <color=white>
                                m_htmlColor = Color.white;
                                m_colorStack.Add(m_htmlColor);
                                return true;
                            case 26556144: // <color=orange>
                                m_htmlColor = new Color32(255, 128, 0, 255);
                                m_colorStack.Add(m_htmlColor);
                                return true;
                            case -36881330: // <color=purple>
                                m_htmlColor = new Color32(160, 32, 240, 255);
                                m_colorStack.Add(m_htmlColor);
                                return true;
                            case 554054276: // <color=yellow>
                                m_htmlColor = Color.yellow;
                                m_colorStack.Add(m_htmlColor);
                                return true;
                        }
                        return false;
                    case 1983971: // <cspace=xx.x>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_cSpacing = value;
                                break;
                            case TagUnits.FontUnits:
                                m_cSpacing = value;
                                m_cSpacing *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
                                break;
                            case TagUnits.Percentage:
                                return false;
                        }
                        return true;
                    case 7513474: // </cspace>
                        m_cSpacing = 0;
                        return true;
                    case 2152041: // <mspace=xx.x>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_monoSpacing = value;
                                break;
                            case TagUnits.FontUnits:
                                m_monoSpacing = value;
                                m_monoSpacing *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
                                break;
                            case TagUnits.Percentage:
                                return false;
                        }
                        return true;
                    case 7681544: // </mspace>
                        m_monoSpacing = 0;
                        return true;
                    case 280416: // <class="name">
                        return false;
                    case 1071884: // </color>
                        m_htmlColor = m_colorStack.Remove();
                        return true;
                    case 2068980: // <indent=10px> <indent=10em> <indent=50%>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                tag_Indent = value;
                                break;
                            case TagUnits.FontUnits:
                                tag_Indent = value;
                                tag_Indent *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
                                break;
                            case TagUnits.Percentage:
                                tag_Indent = m_marginWidth * value / 100;
                                break;
                        }
                        m_indentStack.Add(tag_Indent);

                        m_xAdvance = tag_Indent;
                        return true;
                    case 7598483: // </indent>
                        tag_Indent = m_indentStack.Remove();
                        //m_xAdvance = tag_Indent;
                        return true;
                    case 1109386397: // <line-indent>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                tag_LineIndent = value;
                                break;
                            case TagUnits.FontUnits:
                                tag_LineIndent = value;
                                tag_LineIndent *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
                                break;
                            case TagUnits.Percentage:
                                tag_LineIndent = m_marginWidth * value / 100;
                                break;
                        }

                        m_xAdvance += tag_LineIndent;
                        return true;
                    case -445537194: // </line-indent>
                        tag_LineIndent = 0;
                        return true;
                    case 2246877: // <sprite=x>
                        int spriteAssetHashCode = m_xmlAttribute[0].valueHashCode;
                        TMP_SpriteAsset tempSpriteAsset;

                        // CHECK TAG FORMAT
                        if (m_xmlAttribute[0].valueType == TagType.None || m_xmlAttribute[0].valueType == TagType.NumericalValue)
                        {
                            // No Sprite Asset specified
                            if (m_defaultSpriteAsset == null)
                            {
                                // Load TMP Settings
                                if (m_settings == null) m_settings = TMP_Settings.LoadDefaultSettings();

                                if (m_settings != null && m_settings.spriteAsset != null)
                                    m_defaultSpriteAsset = m_settings.spriteAsset;
                                else
                                    m_defaultSpriteAsset = Resources.Load<TMP_SpriteAsset>("Sprite Assets/Default Sprite Asset");

                            }

                            m_currentSpriteAsset = m_defaultSpriteAsset;

                            // No valid sprite asset available
                            if (m_currentSpriteAsset == null)
                                return false;
                        }
                        else
                        {
                            // A Sprite Asset has been specified
                            if (MaterialReferenceManager.TryGetSpriteAsset(spriteAssetHashCode, out tempSpriteAsset))
                            {
                                m_currentSpriteAsset = tempSpriteAsset;
                            }
                            else
                            {
                                // Load Sprite Asset
                                if (tempSpriteAsset == null)
                                {
                                    tempSpriteAsset = Resources.Load<TMP_SpriteAsset>("Sprites/" + new string(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength));
                                }

                                if (tempSpriteAsset == null)
                                    return false;

                                //Debug.Log("Loading & assigning new Sprite Asset: " + tempSpriteAsset.name);
                                MaterialReferenceManager.AddSpriteAsset(spriteAssetHashCode, tempSpriteAsset);
                                m_currentSpriteAsset = tempSpriteAsset;
                            }
                        }

                        if (m_xmlAttribute[0].valueType == TagType.NumericalValue)
                        {
                            int index = (int)ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                            if (index == -9999) return false;

                            m_spriteIndex = index;
                        }
                        else if (m_xmlAttribute[1].nameHashCode == 43347) // <sprite name="">
                        {
                            //Debug.Log("Name attribute [" + new string(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength) + "].");

                            int index = m_currentSpriteAsset.GetSpriteIndex(m_xmlAttribute[1].valueHashCode);
                            if (index == -1) return false;

                            m_spriteIndex = index;

                        }
                        else if (m_xmlAttribute[1].nameHashCode == 295562) // <sprite index=xx>
                        {
                            int index = (int)ConvertToFloat(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength, m_xmlAttribute[1].valueDecimalIndex);
                            if (index == -9999) return false;

                            m_spriteIndex = index;

                            // Check to make sure sprite index is valid
                            if (m_spriteIndex > m_currentSpriteAsset.spriteInfoList.Count - 1) return false;
                        }
                        else
                        {
                            return false;
                        }

                        // Material HashCode for the Sprite Asset is the Sprite Asset Hash Code
                        m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentSpriteAsset.material, m_currentSpriteAsset, m_materialReferences, m_materialReferenceIndexLookup);

                        //m_materialReferenceStack.Add(m_materialReferenceManager.materialReferences[m_currentMaterialIndex]);

                        m_spriteColor = s_colorWhite;
                        m_tintSprite = false;

                        // Handle Tint Attribute
                        if (m_xmlAttribute[1].nameHashCode == 45819)
                            m_tintSprite = ConvertToFloat(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength, m_xmlAttribute[1].valueDecimalIndex) != 0;
                        else if (m_xmlAttribute[2].nameHashCode == 45819)
                            m_tintSprite = ConvertToFloat(m_htmlTag, m_xmlAttribute[2].valueStartIndex, m_xmlAttribute[2].valueLength, m_xmlAttribute[2].valueDecimalIndex) != 0;

                        // Handle Color Attribute
                        if (m_xmlAttribute[1].nameHashCode == 281955)
                            m_spriteColor = HexCharsToColor(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength);
                        else if (m_xmlAttribute[2].nameHashCode == 281955)
                            m_spriteColor = HexCharsToColor(m_htmlTag, m_xmlAttribute[2].valueStartIndex, m_xmlAttribute[2].valueLength);

                        m_xmlAttribute[1].nameHashCode = 0;
                        m_xmlAttribute[2].nameHashCode = 0;

                        m_textElementType = TMP_TextElementType.Sprite;
                        return true;
                    case 730022849: // <lowercase>
                        m_style |= FontStyles.LowerCase;
                        return true;
                    case -1668324918: // </lowercase>
                        m_style &= ~FontStyles.LowerCase;
                        return true;
                    case 13526026: // <allcaps>
                    case 781906058: // <uppercase>
                        m_style |= FontStyles.UpperCase;
                        return true;
                    case 52232547: // </allcaps>
                    case -1616441709: // </uppercase>
                        m_style &= ~FontStyles.UpperCase;
                        return true;
                    case 766244328: // <smallcaps>
                        m_style |= FontStyles.SmallCaps;
                        return true;
                    case -1632103439: // </smallcaps>
                        m_style &= ~FontStyles.SmallCaps;
                        return true;
                    case 2109854: // <margin=00.0> <margin=00em> <margin=50%>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex); // px
                        if (value == -9999 || value == 0) return false;

                        m_marginLeft = value;
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                // Default behavior
                                break;
                            case TagUnits.FontUnits:
                                m_marginLeft *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
                                break;
                            case TagUnits.Percentage:
                                m_marginLeft = (m_marginWidth - (m_width != -1 ? m_width : 0)) * m_marginLeft / 100;
                                break;
                        }
                        m_marginLeft = m_marginLeft >= 0 ? m_marginLeft : 0;
                        m_marginRight = m_marginLeft;
                        return true;
                    case 7639357: // </margin>
                        m_marginLeft = 0;
                        m_marginRight = 0;
                        return true;
                    case 1100728678: // <margin-left=xx.x>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex); // px
                        if (value == -9999 || value == 0) return false;

                        m_marginLeft = value;
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                // Default behavior
                                break;
                            case TagUnits.FontUnits:
                                m_marginLeft *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
                                break;
                            case TagUnits.Percentage:
                                m_marginLeft = (m_marginWidth - (m_width != -1 ? m_width : 0)) * m_marginLeft / 100;
                                break;
                        }
                        m_marginLeft = m_marginLeft >= 0 ? m_marginLeft : 0;
                        return true;
                    case -884817987: // <margin-right=xx.x>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex); // px
                        if (value == -9999 || value == 0) return false;

                        m_marginRight = value;
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                // Default behavior
                                break;
                            case TagUnits.FontUnits:
                                m_marginRight *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
                                break;
                            case TagUnits.Percentage:
                                m_marginRight = (m_marginWidth - (m_width != -1 ? m_width : 0)) * m_marginRight / 100;
                                break;
                        }
                        m_marginRight = m_marginRight >= 0 ? m_marginRight : 0;
                        return true;
                    case 1109349752: // <line-height=xx.x>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        m_lineHeight = value;
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                //m_lineHeight *= m_isOrthographic ? 1 : 0.1f;
                                break;
                            case TagUnits.FontUnits:
                                m_lineHeight *= m_fontAsset.fontInfo.LineHeight * m_fontScale;
                                break;
                            case TagUnits.Percentage:
                                m_lineHeight = m_fontAsset.fontInfo.LineHeight * m_lineHeight / 100 * m_fontScale;
                                break;
                        }
                        return true;
                    case -445573839: // </line-height>
                        m_lineHeight = 0;
                        return true;
                    case 15115642: // <noparse>
                        tag_NoParsing = true;
                        return true;
                    case 1913798: // <action>
                        // TODO
                        return false;
                    case 7443301: // </action>
                        // TODO
                        return false;
                }
            }
            return false;
        }
Beispiel #39
0
    public override void gaxb_final(TB.TBXMLElement element, object _parent, Hashtable args)
    {
        base.gaxb_final(element, _parent, args);

        string attrib;

        if (font == null) {
            font = DefaultFont;
        }

        if(element != null){
            attrib = element.GetAttribute ("font");
            if (attrib != null) {
                font = attrib;
            }

            attrib = element.GetAttribute ("onLinkClick");
            if (attrib != null) {
                onLinkClick = PlanetUnityOverride.processString (_parent, attrib);
            }

            attrib = element.GetAttribute ("fontSize");
            if (attrib != null) {
                fontSize = (int)(float.Parse (PlanetUnityOverride.processString (_parent, attrib)));
            }

            attrib = element.GetAttribute ("fontStyle");
            if (attrib != null) {
                fontStyle = attrib;
            }

            attrib = element.GetAttribute ("sizeToFit");
            if (attrib != null) {
                sizeToFit = bool.Parse (PlanetUnityOverride.processString(_parent, attrib));
            }

            attrib = element.GetAttribute ("maxSize");
            if (attrib != null) {
                maxSize = (int)(float.Parse (PlanetUnityOverride.processString(_parent, attrib)));
            }

            attrib = element.GetAttribute ("enableWordWrapping");
            if (attrib != null) {
                enableWordWrapping = bool.Parse (attrib);
            }

            attrib = element.GetAttribute ("maxVisibleLines");
            if (attrib != null) {
                maxVisibleLines = int.Parse (attrib);
            }

            attrib = element.GetAttribute ("minSize");
            if (attrib != null) {
                minSize = (int)(float.Parse (PlanetUnityOverride.processString(_parent, attrib)));
            }

            attrib = element.GetAttribute ("alignment");
            if (attrib != null) {
                alignment = (TextAlignmentOptions)Enum.Parse (typeof(TextAlignmentOptions), attrib);
            }

            attrib = element.GetAttribute ("fontColor");
            if (attrib != null) {
                fontColor = fontColor.PUParse (attrib);
            }

            attrib = element.GetAttribute ("overflowMode");
            if (attrib != null) {
                overflowMode = (TextOverflowModes)Enum.Parse(typeof(TextOverflowModes), attrib);
            }

            attrib = element.GetAttribute ("lineSpacing");
            if (attrib != null) {
                lineSpacing = (int)(float.Parse (PlanetUnityOverride.processString(_parent, attrib)));
            }

            value = element.GetAttribute ("value");
            value = PlanetUnityOverride.processString (_parent, value);
        }
    }
Beispiel #40
0
        // Function to identify and validate the rich tag. Returns the position of the > if the tag was valid.
        bool ValidateHtmlTag(int[] chars, int startIndex, out int endIndex)
        {
            Array.Clear(m_htmlTag, 0, m_htmlTag.Length);
            int tagCharCount = 0;
            int tagCode = 0;
            int colorCode = 0;
            int numSequenceStart = 0;
            int numSequenceEnd = 0;
            int numSequenceDecimalPos = 0;

            endIndex = startIndex;

            bool isValidHtmlTag = false;
            int equalSignValue = 1;

            for (int i = startIndex; chars[i] != 0 && tagCharCount < m_htmlTag.Length && chars[i] != 60; i++)
            {
                if (chars[i] == 62) // ASC Code of End Html tag '>'
                {
                    isValidHtmlTag = true;
                    endIndex = i;
                    m_htmlTag[tagCharCount] = (char)0;
                    break;
                }

                m_htmlTag[tagCharCount] = (char)chars[i];
                tagCharCount += 1;

                if (chars[i] == 61) equalSignValue = 0; // Once we encounter the equal sign, we stop adding the tagCode.

                tagCode += chars[i] * tagCharCount * equalSignValue;
                colorCode += chars[i] * tagCharCount * (1 - equalSignValue);
                
                // Get possible positions of numerical values 
                switch ((int)chars[i])
                {
                    case 61: // '='
                        numSequenceStart = tagCharCount;
                        break;
                    case 46: // '.'
                        numSequenceDecimalPos = tagCharCount - 1;
                        break;
                }
            }

            if (!isValidHtmlTag)
            {
                return false;
            }

            //Debug.Log("Tag is [" + m_htmlTag.ArrayToString() + "].  Tag Code:" + tagCode + "  Color Code: " + colorCode);

            if (m_htmlTag[0] == 35 && tagCharCount == 7) // if Tag begins with # and contains 7 characters. 
            {
                m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                m_colorStack[m_colorStackIndex] = m_htmlColor;
                m_colorStackIndex += 1;
                return true;
            }
            else if (m_htmlTag[0] == 35 && tagCharCount == 9) // if Tag begins with # and contains 9 characters. 
            {
                m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                m_colorStack[m_colorStackIndex] = m_htmlColor;
                m_colorStackIndex += 1;
                return true;
            }
            else
            {
                switch (tagCode)
                {
                    case 98: // <b>
                        m_style |= FontStyles.Bold;
                        return true;
                    case 105: // <i>
                        m_style |= FontStyles.Italic;
                        return true;
                    case 117: // <u>
                        m_style |= FontStyles.Underline;
                        return true;
                    case 241: // </a>
                        return true;
                    case 243: // </b>
                        m_style &= ~FontStyles.Bold;
                        return true;
                    case 257: // </i>
                        m_style &= ~FontStyles.Italic;
                        return true;
                    case 281: // </u>
                        m_style &= ~FontStyles.Underline;
                        return true;
                    case 643: // <sub>
                        m_currentFontSize *= m_fontAsset.fontInfo.SubSize > 0 ? m_fontAsset.fontInfo.SubSize : 1; // Subscript characters are half size.
                        m_fontScale = m_currentFontSize / m_fontAsset.fontInfo.PointSize;
                        m_baselineOffset = m_fontAsset.fontInfo.SubscriptOffset * m_fontScale;
                        //m_isRecalculateScaleRequired = true;
                        return true;
                    case 679: // <pos=000.00>
                        float spacing = ConvertToFloat(m_htmlTag, numSequenceStart, tagCharCount - 1, numSequenceDecimalPos);
                        m_xAdvance = spacing * m_fontScale * m_fontAsset.fontInfo.TabWidth;
                        return true;
                    case 685: // <sup>
                        m_currentFontSize *= m_fontAsset.fontInfo.SubSize > 0 ? m_fontAsset.fontInfo.SubSize : 1;
                        m_fontScale = m_currentFontSize / m_fontAsset.fontInfo.PointSize;
                        m_baselineOffset = m_fontAsset.fontInfo.SuperscriptOffset * m_fontScale;
                        //m_isRecalculateScaleRequired = true;
                        return true;
                    case 1019: // <page>
                        // This mode only works when page mode is used.
                        if (m_overflowMode == TextOverflowModes.Page)
                        {
                            m_xAdvance = 0 + m_indent;
                            m_lineOffset = 0;
                            m_pageNumber += 1;
                            m_isNewPage = true;
                            //Debug.Log("m_lineOffet is " + m_lineOffset);
                        }
                        return true;
                    case 1020: // </sub>
                        m_currentFontSize /= m_fontAsset.fontInfo.SubSize > 0 ? m_fontAsset.fontInfo.SubSize : 1; //m_fontSize / m_fontAsset.FontInfo.PointSize * .1f;
                        m_baselineOffset = 0;
                        m_fontScale = m_currentFontSize / m_fontAsset.fontInfo.PointSize;
                        //m_isRecalculateScaleRequired = true;
                        return true;
                    case 1076: // </sup>
                        m_currentFontSize /= m_fontAsset.fontInfo.SubSize > 0 ? m_fontAsset.fontInfo.SubSize : 1; //m_fontSize / m_fontAsset.FontInfo.PointSize * .1f;
                        m_baselineOffset = 0;
                        m_fontScale = m_currentFontSize / m_fontAsset.fontInfo.PointSize;
                        //m_isRecalculateScaleRequired = true;
                        return true;
                    case 1095: // <size=>
                        numSequenceEnd = tagCharCount - 1;
                        float val = 0;

                        if (m_htmlTag[5] == 37) // <size=%00>
                        {
                            val = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                            m_currentFontSize = m_fontSize * val / 100;
                            m_isRecalculateScaleRequired = true;
                            return true;
                        }
                        else if (m_htmlTag[5] == 43) // <size=+00>
                        {
                            val = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                            m_currentFontSize = m_fontSize + val;
                            m_isRecalculateScaleRequired = true;
                            return true;
                        }
                        else if (m_htmlTag[5] == 45) // <size=-00>
                        {
                            val = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                            m_currentFontSize = m_fontSize + val;
                            m_isRecalculateScaleRequired = true;
                            return true;
                        }
                        else // <size=0000.00>
                        {
                            val = ConvertToFloat(m_htmlTag, numSequenceStart, numSequenceEnd, numSequenceDecimalPos);
                            if (val == 73493) return false; // if tag is <size> with no values.
                            m_currentFontSize = val;
                            m_isRecalculateScaleRequired = true;
                            return true;
                        }
                    case 1118: // <font=xx>
                        //Debug.Log("Font Tag used.");
                        m_fontIndex = (int)ConvertToFloat(m_htmlTag, numSequenceStart, tagCharCount - 1, numSequenceDecimalPos);

                        if(m_fontAssetArray[m_fontIndex] == null)
                        {
                            // Load new font asset into index
                            //Debug.Log("Loading Font Asset at Index " + m_fontIndex);
                            m_fontAssetArray[m_fontIndex] = m_fontAsset; // Resources.Load("Fonts & Materials/Bangers SDF", typeof(TextMeshProFont)) as TextMeshProFont; // Hard coded right now to a specific font
                        }
                        else
                        {
                            //Debug.Log("Font Asset at Index " + m_fontIndex + " has already been loaded.");
                        }


                        //m_fontScale = (m_fontSize / m_fontAssetArray[m_fontIndex].fontInfo.PointSize * (m_isOrthographic ? 1 : 0.1f));
                       
                        return true;
                    case 1531: // <space=000.00>
                        spacing = ConvertToFloat(m_htmlTag, numSequenceStart, tagCharCount - 1, numSequenceDecimalPos);
                        m_xAdvance += spacing * m_fontScale * m_fontAsset.fontInfo.TabWidth;
                        return true;
                    case 1550: // <alpha=#FF>
                        m_htmlColor.a = (byte)(HexToInt(m_htmlTag[7]) * 16 + HexToInt(m_htmlTag[8]));
                        return true;
                    case 1585: // </size>
                        m_currentFontSize = m_fontSize;
                        m_isRecalculateScaleRequired = true;
                        //m_fontScale = m_fontSize / m_fontAsset.fontInfo.PointSize * .1f;
                        return true;
                    case 1590: // <align=>
                        //Debug.Log("Align " + colorCode);
                        switch (colorCode)
                        {
                            case 4008: // <align=left>
                                m_lineJustification = TextAlignmentOptions.Left;
                                return true;
                            case 5247: // <align=right>
                                m_lineJustification = TextAlignmentOptions.Right;
                                return true;
                            case 6496: // <align=center>
                                m_lineJustification = TextAlignmentOptions.Center;
                                return true;
                            case 10897: // <align=justified>
                                m_lineJustification = TextAlignmentOptions.Justified;
                                return true;
                        }
                        return false;
                    case 1613: // <width=xx>
                        m_width = ConvertToFloat(m_htmlTag, numSequenceStart, tagCharCount - 1, numSequenceDecimalPos);                  
                        return true;     
                    case 1659: // <color=>                       
                        // Handle <color=#FF00FF> or <color=#FF00FF00>
                        if (m_htmlTag[6] == 35 && tagCharCount == 13)
                        {
                            m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                            m_colorStack[m_colorStackIndex] = m_htmlColor;
                            m_colorStackIndex += 1;
                            return true;
                        }
                        else if (m_htmlTag[6] == 35 && tagCharCount == 15)
                        {
                            m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                            m_colorStack[m_colorStackIndex] = m_htmlColor;
                            m_colorStackIndex += 1;
                            return true;
                        }

                        switch (colorCode)
                        {
                            case 2872: // <color=red>                            
                                m_htmlColor = Color.red;
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case 3979: // <color=blue>
                                m_htmlColor = Color.blue;
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case 4956: // <color=black>
                                m_htmlColor = Color.black;
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case 5128: // <color=green>
                                m_htmlColor = Color.green;
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case 5247: // <color=white>
                                m_htmlColor = Color.white;
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case 6373: // <color=orange>
                                m_htmlColor = new Color32(255, 128, 0, 255);
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case 6632: // <color=purple>
                                m_htmlColor = new Color32(160, 32, 240, 255);
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                            case 6722: // <color=yellow>
                                m_htmlColor = Color.yellow;
                                m_colorStack[m_colorStackIndex] = m_htmlColor;
                                m_colorStackIndex += 1;
                                return true;
                        }
                        return false;
                    case 2030: // <a name="">
                        return true;
                    case 2154: // <cspace=xx.x>
                        m_cSpacing = ConvertToFloat(m_htmlTag, numSequenceStart, tagCharCount - 1, numSequenceDecimalPos);
                        return true;
                    case 2160: // </align>
                        m_lineJustification = m_textAlignment;
                        return true;
                    case 2164: // <mspace=xx.x>
                        m_monoSpacing = ConvertToFloat(m_htmlTag, numSequenceStart, tagCharCount - 1, numSequenceDecimalPos);
                        return true;
                    case 2204: // </width>
                        m_width = 0;
                        return true;
                    case 2249: // </color>
                        m_colorStackIndex -= 1;

                        if (m_colorStackIndex <= 0)
                        {
                            m_htmlColor = m_fontColor32;
                            m_colorStackIndex = 0;
                        }
                        else
                        {
                            m_htmlColor = m_colorStack[m_colorStackIndex - 1];
                        }


                        //m_htmlColor = m_fontColor32;
                        return true;
                    case 2275: // <indent=00.0>
                        m_indent = ConvertToFloat(m_htmlTag, numSequenceStart, tagCharCount - 1, numSequenceDecimalPos) * m_fontScale * m_fontAsset.fontInfo.TabWidth;
                        m_xAdvance = m_indent;                      
                        return true;                      
                    case 2287: // <sprite=x>
                        m_spriteIndex = (int)ConvertToFloat(m_htmlTag, numSequenceStart, tagCharCount - 1, numSequenceDecimalPos);
                        //Debug.Log("Sprite Index is " + ((int)ConvertToFloat(m_htmlTag, numSequenceStart, tagCharCount - 1, numSequenceDecimalPos)));
                        m_isSprite = true;
                        return true;
                    case 2844: // </mspace>
                        m_monoSpacing = 0;
                        return true;
                    case 2824: // </cspace>
                        m_cSpacing = 0;
                        return true;
                    case 2964: // </indent>
                        m_indent = 0;
                        return true;
                    case 2995: // <allcaps>
                        m_style |= FontStyles.UpperCase;
                        return true;
                    case 3778: // </allcaps>
                        m_style &= ~FontStyles.UpperCase;
                        return true;
                    case 4800: // <smallcaps>                      
                        m_style |= FontStyles.SmallCaps;
                        return true;
                    case 5807: // </smallcaps>
                        m_currentFontSize = m_fontSize;
                        m_style &= ~FontStyles.SmallCaps;
                        m_isRecalculateScaleRequired = true;
                        return true;
                    case 6691: // <line-height=xx.x>
                        m_lineHeight = ConvertToFloat(m_htmlTag, numSequenceStart, tagCharCount - 1, numSequenceDecimalPos);
                        return true;
                    case 7840: // </line-height>
                        m_lineHeight = 0;
                        return true;
                }
            }

            return false;
        }