using System;
using System.Diagnostics;
using UnityEngine;
namespace TMPro
{
///
/// Structure used to track basic XML tags which are binary (on / off)
///
public struct TMP_FontStyleStack
{
public byte bold;
public byte italic;
public byte underline;
public byte strikethrough;
public byte highlight;
public byte superscript;
public byte subscript;
public byte uppercase;
public byte lowercase;
public byte smallcaps;
///
/// Clear the basic XML tag stack.
///
public void Clear()
{
bold = 0;
italic = 0;
underline = 0;
strikethrough = 0;
highlight = 0;
superscript = 0;
subscript = 0;
uppercase = 0;
lowercase = 0;
smallcaps = 0;
}
public byte Add(FontStyles style)
{
switch (style)
{
case FontStyles.Bold:
bold++;
return bold;
case FontStyles.Italic:
italic++;
return italic;
case FontStyles.Underline:
underline++;
return underline;
case FontStyles.UpperCase:
uppercase++;
return uppercase;
case FontStyles.LowerCase:
lowercase++;
return lowercase;
case FontStyles.Strikethrough:
strikethrough++;
return strikethrough;
case FontStyles.Superscript:
superscript++;
return superscript;
case FontStyles.Subscript:
subscript++;
return subscript;
case FontStyles.Highlight:
highlight++;
return highlight;
}
return 0;
}
public byte Remove(FontStyles style)
{
switch (style)
{
case FontStyles.Bold:
if (bold > 1)
bold--;
else
bold = 0;
return bold;
case FontStyles.Italic:
if (italic > 1)
italic--;
else
italic = 0;
return italic;
case FontStyles.Underline:
if (underline > 1)
underline--;
else
underline = 0;
return underline;
case FontStyles.UpperCase:
if (uppercase > 1)
uppercase--;
else
uppercase = 0;
return uppercase;
case FontStyles.LowerCase:
if (lowercase > 1)
lowercase--;
else
lowercase = 0;
return lowercase;
case FontStyles.Strikethrough:
if (strikethrough > 1)
strikethrough--;
else
strikethrough = 0;
return strikethrough;
case FontStyles.Highlight:
if (highlight > 1)
highlight--;
else
highlight = 0;
return highlight;
case FontStyles.Superscript:
if (superscript > 1)
superscript--;
else
superscript = 0;
return superscript;
case FontStyles.Subscript:
if (subscript > 1)
subscript--;
else
subscript = 0;
return subscript;
}
return 0;
}
}
///
/// Structure used to track XML tags of various types.
///
/// The element type of the stack.
[DebuggerDisplay("Item count = {m_Count}")]
public struct TMP_TextProcessingStack
{
public T[] itemStack;
public int index;
T m_DefaultItem;
int m_Capacity;
int m_RolloverSize;
int m_Count;
const int k_DefaultCapacity = 4;
///
/// Constructor to create a new item stack.
///
/// Backing array that stores stack entries; capacity equals this array length.
///
/// Initializes internal counters so the stack starts empty while reusing the provided buffer to avoid an extra allocation when the caller already sized the array.
///
public TMP_TextProcessingStack(T[] stack)
{
itemStack = stack;
m_Capacity = stack.Length;
index = 0;
m_RolloverSize = 0;
m_DefaultItem = default(T);
m_Count = 0;
}
///
/// Constructor for a new item stack with the given capacity.
///
/// Number of slots to allocate in the internal item array before any push operations.
///
/// Allocates entries up front so nested rich-text tags can push state without resizing during typical markup depth.
///
public TMP_TextProcessingStack(int capacity)
{
itemStack = new T[capacity];
m_Capacity = capacity;
index = 0;
m_RolloverSize = 0;
m_DefaultItem = default(T);
m_Count = 0;
}
public TMP_TextProcessingStack(int capacity, int rolloverSize)
{
itemStack = new T[capacity];
m_Capacity = capacity;
index = 0;
m_RolloverSize = rolloverSize;
m_DefaultItem = default(T);
m_Count = 0;
}
///
/// Gets the number of items currently stored on the stack.
///
///
/// Backed by m_Count, which push, pop, and remove operations keep aligned with the logical depth of active rich-text scopes.
///
public int Count
{
get { return m_Count; }
}
///
/// Returns the current item on the stack.
///
public T current
{
get
{
if (index > 0)
return itemStack[index - 1];
return itemStack[0];
}
}
///
/// Gets or sets the rollover size used when the stack wraps in circular-buffer mode.
///
///
/// When set to zero, pushes grow the backing array; when positive, the stack index wraps modulo the rollover size to cap memory for unbounded tag nesting.
///
public int rolloverSize
{
get { return m_RolloverSize; }
set
{
m_RolloverSize = value;
//if (m_Capacity < m_RolloverSize)
// Array.Resize(ref itemStack, m_RolloverSize);
}
}
///
/// Set stack elements to default item.
///
/// The stack of elements.
///
internal static void SetDefault(TMP_TextProcessingStack[] stack, T item)
{
for (int i = 0; i < stack.Length; i++)
stack[i].SetDefault(item);
}
///
/// Clears and resets stack to first item.
///
///
/// Resets the logical count and index so the next push or set default rebuilds state from scratch without reallocating the backing array reference.
///
public void Clear()
{
index = 0;
m_Count = 0;
}
///
/// Sets the first item on the stack and reset index.
///
/// Baseline value written to index zero and returned when the stack would otherwise be empty.
///
/// Lazily allocates the backing array when null, then sets index to one so subsequent adds append rich-text overrides above the default style.
///
public void SetDefault(T item)
{
if (itemStack == null)
{
m_Capacity = k_DefaultCapacity;
itemStack = new T[m_Capacity];
m_DefaultItem = default(T);
}
itemStack[0] = item;
index = 1;
m_Count = 1;
}
///
/// Adds a new item to the stack.
///
/// Value to store at the current write index when capacity allows further growth.
///
/// Writes only when index is below the backing array length; this legacy path does not expand storage, unlike .
///
public void Add(T item)
{
if (index < itemStack.Length)
{
itemStack[index] = item;
index += 1;
}
}
///
/// Retrieves an item from the stack.
///
/// The value exposed after decrementing the stack pointer, or the default slot when collapsing to one entry.
///
/// Decrements both index and count, clamping to one level so always has a defined fallback entry at index zero.
///
public T Remove()
{
index -= 1;
m_Count -= 1;
if (index <= 0)
{
m_Count = 0;
index = 1;
return itemStack[0];
}
return itemStack[index - 1];
}
public void Push(T item)
{
if (index == m_Capacity)
{
m_Capacity *= 2;
if (m_Capacity == 0)
m_Capacity = k_DefaultCapacity;
Array.Resize(ref itemStack, m_Capacity);
}
itemStack[index] = item;
if (m_RolloverSize == 0)
{
index += 1;
m_Count += 1;
}
else
{
index = (index + 1) % m_RolloverSize;
m_Count = m_Count < m_RolloverSize ? m_Count + 1 : m_RolloverSize;
}
}
public T Pop()
{
if (index == 0 && m_RolloverSize == 0)
return default(T);
if (m_RolloverSize == 0)
index -= 1;
else
{
index = (index - 1) % m_RolloverSize;
index = index < 0 ? index + m_RolloverSize : index;
}
T item = itemStack[index];
itemStack[index] = m_DefaultItem;
m_Count = m_Count > 0 ? m_Count - 1 : 0;
return item;
}
///
/// Returns the top item on the stack without removing it.
///
/// The most recently pushed value, or the baseline entry at index zero when nothing has been pushed yet.
///
/// Non-destructive read used when parsers need the active style without mutating the stack during lookahead.
///
public T Peek()
{
if (index == 0)
return m_DefaultItem;
return itemStack[index - 1];
}
///
/// Function to retrieve the current item from the stack.
///
/// The current item T from the stack.
public T CurrentItem()
{
if (index > 0)
return itemStack[index - 1];
return itemStack[0];
}
///
/// Retrieves the previous item without affecting the stack.
///
/// The value one level below the top when at least two entries exist; otherwise the first slot.
///
/// Useful when comparing the prior style to the active style while leaving the stack unchanged for subsequent characters.
///
public T PreviousItem()
{
if (index > 1)
return itemStack[index - 2];
return itemStack[0];
}
}
}