You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7509 lines
322 KiB

  1. #define TMP_PRESENT
  2. using UnityEngine;
  3. using UnityEngine.UI;
  4. using UnityEngine.Events;
  5. using UnityEngine.EventSystems;
  6. using System;
  7. using System.Text;
  8. using System.Collections;
  9. using System.Collections.Generic;
  10. namespace TMPro
  11. {
  12. public interface ITextElement
  13. {
  14. Material sharedMaterial { get; }
  15. void Rebuild(CanvasUpdate update);
  16. int GetInstanceID();
  17. }
  18. public enum TextAlignmentOptions
  19. {
  20. TopLeft = _HorizontalAlignmentOptions.Left | _VerticalAlignmentOptions.Top,
  21. Top = _HorizontalAlignmentOptions.Center | _VerticalAlignmentOptions.Top,
  22. TopRight = _HorizontalAlignmentOptions.Right | _VerticalAlignmentOptions.Top,
  23. TopJustified = _HorizontalAlignmentOptions.Justified | _VerticalAlignmentOptions.Top,
  24. TopFlush = _HorizontalAlignmentOptions.Flush | _VerticalAlignmentOptions.Top,
  25. TopGeoAligned = _HorizontalAlignmentOptions.Geometry | _VerticalAlignmentOptions.Top,
  26. Left = _HorizontalAlignmentOptions.Left | _VerticalAlignmentOptions.Middle,
  27. Center = _HorizontalAlignmentOptions.Center | _VerticalAlignmentOptions.Middle,
  28. Right = _HorizontalAlignmentOptions.Right | _VerticalAlignmentOptions.Middle,
  29. Justified = _HorizontalAlignmentOptions.Justified | _VerticalAlignmentOptions.Middle,
  30. Flush = _HorizontalAlignmentOptions.Flush | _VerticalAlignmentOptions.Middle,
  31. CenterGeoAligned = _HorizontalAlignmentOptions.Geometry | _VerticalAlignmentOptions.Middle,
  32. BottomLeft = _HorizontalAlignmentOptions.Left | _VerticalAlignmentOptions.Bottom,
  33. Bottom = _HorizontalAlignmentOptions.Center | _VerticalAlignmentOptions.Bottom,
  34. BottomRight = _HorizontalAlignmentOptions.Right | _VerticalAlignmentOptions.Bottom,
  35. BottomJustified = _HorizontalAlignmentOptions.Justified | _VerticalAlignmentOptions.Bottom,
  36. BottomFlush = _HorizontalAlignmentOptions.Flush | _VerticalAlignmentOptions.Bottom,
  37. BottomGeoAligned = _HorizontalAlignmentOptions.Geometry | _VerticalAlignmentOptions.Bottom,
  38. BaselineLeft = _HorizontalAlignmentOptions.Left | _VerticalAlignmentOptions.Baseline,
  39. Baseline = _HorizontalAlignmentOptions.Center | _VerticalAlignmentOptions.Baseline,
  40. BaselineRight = _HorizontalAlignmentOptions.Right | _VerticalAlignmentOptions.Baseline,
  41. BaselineJustified = _HorizontalAlignmentOptions.Justified | _VerticalAlignmentOptions.Baseline,
  42. BaselineFlush = _HorizontalAlignmentOptions.Flush | _VerticalAlignmentOptions.Baseline,
  43. BaselineGeoAligned = _HorizontalAlignmentOptions.Geometry | _VerticalAlignmentOptions.Baseline,
  44. MidlineLeft = _HorizontalAlignmentOptions.Left | _VerticalAlignmentOptions.Geometry,
  45. Midline = _HorizontalAlignmentOptions.Center | _VerticalAlignmentOptions.Geometry,
  46. MidlineRight = _HorizontalAlignmentOptions.Right | _VerticalAlignmentOptions.Geometry,
  47. MidlineJustified = _HorizontalAlignmentOptions.Justified | _VerticalAlignmentOptions.Geometry,
  48. MidlineFlush = _HorizontalAlignmentOptions.Flush | _VerticalAlignmentOptions.Geometry,
  49. MidlineGeoAligned = _HorizontalAlignmentOptions.Geometry | _VerticalAlignmentOptions.Geometry,
  50. CaplineLeft = _HorizontalAlignmentOptions.Left | _VerticalAlignmentOptions.Capline,
  51. Capline = _HorizontalAlignmentOptions.Center | _VerticalAlignmentOptions.Capline,
  52. CaplineRight = _HorizontalAlignmentOptions.Right | _VerticalAlignmentOptions.Capline,
  53. CaplineJustified = _HorizontalAlignmentOptions.Justified | _VerticalAlignmentOptions.Capline,
  54. CaplineFlush = _HorizontalAlignmentOptions.Flush | _VerticalAlignmentOptions.Capline,
  55. CaplineGeoAligned = _HorizontalAlignmentOptions.Geometry | _VerticalAlignmentOptions.Capline
  56. };
  57. /// <summary>
  58. /// Internal horizontal text alignment options.
  59. /// </summary>
  60. public enum _HorizontalAlignmentOptions
  61. {
  62. Left = 0x1, Center = 0x2, Right = 0x4, Justified = 0x8, Flush = 0x10, Geometry = 0x20
  63. }
  64. /// <summary>
  65. /// Internal vertical text alignment options.
  66. /// </summary>
  67. public enum _VerticalAlignmentOptions
  68. {
  69. Top = 0x100, Middle = 0x200, Bottom = 0x400, Baseline = 0x800, Geometry = 0x1000, Capline = 0x2000,
  70. }
  71. /// <summary>
  72. /// Flags controlling what vertex data gets pushed to the mesh.
  73. /// </summary>
  74. public enum TextRenderFlags
  75. {
  76. DontRender = 0x0,
  77. Render = 0xFF
  78. };
  79. public enum TMP_TextElementType { Character, Sprite };
  80. public enum MaskingTypes { MaskOff = 0, MaskHard = 1, MaskSoft = 2 }; //, MaskTex = 4 };
  81. public enum TextOverflowModes { Overflow = 0, Ellipsis = 1, Masking = 2, Truncate = 3, ScrollRect = 4, Page = 5, Linked = 6 };
  82. public enum MaskingOffsetMode { Percentage = 0, Pixel = 1 };
  83. public enum TextureMappingOptions { Character = 0, Line = 1, Paragraph = 2, MatchAspect = 3 };
  84. public enum FontStyles { Normal = 0x0, Bold = 0x1, Italic = 0x2, Underline = 0x4, LowerCase = 0x8, UpperCase = 0x10, SmallCaps = 0x20, Strikethrough = 0x40, Superscript = 0x80, Subscript = 0x100, Highlight = 0x200 };
  85. public enum FontWeights { Thin = 100, ExtraLight = 200, Light = 300, Normal = 400, Medium = 500, SemiBold = 600, Bold = 700, Heavy = 800, Black = 900 };
  86. public enum TagUnits { Pixels = 0, FontUnits = 1, Percentage = 2 };
  87. public enum TagType { None = 0x0, NumericalValue = 0x1, StringValue = 0x2, ColorValue = 0x4 };
  88. /// <summary>
  89. /// Base class which contains common properties and functions shared between the TextMeshPro and TextMeshProUGUI component.
  90. /// </summary>
  91. public abstract class TMP_Text : MaskableGraphic
  92. {
  93. /// <summary>
  94. /// A string containing the text to be displayed.
  95. /// </summary>
  96. public string text
  97. {
  98. get { return m_text; }
  99. set { if (m_text == value) return; m_text = old_text = value; m_inputSource = TextInputSources.String; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetLayoutDirty(); }
  100. }
  101. [SerializeField]
  102. [TextArea(3, 10)]
  103. protected string m_text;
  104. /// <summary>
  105. ///
  106. /// </summary>
  107. public bool isRightToLeftText
  108. {
  109. get { return m_isRightToLeft; }
  110. set { if (m_isRightToLeft == value) return; m_isRightToLeft = value; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetLayoutDirty(); }
  111. }
  112. [SerializeField]
  113. protected bool m_isRightToLeft = false;
  114. /// <summary>
  115. /// The Font Asset to be assigned to this text object.
  116. /// </summary>
  117. public TMP_FontAsset font
  118. {
  119. get { return m_fontAsset; }
  120. set { if (m_fontAsset == value) return; m_fontAsset = value; LoadFontAsset(); m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetLayoutDirty(); }
  121. }
  122. [SerializeField]
  123. protected TMP_FontAsset m_fontAsset;
  124. protected TMP_FontAsset m_currentFontAsset;
  125. protected bool m_isSDFShader;
  126. /// <summary>
  127. /// The material to be assigned to this text object.
  128. /// </summary>
  129. public virtual Material fontSharedMaterial
  130. {
  131. get { return m_sharedMaterial; }
  132. set { if (m_sharedMaterial == value) return; SetSharedMaterial(value); m_havePropertiesChanged = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetMaterialDirty(); }
  133. }
  134. [SerializeField]
  135. protected Material m_sharedMaterial;
  136. protected Material m_currentMaterial;
  137. protected MaterialReference[] m_materialReferences = new MaterialReference[32];
  138. protected Dictionary<int, int> m_materialReferenceIndexLookup = new Dictionary<int, int>();
  139. protected TMP_XmlTagStack<MaterialReference> m_materialReferenceStack = new TMP_XmlTagStack<MaterialReference>(new MaterialReference[16]);
  140. protected int m_currentMaterialIndex;
  141. //protected int m_sharedMaterialHashCode;
  142. /// <summary>
  143. /// An array containing the materials used by the text object.
  144. /// </summary>
  145. public virtual Material[] fontSharedMaterials
  146. {
  147. get { return GetSharedMaterials(); }
  148. set { SetSharedMaterials(value); m_havePropertiesChanged = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetMaterialDirty(); }
  149. }
  150. [SerializeField]
  151. protected Material[] m_fontSharedMaterials;
  152. /// <summary>
  153. /// The material to be assigned to this text object. An instance of the material will be assigned to the object's renderer.
  154. /// </summary>
  155. public Material fontMaterial
  156. {
  157. // Return an Instance of the current material.
  158. get { return GetMaterial(m_sharedMaterial); }
  159. // Assign new font material
  160. set
  161. {
  162. if (m_sharedMaterial != null && m_sharedMaterial.GetInstanceID() == value.GetInstanceID()) return;
  163. m_sharedMaterial = value;
  164. m_padding = GetPaddingForMaterial();
  165. m_havePropertiesChanged = true;
  166. m_isInputParsingRequired = true;
  167. SetVerticesDirty();
  168. SetMaterialDirty();
  169. }
  170. }
  171. [SerializeField]
  172. protected Material m_fontMaterial;
  173. /// <summary>
  174. /// The materials to be assigned to this text object. An instance of the materials will be assigned.
  175. /// </summary>
  176. public virtual Material[] fontMaterials
  177. {
  178. get { return GetMaterials(m_fontSharedMaterials); }
  179. set { SetSharedMaterials(value); m_havePropertiesChanged = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetMaterialDirty(); }
  180. }
  181. [SerializeField]
  182. protected Material[] m_fontMaterials;
  183. protected bool m_isMaterialDirty;
  184. /// <summary>
  185. /// This is the default vertex color assigned to each vertices. Color tags will override vertex colors unless the overrideColorTags is set.
  186. /// </summary>
  187. public override Color color
  188. {
  189. get { return m_fontColor; }
  190. set { if (m_fontColor == value) return; m_havePropertiesChanged = true; m_fontColor = value; SetVerticesDirty(); }
  191. }
  192. //[UnityEngine.Serialization.FormerlySerializedAs("m_fontColor")] // Required for backwards compatibility with pre-Unity 4.6 releases.
  193. [SerializeField]
  194. protected Color32 m_fontColor32 = Color.white;
  195. [SerializeField]
  196. protected Color m_fontColor = Color.white;
  197. protected static Color32 s_colorWhite = new Color32(255, 255, 255, 255);
  198. protected Color32 m_underlineColor = s_colorWhite;
  199. protected Color32 m_strikethroughColor = s_colorWhite;
  200. protected Color32 m_highlightColor = s_colorWhite;
  201. /// <summary>
  202. /// Sets the vertex color alpha value.
  203. /// </summary>
  204. public float alpha
  205. {
  206. get { return m_fontColor.a; }
  207. set { if (m_fontColor.a == value) return; m_fontColor.a = value; m_havePropertiesChanged = true; SetVerticesDirty(); }
  208. }
  209. /// <summary>
  210. /// Determines if Vertex Color Gradient should be used
  211. /// </summary>
  212. /// <value><c>true</c> if enable vertex gradient; otherwise, <c>false</c>.</value>
  213. public bool enableVertexGradient
  214. {
  215. get { return m_enableVertexGradient; }
  216. set { if (m_enableVertexGradient == value) return; m_havePropertiesChanged = true; m_enableVertexGradient = value; SetVerticesDirty(); }
  217. }
  218. [SerializeField]
  219. protected bool m_enableVertexGradient;
  220. [SerializeField]
  221. protected ColorMode m_colorMode = ColorMode.FourCornersGradient;
  222. /// <summary>
  223. /// Sets the vertex colors for each of the 4 vertices of the character quads.
  224. /// </summary>
  225. /// <value>The color gradient.</value>
  226. public VertexGradient colorGradient
  227. {
  228. get { return m_fontColorGradient; }
  229. set { m_havePropertiesChanged = true; m_fontColorGradient = value; SetVerticesDirty(); }
  230. }
  231. [SerializeField]
  232. protected VertexGradient m_fontColorGradient = new VertexGradient(Color.white);
  233. /// <summary>
  234. /// Set the vertex colors of the 4 vertices of each character quads.
  235. /// </summary>
  236. public TMP_ColorGradient colorGradientPreset
  237. {
  238. get { return m_fontColorGradientPreset; }
  239. set { m_havePropertiesChanged = true; m_fontColorGradientPreset = value; SetVerticesDirty(); }
  240. }
  241. [SerializeField]
  242. protected TMP_ColorGradient m_fontColorGradientPreset;
  243. /// <summary>
  244. /// Default Sprite Asset used by the text object.
  245. /// </summary>
  246. public TMP_SpriteAsset spriteAsset
  247. {
  248. get { return m_spriteAsset; }
  249. set { m_spriteAsset = value; m_havePropertiesChanged = true; m_isInputParsingRequired = true; m_isCalculateSizeRequired = true; SetVerticesDirty(); SetLayoutDirty(); }
  250. }
  251. [SerializeField]
  252. protected TMP_SpriteAsset m_spriteAsset;
  253. /// <summary>
  254. /// Determines whether or not the sprite color is multiplies by the vertex color of the text.
  255. /// </summary>
  256. public bool tintAllSprites
  257. {
  258. get { return m_tintAllSprites; }
  259. set { if (m_tintAllSprites == value) return; m_tintAllSprites = value; m_havePropertiesChanged = true; SetVerticesDirty(); }
  260. }
  261. [SerializeField]
  262. protected bool m_tintAllSprites;
  263. protected bool m_tintSprite;
  264. protected Color32 m_spriteColor;
  265. /// <summary>
  266. /// This overrides the color tags forcing the vertex colors to be the default font color.
  267. /// </summary>
  268. public bool overrideColorTags
  269. {
  270. get { return m_overrideHtmlColors; }
  271. set { if (m_overrideHtmlColors == value) return; m_havePropertiesChanged = true; m_overrideHtmlColors = value; SetVerticesDirty(); }
  272. }
  273. [SerializeField]
  274. protected bool m_overrideHtmlColors = false;
  275. /// <summary>
  276. /// Sets the color of the _FaceColor property of the assigned material. Changing face color will result in an instance of the material.
  277. /// </summary>
  278. public Color32 faceColor
  279. {
  280. get
  281. {
  282. if (m_sharedMaterial == null) return m_faceColor;
  283. m_faceColor = m_sharedMaterial.GetColor(ShaderUtilities.ID_FaceColor);
  284. return m_faceColor;
  285. }
  286. set { if (m_faceColor.Compare(value)) return; SetFaceColor(value); m_havePropertiesChanged = true; m_faceColor = value; SetVerticesDirty(); SetMaterialDirty(); }
  287. }
  288. [SerializeField]
  289. protected Color32 m_faceColor = Color.white;
  290. /// <summary>
  291. /// Sets the color of the _OutlineColor property of the assigned material. Changing outline color will result in an instance of the material.
  292. /// </summary>
  293. public Color32 outlineColor
  294. {
  295. get
  296. {
  297. if (m_sharedMaterial == null) return m_outlineColor;
  298. m_outlineColor = m_sharedMaterial.GetColor(ShaderUtilities.ID_OutlineColor);
  299. return m_outlineColor;
  300. }
  301. set { if (m_outlineColor.Compare(value)) return; SetOutlineColor(value); m_havePropertiesChanged = true; m_outlineColor = value; SetVerticesDirty(); }
  302. }
  303. [SerializeField]
  304. protected Color32 m_outlineColor = Color.black;
  305. /// <summary>
  306. /// Sets the thickness of the outline of the font. Setting this value will result in an instance of the material.
  307. /// </summary>
  308. public float outlineWidth
  309. {
  310. get
  311. {
  312. if (m_sharedMaterial == null) return m_outlineWidth;
  313. m_outlineWidth = m_sharedMaterial.GetFloat(ShaderUtilities.ID_OutlineWidth);
  314. return m_outlineWidth;
  315. }
  316. set { if (m_outlineWidth == value) return; SetOutlineThickness(value); m_havePropertiesChanged = true; m_outlineWidth = value; SetVerticesDirty(); }
  317. }
  318. protected float m_outlineWidth = 0.0f;
  319. /// <summary>
  320. /// The point size of the font.
  321. /// </summary>
  322. public float fontSize
  323. {
  324. get { return m_fontSize; }
  325. set { if (m_fontSize == value) return; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_fontSize = value; if (!m_enableAutoSizing) m_fontSizeBase = m_fontSize; SetVerticesDirty(); SetLayoutDirty(); }
  326. }
  327. [SerializeField]
  328. protected float m_fontSize = 36; // Font Size
  329. protected float m_currentFontSize; // Temporary Font Size affected by tags
  330. [SerializeField]
  331. protected float m_fontSizeBase = 36;
  332. protected TMP_XmlTagStack<float> m_sizeStack = new TMP_XmlTagStack<float>(new float[16]);
  333. /// <summary>
  334. /// The scale of the current text.
  335. /// </summary>
  336. public float fontScale
  337. {
  338. get { return m_fontScale; }
  339. }
  340. /// <summary>
  341. /// Control the weight of the font if an alternative font asset is assigned for the given weight in the font asset editor.
  342. /// </summary>
  343. public int fontWeight
  344. {
  345. get { return m_fontWeight; }
  346. set { if (m_fontWeight == value) return; m_fontWeight = value; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetLayoutDirty(); }
  347. }
  348. [SerializeField]
  349. protected int m_fontWeight = 400;
  350. protected int m_fontWeightInternal;
  351. protected TMP_XmlTagStack<int> m_fontWeightStack = new TMP_XmlTagStack<int>(new int[16]);
  352. /// <summary>
  353. ///
  354. /// </summary>
  355. public float pixelsPerUnit
  356. {
  357. get
  358. {
  359. var localCanvas = canvas;
  360. if (!localCanvas)
  361. return 1;
  362. // For dynamic fonts, ensure we use one pixel per pixel on the screen.
  363. if (!font)
  364. return localCanvas.scaleFactor;
  365. // For non-dynamic fonts, calculate pixels per unit based on specified font size relative to font object's own font size.
  366. if (m_currentFontAsset == null || m_currentFontAsset.fontInfo.PointSize <= 0 || m_fontSize <= 0)
  367. return 1;
  368. return m_fontSize / m_currentFontAsset.fontInfo.PointSize;
  369. }
  370. }
  371. /// <summary>
  372. /// Enable text auto-sizing
  373. /// </summary>
  374. public bool enableAutoSizing
  375. {
  376. get { return m_enableAutoSizing; }
  377. set { if (m_enableAutoSizing == value) return; m_enableAutoSizing = value; SetVerticesDirty(); SetLayoutDirty(); }
  378. }
  379. [SerializeField]
  380. protected bool m_enableAutoSizing;
  381. protected float m_maxFontSize; // Used in conjunction with auto-sizing
  382. protected float m_minFontSize; // Used in conjunction with auto-sizing
  383. /// <summary>
  384. /// Minimum point size of the font when text auto-sizing is enabled.
  385. /// </summary>
  386. public float fontSizeMin
  387. {
  388. get { return m_fontSizeMin; }
  389. set { if (m_fontSizeMin == value) return; m_fontSizeMin = value; SetVerticesDirty(); SetLayoutDirty(); }
  390. }
  391. [SerializeField]
  392. protected float m_fontSizeMin = 0; // Text Auto Sizing Min Font Size.
  393. /// <summary>
  394. /// Maximum point size of the font when text auto-sizing is enabled.
  395. /// </summary>
  396. public float fontSizeMax
  397. {
  398. get { return m_fontSizeMax; }
  399. set { if (m_fontSizeMax == value) return; m_fontSizeMax = value; SetVerticesDirty(); SetLayoutDirty(); }
  400. }
  401. [SerializeField]
  402. protected float m_fontSizeMax = 0; // Text Auto Sizing Max Font Size.
  403. /// <summary>
  404. /// The style of the text
  405. /// </summary>
  406. public FontStyles fontStyle
  407. {
  408. get { return m_fontStyle; }
  409. set { if (m_fontStyle == value) return; m_fontStyle = value; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetLayoutDirty(); }
  410. }
  411. [SerializeField]
  412. protected FontStyles m_fontStyle = FontStyles.Normal;
  413. protected FontStyles m_style = FontStyles.Normal;
  414. protected TMP_BasicXmlTagStack m_fontStyleStack;
  415. /// <summary>
  416. /// Property used in conjunction with padding calculation for the geometry.
  417. /// </summary>
  418. public bool isUsingBold { get { return m_isUsingBold; } }
  419. protected bool m_isUsingBold = false; // Used to ensure GetPadding & Ratios take into consideration bold characters.
  420. /// <summary>
  421. /// Text alignment options
  422. /// </summary>
  423. public TextAlignmentOptions alignment
  424. {
  425. get { return m_textAlignment; }
  426. set { if (m_textAlignment == value) return; m_havePropertiesChanged = true; m_textAlignment = value; SetVerticesDirty(); }
  427. }
  428. [SerializeField]
  429. [UnityEngine.Serialization.FormerlySerializedAs("m_lineJustification")]
  430. protected TextAlignmentOptions m_textAlignment = TextAlignmentOptions.TopLeft;
  431. protected TextAlignmentOptions m_lineJustification;
  432. protected TMP_XmlTagStack<TextAlignmentOptions> m_lineJustificationStack = new TMP_XmlTagStack<TextAlignmentOptions>(new TextAlignmentOptions[16]);
  433. protected Vector3[] m_textContainerLocalCorners = new Vector3[4];
  434. [SerializeField]
  435. protected bool m_isAlignmentEnumConverted;
  436. /// <summary>
  437. /// Use the extents of the text geometry for alignment instead of font metrics.
  438. /// </summary>
  439. //public bool alignByGeometry
  440. //{
  441. // get { return m_alignByGeometry; }
  442. // set { if (m_alignByGeometry == value) return; m_havePropertiesChanged = true; m_alignByGeometry = value; SetVerticesDirty(); }
  443. //}
  444. //[SerializeField]
  445. //protected bool m_alignByGeometry;
  446. /// <summary>
  447. /// The amount of additional spacing between characters.
  448. /// </summary>
  449. public float characterSpacing
  450. {
  451. get { return m_characterSpacing; }
  452. set { if (m_characterSpacing == value) return; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_characterSpacing = value; SetVerticesDirty(); SetLayoutDirty(); }
  453. }
  454. [SerializeField]
  455. protected float m_characterSpacing = 0;
  456. protected float m_cSpacing = 0;
  457. protected float m_monoSpacing = 0;
  458. /// <summary>
  459. /// The amount of additional spacing between words.
  460. /// </summary>
  461. public float wordSpacing
  462. {
  463. get { return m_wordSpacing; }
  464. set { if (m_wordSpacing == value) return; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_wordSpacing = value; SetVerticesDirty(); SetLayoutDirty(); }
  465. }
  466. [SerializeField]
  467. protected float m_wordSpacing = 0;
  468. /// <summary>
  469. /// The amount of additional spacing to add between each lines of text.
  470. /// </summary>
  471. public float lineSpacing
  472. {
  473. get { return m_lineSpacing; }
  474. set { if (m_lineSpacing == value) return; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_lineSpacing = value; SetVerticesDirty(); SetLayoutDirty(); }
  475. }
  476. [SerializeField]
  477. protected float m_lineSpacing = 0;
  478. protected float m_lineSpacingDelta = 0; // Used with Text Auto Sizing feature
  479. protected float m_lineHeight = TMP_Math.FLOAT_UNSET; // Used with the <line-height=xx.x> tag.
  480. /// <summary>
  481. /// The amount of potential line spacing adjustment before text auto sizing kicks in.
  482. /// </summary>
  483. public float lineSpacingAdjustment
  484. {
  485. get { return m_lineSpacingMax; }
  486. set { if (m_lineSpacingMax == value) return; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_lineSpacingMax = value; SetVerticesDirty(); SetLayoutDirty(); }
  487. }
  488. [SerializeField]
  489. protected float m_lineSpacingMax = 0; // Text Auto Sizing Max Line spacing reduction.
  490. //protected bool m_forceLineBreak;
  491. /// <summary>
  492. /// The amount of additional spacing to add between each lines of text.
  493. /// </summary>
  494. public float paragraphSpacing
  495. {
  496. get { return m_paragraphSpacing; }
  497. set { if (m_paragraphSpacing == value) return; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_paragraphSpacing = value; SetVerticesDirty(); SetLayoutDirty(); }
  498. }
  499. [SerializeField]
  500. protected float m_paragraphSpacing = 0;
  501. /// <summary>
  502. /// Percentage the width of characters can be adjusted before text auto-sizing begins to reduce the point size.
  503. /// </summary>
  504. public float characterWidthAdjustment
  505. {
  506. get { return m_charWidthMaxAdj; }
  507. set { if (m_charWidthMaxAdj == value) return; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_charWidthMaxAdj = value; SetVerticesDirty(); SetLayoutDirty(); }
  508. }
  509. [SerializeField]
  510. protected float m_charWidthMaxAdj = 0f; // Text Auto Sizing Max Character Width reduction.
  511. protected float m_charWidthAdjDelta = 0;
  512. /// <summary>
  513. /// Controls whether or not word wrapping is applied. When disabled, the text will be displayed on a single line.
  514. /// </summary>
  515. public bool enableWordWrapping
  516. {
  517. get { return m_enableWordWrapping; }
  518. set { if (m_enableWordWrapping == value) return; m_havePropertiesChanged = true; m_isInputParsingRequired = true; m_isCalculateSizeRequired = true; m_enableWordWrapping = value; SetVerticesDirty(); SetLayoutDirty(); }
  519. }
  520. [SerializeField]
  521. protected bool m_enableWordWrapping = false;
  522. protected bool m_isCharacterWrappingEnabled = false;
  523. protected bool m_isNonBreakingSpace = false;
  524. protected bool m_isIgnoringAlignment;
  525. /// <summary>
  526. /// Controls the blending between using character and word spacing to fill-in the space for justified text.
  527. /// </summary>
  528. public float wordWrappingRatios
  529. {
  530. get { return m_wordWrappingRatios; }
  531. set { if (m_wordWrappingRatios == value) return; m_wordWrappingRatios = value; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; SetVerticesDirty(); SetLayoutDirty(); }
  532. }
  533. [SerializeField]
  534. protected float m_wordWrappingRatios = 0.4f; // Controls word wrapping ratios between word or characters.
  535. /// <summary>
  536. ///
  537. /// </summary>
  538. //public bool enableAdaptiveJustification
  539. //{
  540. // get { return m_enableAdaptiveJustification; }
  541. // set { if (m_enableAdaptiveJustification == value) return; m_enableAdaptiveJustification = value; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; SetVerticesDirty(); SetLayoutDirty(); }
  542. //}
  543. //[SerializeField]
  544. //protected bool m_enableAdaptiveJustification;
  545. //protected float m_adaptiveJustificationThreshold = 10.0f;
  546. /// <summary>
  547. /// Controls the Text Overflow Mode
  548. /// </summary>
  549. public TextOverflowModes overflowMode
  550. {
  551. get { return m_overflowMode; }
  552. set { if (m_overflowMode == value) return; m_overflowMode = value; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; SetVerticesDirty(); SetLayoutDirty(); }
  553. }
  554. [SerializeField]
  555. protected TextOverflowModes m_overflowMode = TextOverflowModes.Overflow;
  556. /// <summary>
  557. /// Indicates if the text exceeds the vertical bounds of its text container.
  558. /// </summary>
  559. public bool isTextOverflowing
  560. {
  561. get { if (m_firstOverflowCharacterIndex != -1) return true; return false; }
  562. }
  563. /// <summary>
  564. /// The first character which exceeds the vertical bounds of its text container.
  565. /// </summary>
  566. public int firstOverflowCharacterIndex
  567. {
  568. get { return m_firstOverflowCharacterIndex; }
  569. }
  570. [SerializeField]
  571. protected int m_firstOverflowCharacterIndex = -1;
  572. /// <summary>
  573. /// The linked text component used for flowing the text from one text component to another.
  574. /// </summary>
  575. public TMP_Text linkedTextComponent
  576. {
  577. get { return m_linkedTextComponent; }
  578. set
  579. {
  580. if (m_linkedTextComponent != value)
  581. {
  582. // Release previously linked text component.
  583. if (m_linkedTextComponent != null)
  584. {
  585. m_linkedTextComponent.overflowMode = TextOverflowModes.Overflow;
  586. m_linkedTextComponent.linkedTextComponent = null;
  587. m_linkedTextComponent.isLinkedTextComponent = false;
  588. }
  589. m_linkedTextComponent = value;
  590. if (m_linkedTextComponent != null)
  591. m_linkedTextComponent.isLinkedTextComponent = true;
  592. }
  593. m_havePropertiesChanged = true;
  594. m_isCalculateSizeRequired = true;
  595. SetVerticesDirty();
  596. SetLayoutDirty();
  597. }
  598. }
  599. [SerializeField]
  600. protected TMP_Text m_linkedTextComponent;
  601. /// <summary>
  602. /// Indicates whether this text component is linked to another.
  603. /// </summary>
  604. public bool isLinkedTextComponent
  605. {
  606. get { return m_isLinkedTextComponent; }
  607. set
  608. {
  609. m_isLinkedTextComponent = value;
  610. if (m_isLinkedTextComponent == false)
  611. m_firstVisibleCharacter = 0;
  612. m_havePropertiesChanged = true;
  613. m_isCalculateSizeRequired = true;
  614. SetVerticesDirty();
  615. SetLayoutDirty();
  616. }
  617. }
  618. [SerializeField]
  619. protected bool m_isLinkedTextComponent;
  620. /// <summary>
  621. /// Property indicating whether the text is Truncated or using Ellipsis.
  622. /// </summary>
  623. public bool isTextTruncated { get { return m_isTextTruncated; } }
  624. [SerializeField]
  625. protected bool m_isTextTruncated;
  626. /// <summary>
  627. /// Determines if kerning is enabled or disabled.
  628. /// </summary>
  629. public bool enableKerning
  630. {
  631. get { return m_enableKerning; }
  632. set { if (m_enableKerning == value) return; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_enableKerning = value; SetVerticesDirty(); SetLayoutDirty(); }
  633. }
  634. [SerializeField]
  635. protected bool m_enableKerning;
  636. /// <summary>
  637. /// Adds extra padding around each character. This may be necessary when the displayed text is very small to prevent clipping.
  638. /// </summary>
  639. public bool extraPadding
  640. {
  641. get { return m_enableExtraPadding; }
  642. set { if (m_enableExtraPadding == value) return; m_havePropertiesChanged = true; m_enableExtraPadding = value; UpdateMeshPadding(); /* m_isCalculateSizeRequired = true;*/ SetVerticesDirty(); /* SetLayoutDirty();*/ }
  643. }
  644. [SerializeField]
  645. protected bool m_enableExtraPadding = false;
  646. [SerializeField]
  647. protected bool checkPaddingRequired;
  648. /// <summary>
  649. /// Enables or Disables Rich Text Tags
  650. /// </summary>
  651. public bool richText
  652. {
  653. get { return m_isRichText; }
  654. set { if (m_isRichText == value) return; m_isRichText = value; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetLayoutDirty(); }
  655. }
  656. [SerializeField]
  657. protected bool m_isRichText = true; // Used to enable or disable Rich Text.
  658. /// <summary>
  659. /// Enables or Disables parsing of CTRL characters in input text.
  660. /// </summary>
  661. public bool parseCtrlCharacters
  662. {
  663. get { return m_parseCtrlCharacters; }
  664. set { if (m_parseCtrlCharacters == value) return; m_parseCtrlCharacters = value; m_havePropertiesChanged = true; m_isCalculateSizeRequired = true; m_isInputParsingRequired = true; SetVerticesDirty(); SetLayoutDirty(); }
  665. }
  666. [SerializeField]
  667. protected bool m_parseCtrlCharacters = true;
  668. /// <summary>
  669. /// Sets the RenderQueue along with Ztest to force the text to be drawn last and on top of scene elements.
  670. /// </summary>
  671. public bool isOverlay
  672. {
  673. get { return m_isOverlay; }
  674. set { if (m_isOverlay == value) return; m_isOverlay = value; SetShaderDepth(); m_havePropertiesChanged = true; SetVerticesDirty(); }
  675. }
  676. protected bool m_isOverlay = false;
  677. /// <summary>
  678. /// Sets Perspective Correction to Zero for Orthographic Camera mode & 0.875f for Perspective Camera mode.
  679. /// </summary>
  680. public bool isOrthographic
  681. {
  682. get { return m_isOrthographic; }
  683. set { if (m_isOrthographic == value) return; m_havePropertiesChanged = true; m_isOrthographic = value; SetVerticesDirty(); }
  684. }
  685. [SerializeField]
  686. protected bool m_isOrthographic = false;
  687. /// <summary>
  688. /// Sets the culling on the shaders. Note changing this value will result in an instance of the material.
  689. /// </summary>
  690. public bool enableCulling
  691. {
  692. get { return m_isCullingEnabled; }
  693. set { if (m_isCullingEnabled == value) return; m_isCullingEnabled = value; SetCulling(); m_havePropertiesChanged = true; }
  694. }
  695. [SerializeField]
  696. protected bool m_isCullingEnabled = false;
  697. /// <summary>
  698. /// Controls whether or not the text object will be culled when using a 2D Rect Mask.
  699. /// </summary>
  700. public bool ignoreRectMaskCulling
  701. {
  702. get { return m_ignoreRectMaskCulling; }
  703. set { if (m_ignoreRectMaskCulling == value) return; m_ignoreRectMaskCulling = value; m_havePropertiesChanged = true; }
  704. }
  705. [SerializeField]
  706. protected bool m_ignoreRectMaskCulling;
  707. /// <summary>
  708. /// Forces objects that are not visible to get refreshed.
  709. /// </summary>
  710. public bool ignoreVisibility
  711. {
  712. get { return m_ignoreCulling; }
  713. set { if (m_ignoreCulling == value) return; m_havePropertiesChanged = true; m_ignoreCulling = value; }
  714. }
  715. [SerializeField]
  716. protected bool m_ignoreCulling = true; // Not implemented yet.
  717. /// <summary>
  718. /// Controls how the face and outline textures will be applied to the text object.
  719. /// </summary>
  720. public TextureMappingOptions horizontalMapping
  721. {
  722. get { return m_horizontalMapping; }
  723. set { if (m_horizontalMapping == value) return; m_havePropertiesChanged = true; m_horizontalMapping = value; SetVerticesDirty(); }
  724. }
  725. [SerializeField]
  726. protected TextureMappingOptions m_horizontalMapping = TextureMappingOptions.Character;
  727. /// <summary>
  728. /// Controls how the face and outline textures will be applied to the text object.
  729. /// </summary>
  730. public TextureMappingOptions verticalMapping
  731. {
  732. get { return m_verticalMapping; }
  733. set { if (m_verticalMapping == value) return; m_havePropertiesChanged = true; m_verticalMapping = value; SetVerticesDirty(); }
  734. }
  735. [SerializeField]
  736. protected TextureMappingOptions m_verticalMapping = TextureMappingOptions.Character;
  737. /// <summary>
  738. /// Controls the UV Offset for the various texture mapping mode on the text object.
  739. /// </summary>
  740. //public Vector2 mappingUvOffset
  741. //{
  742. // get { return m_uvOffset; }
  743. // set { if (m_uvOffset == value) return; m_havePropertiesChanged = true; m_uvOffset = value; SetVerticesDirty(); }
  744. //}
  745. //[SerializeField]
  746. //protected Vector2 m_uvOffset = Vector2.zero; // Used to offset UV on Texturing
  747. /// <summary>
  748. /// Controls the horizontal offset of the UV of the texture mapping mode for each line of the text object.
  749. /// </summary>
  750. public float mappingUvLineOffset
  751. {
  752. get { return m_uvLineOffset; }
  753. set { if (m_uvLineOffset == value) return; m_havePropertiesChanged = true; m_uvLineOffset = value; SetVerticesDirty(); }
  754. }
  755. [SerializeField]
  756. protected float m_uvLineOffset = 0.0f; // Used for UV line offset per line
  757. /// <summary>
  758. /// Determines if the Mesh will be rendered.
  759. /// </summary>
  760. public TextRenderFlags renderMode
  761. {
  762. get { return m_renderMode; }
  763. set { if (m_renderMode == value) return; m_renderMode = value; m_havePropertiesChanged = true; }
  764. }
  765. protected TextRenderFlags m_renderMode = TextRenderFlags.Render;
  766. /// <summary>
  767. /// Determines the sorting order of the geometry of the text object.
  768. /// </summary>
  769. public VertexSortingOrder geometrySortingOrder
  770. {
  771. get { return m_geometrySortingOrder; }
  772. set { m_geometrySortingOrder = value; m_havePropertiesChanged = true; SetVerticesDirty(); }
  773. }
  774. [SerializeField]
  775. protected VertexSortingOrder m_geometrySortingOrder;
  776. /// <summary>
  777. /// The first character which should be made visible in conjunction with the Text Overflow Linked mode.
  778. /// </summary>
  779. public int firstVisibleCharacter
  780. {
  781. get { return m_firstVisibleCharacter; }
  782. set { if (m_firstVisibleCharacter == value) return; m_havePropertiesChanged = true; m_firstVisibleCharacter = value; SetVerticesDirty(); }
  783. }
  784. [SerializeField]
  785. protected int m_firstVisibleCharacter;
  786. /// <summary>
  787. /// Allows to control how many characters are visible from the input.
  788. /// </summary>
  789. public int maxVisibleCharacters
  790. {
  791. get { return m_maxVisibleCharacters; }
  792. set { if (m_maxVisibleCharacters == value) return; m_havePropertiesChanged = true; m_maxVisibleCharacters = value; SetVerticesDirty(); }
  793. }
  794. protected int m_maxVisibleCharacters = 99999;
  795. /// <summary>
  796. /// Allows to control how many words are visible from the input.
  797. /// </summary>
  798. public int maxVisibleWords
  799. {
  800. get { return m_maxVisibleWords; }
  801. set { if (m_maxVisibleWords == value) return; m_havePropertiesChanged = true; m_maxVisibleWords = value; SetVerticesDirty(); }
  802. }
  803. protected int m_maxVisibleWords = 99999;
  804. /// <summary>
  805. /// Allows control over how many lines of text are displayed.
  806. /// </summary>
  807. public int maxVisibleLines
  808. {
  809. get { return m_maxVisibleLines; }
  810. set { if (m_maxVisibleLines == value) return; m_havePropertiesChanged = true; m_isInputParsingRequired = true; m_maxVisibleLines = value; SetVerticesDirty(); }
  811. }
  812. protected int m_maxVisibleLines = 99999;
  813. /// <summary>
  814. /// Determines if the text's vertical alignment will be adjusted based on visible descender of the text.
  815. /// </summary>
  816. public bool useMaxVisibleDescender
  817. {
  818. get { return m_useMaxVisibleDescender; }
  819. set { if (m_useMaxVisibleDescender == value) return; m_havePropertiesChanged = true; m_isInputParsingRequired = true; SetVerticesDirty(); }
  820. }
  821. [SerializeField]
  822. protected bool m_useMaxVisibleDescender = true;
  823. /// <summary>
  824. /// Controls which page of text is shown
  825. /// </summary>
  826. public int pageToDisplay
  827. {
  828. get { return m_pageToDisplay; }
  829. set { if (m_pageToDisplay == value) return; m_havePropertiesChanged = true; m_pageToDisplay = value; SetVerticesDirty(); }
  830. }
  831. [SerializeField]
  832. protected int m_pageToDisplay = 1;
  833. protected bool m_isNewPage = false;
  834. /// <summary>
  835. /// The margins of the text object.
  836. /// </summary>
  837. public virtual Vector4 margin
  838. {
  839. get { return m_margin; }
  840. set { if (m_margin == value) return; m_margin = value; ComputeMarginSize(); m_havePropertiesChanged = true; SetVerticesDirty(); }
  841. }
  842. [SerializeField]
  843. protected Vector4 m_margin = new Vector4(0, 0, 0, 0);
  844. protected float m_marginLeft;
  845. protected float m_marginRight;
  846. protected float m_marginWidth; // Width of the RectTransform minus left and right margins.
  847. protected float m_marginHeight; // Height of the RectTransform minus top and bottom margins.
  848. protected float m_width = -1;
  849. /// <summary>
  850. /// Returns data about the text object which includes information about each character, word, line, link, etc.
  851. /// </summary>
  852. public TMP_TextInfo textInfo
  853. {
  854. get { return m_textInfo; }
  855. }
  856. [SerializeField]
  857. protected TMP_TextInfo m_textInfo; // Class which holds information about the Text object such as characters, lines, mesh data as well as metrics.
  858. /// <summary>
  859. /// Property tracking if any of the text properties have changed. Flag is set before the text is regenerated.
  860. /// </summary>
  861. public bool havePropertiesChanged
  862. {
  863. get { return m_havePropertiesChanged; }
  864. set { if (m_havePropertiesChanged == value) return; m_havePropertiesChanged = value; m_isInputParsingRequired = true; SetAllDirty(); }
  865. }
  866. [SerializeField]
  867. protected bool m_havePropertiesChanged; // Used to track when properties of the text object have changed.
  868. /// <summary>
  869. /// Property to handle legacy animation component.
  870. /// </summary>
  871. public bool isUsingLegacyAnimationComponent
  872. {
  873. get { return m_isUsingLegacyAnimationComponent; }
  874. set { m_isUsingLegacyAnimationComponent = value; }
  875. }
  876. [SerializeField]
  877. protected bool m_isUsingLegacyAnimationComponent;
  878. /// <summary>
  879. /// Returns are reference to the Transform
  880. /// </summary>
  881. public new Transform transform
  882. {
  883. get
  884. {
  885. if (m_transform == null)
  886. m_transform = GetComponent<Transform>();
  887. return m_transform;
  888. }
  889. }
  890. protected Transform m_transform;
  891. /// <summary>
  892. /// Returns are reference to the RectTransform
  893. /// </summary>
  894. public new RectTransform rectTransform
  895. {
  896. get
  897. {
  898. if (m_rectTransform == null)
  899. m_rectTransform = GetComponent<RectTransform>();
  900. return m_rectTransform;
  901. }
  902. }
  903. protected RectTransform m_rectTransform;
  904. /// <summary>
  905. /// Enables control over setting the size of the text container to match the text object.
  906. /// </summary>
  907. public virtual bool autoSizeTextContainer
  908. {
  909. get;
  910. set;
  911. }
  912. protected bool m_autoSizeTextContainer;
  913. /// <summary>
  914. /// The mesh used by the font asset and material assigned to the text object.
  915. /// </summary>
  916. public virtual Mesh mesh
  917. {
  918. get { return m_mesh; }
  919. }
  920. protected Mesh m_mesh;
  921. /// <summary>
  922. /// Determines if the geometry of the characters will be quads or volumetric (cubes).
  923. /// </summary>
  924. public bool isVolumetricText
  925. {
  926. get { return m_isVolumetricText; }
  927. set { if (m_isVolumetricText == value) return; m_havePropertiesChanged = value; m_textInfo.ResetVertexLayout(value); m_isInputParsingRequired = true; SetVerticesDirty(); SetLayoutDirty(); }
  928. }
  929. [SerializeField]
  930. protected bool m_isVolumetricText;
  931. /// <summary>
  932. /// Returns the bounds of the mesh of the text object in world space.
  933. /// </summary>
  934. public Bounds bounds
  935. {
  936. get
  937. {
  938. if (m_mesh == null) return new Bounds();
  939. return GetCompoundBounds();
  940. }
  941. }
  942. /// <summary>
  943. /// Returns the bounds of the text of the text object.
  944. /// </summary>
  945. public Bounds textBounds
  946. {
  947. get
  948. {
  949. if (m_textInfo == null) return new Bounds();
  950. return GetTextBounds();
  951. }
  952. }
  953. // *** Unity Event Handling ***
  954. //[Serializable]
  955. //public class TextChangedEvent : UnityEvent { }
  956. ///// <summary>
  957. ///// Event delegate triggered when text has changed and been rendered.
  958. ///// </summary>
  959. //public TextChangedEvent onTextChanged
  960. //{
  961. // get { return m_OnTextChanged; }
  962. // set { m_OnTextChanged = value; }
  963. //}
  964. //[SerializeField]
  965. //private TextChangedEvent m_OnTextChanged = new TextChangedEvent();
  966. //protected void SendOnTextChanged()
  967. //{
  968. // if (onTextChanged != null)
  969. // onTextChanged.Invoke();
  970. //}
  971. // *** SPECIAL COMPONENTS ***
  972. /// <summary>
  973. /// Component used to control wrapping of text following some arbitrary shape.
  974. /// </summary>
  975. //public MarginShaper marginShaper
  976. //{
  977. // get
  978. // {
  979. // if (m_marginShaper == null) m_marginShaper = GetComponent<MarginShaper>();
  980. // return m_marginShaper;
  981. // }
  982. //}
  983. //[SerializeField]
  984. //protected MarginShaper m_marginShaper;
  985. /// <summary>
  986. /// Component used to control and animate sprites in the text object.
  987. /// </summary>
  988. protected TMP_SpriteAnimator spriteAnimator
  989. {
  990. get
  991. {
  992. if (m_spriteAnimator == null)
  993. {
  994. m_spriteAnimator = GetComponent<TMP_SpriteAnimator>();
  995. if (m_spriteAnimator == null) m_spriteAnimator = gameObject.AddComponent<TMP_SpriteAnimator>();
  996. }
  997. return m_spriteAnimator;
  998. }
  999. }
  1000. [SerializeField]
  1001. protected TMP_SpriteAnimator m_spriteAnimator;
  1002. /// <summary>
  1003. ///
  1004. /// </summary>
  1005. //public TMP_TextShaper textShaper
  1006. //{
  1007. // get
  1008. // {
  1009. // if (m_textShaper == null)
  1010. // m_textShaper = GetComponent<TMP_TextShaper>();
  1011. // return m_textShaper;
  1012. // }
  1013. //}
  1014. //[SerializeField]
  1015. //protected TMP_TextShaper m_textShaper;
  1016. // *** PROPERTIES RELATED TO UNITY LAYOUT SYSTEM ***
  1017. /// <summary>
  1018. ///
  1019. /// </summary>
  1020. public float flexibleHeight { get { return m_flexibleHeight; } }
  1021. protected float m_flexibleHeight = -1f;
  1022. /// <summary>
  1023. ///
  1024. /// </summary>
  1025. public float flexibleWidth { get { return m_flexibleWidth; } }
  1026. protected float m_flexibleWidth = -1f;
  1027. /// <summary>
  1028. ///
  1029. /// </summary>
  1030. public float minWidth { get { return m_minWidth; } }
  1031. protected float m_minWidth;
  1032. /// <summary>
  1033. ///
  1034. /// </summary>
  1035. public float minHeight { get { return m_minHeight; } }
  1036. protected float m_minHeight;
  1037. /// <summary>
  1038. ///
  1039. /// </summary>
  1040. public float maxWidth { get { return m_maxWidth; } }
  1041. protected float m_maxWidth;
  1042. /// <summary>
  1043. ///
  1044. /// </summary>
  1045. public float maxHeight { get { return m_maxHeight; } }
  1046. protected float m_maxHeight;
  1047. /// <summary>
  1048. ///
  1049. /// </summary>
  1050. protected LayoutElement layoutElement
  1051. {
  1052. get
  1053. {
  1054. if (m_LayoutElement == null)
  1055. {
  1056. m_LayoutElement = GetComponent<LayoutElement>();
  1057. }
  1058. return m_LayoutElement;
  1059. }
  1060. }
  1061. protected LayoutElement m_LayoutElement;
  1062. /// <summary>
  1063. /// Computed preferred width of the text object.
  1064. /// </summary>
  1065. public virtual float preferredWidth { get { if (!m_isPreferredWidthDirty) return m_preferredWidth; m_preferredWidth = GetPreferredWidth(); return m_preferredWidth; } }
  1066. protected float m_preferredWidth;
  1067. protected float m_renderedWidth;
  1068. protected bool m_isPreferredWidthDirty;
  1069. /// <summary>
  1070. /// Computed preferred height of the text object.
  1071. /// </summary>
  1072. public virtual float preferredHeight { get { if (!m_isPreferredHeightDirty) return m_preferredHeight; m_preferredHeight = GetPreferredHeight(); return m_preferredHeight; } }
  1073. protected float m_preferredHeight;
  1074. protected float m_renderedHeight;
  1075. protected bool m_isPreferredHeightDirty;
  1076. protected bool m_isCalculatingPreferredValues;
  1077. private int m_recursiveCount;
  1078. /// <summary>
  1079. /// Compute the rendered width of the text object.
  1080. /// </summary>
  1081. public virtual float renderedWidth { get { return GetRenderedWidth(); } }
  1082. /// <summary>
  1083. /// Compute the rendered height of the text object.
  1084. /// </summary>
  1085. public virtual float renderedHeight { get { return GetRenderedHeight(); } }
  1086. /// <summary>
  1087. ///
  1088. /// </summary>
  1089. public int layoutPriority { get { return m_layoutPriority; } }
  1090. protected int m_layoutPriority = 0;
  1091. protected bool m_isCalculateSizeRequired = false;
  1092. protected bool m_isLayoutDirty;
  1093. protected bool m_verticesAlreadyDirty;
  1094. protected bool m_layoutAlreadyDirty;
  1095. protected bool m_isAwake;
  1096. protected bool m_isWaitingOnResourceLoad;
  1097. [SerializeField]
  1098. protected bool m_isInputParsingRequired = false; // Used to determine if the input text needs to be re-parsed.
  1099. // Protected Fields
  1100. protected enum TextInputSources { Text = 0, SetText = 1, SetCharArray = 2, String = 3 };
  1101. [SerializeField]
  1102. protected TextInputSources m_inputSource;
  1103. protected string old_text; // Used by SetText to determine if the text has changed.
  1104. //protected float old_arg0, old_arg1, old_arg2; // Used by SetText to determine if the args have changed.
  1105. protected float m_fontScale; // Scaling of the font based on Atlas true Font Size and Rendered Font Size.
  1106. protected float m_fontScaleMultiplier; // Used for handling of superscript and subscript.
  1107. protected char[] m_htmlTag = new char[128]; // Maximum length of rich text tag. This is preallocated to avoid GC.
  1108. protected XML_TagAttribute[] m_xmlAttribute = new XML_TagAttribute[8];
  1109. protected float[] m_attributeParameterValues = new float[16];
  1110. protected float tag_LineIndent = 0;
  1111. protected float tag_Indent = 0;
  1112. protected TMP_XmlTagStack<float> m_indentStack = new TMP_XmlTagStack<float>(new float[16]);
  1113. protected bool tag_NoParsing;
  1114. //protected TMP_LinkInfo tag_LinkInfo = new TMP_LinkInfo();
  1115. protected bool m_isParsingText;
  1116. protected Matrix4x4 m_FXMatrix;
  1117. protected bool m_isFXMatrixSet;
  1118. protected int[] m_char_buffer; // This array holds the characters to be processed by GenerateMesh();
  1119. private TMP_CharacterInfo[] m_internalCharacterInfo; // Used by functions to calculate preferred values.
  1120. protected char[] m_input_CharArray = new char[256]; // This array hold the characters from the SetText();
  1121. private int m_charArray_Length = 0;
  1122. protected int m_totalCharacterCount;
  1123. // Structures used to save the state of the text layout in conjunction with line breaking / word wrapping.
  1124. protected WordWrapState m_SavedWordWrapState = new WordWrapState();
  1125. protected WordWrapState m_SavedLineState = new WordWrapState();
  1126. //protected WordWrapState m_SavedAlignment = new WordWrapState ();
  1127. // Fields whose state is saved in conjunction with text parsing and word wrapping.
  1128. protected int m_characterCount;
  1129. //protected int m_visibleCharacterCount;
  1130. //protected int m_visibleSpriteCount;
  1131. protected int m_firstCharacterOfLine;
  1132. protected int m_firstVisibleCharacterOfLine;
  1133. protected int m_lastCharacterOfLine;
  1134. protected int m_lastVisibleCharacterOfLine;
  1135. protected int m_lineNumber;
  1136. protected int m_lineVisibleCharacterCount;
  1137. protected int m_pageNumber;
  1138. protected float m_maxAscender;
  1139. protected float m_maxCapHeight;
  1140. protected float m_maxDescender;
  1141. protected float m_maxLineAscender;
  1142. protected float m_maxLineDescender;
  1143. protected float m_startOfLineAscender;
  1144. //protected float m_maxFontScale;
  1145. protected float m_lineOffset;
  1146. protected Extents m_meshExtents;
  1147. // Fields used for vertex colors
  1148. protected Color32 m_htmlColor = new Color(255, 255, 255, 128);
  1149. protected TMP_XmlTagStack<Color32> m_colorStack = new TMP_XmlTagStack<Color32>(new Color32[16]);
  1150. protected TMP_XmlTagStack<Color32> m_underlineColorStack = new TMP_XmlTagStack<Color32>(new Color32[16]);
  1151. protected TMP_XmlTagStack<Color32> m_strikethroughColorStack = new TMP_XmlTagStack<Color32>(new Color32[16]);
  1152. protected TMP_XmlTagStack<Color32> m_highlightColorStack = new TMP_XmlTagStack<Color32>(new Color32[16]);
  1153. protected TMP_ColorGradient m_colorGradientPreset;
  1154. protected TMP_XmlTagStack<TMP_ColorGradient> m_colorGradientStack = new TMP_XmlTagStack<TMP_ColorGradient>(new TMP_ColorGradient[16]);
  1155. protected float m_tabSpacing = 0;
  1156. protected float m_spacing = 0;
  1157. //protected bool IsRectTransformDriven;
  1158. // STYLE TAGS
  1159. protected TMP_XmlTagStack<int> m_styleStack = new TMP_XmlTagStack<int>(new int[16]);
  1160. protected TMP_XmlTagStack<int> m_actionStack = new TMP_XmlTagStack<int>(new int[16]);
  1161. protected float m_padding = 0;
  1162. protected float m_baselineOffset; // Used for superscript and subscript.
  1163. protected TMP_XmlTagStack<float> m_baselineOffsetStack = new TMP_XmlTagStack<float>(new float[16]);
  1164. protected float m_xAdvance; // Tracks x advancement from character to character.
  1165. protected TMP_TextElementType m_textElementType;
  1166. protected TMP_TextElement m_cached_TextElement; // Glyph / Character information is cached into this variable which is faster than having to fetch from the Dictionary multiple times.
  1167. protected TMP_Glyph m_cached_Underline_GlyphInfo; // Same as above but for the underline character which is used for Underline.
  1168. protected TMP_Glyph m_cached_Ellipsis_GlyphInfo;
  1169. protected TMP_SpriteAsset m_defaultSpriteAsset;
  1170. protected TMP_SpriteAsset m_currentSpriteAsset;
  1171. protected int m_spriteCount = 0;
  1172. protected int m_spriteIndex;
  1173. protected int m_spriteAnimationID;
  1174. //protected TMP_XmlTagStack<int> m_spriteAnimationStack = new TMP_XmlTagStack<int>(new int[16]);
  1175. /// <summary>
  1176. /// Method which derived classes need to override to load Font Assets.
  1177. /// </summary>
  1178. protected virtual void LoadFontAsset() { }
  1179. /// <summary>
  1180. /// Function called internally when a new shared material is assigned via the fontSharedMaterial property.
  1181. /// </summary>
  1182. /// <param name="mat"></param>
  1183. protected virtual void SetSharedMaterial(Material mat) { }
  1184. /// <summary>
  1185. /// Function called internally when a new material is assigned via the fontMaterial property.
  1186. /// </summary>
  1187. protected virtual Material GetMaterial(Material mat) { return null; }
  1188. /// <summary>
  1189. /// Function called internally when assigning a new base material.
  1190. /// </summary>
  1191. /// <param name="mat"></param>
  1192. protected virtual void SetFontBaseMaterial(Material mat) { }
  1193. /// <summary>
  1194. /// Method which returns an array containing the materials used by the text object.
  1195. /// </summary>
  1196. /// <returns></returns>
  1197. protected virtual Material[] GetSharedMaterials() { return null; }
  1198. /// <summary>
  1199. ///
  1200. /// </summary>
  1201. protected virtual void SetSharedMaterials(Material[] materials) { }
  1202. /// <summary>
  1203. /// Method returning instances of the materials used by the text object.
  1204. /// </summary>
  1205. /// <returns></returns>
  1206. protected virtual Material[] GetMaterials(Material[] mats) { return null; }
  1207. /// <summary>
  1208. /// Method to set the materials of the text and sub text objects.
  1209. /// </summary>
  1210. /// <param name="mats"></param>
  1211. //protected virtual void SetMaterials (Material[] mats) { }
  1212. /// <summary>
  1213. /// Function used to create an instance of the material
  1214. /// </summary>
  1215. /// <param name="source"></param>
  1216. /// <returns></returns>
  1217. protected virtual Material CreateMaterialInstance(Material source)
  1218. {
  1219. Material mat = new Material(source);
  1220. mat.shaderKeywords = source.shaderKeywords;
  1221. mat.name += " (Instance)";
  1222. return mat;
  1223. }
  1224. protected void SetVertexColorGradient(TMP_ColorGradient gradient)
  1225. {
  1226. if (gradient == null) return;
  1227. m_fontColorGradient.bottomLeft = gradient.bottomLeft;
  1228. m_fontColorGradient.bottomRight = gradient.bottomRight;
  1229. m_fontColorGradient.topLeft = gradient.topLeft;
  1230. m_fontColorGradient.topRight = gradient.topRight;
  1231. SetVerticesDirty();
  1232. }
  1233. /// <summary>
  1234. /// Function to control the sorting of the geometry of the text object.
  1235. /// </summary>
  1236. protected void SetTextSortingOrder(VertexSortingOrder order)
  1237. {
  1238. }
  1239. /// <summary>
  1240. /// Function to sort the geometry of the text object in accordance to the provided order.
  1241. /// </summary>
  1242. /// <param name="order"></param>
  1243. protected void SetTextSortingOrder(int[] order)
  1244. {
  1245. }
  1246. /// <summary>
  1247. /// Function called internally to set the face color of the material. This will results in an instance of the material.
  1248. /// </summary>
  1249. /// <param name="color"></param>
  1250. protected virtual void SetFaceColor(Color32 color) { }
  1251. /// <summary>
  1252. /// Function called internally to set the outline color of the material. This will results in an instance of the material.
  1253. /// </summary>
  1254. /// <param name="color"></param>
  1255. protected virtual void SetOutlineColor(Color32 color) { }
  1256. /// <summary>
  1257. /// Function called internally to set the outline thickness property of the material. This will results in an instance of the material.
  1258. /// </summary>
  1259. /// <param name="thickness"></param>
  1260. protected virtual void SetOutlineThickness(float thickness) { }
  1261. /// <summary>
  1262. /// Set the Render Queue and ZTest mode on the current material
  1263. /// </summary>
  1264. protected virtual void SetShaderDepth() { }
  1265. /// <summary>
  1266. /// Set the culling mode on the material.
  1267. /// </summary>
  1268. protected virtual void SetCulling() { }
  1269. /// <summary>
  1270. /// Get the padding value for the currently assigned material
  1271. /// </summary>
  1272. /// <returns></returns>
  1273. protected virtual float GetPaddingForMaterial() { return 0; }
  1274. /// <summary>
  1275. /// Get the padding value for the given material
  1276. /// </summary>
  1277. /// <returns></returns>
  1278. protected virtual float GetPaddingForMaterial(Material mat) { return 0; }
  1279. /// <summary>
  1280. /// Method to return the local corners of the Text Container or RectTransform.
  1281. /// </summary>
  1282. /// <returns></returns>
  1283. protected virtual Vector3[] GetTextContainerLocalCorners() { return null; }
  1284. // PUBLIC FUNCTIONS
  1285. protected bool m_ignoreActiveState;
  1286. /// <summary>
  1287. /// Function to force the regeneration of the text object.
  1288. /// </summary>
  1289. public virtual void ForceMeshUpdate() { }
  1290. /// <summary>
  1291. /// Method used for resetting vertex layout when switching to and from Volumetric Text mode.
  1292. /// </summary>
  1293. /// <param name="updateMesh"></param>
  1294. //protected virtual void ResetVertexLayout() { }
  1295. /// <summary>
  1296. /// Function to force the regeneration of the text object.
  1297. /// </summary>
  1298. /// <param name="ignoreActiveState">If set to true, the text object will be regenerated regardless of is active state.</param>
  1299. public virtual void ForceMeshUpdate(bool ignoreActiveState) { }
  1300. /// <summary>
  1301. /// Internal function used by the Text Input Field to populate TMP_TextInfo data.
  1302. /// </summary>
  1303. internal void SetTextInternal(string text)
  1304. {
  1305. m_text = text;
  1306. m_renderMode = TextRenderFlags.DontRender;
  1307. m_isInputParsingRequired = true;
  1308. ForceMeshUpdate();
  1309. m_renderMode = TextRenderFlags.Render;
  1310. }
  1311. /// <summary>
  1312. /// Function to force the regeneration of the text object.
  1313. /// </summary>
  1314. /// <param name="flags"> Flags to control which portions of the geometry gets uploaded.</param>
  1315. //public virtual void ForceMeshUpdate(TMP_VertexDataUpdateFlags flags) { }
  1316. /// <summary>
  1317. /// Function to update the geometry of the main and sub text objects.
  1318. /// </summary>
  1319. /// <param name="mesh"></param>
  1320. /// <param name="index"></param>
  1321. public virtual void UpdateGeometry(Mesh mesh, int index) { }
  1322. /// <summary>
  1323. /// Function to push the updated vertex data into the mesh and renderer.
  1324. /// </summary>
  1325. public virtual void UpdateVertexData(TMP_VertexDataUpdateFlags flags) { }
  1326. /// <summary>
  1327. /// Function to push the updated vertex data into the mesh and renderer.
  1328. /// </summary>
  1329. public virtual void UpdateVertexData() { }
  1330. /// <summary>
  1331. /// Function to push a new set of vertices to the mesh.
  1332. /// </summary>
  1333. /// <param name="vertices"></param>
  1334. public virtual void SetVertices(Vector3[] vertices) { }
  1335. /// <summary>
  1336. /// Function to be used to force recomputing of character padding when Shader / Material properties have been changed via script.
  1337. /// </summary>
  1338. public virtual void UpdateMeshPadding() { }
  1339. /// <summary>
  1340. ///
  1341. /// </summary>
  1342. //public virtual new void UpdateGeometry() { }
  1343. /// <summary>
  1344. /// Tweens the CanvasRenderer color associated with this Graphic.
  1345. /// </summary>
  1346. /// <param name="targetColor">Target color.</param>
  1347. /// <param name="duration">Tween duration.</param>
  1348. /// <param name="ignoreTimeScale">Should ignore Time.scale?</param>
  1349. /// <param name="useAlpha">Should also Tween the alpha channel?</param>
  1350. public override void CrossFadeColor(Color targetColor, float duration, bool ignoreTimeScale, bool useAlpha)
  1351. {
  1352. base.CrossFadeColor(targetColor, duration, ignoreTimeScale, useAlpha);
  1353. InternalCrossFadeColor(targetColor, duration, ignoreTimeScale, useAlpha);
  1354. }
  1355. /// <summary>
  1356. /// Tweens the alpha of the CanvasRenderer color associated with this Graphic.
  1357. /// </summary>
  1358. /// <param name="alpha">Target alpha.</param>
  1359. /// <param name="duration">Duration of the tween in seconds.</param>
  1360. /// <param name="ignoreTimeScale">Should ignore Time.scale?</param>
  1361. public override void CrossFadeAlpha(float alpha, float duration, bool ignoreTimeScale)
  1362. {
  1363. base.CrossFadeAlpha(alpha, duration, ignoreTimeScale);
  1364. InternalCrossFadeAlpha(alpha, duration, ignoreTimeScale);
  1365. }
  1366. /// <summary>
  1367. ///
  1368. /// </summary>
  1369. /// <param name="targetColor"></param>
  1370. /// <param name="duration"></param>
  1371. /// <param name="ignoreTimeScale"></param>
  1372. /// <param name="useAlpha"></param>
  1373. /// <param name="useRGB"></param>
  1374. protected virtual void InternalCrossFadeColor(Color targetColor, float duration, bool ignoreTimeScale, bool useAlpha) { }
  1375. /// <summary>
  1376. ///
  1377. /// </summary>
  1378. /// <param name="alpha"></param>
  1379. /// <param name="duration"></param>
  1380. /// <param name="ignoreTimeScale"></param>
  1381. protected virtual void InternalCrossFadeAlpha(float alpha, float duration, bool ignoreTimeScale) { }
  1382. /// <summary>
  1383. /// Method to parse the input text based on its source
  1384. /// </summary>
  1385. protected void ParseInputText()
  1386. {
  1387. //Debug.Log("Re-parsing Text.");
  1388. ////Profiler.BeginSample("ParseInputText()");
  1389. m_isInputParsingRequired = false;
  1390. switch (m_inputSource)
  1391. {
  1392. case TextInputSources.String:
  1393. case TextInputSources.Text:
  1394. StringToCharArray(m_text, ref m_char_buffer);
  1395. break;
  1396. case TextInputSources.SetText:
  1397. SetTextArrayToCharArray(m_input_CharArray, ref m_char_buffer);
  1398. break;
  1399. case TextInputSources.SetCharArray:
  1400. break;
  1401. }
  1402. SetArraySizes(m_char_buffer);
  1403. ////Profiler.EndSample();
  1404. }
  1405. /// <summary>
  1406. ///
  1407. /// </summary>
  1408. /// <param name="text"></param>
  1409. public void SetText(string text)
  1410. {
  1411. SetText(text, true);
  1412. }
  1413. /// <summary>
  1414. ///
  1415. /// </summary>
  1416. /// <param name="text"></param>
  1417. public void SetText(string text, bool syncTextInputBox)
  1418. {
  1419. //if (text == old_text) return;
  1420. //old_text = text;
  1421. m_inputSource = TextInputSources.SetCharArray;
  1422. StringToCharArray(text, ref m_char_buffer);
  1423. #if UNITY_EDITOR
  1424. // Set the text in the Text Input Box in the Unity Editor only.
  1425. // TODO: Could revise to convert to string literal
  1426. if (syncTextInputBox)
  1427. m_text = text;
  1428. #endif
  1429. m_isInputParsingRequired = true;
  1430. m_havePropertiesChanged = true;
  1431. m_isCalculateSizeRequired = true;
  1432. SetVerticesDirty();
  1433. SetLayoutDirty();
  1434. }
  1435. /// <summary>
  1436. /// <para>Formatted string containing a pattern and a value representing the text to be rendered.</para>
  1437. /// <para>ex. TextMeshPro.SetText ("Number is {0:1}.", 5.56f);</para>
  1438. /// </summary>
  1439. /// <typeparam name="T"></typeparam>
  1440. /// <param name="text">String containing the pattern."</param>
  1441. /// <param name="arg0">Value is a float.</param>
  1442. public void SetText(string text, float arg0)
  1443. {
  1444. SetText(text, arg0, 255, 255);
  1445. }
  1446. /// <summary>
  1447. /// <para>Formatted string containing a pattern and a value representing the text to be rendered.</para>
  1448. /// <para>ex. TextMeshPro.SetText ("First number is {0} and second is {1:2}.", 10, 5.756f);</para>
  1449. /// </summary>
  1450. /// <typeparam name="T"></typeparam>
  1451. /// <param name="text">String containing the pattern."</param>
  1452. /// <param name="arg0">Value is a float.</param>
  1453. /// <param name="arg1">Value is a float.</param>
  1454. public void SetText(string text, float arg0, float arg1)
  1455. {
  1456. SetText(text, arg0, arg1, 255);
  1457. }
  1458. /// <summary>
  1459. /// <para>Formatted string containing a pattern and a value representing the text to be rendered.</para>
  1460. /// <para>ex. TextMeshPro.SetText ("A = {0}, B = {1} and C = {2}.", 2, 5, 7);</para>
  1461. /// </summary>
  1462. /// <typeparam name="T"></typeparam>
  1463. /// <param name="text">String containing the pattern."</param>
  1464. /// <param name="arg0">Value is a float.</param>
  1465. /// <param name="arg1">Value is a float.</param>
  1466. /// <param name="arg2">Value is a float.</param>
  1467. public void SetText(string text, float arg0, float arg1, float arg2)
  1468. {
  1469. // Early out if nothing has been changed from previous invocation.
  1470. //if (text == old_text && arg0 == old_arg0 && arg1 == old_arg1 && arg2 == old_arg2)
  1471. //{
  1472. // return;
  1473. //}
  1474. //old_text = text;
  1475. //old_arg1 = 255;
  1476. //old_arg2 = 255;
  1477. int decimalPrecision = 0;
  1478. int index = 0;
  1479. for (int i = 0; i < text.Length; i++)
  1480. {
  1481. char c = text[i];
  1482. if (c == 123) // '{'
  1483. {
  1484. // Check if user is requesting some decimal precision. Format is {0:2}
  1485. if (text[i + 2] == 58) // ':'
  1486. {
  1487. decimalPrecision = text[i + 3] - 48;
  1488. }
  1489. switch (text[i + 1] - 48)
  1490. {
  1491. case 0: // 1st Arg
  1492. //old_arg0 = arg0;
  1493. AddFloatToCharArray(arg0, ref index, decimalPrecision);
  1494. break;
  1495. case 1: // 2nd Arg
  1496. //old_arg1 = arg1;
  1497. AddFloatToCharArray(arg1, ref index, decimalPrecision);
  1498. break;
  1499. case 2: // 3rd Arg
  1500. //old_arg2 = arg2;
  1501. AddFloatToCharArray(arg2, ref index, decimalPrecision);
  1502. break;
  1503. }
  1504. if (text[i + 2] == 58)
  1505. i += 4;
  1506. else
  1507. i += 2;
  1508. continue;
  1509. }
  1510. m_input_CharArray[index] = c;
  1511. index += 1;
  1512. }
  1513. m_input_CharArray[index] = (char)0;
  1514. m_charArray_Length = index; // Set the length to where this '0' termination is.
  1515. #if UNITY_EDITOR
  1516. // Create new string to be displayed in the Input Text Box of the Editor Panel.
  1517. m_text = new string(m_input_CharArray, 0, index);
  1518. #endif
  1519. m_inputSource = TextInputSources.SetText;
  1520. m_isInputParsingRequired = true;
  1521. m_havePropertiesChanged = true;
  1522. m_isCalculateSizeRequired = true;
  1523. SetVerticesDirty();
  1524. SetLayoutDirty();
  1525. }
  1526. /// <summary>
  1527. /// Set the text using a StringBuilder.
  1528. /// </summary>
  1529. /// <description>
  1530. /// Using a StringBuilder instead of concatenating strings prevents memory pollution with temporary objects.
  1531. /// </description>
  1532. /// <param name="text">StringBuilder with text to display.</param>
  1533. public void SetText(StringBuilder text)
  1534. {
  1535. m_inputSource = TextInputSources.SetCharArray;
  1536. #if UNITY_EDITOR
  1537. // Set the text in the Text Input Box in the Unity Editor only.
  1538. m_text = text.ToString();
  1539. #endif
  1540. StringBuilderToIntArray(text, ref m_char_buffer);
  1541. m_isInputParsingRequired = true;
  1542. m_havePropertiesChanged = true;
  1543. m_isCalculateSizeRequired = true;
  1544. SetVerticesDirty();
  1545. SetLayoutDirty();
  1546. }
  1547. /// <summary>
  1548. /// Character array containing the text to be displayed.
  1549. /// </summary>
  1550. /// <param name="sourceText"></param>
  1551. public void SetCharArray(char[] sourceText)
  1552. {
  1553. // Initialize internal character buffer if necessary
  1554. if (m_char_buffer == null) m_char_buffer = new int[8];
  1555. #if UNITY_EDITOR
  1556. // Create new string to be displayed in the Input Text Box of the Editor Panel.
  1557. if (sourceText == null || sourceText.Length == 0)
  1558. m_text = string.Empty;
  1559. else
  1560. m_text = new string(sourceText);
  1561. #endif
  1562. // Clear the Style stack.
  1563. m_styleStack.Clear();
  1564. int writeIndex = 0;
  1565. for (int i = 0; sourceText != null && i < sourceText.Length; i++)
  1566. {
  1567. if (sourceText[i] == 92 && i < sourceText.Length - 1)
  1568. {
  1569. switch ((int)sourceText[i + 1])
  1570. {
  1571. case 110: // \n LineFeed
  1572. if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer);
  1573. m_char_buffer[writeIndex] = (char)10;
  1574. i += 1;
  1575. writeIndex += 1;
  1576. continue;
  1577. case 114: // \r LineFeed
  1578. if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer);
  1579. m_char_buffer[writeIndex] = (char)13;
  1580. i += 1;
  1581. writeIndex += 1;
  1582. continue;
  1583. case 116: // \t Tab
  1584. if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer);
  1585. m_char_buffer[writeIndex] = (char)9;
  1586. i += 1;
  1587. writeIndex += 1;
  1588. continue;
  1589. }
  1590. }
  1591. // Handle inline replacement of <stlye> and <br> tags.
  1592. if (sourceText[i] == 60)
  1593. {
  1594. if (IsTagName(ref sourceText, "<BR>", i))
  1595. {
  1596. if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer);
  1597. m_char_buffer[writeIndex] = 10; ;
  1598. writeIndex += 1;
  1599. i += 3;
  1600. continue;
  1601. }
  1602. else if (IsTagName(ref sourceText, "<STYLE=", i))
  1603. {
  1604. int srcOffset = 0;
  1605. if (ReplaceOpeningStyleTag(ref sourceText, i, out srcOffset, ref m_char_buffer, ref writeIndex))
  1606. {
  1607. i = srcOffset;
  1608. continue;
  1609. }
  1610. }
  1611. else if (IsTagName(ref sourceText, "</STYLE>", i))
  1612. {
  1613. ReplaceClosingStyleTag(ref sourceText, i, ref m_char_buffer, ref writeIndex);
  1614. // Strip </style> even if style is invalid.
  1615. i += 7;
  1616. continue;
  1617. }
  1618. }
  1619. if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer);
  1620. m_char_buffer[writeIndex] = sourceText[i];
  1621. writeIndex += 1;
  1622. }
  1623. if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer);
  1624. m_char_buffer[writeIndex] = (char)0;
  1625. m_inputSource = TextInputSources.SetCharArray;
  1626. m_isInputParsingRequired = true;
  1627. m_havePropertiesChanged = true;
  1628. m_isCalculateSizeRequired = true;
  1629. SetVerticesDirty();
  1630. SetLayoutDirty();
  1631. }
  1632. /// <summary>
  1633. /// Character array containing the text to be displayed.
  1634. /// </summary>
  1635. /// <param name="sourceText"></param>
  1636. public void SetCharArray(char[] sourceText, int start, int length)
  1637. {
  1638. // Initialize internal character buffer if necessary
  1639. if (m_char_buffer == null) m_char_buffer = new int[8];
  1640. #if UNITY_EDITOR
  1641. // Create new string to be displayed in the Input Text Box of the Editor Panel.
  1642. if (sourceText == null || sourceText.Length == 0 || length == 0)
  1643. {
  1644. m_text = string.Empty;
  1645. start = 0;
  1646. length = 0;
  1647. }
  1648. else
  1649. {
  1650. // TODO: Add potential range check on start + length relative to array size.
  1651. m_text = new string(sourceText, start, length);
  1652. }
  1653. #endif
  1654. // Clear the Style stack.
  1655. m_styleStack.Clear();
  1656. int writeIndex = 0;
  1657. int i = start;
  1658. int end = start + length;
  1659. for (; i < end; i++)
  1660. {
  1661. if (sourceText[i] == 92 && i < length - 1)
  1662. {
  1663. switch ((int)sourceText[i + 1])
  1664. {
  1665. case 110: // \n LineFeed
  1666. if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer);
  1667. m_char_buffer[writeIndex] = (char)10;
  1668. i += 1;
  1669. writeIndex += 1;
  1670. continue;
  1671. case 114: // \r LineFeed
  1672. if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer);
  1673. m_char_buffer[writeIndex] = (char)13;
  1674. i += 1;
  1675. writeIndex += 1;
  1676. continue;
  1677. case 116: // \t Tab
  1678. if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer);
  1679. m_char_buffer[writeIndex] = (char)9;
  1680. i += 1;
  1681. writeIndex += 1;
  1682. continue;
  1683. }
  1684. }
  1685. // Handle inline replacement of <stlye> and <br> tags.
  1686. if (sourceText[i] == 60)
  1687. {
  1688. if (IsTagName(ref sourceText, "<BR>", i))
  1689. {
  1690. if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer);
  1691. m_char_buffer[writeIndex] = 10; ;
  1692. writeIndex += 1;
  1693. i += 3;
  1694. continue;
  1695. }
  1696. else if (IsTagName(ref sourceText, "<STYLE=", i))
  1697. {
  1698. int srcOffset = 0;
  1699. if (ReplaceOpeningStyleTag(ref sourceText, i, out srcOffset, ref m_char_buffer, ref writeIndex))
  1700. {
  1701. i = srcOffset;
  1702. continue;
  1703. }
  1704. }
  1705. else if (IsTagName(ref sourceText, "</STYLE>", i))
  1706. {
  1707. ReplaceClosingStyleTag(ref sourceText, i, ref m_char_buffer, ref writeIndex);
  1708. // Strip </style> even if style is invalid.
  1709. i += 7;
  1710. continue;
  1711. }
  1712. }
  1713. if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer);
  1714. m_char_buffer[writeIndex] = sourceText[i];
  1715. writeIndex += 1;
  1716. }
  1717. if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer);
  1718. m_char_buffer[writeIndex] = (char)0;
  1719. m_inputSource = TextInputSources.SetCharArray;
  1720. m_havePropertiesChanged = true;
  1721. m_isInputParsingRequired = true;
  1722. m_isCalculateSizeRequired = true;
  1723. SetVerticesDirty();
  1724. SetLayoutDirty();
  1725. }
  1726. /// <summary>
  1727. /// Character array containing the text to be displayed.
  1728. /// </summary>
  1729. /// <param name="sourceText"></param>
  1730. public void SetCharArray(int[] sourceText, int start, int length)
  1731. {
  1732. // Initialize internal character buffer if necessary
  1733. if (m_char_buffer == null) m_char_buffer = new int[8];
  1734. #if UNITY_EDITOR
  1735. // Create new string to be displayed in the Input Text Box of the Editor Panel.
  1736. if (sourceText == null || sourceText.Length == 0 || length == 0)
  1737. {
  1738. m_text = string.Empty;
  1739. start = 0;
  1740. length = 0;
  1741. }
  1742. else
  1743. {
  1744. m_text = sourceText.IntToString(start, length);
  1745. }
  1746. #endif
  1747. // Clear the Style stack.
  1748. m_styleStack.Clear();
  1749. int writeIndex = 0;
  1750. int end = start + length;
  1751. for (int i = start; i < end; i++)
  1752. {
  1753. if (sourceText[i] == 92 && i < length - 1)
  1754. {
  1755. switch ((int)sourceText[i + 1])
  1756. {
  1757. case 110: // \n LineFeed
  1758. if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer);
  1759. m_char_buffer[writeIndex] = (char)10;
  1760. i += 1;
  1761. writeIndex += 1;
  1762. continue;
  1763. case 114: // \r LineFeed
  1764. if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer);
  1765. m_char_buffer[writeIndex] = (char)13;
  1766. i += 1;
  1767. writeIndex += 1;
  1768. continue;
  1769. case 116: // \t Tab
  1770. if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer);
  1771. m_char_buffer[writeIndex] = (char)9;
  1772. i += 1;
  1773. writeIndex += 1;
  1774. continue;
  1775. }
  1776. }
  1777. // Handle inline replacement of <stlye> and <br> tags.
  1778. if (sourceText[i] == 60)
  1779. {
  1780. if (IsTagName(ref sourceText, "<BR>", i))
  1781. {
  1782. if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer);
  1783. m_char_buffer[writeIndex] = 10; ;
  1784. writeIndex += 1;
  1785. i += 3;
  1786. continue;
  1787. }
  1788. else if (IsTagName(ref sourceText, "<STYLE=", i))
  1789. {
  1790. int srcOffset = 0;
  1791. if (ReplaceOpeningStyleTag(ref sourceText, i, out srcOffset, ref m_char_buffer, ref writeIndex))
  1792. {
  1793. i = srcOffset;
  1794. continue;
  1795. }
  1796. }
  1797. else if (IsTagName(ref sourceText, "</STYLE>", i))
  1798. {
  1799. ReplaceClosingStyleTag(ref sourceText, i, ref m_char_buffer, ref writeIndex);
  1800. // Strip </style> even if style is invalid.
  1801. i += 7;
  1802. continue;
  1803. }
  1804. }
  1805. if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer);
  1806. m_char_buffer[writeIndex] = sourceText[i];
  1807. writeIndex += 1;
  1808. }
  1809. if (writeIndex == m_char_buffer.Length) ResizeInternalArray(ref m_char_buffer);
  1810. m_char_buffer[writeIndex] = (char)0;
  1811. m_inputSource = TextInputSources.SetCharArray;
  1812. m_havePropertiesChanged = true;
  1813. m_isInputParsingRequired = true;
  1814. m_isCalculateSizeRequired = true;
  1815. SetVerticesDirty();
  1816. SetLayoutDirty();
  1817. }
  1818. /// <summary>
  1819. /// Copies Content of formatted SetText() to charBuffer.
  1820. /// </summary>
  1821. /// <param name="sourceText"></param>
  1822. /// <param name="charBuffer"></param>
  1823. protected void SetTextArrayToCharArray(char[] sourceText, ref int[] charBuffer)
  1824. {
  1825. //Debug.Log("SetText Array to Char called.");
  1826. if (sourceText == null || m_charArray_Length == 0)
  1827. return;
  1828. if (charBuffer == null) charBuffer = new int[8];
  1829. // Clear the Style stack.
  1830. m_styleStack.Clear();
  1831. int writeIndex = 0;
  1832. for (int i = 0; i < m_charArray_Length; i++)
  1833. {
  1834. // Handle UTF-32 in the input text (string).
  1835. if (char.IsHighSurrogate(sourceText[i]) && char.IsLowSurrogate(sourceText[i + 1]))
  1836. {
  1837. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  1838. charBuffer[writeIndex] = char.ConvertToUtf32(sourceText[i], sourceText[i + 1]);
  1839. i += 1;
  1840. writeIndex += 1;
  1841. continue;
  1842. }
  1843. // Handle inline replacement of <stlye> and <br> tags.
  1844. if (sourceText[i] == 60)
  1845. {
  1846. if (IsTagName(ref sourceText, "<BR>", i))
  1847. {
  1848. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  1849. charBuffer[writeIndex] = 10;
  1850. writeIndex += 1;
  1851. i += 3;
  1852. continue;
  1853. }
  1854. else if (IsTagName(ref sourceText, "<STYLE=", i))
  1855. {
  1856. int srcOffset = 0;
  1857. if (ReplaceOpeningStyleTag(ref sourceText, i, out srcOffset, ref charBuffer, ref writeIndex))
  1858. {
  1859. i = srcOffset;
  1860. continue;
  1861. }
  1862. }
  1863. else if (IsTagName(ref sourceText, "</STYLE>", i))
  1864. {
  1865. ReplaceClosingStyleTag(ref sourceText, i, ref charBuffer, ref writeIndex);
  1866. // Strip </style> even if style is invalid.
  1867. i += 7;
  1868. continue;
  1869. }
  1870. }
  1871. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  1872. charBuffer[writeIndex] = sourceText[i];
  1873. writeIndex += 1;
  1874. }
  1875. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  1876. charBuffer[writeIndex] = 0;
  1877. }
  1878. /// <summary>
  1879. /// Method to store the content of a string into an integer array.
  1880. /// </summary>
  1881. /// <param name="sourceText"></param>
  1882. /// <param name="charBuffer"></param>
  1883. protected void StringToCharArray(string sourceText, ref int[] charBuffer)
  1884. {
  1885. if (sourceText == null)
  1886. {
  1887. charBuffer[0] = 0;
  1888. return;
  1889. }
  1890. if (charBuffer == null) charBuffer = new int[8];
  1891. // Clear the Style stack.
  1892. m_styleStack.SetDefault(0);
  1893. int writeIndex = 0;
  1894. for (int i = 0; i < sourceText.Length; i++)
  1895. {
  1896. if (m_inputSource == TextInputSources.Text && sourceText[i] == 92 && sourceText.Length > i + 1)
  1897. {
  1898. switch ((int)sourceText[i + 1])
  1899. {
  1900. case 85: // \U00000000 for UTF-32 Unicode
  1901. if (sourceText.Length > i + 9)
  1902. {
  1903. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  1904. charBuffer[writeIndex] = GetUTF32(sourceText, i + 2);
  1905. i += 9;
  1906. writeIndex += 1;
  1907. continue;
  1908. }
  1909. break;
  1910. case 92: // \ escape
  1911. if (!m_parseCtrlCharacters) break;
  1912. if (sourceText.Length <= i + 2) break;
  1913. if (writeIndex + 2 > charBuffer.Length) ResizeInternalArray(ref charBuffer);
  1914. charBuffer[writeIndex] = sourceText[i + 1];
  1915. charBuffer[writeIndex + 1] = sourceText[i + 2];
  1916. i += 2;
  1917. writeIndex += 2;
  1918. continue;
  1919. case 110: // \n LineFeed
  1920. if (!m_parseCtrlCharacters) break;
  1921. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  1922. charBuffer[writeIndex] = (char)10;
  1923. i += 1;
  1924. writeIndex += 1;
  1925. continue;
  1926. case 114: // \r
  1927. if (!m_parseCtrlCharacters) break;
  1928. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  1929. charBuffer[writeIndex] = (char)13;
  1930. i += 1;
  1931. writeIndex += 1;
  1932. continue;
  1933. case 116: // \t Tab
  1934. if (!m_parseCtrlCharacters) break;
  1935. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  1936. charBuffer[writeIndex] = (char)9;
  1937. i += 1;
  1938. writeIndex += 1;
  1939. continue;
  1940. case 117: // \u0000 for UTF-16 Unicode
  1941. if (sourceText.Length > i + 5)
  1942. {
  1943. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  1944. charBuffer[writeIndex] = (char)GetUTF16(sourceText, i + 2);
  1945. i += 5;
  1946. writeIndex += 1;
  1947. continue;
  1948. }
  1949. break;
  1950. }
  1951. }
  1952. // Handle UTF-32 in the input text (string). // Not sure this is needed //
  1953. if (char.IsHighSurrogate(sourceText[i]) && char.IsLowSurrogate(sourceText[i + 1]))
  1954. {
  1955. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  1956. charBuffer[writeIndex] = char.ConvertToUtf32(sourceText[i], sourceText[i + 1]);
  1957. i += 1;
  1958. writeIndex += 1;
  1959. continue;
  1960. }
  1961. //// Handle inline replacement of <stlye> and <br> tags.
  1962. if (sourceText[i] == 60 && m_isRichText)
  1963. {
  1964. if (IsTagName(ref sourceText, "<BR>", i))
  1965. {
  1966. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  1967. charBuffer[writeIndex] = 10; ;
  1968. writeIndex += 1;
  1969. i += 3;
  1970. continue;
  1971. }
  1972. else if (IsTagName(ref sourceText, "<STYLE=", i))
  1973. {
  1974. int srcOffset = 0;
  1975. if (ReplaceOpeningStyleTag(ref sourceText, i, out srcOffset, ref charBuffer, ref writeIndex))
  1976. {
  1977. i = srcOffset;
  1978. continue;
  1979. }
  1980. }
  1981. else if (IsTagName(ref sourceText, "</STYLE>", i))
  1982. {
  1983. ReplaceClosingStyleTag(ref sourceText, i, ref charBuffer, ref writeIndex);
  1984. // Strip </style> even if style is invalid.
  1985. i += 7;
  1986. continue;
  1987. }
  1988. }
  1989. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  1990. charBuffer[writeIndex] = sourceText[i];
  1991. writeIndex += 1;
  1992. }
  1993. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  1994. charBuffer[writeIndex] = (char)0;
  1995. }
  1996. /// <summary>
  1997. /// Copy contents of StringBuilder into int array.
  1998. /// </summary>
  1999. /// <param name="sourceText">Text to copy.</param>
  2000. /// <param name="charBuffer">Array to store contents.</param>
  2001. protected void StringBuilderToIntArray(StringBuilder sourceText, ref int[] charBuffer)
  2002. {
  2003. if (sourceText == null)
  2004. {
  2005. charBuffer[0] = 0;
  2006. return;
  2007. }
  2008. if (charBuffer == null) charBuffer = new int[8];
  2009. // Clear the Style stack.
  2010. m_styleStack.Clear();
  2011. #if UNITY_EDITOR
  2012. // Create new string to be displayed in the Input Text Box of the Editor Panel.
  2013. m_text = sourceText.ToString();
  2014. #endif
  2015. int writeIndex = 0;
  2016. for (int i = 0; i < sourceText.Length; i++)
  2017. {
  2018. if (m_parseCtrlCharacters && sourceText[i] == 92 && sourceText.Length > i + 1)
  2019. {
  2020. switch ((int)sourceText[i + 1])
  2021. {
  2022. case 85: // \U00000000 for UTF-32 Unicode
  2023. if (sourceText.Length > i + 9)
  2024. {
  2025. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2026. charBuffer[writeIndex] = GetUTF32(sourceText, i + 2);
  2027. i += 9;
  2028. writeIndex += 1;
  2029. continue;
  2030. }
  2031. break;
  2032. case 92: // \ escape
  2033. if (sourceText.Length <= i + 2) break;
  2034. if (writeIndex + 2 > charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2035. charBuffer[writeIndex] = sourceText[i + 1];
  2036. charBuffer[writeIndex + 1] = sourceText[i + 2];
  2037. i += 2;
  2038. writeIndex += 2;
  2039. continue;
  2040. case 110: // \n LineFeed
  2041. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2042. charBuffer[writeIndex] = (char)10;
  2043. i += 1;
  2044. writeIndex += 1;
  2045. continue;
  2046. case 114: // \r
  2047. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2048. charBuffer[writeIndex] = (char)13;
  2049. i += 1;
  2050. writeIndex += 1;
  2051. continue;
  2052. case 116: // \t Tab
  2053. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2054. charBuffer[writeIndex] = (char)9;
  2055. i += 1;
  2056. writeIndex += 1;
  2057. continue;
  2058. case 117: // \u0000 for UTF-16 Unicode
  2059. if (sourceText.Length > i + 5)
  2060. {
  2061. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2062. charBuffer[writeIndex] = (char)GetUTF16(sourceText, i + 2);
  2063. i += 5;
  2064. writeIndex += 1;
  2065. continue;
  2066. }
  2067. break;
  2068. }
  2069. }
  2070. // Handle UTF-32 in the input text (string).
  2071. if (char.IsHighSurrogate(sourceText[i]) && char.IsLowSurrogate(sourceText[i + 1]))
  2072. {
  2073. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2074. charBuffer[writeIndex] = char.ConvertToUtf32(sourceText[i], sourceText[i + 1]);
  2075. i += 1;
  2076. writeIndex += 1;
  2077. continue;
  2078. }
  2079. // Handle inline replacement of <stlye> and <br> tags.
  2080. if (sourceText[i] == 60)
  2081. {
  2082. if (IsTagName(ref sourceText, "<BR>", i))
  2083. {
  2084. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2085. charBuffer[writeIndex] = 10;
  2086. writeIndex += 1;
  2087. i += 3;
  2088. continue;
  2089. }
  2090. else if (IsTagName(ref sourceText, "<STYLE=", i))
  2091. {
  2092. int srcOffset = 0;
  2093. if (ReplaceOpeningStyleTag(ref sourceText, i, out srcOffset, ref charBuffer, ref writeIndex))
  2094. {
  2095. i = srcOffset;
  2096. continue;
  2097. }
  2098. }
  2099. else if (IsTagName(ref sourceText, "</STYLE>", i))
  2100. {
  2101. ReplaceClosingStyleTag(ref sourceText, i, ref charBuffer, ref writeIndex);
  2102. // Strip </style> even if style is invalid.
  2103. i += 7;
  2104. continue;
  2105. }
  2106. }
  2107. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2108. charBuffer[writeIndex] = sourceText[i];
  2109. writeIndex += 1;
  2110. }
  2111. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2112. charBuffer[writeIndex] = (char)0;
  2113. }
  2114. /// <summary>
  2115. /// Method to handle inline replacement of style tag by opening style definition.
  2116. /// </summary>
  2117. /// <param name="sourceText"></param>
  2118. /// <param name="srcIndex"></param>
  2119. /// <param name="srcOffset"></param>
  2120. /// <param name="charBuffer"></param>
  2121. /// <param name="writeIndex"></param>
  2122. /// <returns></returns>
  2123. bool ReplaceOpeningStyleTag(ref string sourceText, int srcIndex, out int srcOffset, ref int[] charBuffer, ref int writeIndex)
  2124. {
  2125. // Validate <style> tag.
  2126. int hashCode = GetTagHashCode(ref sourceText, srcIndex + 7, out srcOffset);
  2127. TMP_Style style = TMP_StyleSheet.GetStyle(hashCode);
  2128. // Return if we don't have a valid style.
  2129. if (style == null || srcOffset == 0) return false;
  2130. m_styleStack.Add(style.hashCode);
  2131. int styleLength = style.styleOpeningTagArray.Length;
  2132. // Replace <style> tag with opening definition
  2133. int[] openingTagArray = style.styleOpeningTagArray;
  2134. for (int i = 0; i < styleLength; i++)
  2135. {
  2136. int c = openingTagArray[i];
  2137. if (c == 60)
  2138. {
  2139. if (IsTagName(ref openingTagArray, "<BR>", i))
  2140. {
  2141. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2142. charBuffer[writeIndex] = 10;
  2143. writeIndex += 1;
  2144. i += 3;
  2145. continue;
  2146. }
  2147. else if (IsTagName(ref openingTagArray, "<STYLE=", i))
  2148. {
  2149. int offset = 0;
  2150. if (ReplaceOpeningStyleTag(ref openingTagArray, i, out offset, ref charBuffer, ref writeIndex))
  2151. {
  2152. i = offset;
  2153. continue;
  2154. }
  2155. }
  2156. else if (IsTagName(ref openingTagArray, "</STYLE>", i))
  2157. {
  2158. ReplaceClosingStyleTag(ref openingTagArray, i, ref charBuffer, ref writeIndex);
  2159. // Strip </style> even if style is invalid.
  2160. i += 7;
  2161. continue;
  2162. }
  2163. }
  2164. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2165. charBuffer[writeIndex] = c;
  2166. writeIndex += 1;
  2167. }
  2168. return true;
  2169. }
  2170. /// <summary>
  2171. /// Method to handle inline replacement of style tag by opening style definition.
  2172. /// </summary>
  2173. /// <param name="sourceText"></param>
  2174. /// <param name="srcIndex"></param>
  2175. /// <param name="srcOffset"></param>
  2176. /// <param name="charBuffer"></param>
  2177. /// <param name="writeIndex"></param>
  2178. /// <returns></returns>
  2179. bool ReplaceOpeningStyleTag(ref int[] sourceText, int srcIndex, out int srcOffset, ref int[] charBuffer, ref int writeIndex)
  2180. {
  2181. // Validate <style> tag.
  2182. int hashCode = GetTagHashCode(ref sourceText, srcIndex + 7, out srcOffset);
  2183. TMP_Style style = TMP_StyleSheet.GetStyle(hashCode);
  2184. // Return if we don't have a valid style.
  2185. if (style == null || srcOffset == 0) return false;
  2186. m_styleStack.Add(style.hashCode);
  2187. int styleLength = style.styleOpeningTagArray.Length;
  2188. // Replace <style> tag with opening definition
  2189. int[] openingTagArray = style.styleOpeningTagArray;
  2190. for (int i = 0; i < styleLength; i++)
  2191. {
  2192. int c = openingTagArray[i];
  2193. if (c == 60)
  2194. {
  2195. if (IsTagName(ref openingTagArray, "<BR>", i))
  2196. {
  2197. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2198. charBuffer[writeIndex] = 10;
  2199. writeIndex += 1;
  2200. i += 3;
  2201. continue;
  2202. }
  2203. else if (IsTagName(ref openingTagArray, "<STYLE=", i))
  2204. {
  2205. int offset = 0;
  2206. if (ReplaceOpeningStyleTag(ref openingTagArray, i, out offset, ref charBuffer, ref writeIndex))
  2207. {
  2208. i = offset;
  2209. continue;
  2210. }
  2211. }
  2212. else if (IsTagName(ref openingTagArray, "</STYLE>", i))
  2213. {
  2214. ReplaceClosingStyleTag(ref openingTagArray, i, ref charBuffer, ref writeIndex);
  2215. // Strip </style> even if style is invalid.
  2216. i += 7;
  2217. continue;
  2218. }
  2219. }
  2220. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2221. charBuffer[writeIndex] = c;
  2222. writeIndex += 1;
  2223. }
  2224. return true;
  2225. }
  2226. /// <summary>
  2227. /// Method to handle inline replacement of style tag by opening style definition.
  2228. /// </summary>
  2229. /// <param name="sourceText"></param>
  2230. /// <param name="srcIndex"></param>
  2231. /// <param name="srcOffset"></param>
  2232. /// <param name="charBuffer"></param>
  2233. /// <param name="writeIndex"></param>
  2234. /// <returns></returns>
  2235. bool ReplaceOpeningStyleTag(ref char[] sourceText, int srcIndex, out int srcOffset, ref int[] charBuffer, ref int writeIndex)
  2236. {
  2237. // Validate <style> tag.
  2238. int hashCode = GetTagHashCode(ref sourceText, srcIndex + 7, out srcOffset);
  2239. TMP_Style style = TMP_StyleSheet.GetStyle(hashCode);
  2240. // Return if we don't have a valid style.
  2241. if (style == null || srcOffset == 0) return false;
  2242. m_styleStack.Add(style.hashCode);
  2243. int styleLength = style.styleOpeningTagArray.Length;
  2244. // Replace <style> tag with opening definition
  2245. int[] openingTagArray = style.styleOpeningTagArray;
  2246. for (int i = 0; i < styleLength; i++)
  2247. {
  2248. int c = openingTagArray[i];
  2249. if (c == 60)
  2250. {
  2251. if (IsTagName(ref openingTagArray, "<BR>", i))
  2252. {
  2253. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2254. charBuffer[writeIndex] = 10;
  2255. writeIndex += 1;
  2256. i += 3;
  2257. continue;
  2258. }
  2259. else if (IsTagName(ref openingTagArray, "<STYLE=", i))
  2260. {
  2261. int offset = 0;
  2262. if (ReplaceOpeningStyleTag(ref openingTagArray, i, out offset, ref charBuffer, ref writeIndex))
  2263. {
  2264. i = offset;
  2265. continue;
  2266. }
  2267. }
  2268. else if (IsTagName(ref openingTagArray, "</STYLE>", i))
  2269. {
  2270. ReplaceClosingStyleTag(ref openingTagArray, i, ref charBuffer, ref writeIndex);
  2271. // Strip </style> even if style is invalid.
  2272. i += 7;
  2273. continue;
  2274. }
  2275. }
  2276. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2277. charBuffer[writeIndex] = c;
  2278. writeIndex += 1;
  2279. }
  2280. return true;
  2281. }
  2282. /// <summary>
  2283. /// Method to handle inline replacement of style tag by opening style definition.
  2284. /// </summary>
  2285. /// <param name="sourceText"></param>
  2286. /// <param name="srcIndex"></param>
  2287. /// <param name="srcOffset"></param>
  2288. /// <param name="charBuffer"></param>
  2289. /// <param name="writeIndex"></param>
  2290. /// <returns></returns>
  2291. bool ReplaceOpeningStyleTag(ref StringBuilder sourceText, int srcIndex, out int srcOffset, ref int[] charBuffer, ref int writeIndex)
  2292. {
  2293. // Validate <style> tag.
  2294. int hashCode = GetTagHashCode(ref sourceText, srcIndex + 7, out srcOffset);
  2295. TMP_Style style = TMP_StyleSheet.GetStyle(hashCode);
  2296. // Return if we don't have a valid style.
  2297. if (style == null || srcOffset == 0) return false;
  2298. m_styleStack.Add(style.hashCode);
  2299. int styleLength = style.styleOpeningTagArray.Length;
  2300. // Replace <style> tag with opening definition
  2301. int[] openingTagArray = style.styleOpeningTagArray;
  2302. for (int i = 0; i < styleLength; i++)
  2303. {
  2304. int c = openingTagArray[i];
  2305. if (c == 60)
  2306. {
  2307. if (IsTagName(ref openingTagArray, "<BR>", i))
  2308. {
  2309. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2310. charBuffer[writeIndex] = 10;
  2311. writeIndex += 1;
  2312. i += 3;
  2313. continue;
  2314. }
  2315. else if (IsTagName(ref openingTagArray, "<STYLE=", i))
  2316. {
  2317. int offset = 0;
  2318. if (ReplaceOpeningStyleTag(ref openingTagArray, i, out offset, ref charBuffer, ref writeIndex))
  2319. {
  2320. i = offset;
  2321. continue;
  2322. }
  2323. }
  2324. else if (IsTagName(ref openingTagArray, "</STYLE>", i))
  2325. {
  2326. ReplaceClosingStyleTag(ref openingTagArray, i, ref charBuffer, ref writeIndex);
  2327. // Strip </style> even if style is invalid.
  2328. i += 7;
  2329. continue;
  2330. }
  2331. }
  2332. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2333. charBuffer[writeIndex] = c;
  2334. writeIndex += 1;
  2335. }
  2336. return true;
  2337. }
  2338. /// <summary>
  2339. /// Method to handle inline replacement of style tag by closing style definition.
  2340. /// </summary>
  2341. /// <param name="sourceText"></param>
  2342. /// <param name="srcIndex"></param>
  2343. /// <param name="charBuffer"></param>
  2344. /// <param name="writeIndex"></param>
  2345. /// <returns></returns>
  2346. bool ReplaceClosingStyleTag(ref string sourceText, int srcIndex, ref int[] charBuffer, ref int writeIndex)
  2347. {
  2348. // Get style from the Style Stack
  2349. int hashCode = m_styleStack.CurrentItem();
  2350. TMP_Style style = TMP_StyleSheet.GetStyle(hashCode);
  2351. m_styleStack.Remove();
  2352. // Return if we don't have a valid style.
  2353. if (style == null) return false;
  2354. int styleLength = style.styleClosingTagArray.Length;
  2355. // Replace <style> tag with opening definition
  2356. int[] closingTagArray = style.styleClosingTagArray;
  2357. for (int i = 0; i < styleLength; i++)
  2358. {
  2359. int c = closingTagArray[i];
  2360. if (c == 60)
  2361. {
  2362. if (IsTagName(ref closingTagArray, "<BR>", i))
  2363. {
  2364. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2365. charBuffer[writeIndex] = 10;
  2366. writeIndex += 1;
  2367. i += 3;
  2368. continue;
  2369. }
  2370. else if (IsTagName(ref closingTagArray, "<STYLE=", i))
  2371. {
  2372. int offset = 0;
  2373. if (ReplaceOpeningStyleTag(ref closingTagArray, i, out offset, ref charBuffer, ref writeIndex))
  2374. {
  2375. i = offset;
  2376. continue;
  2377. }
  2378. }
  2379. else if (IsTagName(ref closingTagArray, "</STYLE>", i))
  2380. {
  2381. ReplaceClosingStyleTag(ref closingTagArray, i, ref charBuffer, ref writeIndex);
  2382. // Strip </style> even if style is invalid.
  2383. i += 7;
  2384. continue;
  2385. }
  2386. }
  2387. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2388. charBuffer[writeIndex] = c;
  2389. writeIndex += 1;
  2390. }
  2391. return true;
  2392. }
  2393. /// <summary>
  2394. /// Method to handle inline replacement of style tag by closing style definition.
  2395. /// </summary>
  2396. /// <param name="sourceText"></param>
  2397. /// <param name="srcIndex"></param>
  2398. /// <param name="charBuffer"></param>
  2399. /// <param name="writeIndex"></param>
  2400. /// <returns></returns>
  2401. bool ReplaceClosingStyleTag(ref int[] sourceText, int srcIndex, ref int[] charBuffer, ref int writeIndex)
  2402. {
  2403. // Get style from the Style Stack
  2404. int hashCode = m_styleStack.CurrentItem();
  2405. TMP_Style style = TMP_StyleSheet.GetStyle(hashCode);
  2406. m_styleStack.Remove();
  2407. // Return if we don't have a valid style.
  2408. if (style == null) return false;
  2409. int styleLength = style.styleClosingTagArray.Length;
  2410. // Replace <style> tag with opening definition
  2411. int[] closingTagArray = style.styleClosingTagArray;
  2412. for (int i = 0; i < styleLength; i++)
  2413. {
  2414. int c = closingTagArray[i];
  2415. if (c == 60)
  2416. {
  2417. if (IsTagName(ref closingTagArray, "<BR>", i))
  2418. {
  2419. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2420. charBuffer[writeIndex] = 10;
  2421. writeIndex += 1;
  2422. i += 3;
  2423. continue;
  2424. }
  2425. else if (IsTagName(ref closingTagArray, "<STYLE=", i))
  2426. {
  2427. int offset = 0;
  2428. if (ReplaceOpeningStyleTag(ref closingTagArray, i, out offset, ref charBuffer, ref writeIndex))
  2429. {
  2430. i = offset;
  2431. continue;
  2432. }
  2433. }
  2434. else if (IsTagName(ref closingTagArray, "</STYLE>", i))
  2435. {
  2436. ReplaceClosingStyleTag(ref closingTagArray, i, ref charBuffer, ref writeIndex);
  2437. // Strip </style> even if style is invalid.
  2438. i += 7;
  2439. continue;
  2440. }
  2441. }
  2442. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2443. charBuffer[writeIndex] = c;
  2444. writeIndex += 1;
  2445. }
  2446. return true;
  2447. }
  2448. /// <summary>
  2449. /// Method to handle inline replacement of style tag by closing style definition.
  2450. /// </summary>
  2451. /// <param name="sourceText"></param>
  2452. /// <param name="srcIndex"></param>
  2453. /// <param name="charBuffer"></param>
  2454. /// <param name="writeIndex"></param>
  2455. /// <returns></returns>
  2456. bool ReplaceClosingStyleTag(ref char[] sourceText, int srcIndex, ref int[] charBuffer, ref int writeIndex)
  2457. {
  2458. // Get style from the Style Stack
  2459. int hashCode = m_styleStack.CurrentItem();
  2460. TMP_Style style = TMP_StyleSheet.GetStyle(hashCode);
  2461. m_styleStack.Remove();
  2462. // Return if we don't have a valid style.
  2463. if (style == null) return false;
  2464. int styleLength = style.styleClosingTagArray.Length;
  2465. // Replace <style> tag with opening definition
  2466. int[] closingTagArray = style.styleClosingTagArray;
  2467. for (int i = 0; i < styleLength; i++)
  2468. {
  2469. int c = closingTagArray[i];
  2470. if (c == 60)
  2471. {
  2472. if (IsTagName(ref closingTagArray, "<BR>", i))
  2473. {
  2474. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2475. charBuffer[writeIndex] = 10;
  2476. writeIndex += 1;
  2477. i += 3;
  2478. continue;
  2479. }
  2480. else if (IsTagName(ref closingTagArray, "<STYLE=", i))
  2481. {
  2482. int offset = 0;
  2483. if (ReplaceOpeningStyleTag(ref closingTagArray, i, out offset, ref charBuffer, ref writeIndex))
  2484. {
  2485. i = offset;
  2486. continue;
  2487. }
  2488. }
  2489. else if (IsTagName(ref closingTagArray, "</STYLE>", i))
  2490. {
  2491. ReplaceClosingStyleTag(ref closingTagArray, i, ref charBuffer, ref writeIndex);
  2492. // Strip </style> even if style is invalid.
  2493. i += 7;
  2494. continue;
  2495. }
  2496. }
  2497. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2498. charBuffer[writeIndex] = c;
  2499. writeIndex += 1;
  2500. }
  2501. return true;
  2502. }
  2503. /// <summary>
  2504. /// Method to handle inline replacement of style tag by closing style definition.
  2505. /// </summary>
  2506. /// <param name="sourceText"></param>
  2507. /// <param name="srcIndex"></param>
  2508. /// <param name="charBuffer"></param>
  2509. /// <param name="writeIndex"></param>
  2510. /// <returns></returns>
  2511. bool ReplaceClosingStyleTag(ref StringBuilder sourceText, int srcIndex, ref int[] charBuffer, ref int writeIndex)
  2512. {
  2513. // Get style from the Style Stack
  2514. int hashCode = m_styleStack.CurrentItem();
  2515. TMP_Style style = TMP_StyleSheet.GetStyle(hashCode);
  2516. m_styleStack.Remove();
  2517. // Return if we don't have a valid style.
  2518. if (style == null) return false;
  2519. int styleLength = style.styleClosingTagArray.Length;
  2520. // Replace <style> tag with opening definition
  2521. int[] closingTagArray = style.styleClosingTagArray;
  2522. for (int i = 0; i < styleLength; i++)
  2523. {
  2524. int c = closingTagArray[i];
  2525. if (c == 60)
  2526. {
  2527. if (IsTagName(ref closingTagArray, "<BR>", i))
  2528. {
  2529. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2530. charBuffer[writeIndex] = 10;
  2531. writeIndex += 1;
  2532. i += 3;
  2533. continue;
  2534. }
  2535. else if (IsTagName(ref closingTagArray, "<STYLE=", i))
  2536. {
  2537. int offset = 0;
  2538. if (ReplaceOpeningStyleTag(ref closingTagArray, i, out offset, ref charBuffer, ref writeIndex))
  2539. {
  2540. i = offset;
  2541. continue;
  2542. }
  2543. }
  2544. else if (IsTagName(ref closingTagArray, "</STYLE>", i))
  2545. {
  2546. ReplaceClosingStyleTag(ref closingTagArray, i, ref charBuffer, ref writeIndex);
  2547. // Strip </style> even if style is invalid.
  2548. i += 7;
  2549. continue;
  2550. }
  2551. }
  2552. if (writeIndex == charBuffer.Length) ResizeInternalArray(ref charBuffer);
  2553. charBuffer[writeIndex] = c;
  2554. writeIndex += 1;
  2555. }
  2556. return true;
  2557. }
  2558. /// <summary>
  2559. /// Method to check for a matching rich text tag.
  2560. /// </summary>
  2561. /// <param name="text"></param>
  2562. /// <param name="tag"></param>
  2563. /// <param name="index"></param>
  2564. /// <returns></returns>
  2565. bool IsTagName (ref string text, string tag, int index)
  2566. {
  2567. if (text.Length < index + tag.Length) return false;
  2568. for (int i = 0; i < tag.Length; i++)
  2569. {
  2570. if (TMP_TextUtilities.ToUpperFast(text[index + i]) != tag[i]) return false;
  2571. }
  2572. return true;
  2573. }
  2574. /// <summary>
  2575. /// Method to check for a matching rich text tag.
  2576. /// </summary>
  2577. /// <param name="text"></param>
  2578. /// <param name="tag"></param>
  2579. /// <param name="index"></param>
  2580. /// <returns></returns>
  2581. bool IsTagName(ref char[] text, string tag, int index)
  2582. {
  2583. if (text.Length < index + tag.Length) return false;
  2584. for (int i = 0; i < tag.Length; i++)
  2585. {
  2586. if (TMP_TextUtilities.ToUpperFast(text[index + i]) != tag[i]) return false;
  2587. }
  2588. return true;
  2589. }
  2590. /// <summary>
  2591. /// Method to check for a matching rich text tag.
  2592. /// </summary>
  2593. /// <param name="text"></param>
  2594. /// <param name="tag"></param>
  2595. /// <param name="index"></param>
  2596. /// <returns></returns>
  2597. bool IsTagName(ref int[] text, string tag, int index)
  2598. {
  2599. if (text.Length < index + tag.Length) return false;
  2600. for (int i = 0; i < tag.Length; i++)
  2601. {
  2602. if (TMP_TextUtilities.ToUpperFast((char)text[index + i]) != tag[i]) return false;
  2603. }
  2604. return true;
  2605. }
  2606. /// <summary>
  2607. /// Method to check for a matching rich text tag.
  2608. /// </summary>
  2609. /// <param name="text"></param>
  2610. /// <param name="tag"></param>
  2611. /// <param name="index"></param>
  2612. /// <returns></returns>
  2613. bool IsTagName(ref StringBuilder text, string tag, int index)
  2614. {
  2615. if (text.Length < index + tag.Length) return false;
  2616. for (int i = 0; i < tag.Length; i++)
  2617. {
  2618. if (TMP_TextUtilities.ToUpperFast(text[index + i]) != tag[i]) return false;
  2619. }
  2620. return true;
  2621. }
  2622. /// <summary>
  2623. /// Get Hashcode for a given tag.
  2624. /// </summary>
  2625. /// <param name="text"></param>
  2626. /// <param name="index"></param>
  2627. /// <param name="closeIndex"></param>
  2628. /// <returns></returns>
  2629. int GetTagHashCode(ref string text, int index, out int closeIndex)
  2630. {
  2631. int hashCode = 0;
  2632. closeIndex = 0;
  2633. for (int i = index; i < text.Length; i++)
  2634. {
  2635. // Skip quote '"' character
  2636. if (text[i] == 34) continue;
  2637. // Break at '>'
  2638. if (text[i] == 62) { closeIndex = i; break; }
  2639. hashCode = (hashCode << 5) + hashCode ^ text[i];
  2640. }
  2641. return hashCode;
  2642. }
  2643. /// <summary>
  2644. /// Get Hashcode for a given tag.
  2645. /// </summary>
  2646. /// <param name="text"></param>
  2647. /// <param name="index"></param>
  2648. /// <param name="closeIndex"></param>
  2649. /// <returns></returns>
  2650. int GetTagHashCode(ref char[] text, int index, out int closeIndex)
  2651. {
  2652. int hashCode = 0;
  2653. closeIndex = 0;
  2654. for (int i = index; i < text.Length; i++)
  2655. {
  2656. // Skip quote '"' character
  2657. if (text[i] == 34) continue;
  2658. // Break at '>'
  2659. if (text[i] == 62) { closeIndex = i; break; }
  2660. hashCode = (hashCode << 5) + hashCode ^ text[i];
  2661. }
  2662. return hashCode;
  2663. }
  2664. /// <summary>
  2665. /// Get Hashcode for a given tag.
  2666. /// </summary>
  2667. /// <param name="text"></param>
  2668. /// <param name="index"></param>
  2669. /// <param name="closeIndex"></param>
  2670. /// <returns></returns>
  2671. int GetTagHashCode(ref int[] text, int index, out int closeIndex)
  2672. {
  2673. int hashCode = 0;
  2674. closeIndex = 0;
  2675. for (int i = index; i < text.Length; i++)
  2676. {
  2677. // Skip quote '"' character
  2678. if (text[i] == 34) continue;
  2679. // Break at '>'
  2680. if (text[i] == 62) { closeIndex = i; break; }
  2681. hashCode = (hashCode << 5) + hashCode ^ text[i];
  2682. }
  2683. return hashCode;
  2684. }
  2685. /// <summary>
  2686. /// Get Hashcode for a given tag.
  2687. /// </summary>
  2688. /// <param name="text"></param>
  2689. /// <param name="index"></param>
  2690. /// <param name="closeIndex"></param>
  2691. /// <returns></returns>
  2692. int GetTagHashCode(ref StringBuilder text, int index, out int closeIndex)
  2693. {
  2694. int hashCode = 0;
  2695. closeIndex = 0;
  2696. for (int i = index; i < text.Length; i++)
  2697. {
  2698. // Skip quote '"' character
  2699. if (text[i] == 34) continue;
  2700. // Break at '>'
  2701. if (text[i] == 62) { closeIndex = i; break; }
  2702. hashCode = (hashCode << 5) + hashCode ^ text[i];
  2703. }
  2704. return hashCode;
  2705. }
  2706. /// <summary>
  2707. ///
  2708. /// </summary>
  2709. void ResizeInternalArray <T>(ref T[] array)
  2710. {
  2711. int size = Mathf.NextPowerOfTwo(array.Length + 1);
  2712. System.Array.Resize(ref array, size);
  2713. }
  2714. private readonly float[] k_Power = { 5e-1f, 5e-2f, 5e-3f, 5e-4f, 5e-5f, 5e-6f, 5e-7f, 5e-8f, 5e-9f, 5e-10f }; // Used by FormatText to enable rounding and avoid using Mathf.Pow.
  2715. /// <summary>
  2716. /// Function used in conjunction with SetText()
  2717. /// </summary>
  2718. /// <param name="number"></param>
  2719. /// <param name="index"></param>
  2720. /// <param name="precision"></param>
  2721. protected void AddFloatToCharArray(float number, ref int index, int precision)
  2722. {
  2723. if (number < 0)
  2724. {
  2725. m_input_CharArray[index++] = '-';
  2726. number = -number;
  2727. }
  2728. number += k_Power[Mathf.Min(9, precision)];
  2729. int integer = (int)number;
  2730. AddIntToCharArray(integer, ref index, precision);
  2731. if (precision > 0)
  2732. {
  2733. // Add the decimal point
  2734. m_input_CharArray[index++] = '.';
  2735. number -= integer;
  2736. for (int p = 0; p < precision; p++)
  2737. {
  2738. number *= 10;
  2739. int d = (int)(number);
  2740. m_input_CharArray[index++] = (char)(d + 48);
  2741. number -= d;
  2742. }
  2743. }
  2744. }
  2745. /// <summary>
  2746. /// // Function used in conjunction with SetText()
  2747. /// </summary>
  2748. /// <param name="number"></param>
  2749. /// <param name="index"></param>
  2750. /// <param name="precision"></param>
  2751. protected void AddIntToCharArray(int number, ref int index, int precision)
  2752. {
  2753. if (number < 0)
  2754. {
  2755. m_input_CharArray[index++] = '-';
  2756. number = -number;
  2757. }
  2758. int i = index;
  2759. do
  2760. {
  2761. m_input_CharArray[i++] = (char)(number % 10 + 48);
  2762. number /= 10;
  2763. } while (number > 0);
  2764. int lastIndex = i;
  2765. // Reverse string
  2766. while (index + 1 < i)
  2767. {
  2768. i -= 1;
  2769. char t = m_input_CharArray[index];
  2770. m_input_CharArray[index] = m_input_CharArray[i];
  2771. m_input_CharArray[i] = t;
  2772. index += 1;
  2773. }
  2774. index = lastIndex;
  2775. }
  2776. /// <summary>
  2777. /// Method used to determine the number of visible characters and required buffer allocations.
  2778. /// </summary>
  2779. /// <param name="chars"></param>
  2780. /// <returns></returns>
  2781. protected virtual int SetArraySizes(int[] chars) { return 0; }
  2782. /// <summary>
  2783. /// Method which parses the text input, does the layout of the text as well as generating the geometry.
  2784. /// </summary>
  2785. protected virtual void GenerateTextMesh() { }
  2786. /// <summary>
  2787. /// Function to Calculate the Preferred Width and Height of the text object.
  2788. /// </summary>
  2789. /// <returns></returns>
  2790. public Vector2 GetPreferredValues()
  2791. {
  2792. if (m_isInputParsingRequired || m_isTextTruncated)
  2793. {
  2794. m_isCalculatingPreferredValues = true;
  2795. ParseInputText();
  2796. }
  2797. // CALCULATE PREFERRED WIDTH
  2798. float preferredWidth = GetPreferredWidth();
  2799. // CALCULATE PREFERRED HEIGHT
  2800. float preferredHeight = GetPreferredHeight();
  2801. return new Vector2(preferredWidth, preferredHeight);
  2802. }
  2803. /// <summary>
  2804. /// Function to Calculate the Preferred Width and Height of the text object given the provided width and height.
  2805. /// </summary>
  2806. /// <returns></returns>
  2807. public Vector2 GetPreferredValues(float width, float height)
  2808. {
  2809. if (m_isInputParsingRequired || m_isTextTruncated)
  2810. {
  2811. m_isCalculatingPreferredValues = true;
  2812. ParseInputText();
  2813. }
  2814. Vector2 margin = new Vector2(width, height);
  2815. // CALCULATE PREFERRED WIDTH
  2816. float preferredWidth = GetPreferredWidth(margin);
  2817. // CALCULATE PREFERRED HEIGHT
  2818. float preferredHeight = GetPreferredHeight(margin);
  2819. return new Vector2(preferredWidth, preferredHeight);
  2820. }
  2821. /// <summary>
  2822. /// Function to Calculate the Preferred Width and Height of the text object given a certain string.
  2823. /// </summary>
  2824. /// <param name="text"></param>
  2825. /// <returns></returns>
  2826. public Vector2 GetPreferredValues(string text)
  2827. {
  2828. m_isCalculatingPreferredValues = true;
  2829. StringToCharArray(text, ref m_char_buffer);
  2830. SetArraySizes(m_char_buffer);
  2831. Vector2 margin = k_LargePositiveVector2;
  2832. // CALCULATE PREFERRED WIDTH
  2833. float preferredWidth = GetPreferredWidth(margin);
  2834. // CALCULATE PREFERRED HEIGHT
  2835. float preferredHeight = GetPreferredHeight(margin);
  2836. return new Vector2(preferredWidth, preferredHeight);
  2837. }
  2838. /// <summary>
  2839. /// Function to Calculate the Preferred Width and Height of the text object given a certain string and size of text container.
  2840. /// </summary>
  2841. /// <param name="text"></param>
  2842. /// <returns></returns>
  2843. public Vector2 GetPreferredValues(string text, float width, float height)
  2844. {
  2845. m_isCalculatingPreferredValues = true;
  2846. StringToCharArray(text, ref m_char_buffer);
  2847. SetArraySizes(m_char_buffer);
  2848. Vector2 margin = new Vector2(width, height);
  2849. // CALCULATE PREFERRED WIDTH
  2850. float preferredWidth = GetPreferredWidth(margin);
  2851. // CALCULATE PREFERRED HEIGHT
  2852. float preferredHeight = GetPreferredHeight(margin);
  2853. return new Vector2(preferredWidth, preferredHeight);
  2854. }
  2855. /// <summary>
  2856. /// Method to calculate the preferred width of a text object.
  2857. /// </summary>
  2858. /// <returns></returns>
  2859. protected float GetPreferredWidth()
  2860. {
  2861. if (TMP_Settings.instance == null) return 0;
  2862. float fontSize = m_enableAutoSizing ? m_fontSizeMax : m_fontSize;
  2863. // Reset auto sizing point size bounds
  2864. m_minFontSize = m_fontSizeMin;
  2865. m_maxFontSize = m_fontSizeMax;
  2866. m_charWidthAdjDelta = 0;
  2867. // Set Margins to Infinity
  2868. Vector2 margin = k_LargePositiveVector2;
  2869. if (m_isInputParsingRequired || m_isTextTruncated)
  2870. {
  2871. m_isCalculatingPreferredValues = true;
  2872. ParseInputText();
  2873. }
  2874. m_recursiveCount = 0;
  2875. float preferredWidth = CalculatePreferredValues(fontSize, margin, true).x;
  2876. m_isPreferredWidthDirty = false;
  2877. //Debug.Log("GetPreferredWidth() Called at frame " + Time.frameCount + ". Returning width of " + preferredWidth);
  2878. return preferredWidth;
  2879. }
  2880. /// <summary>
  2881. /// Method to calculate the preferred width of a text object.
  2882. /// </summary>
  2883. /// <param name="margin"></param>
  2884. /// <returns></returns>
  2885. protected float GetPreferredWidth(Vector2 margin)
  2886. {
  2887. float fontSize = m_enableAutoSizing ? m_fontSizeMax : m_fontSize;
  2888. // Reset auto sizing point size bounds
  2889. m_minFontSize = m_fontSizeMin;
  2890. m_maxFontSize = m_fontSizeMax;
  2891. m_charWidthAdjDelta = 0;
  2892. m_recursiveCount = 0;
  2893. float preferredWidth = CalculatePreferredValues(fontSize, margin, true).x;
  2894. //Debug.Log("GetPreferredWidth() Called. Returning width of " + preferredWidth);
  2895. return preferredWidth;
  2896. }
  2897. /// <summary>
  2898. /// Method to calculate the preferred height of a text object.
  2899. /// </summary>
  2900. /// <returns></returns>
  2901. protected float GetPreferredHeight()
  2902. {
  2903. if (TMP_Settings.instance == null) return 0;
  2904. float fontSize = m_enableAutoSizing ? m_fontSizeMax : m_fontSize;
  2905. // Reset auto sizing point size bounds
  2906. m_minFontSize = m_fontSizeMin;
  2907. m_maxFontSize = m_fontSizeMax;
  2908. m_charWidthAdjDelta = 0;
  2909. Vector2 margin = new Vector2(m_marginWidth != 0 ? m_marginWidth : k_LargePositiveFloat, k_LargePositiveFloat);
  2910. if (m_isInputParsingRequired || m_isTextTruncated)
  2911. {
  2912. m_isCalculatingPreferredValues = true;
  2913. ParseInputText();
  2914. }
  2915. m_recursiveCount = 0;
  2916. float preferredHeight = CalculatePreferredValues(fontSize, margin, !m_enableAutoSizing).y;
  2917. m_isPreferredHeightDirty = false;
  2918. //Debug.Log("GetPreferredHeight() Called. Returning height of " + preferredHeight);
  2919. return preferredHeight;
  2920. }
  2921. /// <summary>
  2922. /// Method to calculate the preferred height of a text object.
  2923. /// </summary>
  2924. /// <param name="margin"></param>
  2925. /// <returns></returns>
  2926. protected float GetPreferredHeight(Vector2 margin)
  2927. {
  2928. float fontSize = m_enableAutoSizing ? m_fontSizeMax : m_fontSize;
  2929. // Reset auto sizing point size bounds
  2930. m_minFontSize = m_fontSizeMin;
  2931. m_maxFontSize = m_fontSizeMax;
  2932. m_charWidthAdjDelta = 0;
  2933. m_recursiveCount = 0;
  2934. float preferredHeight = CalculatePreferredValues(fontSize, margin, true).y;
  2935. //Debug.Log("GetPreferredHeight() Called. Returning height of " + preferredHeight);
  2936. return preferredHeight;
  2937. }
  2938. /// <summary>
  2939. /// Method returning the rendered width and height of the text object.
  2940. /// </summary>
  2941. /// <returns></returns>
  2942. public Vector2 GetRenderedValues()
  2943. {
  2944. return GetTextBounds().size;
  2945. }
  2946. /// <summary>
  2947. ///
  2948. /// </summary>
  2949. /// <param name="onlyVisibleCharacters">Should returned value only factor in visible characters and exclude those greater than maxVisibleCharacters for instance.</param>
  2950. /// <returns></returns>
  2951. public Vector2 GetRenderedValues(bool onlyVisibleCharacters)
  2952. {
  2953. return GetTextBounds(onlyVisibleCharacters).size;
  2954. }
  2955. /// <summary>
  2956. /// Method returning the rendered width of the text object.
  2957. /// </summary>
  2958. /// <returns></returns>
  2959. protected float GetRenderedWidth()
  2960. {
  2961. return GetRenderedValues().x;
  2962. }
  2963. /// <summary>
  2964. /// Method returning the rendered width of the text object.
  2965. /// </summary>
  2966. /// <returns></returns>
  2967. protected float GetRenderedWidth(bool onlyVisibleCharacters)
  2968. {
  2969. return GetRenderedValues(onlyVisibleCharacters).x;
  2970. }
  2971. /// <summary>
  2972. /// Method returning the rendered height of the text object.
  2973. /// </summary>
  2974. /// <returns></returns>
  2975. protected float GetRenderedHeight()
  2976. {
  2977. return GetRenderedValues().y;
  2978. }
  2979. /// <summary>
  2980. /// Method returning the rendered height of the text object.
  2981. /// </summary>
  2982. /// <returns></returns>
  2983. protected float GetRenderedHeight(bool onlyVisibleCharacters)
  2984. {
  2985. return GetRenderedValues(onlyVisibleCharacters).y;
  2986. }
  2987. /// <summary>
  2988. /// Method to calculate the preferred width and height of the text object.
  2989. /// </summary>
  2990. /// <returns></returns>
  2991. protected virtual Vector2 CalculatePreferredValues(float defaultFontSize, Vector2 marginSize, bool ignoreTextAutoSizing)
  2992. {
  2993. //Debug.Log("*** CalculatePreferredValues() ***"); // ***** Frame: " + Time.frameCount);
  2994. ////Profiler.BeginSample("TMP Generate Text - Phase I");
  2995. // Early exit if no font asset was assigned. This should not be needed since LiberationSans SDF will be assigned by default.
  2996. if (m_fontAsset == null || m_fontAsset.characterDictionary == null)
  2997. {
  2998. Debug.LogWarning("Can't Generate Mesh! No Font Asset has been assigned to Object ID: " + this.GetInstanceID());
  2999. return Vector2.zero;
  3000. }
  3001. // Early exit if we don't have any Text to generate.
  3002. if (m_char_buffer == null || m_char_buffer.Length == 0 || m_char_buffer[0] == (char)0)
  3003. {
  3004. return Vector2.zero;
  3005. }
  3006. m_currentFontAsset = m_fontAsset;
  3007. m_currentMaterial = m_sharedMaterial;
  3008. m_currentMaterialIndex = 0;
  3009. m_materialReferenceStack.SetDefault(new MaterialReference(0, m_currentFontAsset, null, m_currentMaterial, m_padding));
  3010. // Total character count is computed when the text is parsed.
  3011. int totalCharacterCount = m_totalCharacterCount; // m_VisibleCharacters.Count;
  3012. if (m_internalCharacterInfo == null || totalCharacterCount > m_internalCharacterInfo.Length)
  3013. {
  3014. m_internalCharacterInfo = new TMP_CharacterInfo[totalCharacterCount > 1024 ? totalCharacterCount + 256 : Mathf.NextPowerOfTwo(totalCharacterCount)];
  3015. }
  3016. // Calculate the scale of the font based on selected font size and sampling point size.
  3017. // baseScale is calculated using the font asset assigned to the text object.
  3018. float baseScale = m_fontScale = (defaultFontSize / m_fontAsset.fontInfo.PointSize * m_fontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
  3019. float currentElementScale = baseScale;
  3020. m_fontScaleMultiplier = 1;
  3021. m_currentFontSize = defaultFontSize;
  3022. m_sizeStack.SetDefault(m_currentFontSize);
  3023. float fontSizeDelta = 0;
  3024. int charCode = 0; // Holds the character code of the currently being processed character.
  3025. m_style = m_fontStyle; // Set the default style.
  3026. m_lineJustification = m_textAlignment; // Sets the line justification mode to match editor alignment.
  3027. m_lineJustificationStack.SetDefault(m_lineJustification);
  3028. float bold_xAdvance_multiplier = 1; // Used to increase spacing between character when style is bold.
  3029. m_baselineOffset = 0; // Used by subscript characters.
  3030. m_baselineOffsetStack.Clear();
  3031. m_lineOffset = 0; // Amount of space between lines (font line spacing + m_linespacing).
  3032. m_lineHeight = TMP_Math.FLOAT_UNSET;
  3033. float lineGap = m_currentFontAsset.fontInfo.LineHeight - (m_currentFontAsset.fontInfo.Ascender - m_currentFontAsset.fontInfo.Descender);
  3034. m_cSpacing = 0; // Amount of space added between characters as a result of the use of the <cspace> tag.
  3035. m_monoSpacing = 0;
  3036. float lineOffsetDelta = 0;
  3037. m_xAdvance = 0; // Used to track the position of each character.
  3038. float maxXAdvance = 0; // Used to determine Preferred Width.
  3039. tag_LineIndent = 0; // Used for indentation of text.
  3040. tag_Indent = 0;
  3041. m_indentStack.SetDefault(0);
  3042. tag_NoParsing = false;
  3043. //m_isIgnoringAlignment = false;
  3044. m_characterCount = 0; // Total characters in the char[]
  3045. // Tracking of line information
  3046. m_firstCharacterOfLine = 0;
  3047. m_maxLineAscender = k_LargeNegativeFloat;
  3048. m_maxLineDescender = k_LargePositiveFloat;
  3049. m_lineNumber = 0;
  3050. float marginWidth = marginSize.x;
  3051. //float marginHeight = marginSize.y;
  3052. m_marginLeft = 0;
  3053. m_marginRight = 0;
  3054. m_width = -1;
  3055. // Used by Unity's Auto Layout system.
  3056. float renderedWidth = 0;
  3057. float renderedHeight = 0;
  3058. float linebreakingWidth = 0;
  3059. m_isCalculatingPreferredValues = true;
  3060. // Tracking of the highest Ascender
  3061. m_maxAscender = 0;
  3062. m_maxDescender = 0;
  3063. // Initialize struct to track states of word wrapping
  3064. bool isFirstWord = true;
  3065. bool isLastBreakingChar = false;
  3066. WordWrapState savedLineState = new WordWrapState();
  3067. SaveWordWrappingState(ref savedLineState, 0, 0);
  3068. WordWrapState savedWordWrapState = new WordWrapState();
  3069. int wrappingIndex = 0;
  3070. // Counter to prevent recursive lockup when computing preferred values.
  3071. m_recursiveCount += 1;
  3072. int endTagIndex = 0;
  3073. // Parse through Character buffer to read HTML tags and begin creating mesh.
  3074. for (int i = 0; m_char_buffer[i] != 0; i++)
  3075. {
  3076. charCode = m_char_buffer[i];
  3077. // Parse Rich Text Tag
  3078. #region Parse Rich Text Tag
  3079. if (m_isRichText && charCode == 60) // '<'
  3080. {
  3081. m_isParsingText = true;
  3082. m_textElementType = TMP_TextElementType.Character;
  3083. // Check if Tag is valid. If valid, skip to the end of the validated tag.
  3084. if (ValidateHtmlTag(m_char_buffer, i + 1, out endTagIndex))
  3085. {
  3086. i = endTagIndex;
  3087. // Continue to next character or handle the sprite element
  3088. if (m_textElementType == TMP_TextElementType.Character)
  3089. continue;
  3090. }
  3091. }
  3092. else
  3093. {
  3094. m_textElementType = m_textInfo.characterInfo[m_characterCount].elementType;
  3095. m_currentMaterialIndex = m_textInfo.characterInfo[m_characterCount].materialReferenceIndex;
  3096. m_currentFontAsset = m_textInfo.characterInfo[m_characterCount].fontAsset;
  3097. }
  3098. #endregion End Parse Rich Text Tag
  3099. int prev_MaterialIndex = m_currentMaterialIndex;
  3100. bool isUsingAltTypeface = m_textInfo.characterInfo[m_characterCount].isUsingAlternateTypeface;
  3101. m_isParsingText = false;
  3102. // Handle Font Styles like LowerCase, UpperCase and SmallCaps.
  3103. #region Handling of LowerCase, UpperCase and SmallCaps Font Styles
  3104. float smallCapsMultiplier = 1.0f;
  3105. if (m_textElementType == TMP_TextElementType.Character)
  3106. {
  3107. if ((m_style & FontStyles.UpperCase) == FontStyles.UpperCase)
  3108. {
  3109. // If this character is lowercase, switch to uppercase.
  3110. if (char.IsLower((char)charCode))
  3111. charCode = char.ToUpper((char)charCode);
  3112. }
  3113. else if ((m_style & FontStyles.LowerCase) == FontStyles.LowerCase)
  3114. {
  3115. // If this character is uppercase, switch to lowercase.
  3116. if (char.IsUpper((char)charCode))
  3117. charCode = char.ToLower((char)charCode);
  3118. }
  3119. else if ((m_fontStyle & FontStyles.SmallCaps) == FontStyles.SmallCaps || (m_style & FontStyles.SmallCaps) == FontStyles.SmallCaps)
  3120. {
  3121. if (char.IsLower((char)charCode))
  3122. {
  3123. smallCapsMultiplier = 0.8f;
  3124. charCode = char.ToUpper((char)charCode);
  3125. }
  3126. }
  3127. }
  3128. #endregion
  3129. // Look up Character Data from Dictionary and cache it.
  3130. #region Look up Character Data
  3131. if (m_textElementType == TMP_TextElementType.Sprite)
  3132. {
  3133. // If a sprite is used as a fallback then get a reference to it and set the color to white.
  3134. m_currentSpriteAsset = m_textInfo.characterInfo[m_characterCount].spriteAsset;
  3135. m_spriteIndex = m_textInfo.characterInfo[m_characterCount].spriteIndex;
  3136. TMP_Sprite sprite = m_currentSpriteAsset.spriteInfoList[m_spriteIndex];
  3137. if (sprite == null) continue;
  3138. // Sprites are assigned in the E000 Private Area + sprite Index
  3139. if (charCode == 60)
  3140. charCode = 57344 + m_spriteIndex;
  3141. m_currentFontAsset = m_fontAsset;
  3142. // The sprite scale calculations are based on the font asset assigned to the text object.
  3143. // Sprite scale is used to determine line height
  3144. // Current element scale represents a modified scale to normalize the sprite based on the font baseline to ascender.
  3145. float spriteScale = (m_currentFontSize / m_fontAsset.fontInfo.PointSize * m_fontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
  3146. currentElementScale = m_fontAsset.fontInfo.Ascender / sprite.height * sprite.scale * spriteScale;
  3147. m_cached_TextElement = sprite;
  3148. m_internalCharacterInfo[m_characterCount].elementType = TMP_TextElementType.Sprite;
  3149. m_internalCharacterInfo[m_characterCount].scale = spriteScale;
  3150. //m_internalCharacterInfo[m_characterCount].spriteAsset = m_currentSpriteAsset;
  3151. //m_internalCharacterInfo[m_characterCount].fontAsset = m_currentFontAsset;
  3152. //m_internalCharacterInfo[m_characterCount].materialReferenceIndex = m_currentMaterialIndex;
  3153. m_currentMaterialIndex = prev_MaterialIndex;
  3154. }
  3155. else if (m_textElementType == TMP_TextElementType.Character)
  3156. {
  3157. m_cached_TextElement = m_textInfo.characterInfo[m_characterCount].textElement;
  3158. if (m_cached_TextElement == null) continue;
  3159. //m_currentFontAsset = m_textInfo.characterInfo[m_characterCount].fontAsset;
  3160. //m_currentMaterial = m_textInfo.characterInfo[m_characterCount].material;
  3161. m_currentMaterialIndex = m_textInfo.characterInfo[m_characterCount].materialReferenceIndex;
  3162. // Re-calculate font scale as the font asset may have changed.
  3163. m_fontScale = m_currentFontSize * smallCapsMultiplier / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f);
  3164. currentElementScale = m_fontScale * m_fontScaleMultiplier * m_cached_TextElement.scale;
  3165. m_internalCharacterInfo[m_characterCount].elementType = TMP_TextElementType.Character;
  3166. }
  3167. #endregion
  3168. // Handle Soft Hyphen
  3169. #region Handle Soft Hyphen
  3170. float old_scale = currentElementScale;
  3171. if (charCode == 0xAD)
  3172. {
  3173. currentElementScale = 0;
  3174. }
  3175. #endregion
  3176. // Store some of the text object's information
  3177. m_internalCharacterInfo[m_characterCount].character = (char)charCode;
  3178. // Handle Kerning if Enabled.
  3179. #region Handle Kerning
  3180. GlyphValueRecord glyphAdjustments = new GlyphValueRecord();
  3181. if (m_enableKerning)
  3182. {
  3183. KerningPair adjustmentPair = null;
  3184. if (m_characterCount < totalCharacterCount - 1)
  3185. {
  3186. uint nextGlyph = m_textInfo.characterInfo[m_characterCount + 1].character;
  3187. KerningPairKey keyValue = new KerningPairKey((uint)charCode, nextGlyph);
  3188. m_currentFontAsset.kerningDictionary.TryGetValue((int)keyValue.key, out adjustmentPair);
  3189. if (adjustmentPair != null)
  3190. glyphAdjustments = adjustmentPair.firstGlyphAdjustments;
  3191. }
  3192. if (m_characterCount >= 1)
  3193. {
  3194. uint previousGlyph = m_textInfo.characterInfo[m_characterCount - 1].character;
  3195. KerningPairKey keyValue = new KerningPairKey(previousGlyph, (uint)charCode);
  3196. m_currentFontAsset.kerningDictionary.TryGetValue((int)keyValue.key, out adjustmentPair);
  3197. if (adjustmentPair != null)
  3198. glyphAdjustments += adjustmentPair.secondGlyphAdjustments;
  3199. }
  3200. }
  3201. #endregion
  3202. // Initial Implementation for RTL support.
  3203. #region Handle Right-to-Left
  3204. //if (m_isRightToLeft)
  3205. //{
  3206. // m_xAdvance -= ((m_cached_TextElement.xAdvance * bold_xAdvance_multiplier + m_characterSpacing + m_wordSpacing + m_currentFontAsset.normalSpacingOffset) * currentElementScale + m_cSpacing) * (1 - m_charWidthAdjDelta);
  3207. // if (char.IsWhiteSpace((char)charCode) || charCode == 0x200B)
  3208. // m_xAdvance -= m_wordSpacing * currentElementScale;
  3209. //}
  3210. #endregion
  3211. // Handle Mono Spacing
  3212. #region Handle Mono Spacing
  3213. float monoAdvance = 0;
  3214. if (m_monoSpacing != 0)
  3215. {
  3216. monoAdvance = (m_monoSpacing / 2 - (m_cached_TextElement.width / 2 + m_cached_TextElement.xOffset) * currentElementScale);
  3217. m_xAdvance += monoAdvance;
  3218. }
  3219. #endregion
  3220. // Set Padding based on selected font style
  3221. #region Handle Style Padding
  3222. if (m_textElementType == TMP_TextElementType.Character && !isUsingAltTypeface && ((m_style & FontStyles.Bold) == FontStyles.Bold || (m_fontStyle & FontStyles.Bold) == FontStyles.Bold)) // Checks for any combination of Bold Style.
  3223. {
  3224. //style_padding = m_currentFontAsset.boldStyle * 2;
  3225. bold_xAdvance_multiplier = 1 + m_currentFontAsset.boldSpacing * 0.01f;
  3226. }
  3227. else
  3228. {
  3229. //style_padding = m_currentFontAsset.normalStyle * 2;
  3230. bold_xAdvance_multiplier = 1.0f;
  3231. }
  3232. #endregion Handle Style Padding
  3233. m_internalCharacterInfo[m_characterCount].baseLine = 0 - m_lineOffset + m_baselineOffset;
  3234. // Compute and save text element Ascender and maximum line Ascender.
  3235. float elementAscender = m_currentFontAsset.fontInfo.Ascender * (m_textElementType == TMP_TextElementType.Character ? currentElementScale / smallCapsMultiplier : m_internalCharacterInfo[m_characterCount].scale) + m_baselineOffset;
  3236. m_internalCharacterInfo[m_characterCount].ascender = elementAscender - m_lineOffset;
  3237. m_maxLineAscender = elementAscender > m_maxLineAscender ? elementAscender : m_maxLineAscender;
  3238. // Compute and save text element Descender and maximum line Descender.
  3239. float elementDescender = m_currentFontAsset.fontInfo.Descender * (m_textElementType == TMP_TextElementType.Character ? currentElementScale / smallCapsMultiplier: m_internalCharacterInfo[m_characterCount].scale) + m_baselineOffset;
  3240. float elementDescenderII = m_internalCharacterInfo[m_characterCount].descender = elementDescender - m_lineOffset;
  3241. m_maxLineDescender = elementDescender < m_maxLineDescender ? elementDescender : m_maxLineDescender;
  3242. // Adjust maxLineAscender and maxLineDescender if style is superscript or subscript
  3243. if ((m_style & FontStyles.Subscript) == FontStyles.Subscript || (m_style & FontStyles.Superscript) == FontStyles.Superscript)
  3244. {
  3245. float baseAscender = (elementAscender - m_baselineOffset) / m_currentFontAsset.fontInfo.SubSize;
  3246. elementAscender = m_maxLineAscender;
  3247. m_maxLineAscender = baseAscender > m_maxLineAscender ? baseAscender : m_maxLineAscender;
  3248. float baseDescender = (elementDescender - m_baselineOffset) / m_currentFontAsset.fontInfo.SubSize;
  3249. elementDescender = m_maxLineDescender;
  3250. m_maxLineDescender = baseDescender < m_maxLineDescender ? baseDescender : m_maxLineDescender;
  3251. }
  3252. if (m_lineNumber == 0) m_maxAscender = m_maxAscender > elementAscender ? m_maxAscender : elementAscender;
  3253. //if (m_lineOffset == 0) pageAscender = pageAscender > elementAscender ? pageAscender : elementAscender;
  3254. // Setup Mesh for visible text elements. ie. not a SPACE / LINEFEED / CARRIAGE RETURN.
  3255. #region Handle Visible Characters
  3256. if (charCode == 9 || charCode == 0xA0 || charCode == 0x2007 || (!char.IsWhiteSpace((char)charCode) && charCode != 0x200B) || m_textElementType == TMP_TextElementType.Sprite)
  3257. {
  3258. // Check if Character exceeds the width of the Text Container
  3259. #region Handle Line Breaking, Text Auto-Sizing and Horizontal Overflow
  3260. float width = m_width != -1 ? Mathf.Min(marginWidth + 0.0001f - m_marginLeft - m_marginRight, m_width) : marginWidth + 0.0001f - m_marginLeft - m_marginRight;
  3261. bool isJustifiedOrFlush = ((_HorizontalAlignmentOptions)m_lineJustification & _HorizontalAlignmentOptions.Flush) == _HorizontalAlignmentOptions.Flush || ((_HorizontalAlignmentOptions)m_lineJustification & _HorizontalAlignmentOptions.Justified) == _HorizontalAlignmentOptions.Justified;
  3262. // Calculate the line breaking width of the text.
  3263. linebreakingWidth = m_xAdvance + m_cached_TextElement.xAdvance * (1 - m_charWidthAdjDelta) * (charCode != 0xAD ? currentElementScale : old_scale);
  3264. // Check if Character exceeds the width of the Text Container
  3265. if (linebreakingWidth > width * (isJustifiedOrFlush ? 1.05f : 1.0f))
  3266. {
  3267. // Word Wrapping
  3268. #region Handle Word Wrapping
  3269. if (enableWordWrapping && m_characterCount != m_firstCharacterOfLine)
  3270. {
  3271. // Check if word wrapping is still possible
  3272. #region Line Breaking Check
  3273. if (wrappingIndex == savedWordWrapState.previous_WordBreak || isFirstWord)
  3274. {
  3275. // Word wrapping is no longer possible. Shrink size of text if auto-sizing is enabled.
  3276. #region Text Auto-Sizing
  3277. if (ignoreTextAutoSizing == false && m_currentFontSize > m_fontSizeMin)
  3278. {
  3279. // Handle Character Width Adjustments
  3280. #region Character Width Adjustments
  3281. if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100)
  3282. {
  3283. m_recursiveCount = 0;
  3284. m_charWidthAdjDelta += 0.01f;
  3285. return CalculatePreferredValues(defaultFontSize, marginSize, false);
  3286. }
  3287. #endregion
  3288. // Adjust Point Size
  3289. m_maxFontSize = defaultFontSize;
  3290. defaultFontSize -= Mathf.Max((defaultFontSize - m_minFontSize) / 2, 0.05f);
  3291. defaultFontSize = (int)(Mathf.Max(defaultFontSize, m_fontSizeMin) * 20 + 0.5f) / 20f;
  3292. if (m_recursiveCount > 20) return new Vector2(renderedWidth, renderedHeight);
  3293. return CalculatePreferredValues(defaultFontSize, marginSize, false);
  3294. }
  3295. #endregion
  3296. // Word wrapping is no longer possible, now breaking up individual words.
  3297. if (m_isCharacterWrappingEnabled == false)
  3298. {
  3299. m_isCharacterWrappingEnabled = true;
  3300. }
  3301. else
  3302. isLastBreakingChar = true;
  3303. }
  3304. #endregion
  3305. // Restore to previously stored state of last valid (space character or linefeed)
  3306. i = RestoreWordWrappingState(ref savedWordWrapState);
  3307. wrappingIndex = i; // Used to detect when line length can no longer be reduced.
  3308. // Handling for Soft Hyphen
  3309. if (m_char_buffer[i] == 0xAD) // && !m_isCharacterWrappingEnabled) // && ellipsisIndex != i && !m_isCharacterWrappingEnabled)
  3310. {
  3311. m_isTextTruncated = true;
  3312. m_char_buffer[i] = 0x2D;
  3313. return CalculatePreferredValues(defaultFontSize, marginSize, true);
  3314. }
  3315. // Check if Line Spacing of previous line needs to be adjusted.
  3316. if (m_lineNumber > 0 && !TMP_Math.Approximately(m_maxLineAscender, m_startOfLineAscender) && m_lineHeight == TMP_Math.FLOAT_UNSET)
  3317. {
  3318. //Debug.Log("(1) Adjusting Line Spacing on line #" + m_lineNumber);
  3319. float offsetDelta = m_maxLineAscender - m_startOfLineAscender;
  3320. //AdjustLineOffset(m_firstCharacterOfLine, m_characterCount, offsetDelta);
  3321. m_lineOffset += offsetDelta;
  3322. savedWordWrapState.lineOffset = m_lineOffset;
  3323. savedWordWrapState.previousLineAscender = m_maxLineAscender;
  3324. // TODO - Add check for character exceeding vertical bounds
  3325. }
  3326. //m_isNewPage = false;
  3327. // Calculate lineAscender & make sure if last character is superscript or subscript that we check that as well.
  3328. float lineAscender = m_maxLineAscender - m_lineOffset;
  3329. float lineDescender = m_maxLineDescender - m_lineOffset;
  3330. // Update maxDescender and maxVisibleDescender
  3331. m_maxDescender = m_maxDescender < lineDescender ? m_maxDescender : lineDescender;
  3332. m_firstCharacterOfLine = m_characterCount; // Store first character of the next line.
  3333. // Compute Preferred Width & Height
  3334. renderedWidth += m_xAdvance;
  3335. if (m_enableWordWrapping)
  3336. renderedHeight = m_maxAscender - m_maxDescender;
  3337. else
  3338. renderedHeight = Mathf.Max(renderedHeight, lineAscender - lineDescender);
  3339. // Store the state of the line before starting on the new line.
  3340. SaveWordWrappingState(ref savedLineState, i, m_characterCount - 1);
  3341. m_lineNumber += 1;
  3342. //isStartOfNewLine = true;
  3343. // Check to make sure Array is large enough to hold a new line.
  3344. //if (m_lineNumber >= m_internalTextInfo.lineInfo.Length)
  3345. // ResizeLineExtents(m_lineNumber);
  3346. // Apply Line Spacing based on scale of the last character of the line.
  3347. if (m_lineHeight == TMP_Math.FLOAT_UNSET)
  3348. {
  3349. float ascender = m_internalCharacterInfo[m_characterCount].ascender - m_internalCharacterInfo[m_characterCount].baseLine;
  3350. lineOffsetDelta = 0 - m_maxLineDescender + ascender + (lineGap + m_lineSpacing + m_lineSpacingDelta) * baseScale;
  3351. m_lineOffset += lineOffsetDelta;
  3352. m_startOfLineAscender = ascender;
  3353. }
  3354. else
  3355. m_lineOffset += m_lineHeight + m_lineSpacing * baseScale;
  3356. m_maxLineAscender = k_LargeNegativeFloat;
  3357. m_maxLineDescender = k_LargePositiveFloat;
  3358. m_xAdvance = 0 + tag_Indent;
  3359. continue;
  3360. }
  3361. #endregion End Word Wrapping
  3362. // Text Auto-Sizing (text exceeding Width of container.
  3363. #region Handle Text Auto-Sizing
  3364. if (ignoreTextAutoSizing == false && defaultFontSize > m_fontSizeMin)
  3365. {
  3366. // Handle Character Width Adjustments
  3367. #region Character Width Adjustments
  3368. if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100)
  3369. {
  3370. m_recursiveCount = 0;
  3371. m_charWidthAdjDelta += 0.01f;
  3372. return CalculatePreferredValues(defaultFontSize, marginSize, false);
  3373. }
  3374. #endregion
  3375. // Adjust Point Size
  3376. m_maxFontSize = defaultFontSize;
  3377. defaultFontSize -= Mathf.Max((defaultFontSize - m_minFontSize) / 2, 0.05f);
  3378. defaultFontSize = (int)(Mathf.Max(defaultFontSize, m_fontSizeMin) * 20 + 0.5f) / 20f;
  3379. if (m_recursiveCount > 20) return new Vector2(renderedWidth, renderedHeight);
  3380. return CalculatePreferredValues(defaultFontSize, marginSize, false);
  3381. }
  3382. #endregion End Text Auto-Sizing
  3383. }
  3384. #endregion End Check for Characters Exceeding Width of Text Container
  3385. }
  3386. #endregion Handle Visible Characters
  3387. // Check if Line Spacing of previous line needs to be adjusted.
  3388. #region Adjust Line Spacing
  3389. if (m_lineNumber > 0 && !TMP_Math.Approximately(m_maxLineAscender, m_startOfLineAscender) && m_lineHeight == TMP_Math.FLOAT_UNSET && !m_isNewPage)
  3390. {
  3391. //Debug.Log("Inline - Adjusting Line Spacing on line #" + m_lineNumber);
  3392. //float gap = 0; // Compute gap.
  3393. float offsetDelta = m_maxLineAscender - m_startOfLineAscender;
  3394. //AdjustLineOffset(m_firstCharacterOfLine, m_characterCount, offsetDelta);
  3395. elementDescenderII -= offsetDelta;
  3396. m_lineOffset += offsetDelta;
  3397. m_startOfLineAscender += offsetDelta;
  3398. savedWordWrapState.lineOffset = m_lineOffset;
  3399. savedWordWrapState.previousLineAscender = m_startOfLineAscender;
  3400. }
  3401. #endregion
  3402. // Check if text Exceeds the vertical bounds of the margin area.
  3403. #region Check Vertical Bounds & Auto-Sizing
  3404. /*
  3405. if (m_maxAscender - elementDescenderII > marginHeight + 0.0001f)
  3406. {
  3407. // Handle Line spacing adjustments
  3408. #region Line Spacing Adjustments
  3409. if (m_enableAutoSizing && m_lineSpacingDelta > m_lineSpacingMax && m_lineNumber > 0)
  3410. {
  3411. //loopCountA = 0;
  3412. //m_lineSpacingDelta -= 1;
  3413. //GenerateTextMesh();
  3414. //return;
  3415. }
  3416. #endregion
  3417. // Handle Text Auto-sizing resulting from text exceeding vertical bounds.
  3418. #region Text Auto-Sizing (Text greater than vertical bounds)
  3419. if (m_enableAutoSizing && m_fontSize > m_fontSizeMin)
  3420. {
  3421. m_maxFontSize = m_fontSize;
  3422. m_fontSize -= Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f);
  3423. m_fontSize = (int)(Mathf.Max(m_fontSize, m_fontSizeMin) * 20 + 0.5f) / 20f;
  3424. //m_recursiveCount = 0;
  3425. //if (loopCountA > 20) return; // Added to debug
  3426. CalculatePreferredValues(m_fontSize, marginSize, false);
  3427. return Vector2.zero;
  3428. }
  3429. #endregion Text Auto-Sizing
  3430. }
  3431. */
  3432. #endregion Check Vertical Bounds
  3433. // Handle xAdvance & Tabulation Stops. Tab stops at every 25% of Font Size.
  3434. #region XAdvance, Tabulation & Stops
  3435. if (charCode == 9)
  3436. {
  3437. float tabSize = m_currentFontAsset.fontInfo.TabWidth * currentElementScale;
  3438. float tabs = Mathf.Ceil(m_xAdvance / tabSize) * tabSize;
  3439. m_xAdvance = tabs > m_xAdvance ? tabs : m_xAdvance + tabSize;
  3440. }
  3441. else if (m_monoSpacing != 0)
  3442. {
  3443. m_xAdvance += (m_monoSpacing - monoAdvance + ((m_characterSpacing + m_currentFontAsset.normalSpacingOffset) * currentElementScale) + m_cSpacing) * (1 - m_charWidthAdjDelta);
  3444. if (char.IsWhiteSpace((char)charCode) || charCode == 0x200B)
  3445. m_xAdvance += m_wordSpacing * currentElementScale;
  3446. }
  3447. else
  3448. {
  3449. m_xAdvance += ((m_cached_TextElement.xAdvance * bold_xAdvance_multiplier + m_characterSpacing + m_currentFontAsset.normalSpacingOffset + glyphAdjustments.xAdvance) * currentElementScale + m_cSpacing) * (1 - m_charWidthAdjDelta);
  3450. if (char.IsWhiteSpace((char)charCode) || charCode == 0x200B)
  3451. m_xAdvance += m_wordSpacing * currentElementScale;
  3452. }
  3453. #endregion Tabulation & Stops
  3454. // Handle Carriage Return
  3455. #region Carriage Return
  3456. if (charCode == 13)
  3457. {
  3458. maxXAdvance = Mathf.Max(maxXAdvance, renderedWidth + m_xAdvance);
  3459. renderedWidth = 0;
  3460. m_xAdvance = 0 + tag_Indent;
  3461. }
  3462. #endregion Carriage Return
  3463. // Handle Line Spacing Adjustments + Word Wrapping & special case for last line.
  3464. #region Check for Line Feed and Last Character
  3465. if (charCode == 10 || m_characterCount == totalCharacterCount - 1)
  3466. {
  3467. // Check if Line Spacing of previous line needs to be adjusted.
  3468. if (m_lineNumber > 0 && !TMP_Math.Approximately(m_maxLineAscender, m_startOfLineAscender) && m_lineHeight == TMP_Math.FLOAT_UNSET)
  3469. {
  3470. //Debug.Log("(2) Adjusting Line Spacing on line #" + m_lineNumber);
  3471. float offsetDelta = m_maxLineAscender - m_startOfLineAscender;
  3472. //AdjustLineOffset(m_firstCharacterOfLine, m_characterCount, offsetDelta);
  3473. elementDescenderII -= offsetDelta;
  3474. m_lineOffset += offsetDelta;
  3475. }
  3476. // Calculate lineAscender & make sure if last character is superscript or subscript that we check that as well.
  3477. //float lineAscender = m_maxLineAscender - m_lineOffset;
  3478. float lineDescender = m_maxLineDescender - m_lineOffset;
  3479. // Update maxDescender and maxVisibleDescender
  3480. m_maxDescender = m_maxDescender < lineDescender ? m_maxDescender : lineDescender;
  3481. m_firstCharacterOfLine = m_characterCount + 1;
  3482. // Store PreferredWidth paying attention to linefeed and last character of text.
  3483. if (charCode == 10 && m_characterCount != totalCharacterCount - 1)
  3484. {
  3485. maxXAdvance = Mathf.Max(maxXAdvance, renderedWidth + linebreakingWidth);
  3486. renderedWidth = 0;
  3487. }
  3488. else
  3489. renderedWidth = Mathf.Max(maxXAdvance, renderedWidth + linebreakingWidth);
  3490. renderedHeight = m_maxAscender - m_maxDescender;
  3491. // Add new line if not last lines or character.
  3492. if (charCode == 10)
  3493. {
  3494. // Store the state of the line before starting on the new line.
  3495. SaveWordWrappingState(ref savedLineState, i, m_characterCount);
  3496. // Store the state of the last Character before the new line.
  3497. SaveWordWrappingState(ref savedWordWrapState, i, m_characterCount);
  3498. m_lineNumber += 1;
  3499. // Apply Line Spacing
  3500. if (m_lineHeight == TMP_Math.FLOAT_UNSET)
  3501. {
  3502. lineOffsetDelta = 0 - m_maxLineDescender + elementAscender + (lineGap + m_lineSpacing + m_paragraphSpacing + m_lineSpacingDelta) * baseScale;
  3503. m_lineOffset += lineOffsetDelta;
  3504. }
  3505. else
  3506. m_lineOffset += m_lineHeight + (m_lineSpacing + m_paragraphSpacing) * baseScale;
  3507. m_maxLineAscender = k_LargeNegativeFloat;
  3508. m_maxLineDescender = k_LargePositiveFloat;
  3509. m_startOfLineAscender = elementAscender;
  3510. m_xAdvance = 0 + tag_LineIndent + tag_Indent;
  3511. m_characterCount += 1;
  3512. continue;
  3513. }
  3514. }
  3515. #endregion Check for Linefeed or Last Character
  3516. // Save State of Mesh Creation for handling of Word Wrapping
  3517. #region Save Word Wrapping State
  3518. if (m_enableWordWrapping || m_overflowMode == TextOverflowModes.Truncate || m_overflowMode == TextOverflowModes.Ellipsis)
  3519. {
  3520. if ((char.IsWhiteSpace((char)charCode) || charCode == 0x200B || charCode == 0x2D || charCode == 0xAD) && !m_isNonBreakingSpace && charCode != 0xA0 && charCode != 0x2011 && charCode != 0x202F && charCode != 0x2060)
  3521. {
  3522. // We store the state of numerous variables for the most recent Space, LineFeed or Carriage Return to enable them to be restored
  3523. // for Word Wrapping.
  3524. SaveWordWrappingState(ref savedWordWrapState, i, m_characterCount);
  3525. m_isCharacterWrappingEnabled = false;
  3526. isFirstWord = false;
  3527. }
  3528. // Handling for East Asian languages
  3529. else if ((charCode > 0x1100 && charCode < 0x11ff || /* Hangul Jamo */
  3530. charCode > 0x2E80 && charCode < 0x9FFF || /* CJK */
  3531. charCode > 0xA960 && charCode < 0xA97F || /* Hangul Jame Extended-A */
  3532. charCode > 0xAC00 && charCode < 0xD7FF || /* Hangul Syllables */
  3533. charCode > 0xF900 && charCode < 0xFAFF || /* CJK Compatibility Ideographs */
  3534. charCode > 0xFE30 && charCode < 0xFE4F || /* CJK Compatibility Forms */
  3535. charCode > 0xFF00 && charCode < 0xFFEF) /* CJK Halfwidth */
  3536. && !m_isNonBreakingSpace)
  3537. {
  3538. if (isFirstWord || isLastBreakingChar || TMP_Settings.linebreakingRules.leadingCharacters.ContainsKey(charCode) == false &&
  3539. (m_characterCount < totalCharacterCount - 1 &&
  3540. TMP_Settings.linebreakingRules.followingCharacters.ContainsKey(m_internalCharacterInfo[m_characterCount + 1].character) == false))
  3541. {
  3542. SaveWordWrappingState(ref savedWordWrapState, i, m_characterCount);
  3543. m_isCharacterWrappingEnabled = false;
  3544. isFirstWord = false;
  3545. }
  3546. }
  3547. else if ((isFirstWord || m_isCharacterWrappingEnabled == true || isLastBreakingChar))
  3548. SaveWordWrappingState(ref savedWordWrapState, i, m_characterCount);
  3549. }
  3550. #endregion Save Word Wrapping State
  3551. m_characterCount += 1;
  3552. }
  3553. // Check Auto Sizing and increase font size to fill text container.
  3554. #region Check Auto-Sizing (Upper Font Size Bounds)
  3555. fontSizeDelta = m_maxFontSize - m_minFontSize;
  3556. if (!m_isCharacterWrappingEnabled && ignoreTextAutoSizing == false && fontSizeDelta > 0.051f && defaultFontSize < m_fontSizeMax)
  3557. {
  3558. m_minFontSize = defaultFontSize;
  3559. defaultFontSize += Mathf.Max((m_maxFontSize - defaultFontSize) / 2, 0.05f);
  3560. defaultFontSize = (int)(Mathf.Min(defaultFontSize, m_fontSizeMax) * 20 + 0.5f) / 20f;
  3561. if (m_recursiveCount > 20) return new Vector2(renderedWidth, renderedHeight);
  3562. return CalculatePreferredValues(defaultFontSize, marginSize, false);
  3563. }
  3564. #endregion End Auto-sizing Check
  3565. m_isCharacterWrappingEnabled = false;
  3566. m_isCalculatingPreferredValues = false;
  3567. // Adjust Preferred Width and Height to account for Margins.
  3568. renderedWidth += m_margin.x > 0 ? m_margin.x : 0;
  3569. renderedWidth += m_margin.z > 0 ? m_margin.z : 0;
  3570. renderedHeight += m_margin.y > 0 ? m_margin.y : 0;
  3571. renderedHeight += m_margin.w > 0 ? m_margin.w : 0;
  3572. // Round Preferred Values to nearest 5/100.
  3573. renderedWidth = (int)(renderedWidth * 100 + 1f) / 100f;
  3574. renderedHeight = (int)(renderedHeight * 100 + 1f) / 100f;
  3575. //Debug.Log("Preferred Values: (" + renderedWidth + ", " + renderedHeight + ") with Recursive count of " + m_recursiveCount);
  3576. ////Profiler.EndSample();
  3577. return new Vector2(renderedWidth, renderedHeight);
  3578. }
  3579. /// <summary>
  3580. /// Method returning the compound bounds of the text object and child sub objects.
  3581. /// </summary>
  3582. /// <returns></returns>
  3583. protected virtual Bounds GetCompoundBounds() { return new Bounds(); }
  3584. /// <summary>
  3585. /// Method which returns the bounds of the text object;
  3586. /// </summary>
  3587. /// <returns></returns>
  3588. protected Bounds GetTextBounds()
  3589. {
  3590. if (m_textInfo == null || m_textInfo.characterCount > m_textInfo.characterInfo.Length) return new Bounds();
  3591. Extents extent = new Extents(k_LargePositiveVector2, k_LargeNegativeVector2);
  3592. for (int i = 0; i < m_textInfo.characterCount && i < m_textInfo.characterInfo.Length; i++)
  3593. {
  3594. if (!m_textInfo.characterInfo[i].isVisible) continue;
  3595. extent.min.x = Mathf.Min(extent.min.x, m_textInfo.characterInfo[i].bottomLeft.x);
  3596. extent.min.y = Mathf.Min(extent.min.y, m_textInfo.characterInfo[i].descender);
  3597. extent.max.x = Mathf.Max(extent.max.x, m_textInfo.characterInfo[i].xAdvance);
  3598. extent.max.y = Mathf.Max(extent.max.y, m_textInfo.characterInfo[i].ascender);
  3599. }
  3600. Vector2 size;
  3601. size.x = extent.max.x - extent.min.x;
  3602. size.y = extent.max.y - extent.min.y;
  3603. Vector3 center = (extent.min + extent.max) / 2;
  3604. return new Bounds(center, size);
  3605. }
  3606. /// <summary>
  3607. /// Method which returns the bounds of the text object;
  3608. /// </summary>
  3609. /// <param name="onlyVisibleCharacters"></param>
  3610. /// <returns></returns>
  3611. protected Bounds GetTextBounds(bool onlyVisibleCharacters)
  3612. {
  3613. if (m_textInfo == null) return new Bounds();
  3614. Extents extent = new Extents(k_LargePositiveVector2, k_LargeNegativeVector2);
  3615. for (int i = 0; i < m_textInfo.characterCount; i++)
  3616. {
  3617. if ((i > maxVisibleCharacters || m_textInfo.characterInfo[i].lineNumber > m_maxVisibleLines) && onlyVisibleCharacters) break;
  3618. if (onlyVisibleCharacters && !m_textInfo.characterInfo[i].isVisible) continue;
  3619. extent.min.x = Mathf.Min(extent.min.x, m_textInfo.characterInfo[i].origin);
  3620. extent.min.y = Mathf.Min(extent.min.y, m_textInfo.characterInfo[i].descender);
  3621. extent.max.x = Mathf.Max(extent.max.x, m_textInfo.characterInfo[i].xAdvance);
  3622. extent.max.y = Mathf.Max(extent.max.y, m_textInfo.characterInfo[i].ascender);
  3623. }
  3624. Vector2 size;
  3625. size.x = extent.max.x - extent.min.x;
  3626. size.y = extent.max.y - extent.min.y;
  3627. Vector2 center = (extent.min + extent.max) / 2;
  3628. return new Bounds(center, size);
  3629. }
  3630. /// <summary>
  3631. /// Method to adjust line spacing as a result of using different fonts or font point size.
  3632. /// </summary>
  3633. /// <param name="startIndex"></param>
  3634. /// <param name="endIndex"></param>
  3635. /// <param name="offset"></param>
  3636. protected virtual void AdjustLineOffset(int startIndex, int endIndex, float offset) { }
  3637. /// <summary>
  3638. /// Function to increase the size of the Line Extents Array.
  3639. /// </summary>
  3640. /// <param name="size"></param>
  3641. protected void ResizeLineExtents(int size)
  3642. {
  3643. size = size > 1024 ? size + 256 : Mathf.NextPowerOfTwo(size + 1);
  3644. TMP_LineInfo[] temp_lineInfo = new TMP_LineInfo[size];
  3645. for (int i = 0; i < size; i++)
  3646. {
  3647. if (i < m_textInfo.lineInfo.Length)
  3648. temp_lineInfo[i] = m_textInfo.lineInfo[i];
  3649. else
  3650. {
  3651. temp_lineInfo[i].lineExtents.min = k_LargePositiveVector2;
  3652. temp_lineInfo[i].lineExtents.max = k_LargeNegativeVector2;
  3653. temp_lineInfo[i].ascender = k_LargeNegativeFloat;
  3654. temp_lineInfo[i].descender = k_LargePositiveFloat;
  3655. }
  3656. }
  3657. m_textInfo.lineInfo = temp_lineInfo;
  3658. }
  3659. protected static Vector2 k_LargePositiveVector2 = new Vector2(TMP_Math.INT_MAX, TMP_Math.INT_MAX);
  3660. protected static Vector2 k_LargeNegativeVector2 = new Vector2(TMP_Math.INT_MIN, TMP_Math.INT_MIN);
  3661. protected static float k_LargePositiveFloat = TMP_Math.FLOAT_MAX;
  3662. protected static float k_LargeNegativeFloat = TMP_Math.FLOAT_MIN;
  3663. protected static int k_LargePositiveInt = TMP_Math.INT_MAX;
  3664. protected static int k_LargeNegativeInt = TMP_Math.INT_MIN;
  3665. /// <summary>
  3666. /// Function used to evaluate the length of a text string.
  3667. /// </summary>
  3668. /// <param name="text"></param>
  3669. /// <returns></returns>
  3670. public virtual TMP_TextInfo GetTextInfo(string text) { return null; }
  3671. /// <summary>
  3672. /// Function to force an update of the margin size.
  3673. /// </summary>
  3674. public virtual void ComputeMarginSize() { }
  3675. /// <summary>
  3676. /// Function used in conjunction with GetTextInfo to figure out Array allocations.
  3677. /// </summary>
  3678. /// <param name="chars"></param>
  3679. /// <returns></returns>
  3680. //protected int GetArraySizes(int[] chars)
  3681. //{
  3682. // //Debug.Log("Set Array Size called.");
  3683. // //int visibleCount = 0;
  3684. // //int totalCount = 0;
  3685. // int tagEnd = 0;
  3686. // m_totalCharacterCount = 0;
  3687. // m_isUsingBold = false;
  3688. // m_isParsingText = false;
  3689. // //m_VisibleCharacters.Clear();
  3690. // for (int i = 0; chars[i] != 0; i++)
  3691. // {
  3692. // int c = chars[i];
  3693. // if (m_isRichText && c == 60) // if Char '<'
  3694. // {
  3695. // // Check if Tag is Valid
  3696. // if (ValidateHtmlTag(chars, i + 1, out tagEnd))
  3697. // {
  3698. // i = tagEnd;
  3699. // //if ((m_style & FontStyles.Underline) == FontStyles.Underline) visibleCount += 3;
  3700. // if ((m_style & FontStyles.Bold) == FontStyles.Bold) m_isUsingBold = true;
  3701. // continue;
  3702. // }
  3703. // }
  3704. // //if (!char.IsWhiteSpace((char)c) && c != 0x200B)
  3705. // //{
  3706. // //visibleCount += 1;
  3707. // //}
  3708. // //m_VisibleCharacters.Add((char)c);
  3709. // m_totalCharacterCount += 1;
  3710. // }
  3711. // return m_totalCharacterCount;
  3712. //}
  3713. /// <summary>
  3714. /// Save the State of various variables used in the mesh creation loop in conjunction with Word Wrapping
  3715. /// </summary>
  3716. /// <param name="state"></param>
  3717. /// <param name="index"></param>
  3718. /// <param name="count"></param>
  3719. protected void SaveWordWrappingState(ref WordWrapState state, int index, int count)
  3720. {
  3721. // Multi Font & Material support related
  3722. state.currentFontAsset = m_currentFontAsset;
  3723. state.currentSpriteAsset = m_currentSpriteAsset;
  3724. state.currentMaterial = m_currentMaterial;
  3725. state.currentMaterialIndex = m_currentMaterialIndex;
  3726. state.previous_WordBreak = index;
  3727. state.total_CharacterCount = count;
  3728. state.visible_CharacterCount = m_lineVisibleCharacterCount;
  3729. //state.visible_CharacterCount = m_visibleCharacterCount;
  3730. //state.visible_SpriteCount = m_visibleSpriteCount;
  3731. state.visible_LinkCount = m_textInfo.linkCount;
  3732. state.firstCharacterIndex = m_firstCharacterOfLine;
  3733. state.firstVisibleCharacterIndex = m_firstVisibleCharacterOfLine;
  3734. state.lastVisibleCharIndex = m_lastVisibleCharacterOfLine;
  3735. state.fontStyle = m_style;
  3736. state.fontScale = m_fontScale;
  3737. //state.maxFontScale = m_maxFontScale;
  3738. state.fontScaleMultiplier = m_fontScaleMultiplier;
  3739. state.currentFontSize = m_currentFontSize;
  3740. state.xAdvance = m_xAdvance;
  3741. state.maxCapHeight = m_maxCapHeight;
  3742. state.maxAscender = m_maxAscender;
  3743. state.maxDescender = m_maxDescender;
  3744. state.maxLineAscender = m_maxLineAscender;
  3745. state.maxLineDescender = m_maxLineDescender;
  3746. state.previousLineAscender = m_startOfLineAscender;
  3747. state.preferredWidth = m_preferredWidth;
  3748. state.preferredHeight = m_preferredHeight;
  3749. state.meshExtents = m_meshExtents;
  3750. state.lineNumber = m_lineNumber;
  3751. state.lineOffset = m_lineOffset;
  3752. state.baselineOffset = m_baselineOffset;
  3753. //state.alignment = m_lineJustification;
  3754. state.vertexColor = m_htmlColor;
  3755. state.underlineColor = m_underlineColor;
  3756. state.strikethroughColor = m_strikethroughColor;
  3757. state.highlightColor = m_highlightColor;
  3758. state.isNonBreakingSpace = m_isNonBreakingSpace;
  3759. state.tagNoParsing = tag_NoParsing;
  3760. // XML Tag Stack
  3761. state.basicStyleStack = m_fontStyleStack;
  3762. state.colorStack = m_colorStack;
  3763. state.underlineColorStack = m_underlineColorStack;
  3764. state.strikethroughColorStack = m_strikethroughColorStack;
  3765. state.highlightColorStack = m_highlightColorStack;
  3766. state.colorGradientStack = m_colorGradientStack;
  3767. state.sizeStack = m_sizeStack;
  3768. state.indentStack = m_indentStack;
  3769. state.fontWeightStack = m_fontWeightStack;
  3770. state.styleStack = m_styleStack;
  3771. state.baselineStack = m_baselineOffsetStack;
  3772. state.actionStack = m_actionStack;
  3773. state.materialReferenceStack = m_materialReferenceStack;
  3774. state.lineJustificationStack = m_lineJustificationStack;
  3775. //state.spriteAnimationStack = m_spriteAnimationStack;
  3776. state.spriteAnimationID = m_spriteAnimationID;
  3777. if (m_lineNumber < m_textInfo.lineInfo.Length)
  3778. state.lineInfo = m_textInfo.lineInfo[m_lineNumber];
  3779. }
  3780. /// <summary>
  3781. /// Restore the State of various variables used in the mesh creation loop.
  3782. /// </summary>
  3783. /// <param name="state"></param>
  3784. /// <returns></returns>
  3785. protected int RestoreWordWrappingState(ref WordWrapState state)
  3786. {
  3787. int index = state.previous_WordBreak;
  3788. // Multi Font & Material support related
  3789. m_currentFontAsset = state.currentFontAsset;
  3790. m_currentSpriteAsset = state.currentSpriteAsset;
  3791. m_currentMaterial = state.currentMaterial;
  3792. m_currentMaterialIndex = state.currentMaterialIndex;
  3793. m_characterCount = state.total_CharacterCount + 1;
  3794. m_lineVisibleCharacterCount = state.visible_CharacterCount;
  3795. //m_visibleCharacterCount = state.visible_CharacterCount;
  3796. //m_visibleSpriteCount = state.visible_SpriteCount;
  3797. m_textInfo.linkCount = state.visible_LinkCount;
  3798. m_firstCharacterOfLine = state.firstCharacterIndex;
  3799. m_firstVisibleCharacterOfLine = state.firstVisibleCharacterIndex;
  3800. m_lastVisibleCharacterOfLine = state.lastVisibleCharIndex;
  3801. m_style = state.fontStyle;
  3802. m_fontScale = state.fontScale;
  3803. m_fontScaleMultiplier = state.fontScaleMultiplier;
  3804. //m_maxFontScale = state.maxFontScale;
  3805. m_currentFontSize = state.currentFontSize;
  3806. m_xAdvance = state.xAdvance;
  3807. m_maxCapHeight = state.maxCapHeight;
  3808. m_maxAscender = state.maxAscender;
  3809. m_maxDescender = state.maxDescender;
  3810. m_maxLineAscender = state.maxLineAscender;
  3811. m_maxLineDescender = state.maxLineDescender;
  3812. m_startOfLineAscender = state.previousLineAscender;
  3813. m_preferredWidth = state.preferredWidth;
  3814. m_preferredHeight = state.preferredHeight;
  3815. m_meshExtents = state.meshExtents;
  3816. m_lineNumber = state.lineNumber;
  3817. m_lineOffset = state.lineOffset;
  3818. m_baselineOffset = state.baselineOffset;
  3819. //m_lineJustification = state.alignment;
  3820. m_htmlColor = state.vertexColor;
  3821. m_underlineColor = state.underlineColor;
  3822. m_strikethroughColor = state.strikethroughColor;
  3823. m_highlightColor = state.highlightColor;
  3824. m_isNonBreakingSpace = state.isNonBreakingSpace;
  3825. tag_NoParsing = state.tagNoParsing;
  3826. // XML Tag Stack
  3827. m_fontStyleStack = state.basicStyleStack;
  3828. m_colorStack = state.colorStack;
  3829. m_underlineColorStack = state.underlineColorStack;
  3830. m_strikethroughColorStack = state.strikethroughColorStack;
  3831. m_highlightColorStack = state.highlightColorStack;
  3832. m_colorGradientStack = state.colorGradientStack;
  3833. m_sizeStack = state.sizeStack;
  3834. m_indentStack = state.indentStack;
  3835. m_fontWeightStack = state.fontWeightStack;
  3836. m_styleStack = state.styleStack;
  3837. m_baselineOffsetStack = state.baselineStack;
  3838. m_actionStack = state.actionStack;
  3839. m_materialReferenceStack = state.materialReferenceStack;
  3840. m_lineJustificationStack = state.lineJustificationStack;
  3841. //m_spriteAnimationStack = state.spriteAnimationStack;
  3842. m_spriteAnimationID = state.spriteAnimationID;
  3843. if (m_lineNumber < m_textInfo.lineInfo.Length)
  3844. m_textInfo.lineInfo[m_lineNumber] = state.lineInfo;
  3845. return index;
  3846. }
  3847. /// <summary>
  3848. /// Store vertex information for each character.
  3849. /// </summary>
  3850. /// <param name="style_padding">Style_padding.</param>
  3851. /// <param name="vertexColor">Vertex color.</param>
  3852. protected virtual void SaveGlyphVertexInfo(float padding, float style_padding, Color32 vertexColor)
  3853. {
  3854. // Save the Vertex Position for the Character
  3855. #region Setup Mesh Vertices
  3856. m_textInfo.characterInfo[m_characterCount].vertex_BL.position = m_textInfo.characterInfo[m_characterCount].bottomLeft;
  3857. m_textInfo.characterInfo[m_characterCount].vertex_TL.position = m_textInfo.characterInfo[m_characterCount].topLeft;
  3858. m_textInfo.characterInfo[m_characterCount].vertex_TR.position = m_textInfo.characterInfo[m_characterCount].topRight;
  3859. m_textInfo.characterInfo[m_characterCount].vertex_BR.position = m_textInfo.characterInfo[m_characterCount].bottomRight;
  3860. #endregion
  3861. #region Setup Vertex Colors
  3862. // Alpha is the lower of the vertex color or tag color alpha used.
  3863. vertexColor.a = m_fontColor32.a < vertexColor.a ? (byte)(m_fontColor32.a) : (byte)(vertexColor.a);
  3864. // Handle Vertex Colors & Vertex Color Gradient
  3865. if (!m_enableVertexGradient)
  3866. {
  3867. m_textInfo.characterInfo[m_characterCount].vertex_BL.color = vertexColor;
  3868. m_textInfo.characterInfo[m_characterCount].vertex_TL.color = vertexColor;
  3869. m_textInfo.characterInfo[m_characterCount].vertex_TR.color = vertexColor;
  3870. m_textInfo.characterInfo[m_characterCount].vertex_BR.color = vertexColor;
  3871. }
  3872. else
  3873. {
  3874. if (!m_overrideHtmlColors && m_colorStack.index > 1)
  3875. {
  3876. m_textInfo.characterInfo[m_characterCount].vertex_BL.color = vertexColor;
  3877. m_textInfo.characterInfo[m_characterCount].vertex_TL.color = vertexColor;
  3878. m_textInfo.characterInfo[m_characterCount].vertex_TR.color = vertexColor;
  3879. m_textInfo.characterInfo[m_characterCount].vertex_BR.color = vertexColor;
  3880. }
  3881. else // Handle Vertex Color Gradient
  3882. {
  3883. // Use Vertex Color Gradient Preset (if one is assigned)
  3884. if (m_fontColorGradientPreset != null)
  3885. {
  3886. m_textInfo.characterInfo[m_characterCount].vertex_BL.color = m_fontColorGradientPreset.bottomLeft * vertexColor;
  3887. m_textInfo.characterInfo[m_characterCount].vertex_TL.color = m_fontColorGradientPreset.topLeft * vertexColor;
  3888. m_textInfo.characterInfo[m_characterCount].vertex_TR.color = m_fontColorGradientPreset.topRight * vertexColor;
  3889. m_textInfo.characterInfo[m_characterCount].vertex_BR.color = m_fontColorGradientPreset.bottomRight * vertexColor;
  3890. }
  3891. else
  3892. {
  3893. m_textInfo.characterInfo[m_characterCount].vertex_BL.color = m_fontColorGradient.bottomLeft * vertexColor;
  3894. m_textInfo.characterInfo[m_characterCount].vertex_TL.color = m_fontColorGradient.topLeft * vertexColor;
  3895. m_textInfo.characterInfo[m_characterCount].vertex_TR.color = m_fontColorGradient.topRight * vertexColor;
  3896. m_textInfo.characterInfo[m_characterCount].vertex_BR.color = m_fontColorGradient.bottomRight * vertexColor;
  3897. }
  3898. }
  3899. }
  3900. if (m_colorGradientPreset != null)
  3901. {
  3902. m_textInfo.characterInfo[m_characterCount].vertex_BL.color *= m_colorGradientPreset.bottomLeft;
  3903. m_textInfo.characterInfo[m_characterCount].vertex_TL.color *= m_colorGradientPreset.topLeft;
  3904. m_textInfo.characterInfo[m_characterCount].vertex_TR.color *= m_colorGradientPreset.topRight;
  3905. m_textInfo.characterInfo[m_characterCount].vertex_BR.color *= m_colorGradientPreset.bottomRight;
  3906. }
  3907. #endregion
  3908. // Apply style_padding only if this is a SDF Shader.
  3909. if (!m_isSDFShader)
  3910. style_padding = 0;
  3911. // Setup UVs for the Character
  3912. #region Setup UVs
  3913. FaceInfo faceInfo = m_currentFontAsset.fontInfo;
  3914. Vector2 uv0;
  3915. uv0.x = (m_cached_TextElement.x - padding - style_padding) / faceInfo.AtlasWidth;
  3916. uv0.y = 1 - (m_cached_TextElement.y + padding + style_padding + m_cached_TextElement.height) / faceInfo.AtlasHeight;
  3917. Vector2 uv1;
  3918. uv1.x = uv0.x;
  3919. uv1.y = 1 - (m_cached_TextElement.y - padding - style_padding) / faceInfo.AtlasHeight;
  3920. Vector2 uv2;
  3921. uv2.x = (m_cached_TextElement.x + padding + style_padding + m_cached_TextElement.width) / faceInfo.AtlasWidth;
  3922. uv2.y = uv1.y;
  3923. Vector2 uv3;
  3924. uv3.x = uv2.x;
  3925. uv3.y = uv0.y;
  3926. //Vector2 uv0 = new Vector2((m_cached_TextElement.x - padding - style_padding) / faceInfo.AtlasWidth, 1 - (m_cached_TextElement.y + padding + style_padding + m_cached_TextElement.height) / faceInfo.AtlasHeight); // bottom left
  3927. //Vector2 uv1 = new Vector2(uv0.x, 1 - (m_cached_TextElement.y - padding - style_padding) / faceInfo.AtlasHeight); // top left
  3928. //Vector2 uv2 = new Vector2((m_cached_TextElement.x + padding + style_padding + m_cached_TextElement.width) / faceInfo.AtlasWidth, uv1.y); // top right
  3929. //Vector2 uv3 = new Vector2(uv2.x, uv0.y); // bottom right
  3930. // Store UV Information
  3931. m_textInfo.characterInfo[m_characterCount].vertex_BL.uv = uv0;
  3932. m_textInfo.characterInfo[m_characterCount].vertex_TL.uv = uv1;
  3933. m_textInfo.characterInfo[m_characterCount].vertex_TR.uv = uv2;
  3934. m_textInfo.characterInfo[m_characterCount].vertex_BR.uv = uv3;
  3935. #endregion Setup UVs
  3936. // Normal
  3937. #region Setup Normals & Tangents
  3938. //Vector3 normal = new Vector3(0, 0, -1);
  3939. //m_textInfo.characterInfo[m_characterCount].vertex_BL.normal = normal;
  3940. //m_textInfo.characterInfo[m_characterCount].vertex_TL.normal = normal;
  3941. //m_textInfo.characterInfo[m_characterCount].vertex_TR.normal = normal;
  3942. //m_textInfo.characterInfo[m_characterCount].vertex_BR.normal = normal;
  3943. // Tangents
  3944. //Vector4 tangent = new Vector4(-1, 0, 0, 1);
  3945. //m_textInfo.characterInfo[m_characterCount].vertex_BL.tangent = tangent;
  3946. //m_textInfo.characterInfo[m_characterCount].vertex_TL.tangent = tangent;
  3947. //m_textInfo.characterInfo[m_characterCount].vertex_TR.tangent = tangent;
  3948. //m_textInfo.characterInfo[m_characterCount].vertex_BR.tangent = tangent;
  3949. #endregion end Normals & Tangents
  3950. }
  3951. /// <summary>
  3952. /// Store vertex information for each sprite.
  3953. /// </summary>
  3954. /// <param name="padding"></param>
  3955. /// <param name="style_padding"></param>
  3956. /// <param name="vertexColor"></param>
  3957. protected virtual void SaveSpriteVertexInfo(Color32 vertexColor)
  3958. {
  3959. // Save the Vertex Position for the Character
  3960. #region Setup Mesh Vertices
  3961. m_textInfo.characterInfo[m_characterCount].vertex_BL.position = m_textInfo.characterInfo[m_characterCount].bottomLeft;
  3962. m_textInfo.characterInfo[m_characterCount].vertex_TL.position = m_textInfo.characterInfo[m_characterCount].topLeft;
  3963. m_textInfo.characterInfo[m_characterCount].vertex_TR.position = m_textInfo.characterInfo[m_characterCount].topRight;
  3964. m_textInfo.characterInfo[m_characterCount].vertex_BR.position = m_textInfo.characterInfo[m_characterCount].bottomRight;
  3965. #endregion
  3966. // Vertex Color Alpha
  3967. if (m_tintAllSprites) m_tintSprite = true;
  3968. Color32 spriteColor = m_tintSprite ? m_spriteColor.Multiply(vertexColor) : m_spriteColor;
  3969. spriteColor.a = spriteColor.a < m_fontColor32.a ? spriteColor.a = spriteColor.a < vertexColor.a ? spriteColor.a : vertexColor.a : m_fontColor32.a;
  3970. Color32 c0 = spriteColor;
  3971. Color32 c1 = spriteColor;
  3972. Color32 c2 = spriteColor;
  3973. Color32 c3 = spriteColor;
  3974. if (m_enableVertexGradient)
  3975. {
  3976. if (m_fontColorGradientPreset != null)
  3977. {
  3978. c0 = m_tintSprite ? c0.Multiply(m_fontColorGradientPreset.bottomLeft) : c0;
  3979. c1 = m_tintSprite ? c1.Multiply(m_fontColorGradientPreset.topLeft) : c1;
  3980. c2 = m_tintSprite ? c2.Multiply(m_fontColorGradientPreset.topRight) : c2;
  3981. c3 = m_tintSprite ? c3.Multiply(m_fontColorGradientPreset.bottomRight) : c3;
  3982. }
  3983. else
  3984. {
  3985. c0 = m_tintSprite ? c0.Multiply(m_fontColorGradient.bottomLeft) : c0;
  3986. c1 = m_tintSprite ? c1.Multiply(m_fontColorGradient.topLeft) : c1;
  3987. c2 = m_tintSprite ? c2.Multiply(m_fontColorGradient.topRight) : c2;
  3988. c3 = m_tintSprite ? c3.Multiply(m_fontColorGradient.bottomRight) : c3;
  3989. }
  3990. }
  3991. if (m_colorGradientPreset != null)
  3992. {
  3993. c0 = m_tintSprite ? c0.Multiply(m_colorGradientPreset.bottomLeft) : c0;
  3994. c1 = m_tintSprite ? c1.Multiply(m_colorGradientPreset.topLeft) : c1;
  3995. c2 = m_tintSprite ? c2.Multiply(m_colorGradientPreset.topRight) : c2;
  3996. c3 = m_tintSprite ? c3.Multiply(m_colorGradientPreset.bottomRight) : c3;
  3997. }
  3998. m_textInfo.characterInfo[m_characterCount].vertex_BL.color = c0;
  3999. m_textInfo.characterInfo[m_characterCount].vertex_TL.color = c1;
  4000. m_textInfo.characterInfo[m_characterCount].vertex_TR.color = c2;
  4001. m_textInfo.characterInfo[m_characterCount].vertex_BR.color = c3;
  4002. // Setup UVs for the Character
  4003. #region Setup UVs
  4004. Vector2 uv0 = new Vector2(m_cached_TextElement.x / m_currentSpriteAsset.spriteSheet.width, m_cached_TextElement.y / m_currentSpriteAsset.spriteSheet.height); // bottom left
  4005. Vector2 uv1 = new Vector2(uv0.x, (m_cached_TextElement.y + m_cached_TextElement.height) / m_currentSpriteAsset.spriteSheet.height); // top left
  4006. Vector2 uv2 = new Vector2((m_cached_TextElement.x + m_cached_TextElement.width) / m_currentSpriteAsset.spriteSheet.width, uv1.y); // top right
  4007. Vector2 uv3 = new Vector2(uv2.x, uv0.y); // bottom right
  4008. // Store UV Information
  4009. m_textInfo.characterInfo[m_characterCount].vertex_BL.uv = uv0;
  4010. m_textInfo.characterInfo[m_characterCount].vertex_TL.uv = uv1;
  4011. m_textInfo.characterInfo[m_characterCount].vertex_TR.uv = uv2;
  4012. m_textInfo.characterInfo[m_characterCount].vertex_BR.uv = uv3;
  4013. #endregion Setup UVs
  4014. // Normal
  4015. #region Setup Normals & Tangents
  4016. //Vector3 normal = new Vector3(0, 0, -1);
  4017. //m_textInfo.characterInfo[m_characterCount].vertex_BL.normal = normal;
  4018. //m_textInfo.characterInfo[m_characterCount].vertex_TL.normal = normal;
  4019. //m_textInfo.characterInfo[m_characterCount].vertex_TR.normal = normal;
  4020. //m_textInfo.characterInfo[m_characterCount].vertex_BR.normal = normal;
  4021. // Tangents
  4022. //Vector4 tangent = new Vector4(-1, 0, 0, 1);
  4023. //m_textInfo.characterInfo[m_characterCount].vertex_BL.tangent = tangent;
  4024. //m_textInfo.characterInfo[m_characterCount].vertex_TL.tangent = tangent;
  4025. //m_textInfo.characterInfo[m_characterCount].vertex_TR.tangent = tangent;
  4026. //m_textInfo.characterInfo[m_characterCount].vertex_BR.tangent = tangent;
  4027. #endregion end Normals & Tangents
  4028. }
  4029. /// <summary>
  4030. /// Store vertex attributes into the appropriate TMP_MeshInfo.
  4031. /// </summary>
  4032. /// <param name="i"></param>
  4033. /// <param name="index_X4"></param>
  4034. protected virtual void FillCharacterVertexBuffers(int i, int index_X4)
  4035. {
  4036. int materialIndex = m_textInfo.characterInfo[i].materialReferenceIndex;
  4037. index_X4 = m_textInfo.meshInfo[materialIndex].vertexCount;
  4038. // Make sure buffers allocation are sufficient to hold the vertex data
  4039. //if (m_textInfo.meshInfo[materialIndex].vertices.Length < index_X4 + 4)
  4040. // m_textInfo.meshInfo[materialIndex].ResizeMeshInfo(Mathf.NextPowerOfTwo(index_X4 + 4));
  4041. TMP_CharacterInfo[] characterInfoArray = m_textInfo.characterInfo;
  4042. m_textInfo.characterInfo[i].vertexIndex = index_X4;
  4043. // Setup Vertices for Characters
  4044. m_textInfo.meshInfo[materialIndex].vertices[0 + index_X4] = characterInfoArray[i].vertex_BL.position;
  4045. m_textInfo.meshInfo[materialIndex].vertices[1 + index_X4] = characterInfoArray[i].vertex_TL.position;
  4046. m_textInfo.meshInfo[materialIndex].vertices[2 + index_X4] = characterInfoArray[i].vertex_TR.position;
  4047. m_textInfo.meshInfo[materialIndex].vertices[3 + index_X4] = characterInfoArray[i].vertex_BR.position;
  4048. // Setup UVS0
  4049. m_textInfo.meshInfo[materialIndex].uvs0[0 + index_X4] = characterInfoArray[i].vertex_BL.uv;
  4050. m_textInfo.meshInfo[materialIndex].uvs0[1 + index_X4] = characterInfoArray[i].vertex_TL.uv;
  4051. m_textInfo.meshInfo[materialIndex].uvs0[2 + index_X4] = characterInfoArray[i].vertex_TR.uv;
  4052. m_textInfo.meshInfo[materialIndex].uvs0[3 + index_X4] = characterInfoArray[i].vertex_BR.uv;
  4053. // Setup UVS2
  4054. m_textInfo.meshInfo[materialIndex].uvs2[0 + index_X4] = characterInfoArray[i].vertex_BL.uv2;
  4055. m_textInfo.meshInfo[materialIndex].uvs2[1 + index_X4] = characterInfoArray[i].vertex_TL.uv2;
  4056. m_textInfo.meshInfo[materialIndex].uvs2[2 + index_X4] = characterInfoArray[i].vertex_TR.uv2;
  4057. m_textInfo.meshInfo[materialIndex].uvs2[3 + index_X4] = characterInfoArray[i].vertex_BR.uv2;
  4058. // Setup UVS4
  4059. //m_textInfo.meshInfo[0].uvs4[0 + index_X4] = characterInfoArray[i].vertex_BL.uv4;
  4060. //m_textInfo.meshInfo[0].uvs4[1 + index_X4] = characterInfoArray[i].vertex_TL.uv4;
  4061. //m_textInfo.meshInfo[0].uvs4[2 + index_X4] = characterInfoArray[i].vertex_TR.uv4;
  4062. //m_textInfo.meshInfo[0].uvs4[3 + index_X4] = characterInfoArray[i].vertex_BR.uv4;
  4063. // setup Vertex Colors
  4064. m_textInfo.meshInfo[materialIndex].colors32[0 + index_X4] = characterInfoArray[i].vertex_BL.color;
  4065. m_textInfo.meshInfo[materialIndex].colors32[1 + index_X4] = characterInfoArray[i].vertex_TL.color;
  4066. m_textInfo.meshInfo[materialIndex].colors32[2 + index_X4] = characterInfoArray[i].vertex_TR.color;
  4067. m_textInfo.meshInfo[materialIndex].colors32[3 + index_X4] = characterInfoArray[i].vertex_BR.color;
  4068. m_textInfo.meshInfo[materialIndex].vertexCount = index_X4 + 4;
  4069. }
  4070. protected virtual void FillCharacterVertexBuffers(int i, int index_X4, bool isVolumetric)
  4071. {
  4072. int materialIndex = m_textInfo.characterInfo[i].materialReferenceIndex;
  4073. index_X4 = m_textInfo.meshInfo[materialIndex].vertexCount;
  4074. TMP_CharacterInfo[] characterInfoArray = m_textInfo.characterInfo;
  4075. m_textInfo.characterInfo[i].vertexIndex = index_X4;
  4076. // Setup Vertices for Characters
  4077. m_textInfo.meshInfo[materialIndex].vertices[0 + index_X4] = characterInfoArray[i].vertex_BL.position;
  4078. m_textInfo.meshInfo[materialIndex].vertices[1 + index_X4] = characterInfoArray[i].vertex_TL.position;
  4079. m_textInfo.meshInfo[materialIndex].vertices[2 + index_X4] = characterInfoArray[i].vertex_TR.position;
  4080. m_textInfo.meshInfo[materialIndex].vertices[3 + index_X4] = characterInfoArray[i].vertex_BR.position;
  4081. if (isVolumetric)
  4082. {
  4083. Vector3 depth = new Vector3(0, 0, m_fontSize * m_fontScale);
  4084. m_textInfo.meshInfo[materialIndex].vertices[4 + index_X4] = characterInfoArray[i].vertex_BL.position + depth;
  4085. m_textInfo.meshInfo[materialIndex].vertices[5 + index_X4] = characterInfoArray[i].vertex_TL.position + depth;
  4086. m_textInfo.meshInfo[materialIndex].vertices[6 + index_X4] = characterInfoArray[i].vertex_TR.position + depth;
  4087. m_textInfo.meshInfo[materialIndex].vertices[7 + index_X4] = characterInfoArray[i].vertex_BR.position + depth;
  4088. }
  4089. // Setup UVS0
  4090. m_textInfo.meshInfo[materialIndex].uvs0[0 + index_X4] = characterInfoArray[i].vertex_BL.uv;
  4091. m_textInfo.meshInfo[materialIndex].uvs0[1 + index_X4] = characterInfoArray[i].vertex_TL.uv;
  4092. m_textInfo.meshInfo[materialIndex].uvs0[2 + index_X4] = characterInfoArray[i].vertex_TR.uv;
  4093. m_textInfo.meshInfo[materialIndex].uvs0[3 + index_X4] = characterInfoArray[i].vertex_BR.uv;
  4094. if (isVolumetric)
  4095. {
  4096. m_textInfo.meshInfo[materialIndex].uvs0[4 + index_X4] = characterInfoArray[i].vertex_BL.uv;
  4097. m_textInfo.meshInfo[materialIndex].uvs0[5 + index_X4] = characterInfoArray[i].vertex_TL.uv;
  4098. m_textInfo.meshInfo[materialIndex].uvs0[6 + index_X4] = characterInfoArray[i].vertex_TR.uv;
  4099. m_textInfo.meshInfo[materialIndex].uvs0[7 + index_X4] = characterInfoArray[i].vertex_BR.uv;
  4100. }
  4101. // Setup UVS2
  4102. m_textInfo.meshInfo[materialIndex].uvs2[0 + index_X4] = characterInfoArray[i].vertex_BL.uv2;
  4103. m_textInfo.meshInfo[materialIndex].uvs2[1 + index_X4] = characterInfoArray[i].vertex_TL.uv2;
  4104. m_textInfo.meshInfo[materialIndex].uvs2[2 + index_X4] = characterInfoArray[i].vertex_TR.uv2;
  4105. m_textInfo.meshInfo[materialIndex].uvs2[3 + index_X4] = characterInfoArray[i].vertex_BR.uv2;
  4106. if (isVolumetric)
  4107. {
  4108. m_textInfo.meshInfo[materialIndex].uvs2[4 + index_X4] = characterInfoArray[i].vertex_BL.uv2;
  4109. m_textInfo.meshInfo[materialIndex].uvs2[5 + index_X4] = characterInfoArray[i].vertex_TL.uv2;
  4110. m_textInfo.meshInfo[materialIndex].uvs2[6 + index_X4] = characterInfoArray[i].vertex_TR.uv2;
  4111. m_textInfo.meshInfo[materialIndex].uvs2[7 + index_X4] = characterInfoArray[i].vertex_BR.uv2;
  4112. }
  4113. // Setup UVS4
  4114. //m_textInfo.meshInfo[0].uvs4[0 + index_X4] = characterInfoArray[i].vertex_BL.uv4;
  4115. //m_textInfo.meshInfo[0].uvs4[1 + index_X4] = characterInfoArray[i].vertex_TL.uv4;
  4116. //m_textInfo.meshInfo[0].uvs4[2 + index_X4] = characterInfoArray[i].vertex_TR.uv4;
  4117. //m_textInfo.meshInfo[0].uvs4[3 + index_X4] = characterInfoArray[i].vertex_BR.uv4;
  4118. // setup Vertex Colors
  4119. m_textInfo.meshInfo[materialIndex].colors32[0 + index_X4] = characterInfoArray[i].vertex_BL.color;
  4120. m_textInfo.meshInfo[materialIndex].colors32[1 + index_X4] = characterInfoArray[i].vertex_TL.color;
  4121. m_textInfo.meshInfo[materialIndex].colors32[2 + index_X4] = characterInfoArray[i].vertex_TR.color;
  4122. m_textInfo.meshInfo[materialIndex].colors32[3 + index_X4] = characterInfoArray[i].vertex_BR.color;
  4123. if (isVolumetric)
  4124. {
  4125. Color32 backColor = new Color32(255, 255, 128, 255);
  4126. m_textInfo.meshInfo[materialIndex].colors32[4 + index_X4] = backColor; //characterInfoArray[i].vertex_BL.color;
  4127. m_textInfo.meshInfo[materialIndex].colors32[5 + index_X4] = backColor; //characterInfoArray[i].vertex_TL.color;
  4128. m_textInfo.meshInfo[materialIndex].colors32[6 + index_X4] = backColor; //characterInfoArray[i].vertex_TR.color;
  4129. m_textInfo.meshInfo[materialIndex].colors32[7 + index_X4] = backColor; //characterInfoArray[i].vertex_BR.color;
  4130. }
  4131. m_textInfo.meshInfo[materialIndex].vertexCount = index_X4 + (!isVolumetric ? 4 : 8);
  4132. }
  4133. /// <summary>
  4134. /// Fill Vertex Buffers for Sprites
  4135. /// </summary>
  4136. /// <param name="i"></param>
  4137. /// <param name="spriteIndex_X4"></param>
  4138. protected virtual void FillSpriteVertexBuffers(int i, int index_X4)
  4139. {
  4140. int materialIndex = m_textInfo.characterInfo[i].materialReferenceIndex;
  4141. index_X4 = m_textInfo.meshInfo[materialIndex].vertexCount;
  4142. TMP_CharacterInfo[] characterInfoArray = m_textInfo.characterInfo;
  4143. m_textInfo.characterInfo[i].vertexIndex = index_X4;
  4144. // Setup Vertices for Characters
  4145. m_textInfo.meshInfo[materialIndex].vertices[0 + index_X4] = characterInfoArray[i].vertex_BL.position;
  4146. m_textInfo.meshInfo[materialIndex].vertices[1 + index_X4] = characterInfoArray[i].vertex_TL.position;
  4147. m_textInfo.meshInfo[materialIndex].vertices[2 + index_X4] = characterInfoArray[i].vertex_TR.position;
  4148. m_textInfo.meshInfo[materialIndex].vertices[3 + index_X4] = characterInfoArray[i].vertex_BR.position;
  4149. // Setup UVS0
  4150. m_textInfo.meshInfo[materialIndex].uvs0[0 + index_X4] = characterInfoArray[i].vertex_BL.uv;
  4151. m_textInfo.meshInfo[materialIndex].uvs0[1 + index_X4] = characterInfoArray[i].vertex_TL.uv;
  4152. m_textInfo.meshInfo[materialIndex].uvs0[2 + index_X4] = characterInfoArray[i].vertex_TR.uv;
  4153. m_textInfo.meshInfo[materialIndex].uvs0[3 + index_X4] = characterInfoArray[i].vertex_BR.uv;
  4154. // Setup UVS2
  4155. m_textInfo.meshInfo[materialIndex].uvs2[0 + index_X4] = characterInfoArray[i].vertex_BL.uv2;
  4156. m_textInfo.meshInfo[materialIndex].uvs2[1 + index_X4] = characterInfoArray[i].vertex_TL.uv2;
  4157. m_textInfo.meshInfo[materialIndex].uvs2[2 + index_X4] = characterInfoArray[i].vertex_TR.uv2;
  4158. m_textInfo.meshInfo[materialIndex].uvs2[3 + index_X4] = characterInfoArray[i].vertex_BR.uv2;
  4159. // Setup UVS4
  4160. //m_textInfo.meshInfo[0].uvs4[0 + index_X4] = characterInfoArray[i].vertex_BL.uv4;
  4161. //m_textInfo.meshInfo[0].uvs4[1 + index_X4] = characterInfoArray[i].vertex_TL.uv4;
  4162. //m_textInfo.meshInfo[0].uvs4[2 + index_X4] = characterInfoArray[i].vertex_TR.uv4;
  4163. //m_textInfo.meshInfo[0].uvs4[3 + index_X4] = characterInfoArray[i].vertex_BR.uv4;
  4164. // setup Vertex Colors
  4165. m_textInfo.meshInfo[materialIndex].colors32[0 + index_X4] = characterInfoArray[i].vertex_BL.color;
  4166. m_textInfo.meshInfo[materialIndex].colors32[1 + index_X4] = characterInfoArray[i].vertex_TL.color;
  4167. m_textInfo.meshInfo[materialIndex].colors32[2 + index_X4] = characterInfoArray[i].vertex_TR.color;
  4168. m_textInfo.meshInfo[materialIndex].colors32[3 + index_X4] = characterInfoArray[i].vertex_BR.color;
  4169. m_textInfo.meshInfo[materialIndex].vertexCount = index_X4 + 4;
  4170. }
  4171. /// <summary>
  4172. /// Method to add the underline geometry.
  4173. /// </summary>
  4174. /// <param name="start"></param>
  4175. /// <param name="end"></param>
  4176. /// <param name="startScale"></param>
  4177. /// <param name="endScale"></param>
  4178. /// <param name="maxScale"></param>
  4179. /// <param name="underlineColor"></param>
  4180. protected virtual void DrawUnderlineMesh(Vector3 start, Vector3 end, ref int index, float startScale, float endScale, float maxScale, float sdfScale, Color32 underlineColor)
  4181. {
  4182. if (m_cached_Underline_GlyphInfo == null)
  4183. {
  4184. if (!TMP_Settings.warningsDisabled) Debug.LogWarning("Unable to add underline since the Font Asset doesn't contain the underline character.", this);
  4185. return;
  4186. }
  4187. int verticesCount = index + 12;
  4188. // Check to make sure our current mesh buffer allocations can hold these new Quads.
  4189. if (verticesCount > m_textInfo.meshInfo[0].vertices.Length)
  4190. {
  4191. // Resize Mesh Buffers
  4192. m_textInfo.meshInfo[0].ResizeMeshInfo(verticesCount / 4);
  4193. }
  4194. // Adjust the position of the underline based on the lowest character. This matters for subscript character.
  4195. start.y = Mathf.Min(start.y, end.y);
  4196. end.y = Mathf.Min(start.y, end.y);
  4197. float segmentWidth = m_cached_Underline_GlyphInfo.width / 2 * maxScale;
  4198. if (end.x - start.x < m_cached_Underline_GlyphInfo.width * maxScale)
  4199. {
  4200. segmentWidth = (end.x - start.x) / 2f;
  4201. }
  4202. float startPadding = m_padding * startScale / maxScale;
  4203. float endPadding = m_padding * endScale / maxScale;
  4204. float underlineThickness = m_cached_Underline_GlyphInfo.height;
  4205. // UNDERLINE VERTICES FOR (3) LINE SEGMENTS
  4206. #region UNDERLINE VERTICES
  4207. Vector3[] vertices = m_textInfo.meshInfo[0].vertices;
  4208. // Front Part of the Underline
  4209. vertices[index + 0] = start + new Vector3(0, 0 - (underlineThickness + m_padding) * maxScale, 0); // BL
  4210. vertices[index + 1] = start + new Vector3(0, m_padding * maxScale, 0); // TL
  4211. vertices[index + 2] = vertices[index + 1] + new Vector3(segmentWidth, 0, 0); // TR
  4212. vertices[index + 3] = vertices[index + 0] + new Vector3(segmentWidth, 0, 0); // BR
  4213. // Middle Part of the Underline
  4214. vertices[index + 4] = vertices[index + 3]; // BL
  4215. vertices[index + 5] = vertices[index + 2]; // TL
  4216. vertices[index + 6] = end + new Vector3(-segmentWidth, m_padding * maxScale, 0); // TR
  4217. vertices[index + 7] = end + new Vector3(-segmentWidth, -(underlineThickness + m_padding) * maxScale, 0); // BR
  4218. // End Part of the Underline
  4219. vertices[index + 8] = vertices[index + 7]; // BL
  4220. vertices[index + 9] = vertices[index + 6]; // TL
  4221. vertices[index + 10] = end + new Vector3(0, m_padding * maxScale, 0); // TR
  4222. vertices[index + 11] = end + new Vector3(0, -(underlineThickness + m_padding) * maxScale, 0); // BR
  4223. #endregion
  4224. // UNDERLINE UV0
  4225. #region HANDLE UV0
  4226. Vector2[] uvs0 = m_textInfo.meshInfo[0].uvs0;
  4227. // Calculate UV required to setup the 3 Quads for the Underline.
  4228. Vector2 uv0 = new Vector2((m_cached_Underline_GlyphInfo.x - startPadding) / m_fontAsset.fontInfo.AtlasWidth, 1 - (m_cached_Underline_GlyphInfo.y + m_padding + m_cached_Underline_GlyphInfo.height) / m_fontAsset.fontInfo.AtlasHeight); // bottom left
  4229. Vector2 uv1 = new Vector2(uv0.x, 1 - (m_cached_Underline_GlyphInfo.y - m_padding) / m_fontAsset.fontInfo.AtlasHeight); // top left
  4230. Vector2 uv2 = new Vector2((m_cached_Underline_GlyphInfo.x - startPadding + m_cached_Underline_GlyphInfo.width / 2) / m_fontAsset.fontInfo.AtlasWidth, uv1.y); // Mid Top Left
  4231. Vector2 uv3 = new Vector2(uv2.x, uv0.y); // Mid Bottom Left
  4232. Vector2 uv4 = new Vector2((m_cached_Underline_GlyphInfo.x + endPadding + m_cached_Underline_GlyphInfo.width / 2) / m_fontAsset.fontInfo.AtlasWidth, uv1.y); // Mid Top Right
  4233. Vector2 uv5 = new Vector2(uv4.x, uv0.y); // Mid Bottom right
  4234. Vector2 uv6 = new Vector2((m_cached_Underline_GlyphInfo.x + endPadding + m_cached_Underline_GlyphInfo.width) / m_fontAsset.fontInfo.AtlasWidth, uv1.y); // End Part - Bottom Right
  4235. Vector2 uv7 = new Vector2(uv6.x, uv0.y); // End Part - Top Right
  4236. // Left Part of the Underline
  4237. uvs0[0 + index] = uv0; // BL
  4238. uvs0[1 + index] = uv1; // TL
  4239. uvs0[2 + index] = uv2; // TR
  4240. uvs0[3 + index] = uv3; // BR
  4241. // Middle Part of the Underline
  4242. uvs0[4 + index] = new Vector2(uv2.x - uv2.x * 0.001f, uv0.y);
  4243. uvs0[5 + index] = new Vector2(uv2.x - uv2.x * 0.001f, uv1.y);
  4244. uvs0[6 + index] = new Vector2(uv2.x + uv2.x * 0.001f, uv1.y);
  4245. uvs0[7 + index] = new Vector2(uv2.x + uv2.x * 0.001f, uv0.y);
  4246. // Right Part of the Underline
  4247. uvs0[8 + index] = uv5;
  4248. uvs0[9 + index] = uv4;
  4249. uvs0[10 + index] = uv6;
  4250. uvs0[11 + index] = uv7;
  4251. #endregion
  4252. // UNDERLINE UV2
  4253. #region HANDLE UV2 - SDF SCALE
  4254. // UV1 contains Face / Border UV layout.
  4255. float min_UvX = 0;
  4256. float max_UvX = (vertices[index + 2].x - start.x) / (end.x - start.x);
  4257. //Calculate the xScale or how much the UV's are getting stretched on the X axis for the middle section of the underline.
  4258. float xScale = Mathf.Abs(sdfScale);
  4259. Vector2[] uvs2 = m_textInfo.meshInfo[0].uvs2;
  4260. uvs2[0 + index] = PackUV(0, 0, xScale);
  4261. uvs2[1 + index] = PackUV(0, 1, xScale);
  4262. uvs2[2 + index] = PackUV(max_UvX, 1, xScale);
  4263. uvs2[3 + index] = PackUV(max_UvX, 0, xScale);
  4264. min_UvX = (vertices[index + 4].x - start.x) / (end.x - start.x);
  4265. max_UvX = (vertices[index + 6].x - start.x) / (end.x - start.x);
  4266. uvs2[4 + index] = PackUV(min_UvX, 0, xScale);
  4267. uvs2[5 + index] = PackUV(min_UvX, 1, xScale);
  4268. uvs2[6 + index] = PackUV(max_UvX, 1, xScale);
  4269. uvs2[7 + index] = PackUV(max_UvX, 0, xScale);
  4270. min_UvX = (vertices[index + 8].x - start.x) / (end.x - start.x);
  4271. max_UvX = (vertices[index + 6].x - start.x) / (end.x - start.x);
  4272. uvs2[8 + index] = PackUV(min_UvX, 0, xScale);
  4273. uvs2[9 + index] = PackUV(min_UvX, 1, xScale);
  4274. uvs2[10 + index] = PackUV(1, 1, xScale);
  4275. uvs2[11 + index] = PackUV(1, 0, xScale);
  4276. #endregion
  4277. // UNDERLINE VERTEX COLORS
  4278. #region
  4279. // Alpha is the lower of the vertex color or tag color alpha used.
  4280. underlineColor.a = m_fontColor32.a < underlineColor.a ? (byte)(m_fontColor32.a) : (byte)(underlineColor.a);
  4281. Color32[] colors32 = m_textInfo.meshInfo[0].colors32;
  4282. colors32[0 + index] = underlineColor;
  4283. colors32[1 + index] = underlineColor;
  4284. colors32[2 + index] = underlineColor;
  4285. colors32[3 + index] = underlineColor;
  4286. colors32[4 + index] = underlineColor;
  4287. colors32[5 + index] = underlineColor;
  4288. colors32[6 + index] = underlineColor;
  4289. colors32[7 + index] = underlineColor;
  4290. colors32[8 + index] = underlineColor;
  4291. colors32[9 + index] = underlineColor;
  4292. colors32[10 + index] = underlineColor;
  4293. colors32[11 + index] = underlineColor;
  4294. #endregion
  4295. index += 12;
  4296. }
  4297. protected virtual void DrawTextHighlight(Vector3 start, Vector3 end, ref int index, Color32 highlightColor)
  4298. {
  4299. if (m_cached_Underline_GlyphInfo == null)
  4300. {
  4301. if (!TMP_Settings.warningsDisabled) Debug.LogWarning("Unable to add underline since the Font Asset doesn't contain the underline character.", this);
  4302. return;
  4303. }
  4304. int verticesCount = index + 4;
  4305. // Check to make sure our current mesh buffer allocations can hold these new Quads.
  4306. if (verticesCount > m_textInfo.meshInfo[0].vertices.Length)
  4307. {
  4308. // Resize Mesh Buffers
  4309. m_textInfo.meshInfo[0].ResizeMeshInfo(verticesCount / 4);
  4310. }
  4311. // UNDERLINE VERTICES FOR (3) LINE SEGMENTS
  4312. #region HIGHLIGHT VERTICES
  4313. Vector3[] vertices = m_textInfo.meshInfo[0].vertices;
  4314. // Front Part of the Underline
  4315. vertices[index + 0] = start; // BL
  4316. vertices[index + 1] = new Vector3(start.x, end.y, 0); // TL
  4317. vertices[index + 2] = end; // TR
  4318. vertices[index + 3] = new Vector3(end.x, start.y, 0); // BR
  4319. #endregion
  4320. // UNDERLINE UV0
  4321. #region HANDLE UV0
  4322. Vector2[] uvs0 = m_textInfo.meshInfo[0].uvs0;
  4323. // Calculate UV required to setup the 3 Quads for the Underline.
  4324. Vector2 uv0 = new Vector2((m_cached_Underline_GlyphInfo.x + m_cached_Underline_GlyphInfo.width / 2) / m_fontAsset.fontInfo.AtlasWidth, 1 - (m_cached_Underline_GlyphInfo.y + m_cached_Underline_GlyphInfo.height / 2) / m_fontAsset.fontInfo.AtlasHeight); // bottom left
  4325. //Vector2 uv1 = new Vector2(uv0.x, uv0.y); // top left
  4326. //Vector2 uv2 = new Vector2(uv0.x, uv0.y); // Top Right
  4327. //Vector2 uv3 = new Vector2(uv2.x, uv0.y); // Bottom Right
  4328. // Left Part of the Underline
  4329. uvs0[0 + index] = uv0; // BL
  4330. uvs0[1 + index] = uv0; // TL
  4331. uvs0[2 + index] = uv0; // TR
  4332. uvs0[3 + index] = uv0; // BR
  4333. #endregion
  4334. // UNDERLINE UV2
  4335. #region HANDLE UV2 - SDF SCALE
  4336. // UV1 contains Face / Border UV layout.
  4337. //float min_UvX = 0;
  4338. //float max_UvX = (vertices[index + 2].x - start.x) / (end.x - start.x);
  4339. ////Calculate the xScale or how much the UV's are getting stretched on the X axis for the middle section of the underline.
  4340. //float xScale = 0; // Mathf.Abs(sdfScale);
  4341. Vector2[] uvs2 = m_textInfo.meshInfo[0].uvs2;
  4342. Vector2 customUV = new Vector2(0, 1);
  4343. uvs2[0 + index] = customUV; // PackUV(-0.2f, -0.2f, xScale);
  4344. uvs2[1 + index] = customUV; // PackUV(-0.2f, -0.1f, xScale);
  4345. uvs2[2 + index] = customUV; // PackUV(-0.1f, -0.1f, xScale);
  4346. uvs2[3 + index] = customUV; // PackUV(-0.1f, -0.2f, xScale);
  4347. #endregion
  4348. // HIGHLIGHT VERTEX COLORS
  4349. #region
  4350. // Alpha is the lower of the vertex color or tag color alpha used.
  4351. highlightColor.a = m_fontColor32.a < highlightColor.a ? m_fontColor32.a : highlightColor.a;
  4352. Color32[] colors32 = m_textInfo.meshInfo[0].colors32;
  4353. colors32[0 + index] = highlightColor;
  4354. colors32[1 + index] = highlightColor;
  4355. colors32[2 + index] = highlightColor;
  4356. colors32[3 + index] = highlightColor;
  4357. #endregion
  4358. index += 4;
  4359. }
  4360. /// <summary>
  4361. /// Internal function used to load the default settings of text objects.
  4362. /// </summary>
  4363. protected void LoadDefaultSettings()
  4364. {
  4365. if (m_text == null || m_isWaitingOnResourceLoad)
  4366. {
  4367. if (TMP_Settings.autoSizeTextContainer)
  4368. autoSizeTextContainer = true;
  4369. else
  4370. {
  4371. m_rectTransform = this.rectTransform;
  4372. if (GetType() == typeof(TextMeshPro))
  4373. m_rectTransform.sizeDelta = TMP_Settings.defaultTextMeshProTextContainerSize;
  4374. else
  4375. m_rectTransform.sizeDelta = TMP_Settings.defaultTextMeshProUITextContainerSize;
  4376. }
  4377. m_enableWordWrapping = TMP_Settings.enableWordWrapping;
  4378. m_enableKerning = TMP_Settings.enableKerning;
  4379. m_enableExtraPadding = TMP_Settings.enableExtraPadding;
  4380. m_tintAllSprites = TMP_Settings.enableTintAllSprites;
  4381. m_parseCtrlCharacters = TMP_Settings.enableParseEscapeCharacters;
  4382. m_fontSize = m_fontSizeBase = TMP_Settings.defaultFontSize;
  4383. m_fontSizeMin = m_fontSize * TMP_Settings.defaultTextAutoSizingMinRatio;
  4384. m_fontSizeMax = m_fontSize * TMP_Settings.defaultTextAutoSizingMaxRatio;
  4385. m_isAlignmentEnumConverted = true;
  4386. m_isWaitingOnResourceLoad = false;
  4387. }
  4388. else if (m_isAlignmentEnumConverted == false)
  4389. {
  4390. // Convert TextAlignmentOptions enumerations.
  4391. m_isAlignmentEnumConverted = true;
  4392. m_textAlignment = TMP_Compatibility.ConvertTextAlignmentEnumValues(m_textAlignment);
  4393. }
  4394. }
  4395. /// <summary>
  4396. /// Method used to find and cache references to the Underline and Ellipsis characters.
  4397. /// </summary>
  4398. /// <param name=""></param>
  4399. protected void GetSpecialCharacters(TMP_FontAsset fontAsset)
  4400. {
  4401. // Check & Assign Underline Character for use with the Underline tag.
  4402. if (!fontAsset.characterDictionary.TryGetValue(95, out m_cached_Underline_GlyphInfo)) //95
  4403. {
  4404. // Check fallback fonts
  4405. // TODO
  4406. }
  4407. // Check & Assign Underline Character for use with the Underline tag.
  4408. if (!fontAsset.characterDictionary.TryGetValue(8230, out m_cached_Ellipsis_GlyphInfo)) //95
  4409. {
  4410. // Check fallback fonts
  4411. // TODO
  4412. }
  4413. }
  4414. /// <summary>
  4415. /// Replace a given number of characters (tag) in the array with a new character and shift subsequent characters in the array.
  4416. /// </summary>
  4417. /// <param name="chars">Array which contains the text.</param>
  4418. /// <param name="insertionIndex">The index of where the new character will be inserted</param>
  4419. /// <param name="tagLength">Length of the tag being replaced.</param>
  4420. /// <param name="c">The replacement character.</param>
  4421. protected void ReplaceTagWithCharacter(int[] chars, int insertionIndex, int tagLength, char c)
  4422. {
  4423. chars[insertionIndex] = c;
  4424. for (int i = insertionIndex + tagLength; i < chars.Length; i++)
  4425. {
  4426. chars[i - 3] = chars[i];
  4427. }
  4428. }
  4429. /// <summary>
  4430. ///
  4431. /// </summary>
  4432. /// <returns></returns>
  4433. //protected int GetMaterialReferenceForFontWeight()
  4434. //{
  4435. // //bool isItalic = (m_style & FontStyles.Italic) == FontStyles.Italic || (m_fontStyle & FontStyles.Italic) == FontStyles.Italic;
  4436. // m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentFontAsset.fontWeights[0].italicTypeface.material, m_currentFontAsset.fontWeights[0].italicTypeface, m_materialReferences, m_materialReferenceIndexLookup);
  4437. // return 0;
  4438. //}
  4439. /// <summary>
  4440. ///
  4441. /// </summary>
  4442. /// <returns></returns>
  4443. protected TMP_FontAsset GetFontAssetForWeight(int fontWeight)
  4444. {
  4445. bool isItalic = (m_style & FontStyles.Italic) == FontStyles.Italic || (m_fontStyle & FontStyles.Italic) == FontStyles.Italic;
  4446. TMP_FontAsset fontAsset = null;
  4447. int weightIndex = fontWeight / 100;
  4448. if (isItalic)
  4449. fontAsset = m_currentFontAsset.fontWeights[weightIndex].italicTypeface;
  4450. else
  4451. fontAsset = m_currentFontAsset.fontWeights[weightIndex].regularTypeface;
  4452. return fontAsset;
  4453. }
  4454. /// <summary>
  4455. /// Method to Enable or Disable child SubMesh objects.
  4456. /// </summary>
  4457. /// <param name="state"></param>
  4458. protected virtual void SetActiveSubMeshes(bool state) { }
  4459. /// <summary>
  4460. /// Destroy Sub Mesh Objects.
  4461. /// </summary>
  4462. protected virtual void ClearSubMeshObjects() { }
  4463. /// <summary>
  4464. /// Function to clear the geometry of the Primary and Sub Text objects.
  4465. /// </summary>
  4466. public virtual void ClearMesh() { }
  4467. /// <summary>
  4468. /// Function to clear the geometry of the Primary and Sub Text objects.
  4469. /// </summary>
  4470. public virtual void ClearMesh(bool uploadGeometry) { }
  4471. /// <summary>
  4472. /// Function which returns the text after it has been parsed and rich text tags removed.
  4473. /// </summary>
  4474. /// <returns></returns>
  4475. public virtual string GetParsedText()
  4476. {
  4477. if (m_textInfo == null)
  4478. return string.Empty;
  4479. int characterCount = m_textInfo.characterCount;
  4480. // TODO - Could implement some static buffer pool shared by all instances of TMP objects.
  4481. char[] buffer = new char[characterCount];
  4482. for (int i = 0; i < characterCount && i < m_textInfo.characterInfo.Length; i++)
  4483. {
  4484. buffer[i] = m_textInfo.characterInfo[i].character;
  4485. }
  4486. return new string(buffer);
  4487. }
  4488. /// <summary>
  4489. /// Function to pack scale information in the UV2 Channel.
  4490. /// </summary>
  4491. /// <param name="x"></param>
  4492. /// <param name="y"></param>
  4493. /// <param name="scale"></param>
  4494. /// <returns></returns>
  4495. //protected Vector2 PackUV(float x, float y, float scale)
  4496. //{
  4497. // Vector2 output;
  4498. // output.x = Mathf.Floor(x * 4095);
  4499. // output.y = Mathf.Floor(y * 4095);
  4500. // output.x = (output.x * 4096) + output.y;
  4501. // output.y = scale;
  4502. // return output;
  4503. //}
  4504. /// <summary>
  4505. /// Function to pack scale information in the UV2 Channel.
  4506. /// </summary>
  4507. /// <param name="x"></param>
  4508. /// <param name="y"></param>
  4509. /// <param name="scale"></param>
  4510. /// <returns></returns>
  4511. protected Vector2 PackUV(float x, float y, float scale)
  4512. {
  4513. Vector2 output;
  4514. output.x = (int)(x * 511);
  4515. output.y = (int)(y * 511);
  4516. output.x = (output.x * 4096) + output.y;
  4517. output.y = scale;
  4518. return output;
  4519. }
  4520. /// <summary>
  4521. ///
  4522. /// </summary>
  4523. /// <param name="x"></param>
  4524. /// <param name="y"></param>
  4525. /// <returns></returns>
  4526. protected float PackUV(float x, float y)
  4527. {
  4528. double x0 = (int)(x * 511);
  4529. double y0 = (int)(y * 511);
  4530. return (float)((x0 * 4096) + y0);
  4531. }
  4532. /// <summary>
  4533. /// Function to pack scale information in the UV2 Channel.
  4534. /// </summary>
  4535. /// <param name="x"></param>
  4536. /// <param name="y"></param>
  4537. /// <param name="scale"></param>
  4538. /// <returns></returns>
  4539. //protected Vector2 PackUV(float x, float y, float scale)
  4540. //{
  4541. // Vector2 output;
  4542. // output.x = Mathf.Floor(x * 4095);
  4543. // output.y = Mathf.Floor(y * 4095);
  4544. // return new Vector2((output.x * 4096) + output.y, scale);
  4545. //}
  4546. /// <summary>
  4547. ///
  4548. /// </summary>
  4549. /// <param name="x"></param>
  4550. /// <param name="y"></param>
  4551. /// <returns></returns>
  4552. //protected float PackUV(float x, float y)
  4553. //{
  4554. // x = (x % 5) / 5;
  4555. // y = (y % 5) / 5;
  4556. // return Mathf.Round(x * 4096) + y;
  4557. //}
  4558. /// <summary>
  4559. /// Method to convert Hex to Int
  4560. /// </summary>
  4561. /// <param name="hex"></param>
  4562. /// <returns></returns>
  4563. protected int HexToInt(char hex)
  4564. {
  4565. switch (hex)
  4566. {
  4567. case '0': return 0;
  4568. case '1': return 1;
  4569. case '2': return 2;
  4570. case '3': return 3;
  4571. case '4': return 4;
  4572. case '5': return 5;
  4573. case '6': return 6;
  4574. case '7': return 7;
  4575. case '8': return 8;
  4576. case '9': return 9;
  4577. case 'A': return 10;
  4578. case 'B': return 11;
  4579. case 'C': return 12;
  4580. case 'D': return 13;
  4581. case 'E': return 14;
  4582. case 'F': return 15;
  4583. case 'a': return 10;
  4584. case 'b': return 11;
  4585. case 'c': return 12;
  4586. case 'd': return 13;
  4587. case 'e': return 14;
  4588. case 'f': return 15;
  4589. }
  4590. return 15;
  4591. }
  4592. /// <summary>
  4593. /// Convert UTF-16 Hex to Char
  4594. /// </summary>
  4595. /// <returns>The Unicode hex.</returns>
  4596. /// <param name="i">The index.</param>
  4597. protected int GetUTF16(string text, int i)
  4598. {
  4599. int unicode = 0;
  4600. unicode += HexToInt(text[i]) << 12;
  4601. unicode += HexToInt(text[i + 1]) << 8;
  4602. unicode += HexToInt(text[i + 2]) << 4;
  4603. unicode += HexToInt(text[i + 3]);
  4604. return unicode;
  4605. }
  4606. /// <summary>
  4607. /// Convert UTF-16 Hex to Char
  4608. /// </summary>
  4609. /// <returns>The Unicode hex.</returns>
  4610. /// <param name="i">The index.</param>
  4611. protected int GetUTF16(StringBuilder text, int i)
  4612. {
  4613. int unicode = 0;
  4614. unicode += HexToInt(text[i]) << 12;
  4615. unicode += HexToInt(text[i + 1]) << 8;
  4616. unicode += HexToInt(text[i + 2]) << 4;
  4617. unicode += HexToInt(text[i + 3]);
  4618. return unicode;
  4619. }
  4620. /// <summary>
  4621. /// Convert UTF-32 Hex to Char
  4622. /// </summary>
  4623. /// <returns>The Unicode hex.</returns>
  4624. /// <param name="i">The index.</param>
  4625. protected int GetUTF32(string text, int i)
  4626. {
  4627. int unicode = 0;
  4628. unicode += HexToInt(text[i]) << 30;
  4629. unicode += HexToInt(text[i + 1]) << 24;
  4630. unicode += HexToInt(text[i + 2]) << 20;
  4631. unicode += HexToInt(text[i + 3]) << 16;
  4632. unicode += HexToInt(text[i + 4]) << 12;
  4633. unicode += HexToInt(text[i + 5]) << 8;
  4634. unicode += HexToInt(text[i + 6]) << 4;
  4635. unicode += HexToInt(text[i + 7]);
  4636. return unicode;
  4637. }
  4638. /// <summary>
  4639. /// Convert UTF-32 Hex to Char
  4640. /// </summary>
  4641. /// <returns>The Unicode hex.</returns>
  4642. /// <param name="i">The index.</param>
  4643. protected int GetUTF32(StringBuilder text, int i)
  4644. {
  4645. int unicode = 0;
  4646. unicode += HexToInt(text[i]) << 30;
  4647. unicode += HexToInt(text[i + 1]) << 24;
  4648. unicode += HexToInt(text[i + 2]) << 20;
  4649. unicode += HexToInt(text[i + 3]) << 16;
  4650. unicode += HexToInt(text[i + 4]) << 12;
  4651. unicode += HexToInt(text[i + 5]) << 8;
  4652. unicode += HexToInt(text[i + 6]) << 4;
  4653. unicode += HexToInt(text[i + 7]);
  4654. return unicode;
  4655. }
  4656. /// <summary>
  4657. /// Method to convert Hex color values to Color32
  4658. /// </summary>
  4659. /// <param name="hexChars"></param>
  4660. /// <param name="tagCount"></param>
  4661. /// <returns></returns>
  4662. protected Color32 HexCharsToColor(char[] hexChars, int tagCount)
  4663. {
  4664. if (tagCount == 4)
  4665. {
  4666. byte r = (byte)(HexToInt(hexChars[1]) * 16 + HexToInt(hexChars[1]));
  4667. byte g = (byte)(HexToInt(hexChars[2]) * 16 + HexToInt(hexChars[2]));
  4668. byte b = (byte)(HexToInt(hexChars[3]) * 16 + HexToInt(hexChars[3]));
  4669. return new Color32(r, g, b, 255);
  4670. }
  4671. else if (tagCount == 5)
  4672. {
  4673. byte r = (byte)(HexToInt(hexChars[1]) * 16 + HexToInt(hexChars[1]));
  4674. byte g = (byte)(HexToInt(hexChars[2]) * 16 + HexToInt(hexChars[2]));
  4675. byte b = (byte)(HexToInt(hexChars[3]) * 16 + HexToInt(hexChars[3]));
  4676. byte a = (byte)(HexToInt(hexChars[4]) * 16 + HexToInt(hexChars[4]));
  4677. return new Color32(r, g, b, a);
  4678. }
  4679. else if (tagCount == 7)
  4680. {
  4681. byte r = (byte)(HexToInt(hexChars[1]) * 16 + HexToInt(hexChars[2]));
  4682. byte g = (byte)(HexToInt(hexChars[3]) * 16 + HexToInt(hexChars[4]));
  4683. byte b = (byte)(HexToInt(hexChars[5]) * 16 + HexToInt(hexChars[6]));
  4684. return new Color32(r, g, b, 255);
  4685. }
  4686. else if (tagCount == 9)
  4687. {
  4688. byte r = (byte)(HexToInt(hexChars[1]) * 16 + HexToInt(hexChars[2]));
  4689. byte g = (byte)(HexToInt(hexChars[3]) * 16 + HexToInt(hexChars[4]));
  4690. byte b = (byte)(HexToInt(hexChars[5]) * 16 + HexToInt(hexChars[6]));
  4691. byte a = (byte)(HexToInt(hexChars[7]) * 16 + HexToInt(hexChars[8]));
  4692. return new Color32(r, g, b, a);
  4693. }
  4694. else if (tagCount == 10)
  4695. {
  4696. byte r = (byte)(HexToInt(hexChars[7]) * 16 + HexToInt(hexChars[7]));
  4697. byte g = (byte)(HexToInt(hexChars[8]) * 16 + HexToInt(hexChars[8]));
  4698. byte b = (byte)(HexToInt(hexChars[9]) * 16 + HexToInt(hexChars[9]));
  4699. return new Color32(r, g, b, 255);
  4700. }
  4701. else if (tagCount == 11)
  4702. {
  4703. byte r = (byte)(HexToInt(hexChars[7]) * 16 + HexToInt(hexChars[7]));
  4704. byte g = (byte)(HexToInt(hexChars[8]) * 16 + HexToInt(hexChars[8]));
  4705. byte b = (byte)(HexToInt(hexChars[9]) * 16 + HexToInt(hexChars[9]));
  4706. byte a = (byte)(HexToInt(hexChars[10]) * 16 + HexToInt(hexChars[10]));
  4707. return new Color32(r, g, b, a);
  4708. }
  4709. else if (tagCount == 13)
  4710. {
  4711. byte r = (byte)(HexToInt(hexChars[7]) * 16 + HexToInt(hexChars[8]));
  4712. byte g = (byte)(HexToInt(hexChars[9]) * 16 + HexToInt(hexChars[10]));
  4713. byte b = (byte)(HexToInt(hexChars[11]) * 16 + HexToInt(hexChars[12]));
  4714. return new Color32(r, g, b, 255);
  4715. }
  4716. else if (tagCount == 15)
  4717. {
  4718. byte r = (byte)(HexToInt(hexChars[7]) * 16 + HexToInt(hexChars[8]));
  4719. byte g = (byte)(HexToInt(hexChars[9]) * 16 + HexToInt(hexChars[10]));
  4720. byte b = (byte)(HexToInt(hexChars[11]) * 16 + HexToInt(hexChars[12]));
  4721. byte a = (byte)(HexToInt(hexChars[13]) * 16 + HexToInt(hexChars[14]));
  4722. return new Color32(r, g, b, a);
  4723. }
  4724. return new Color32(255, 255, 255, 255);
  4725. }
  4726. /// <summary>
  4727. /// Method to convert Hex Color values to Color32
  4728. /// </summary>
  4729. /// <param name="hexChars"></param>
  4730. /// <param name="startIndex"></param>
  4731. /// <param name="length"></param>
  4732. /// <returns></returns>
  4733. protected Color32 HexCharsToColor(char[] hexChars, int startIndex, int length)
  4734. {
  4735. if (length == 7)
  4736. {
  4737. byte r = (byte)(HexToInt(hexChars[startIndex + 1]) * 16 + HexToInt(hexChars[startIndex + 2]));
  4738. byte g = (byte)(HexToInt(hexChars[startIndex + 3]) * 16 + HexToInt(hexChars[startIndex + 4]));
  4739. byte b = (byte)(HexToInt(hexChars[startIndex + 5]) * 16 + HexToInt(hexChars[startIndex + 6]));
  4740. return new Color32(r, g, b, 255);
  4741. }
  4742. else if (length == 9)
  4743. {
  4744. byte r = (byte)(HexToInt(hexChars[startIndex + 1]) * 16 + HexToInt(hexChars[startIndex + 2]));
  4745. byte g = (byte)(HexToInt(hexChars[startIndex + 3]) * 16 + HexToInt(hexChars[startIndex + 4]));
  4746. byte b = (byte)(HexToInt(hexChars[startIndex + 5]) * 16 + HexToInt(hexChars[startIndex + 6]));
  4747. byte a = (byte)(HexToInt(hexChars[startIndex + 7]) * 16 + HexToInt(hexChars[startIndex + 8]));
  4748. return new Color32(r, g, b, a);
  4749. }
  4750. return s_colorWhite;
  4751. }
  4752. /// <summary>
  4753. /// Method which returns the number of parameters used in a tag attribute and populates an array with such values.
  4754. /// </summary>
  4755. /// <param name="chars">Char[] containing the tag attribute and data</param>
  4756. /// <param name="startIndex">The index of the first char of the data</param>
  4757. /// <param name="length">The length of the data</param>
  4758. /// <param name="parameters">The number of parameters contained in the Char[]</param>
  4759. /// <returns></returns>
  4760. int GetAttributeParameters(char[] chars, int startIndex, int length, ref float[] parameters)
  4761. {
  4762. int endIndex = startIndex;
  4763. int attributeCount = 0;
  4764. while (endIndex < startIndex + length)
  4765. {
  4766. parameters[attributeCount] = ConvertToFloat(chars, startIndex, length, out endIndex);
  4767. length -= (endIndex - startIndex) + 1;
  4768. startIndex = endIndex + 1;
  4769. attributeCount += 1;
  4770. }
  4771. return attributeCount;
  4772. }
  4773. /// <summary>
  4774. /// Extracts a float value from char[] assuming we know the position of the start, end and decimal point.
  4775. /// </summary>
  4776. /// <param name="chars"></param>
  4777. /// <param name="startIndex"></param>
  4778. /// <param name="length"></param>
  4779. /// <returns></returns>
  4780. protected float ConvertToFloat(char[] chars, int startIndex, int length)
  4781. {
  4782. int lastIndex = 0;
  4783. return ConvertToFloat(chars, startIndex, length, out lastIndex);
  4784. }
  4785. /// <summary>
  4786. /// Extracts a float value from char[] given a start index and length.
  4787. /// </summary>
  4788. /// <param name="chars"></param> The Char[] containing the numerical sequence.
  4789. /// <param name="startIndex"></param> The index of the start of the numerical sequence.
  4790. /// <param name="length"></param> The length of the numerical sequence.
  4791. /// <param name="lastIndex"></param> Index of the last character in the validated sequence.
  4792. /// <returns></returns>
  4793. protected float ConvertToFloat(char[] chars, int startIndex, int length, out int lastIndex)
  4794. {
  4795. if (startIndex == 0) { lastIndex = 0; return -9999; }
  4796. int endIndex = startIndex + length;
  4797. bool isIntegerValue = true;
  4798. float decimalPointMultiplier = 0;
  4799. // Set value multiplier checking the first character to determine if we are using '+' or '-'
  4800. int valueSignMultiplier = 1;
  4801. if (chars[startIndex] == '+')
  4802. {
  4803. valueSignMultiplier = 1;
  4804. startIndex += 1;
  4805. }
  4806. else if (chars[startIndex] == '-')
  4807. {
  4808. valueSignMultiplier = -1;
  4809. startIndex += 1;
  4810. }
  4811. float value = 0;
  4812. for (int i = startIndex; i < endIndex; i++)
  4813. {
  4814. uint c = chars[i];
  4815. if (c >= '0' && c <= '9' || c == '.')
  4816. {
  4817. if (c == '.')
  4818. {
  4819. isIntegerValue = false;
  4820. decimalPointMultiplier = 0.1f;
  4821. continue;
  4822. }
  4823. //Calculate integer and floating point value
  4824. if (isIntegerValue)
  4825. value = value * 10 + (c - 48) * valueSignMultiplier;
  4826. else
  4827. {
  4828. value = value + (c - 48) * decimalPointMultiplier * valueSignMultiplier;
  4829. decimalPointMultiplier *= 0.1f;
  4830. }
  4831. continue;
  4832. }
  4833. else if (c == ',')
  4834. {
  4835. if (i + 1 < endIndex && chars[i + 1] == ' ')
  4836. lastIndex = i + 1;
  4837. else
  4838. lastIndex = i;
  4839. return value;
  4840. }
  4841. }
  4842. lastIndex = endIndex;
  4843. return value;
  4844. }
  4845. /// <summary>
  4846. /// Function to identify and validate the rich tag. Returns the position of the > if the tag was valid.
  4847. /// </summary>
  4848. /// <param name="chars"></param>
  4849. /// <param name="startIndex"></param>
  4850. /// <param name="endIndex"></param>
  4851. /// <returns></returns>
  4852. protected bool ValidateHtmlTag(int[] chars, int startIndex, out int endIndex)
  4853. {
  4854. int tagCharCount = 0;
  4855. byte attributeFlag = 0;
  4856. TagUnits tagUnits = TagUnits.Pixels;
  4857. TagType tagType = TagType.None;
  4858. int attributeIndex = 0;
  4859. m_xmlAttribute[attributeIndex].nameHashCode = 0;
  4860. m_xmlAttribute[attributeIndex].valueType = TagType.None;
  4861. m_xmlAttribute[attributeIndex].valueHashCode = 0;
  4862. m_xmlAttribute[attributeIndex].valueStartIndex = 0;
  4863. m_xmlAttribute[attributeIndex].valueLength = 0;
  4864. // Clear attribute name hash codes
  4865. m_xmlAttribute[1].nameHashCode = 0;
  4866. m_xmlAttribute[2].nameHashCode = 0;
  4867. m_xmlAttribute[3].nameHashCode = 0;
  4868. m_xmlAttribute[4].nameHashCode = 0;
  4869. endIndex = startIndex;
  4870. bool isTagSet = false;
  4871. bool isValidHtmlTag = false;
  4872. for (int i = startIndex; i < chars.Length && chars[i] != 0 && tagCharCount < m_htmlTag.Length && chars[i] != 60; i++)
  4873. {
  4874. if (chars[i] == 62) // ASCII Code of End HTML tag '>'
  4875. {
  4876. isValidHtmlTag = true;
  4877. endIndex = i;
  4878. m_htmlTag[tagCharCount] = (char)0;
  4879. break;
  4880. }
  4881. m_htmlTag[tagCharCount] = (char)chars[i];
  4882. tagCharCount += 1;
  4883. if (attributeFlag == 1)
  4884. {
  4885. if (tagType == TagType.None)
  4886. {
  4887. // Check for attribute type
  4888. if (chars[i] == 43 || chars[i] == 45 || chars[i] == 46 || (chars[i] >= '0' && chars[i] <= '9'))
  4889. {
  4890. tagType = TagType.NumericalValue;
  4891. m_xmlAttribute[attributeIndex].valueType = TagType.NumericalValue;
  4892. m_xmlAttribute[attributeIndex].valueStartIndex = tagCharCount - 1;
  4893. m_xmlAttribute[attributeIndex].valueLength += 1;
  4894. }
  4895. else if (chars[i] == 35)
  4896. {
  4897. tagType = TagType.ColorValue;
  4898. m_xmlAttribute[attributeIndex].valueType = TagType.ColorValue;
  4899. m_xmlAttribute[attributeIndex].valueStartIndex = tagCharCount - 1;
  4900. m_xmlAttribute[attributeIndex].valueLength += 1;
  4901. }
  4902. else if (chars[i] == 34)
  4903. {
  4904. tagType = TagType.StringValue;
  4905. m_xmlAttribute[attributeIndex].valueType = TagType.StringValue;
  4906. m_xmlAttribute[attributeIndex].valueStartIndex = tagCharCount;
  4907. }
  4908. else
  4909. {
  4910. tagType = TagType.StringValue;
  4911. m_xmlAttribute[attributeIndex].valueType = TagType.StringValue;
  4912. m_xmlAttribute[attributeIndex].valueStartIndex = tagCharCount - 1;
  4913. m_xmlAttribute[attributeIndex].valueHashCode = (m_xmlAttribute[attributeIndex].valueHashCode << 5) + m_xmlAttribute[attributeIndex].valueHashCode ^ chars[i];
  4914. m_xmlAttribute[attributeIndex].valueLength += 1;
  4915. }
  4916. }
  4917. else
  4918. {
  4919. if (tagType == TagType.NumericalValue)
  4920. {
  4921. // Check for termination of numerical value.
  4922. if (chars[i] == 112 || chars[i] == 101 || chars[i] == 37 || chars[i] == 32)
  4923. {
  4924. attributeFlag = 2;
  4925. tagType = TagType.None;
  4926. attributeIndex += 1;
  4927. m_xmlAttribute[attributeIndex].nameHashCode = 0;
  4928. m_xmlAttribute[attributeIndex].valueType = TagType.None;
  4929. m_xmlAttribute[attributeIndex].valueHashCode = 0;
  4930. m_xmlAttribute[attributeIndex].valueStartIndex = 0;
  4931. m_xmlAttribute[attributeIndex].valueLength = 0;
  4932. if (chars[i] == 101)
  4933. tagUnits = TagUnits.FontUnits;
  4934. else if (chars[i] == 37)
  4935. tagUnits = TagUnits.Percentage;
  4936. }
  4937. else if (attributeFlag != 2)
  4938. {
  4939. m_xmlAttribute[attributeIndex].valueLength += 1;
  4940. }
  4941. }
  4942. else if (tagType == TagType.ColorValue)
  4943. {
  4944. if (chars[i] != 32)
  4945. {
  4946. m_xmlAttribute[attributeIndex].valueLength += 1;
  4947. }
  4948. else
  4949. {
  4950. attributeFlag = 2;
  4951. tagType = TagType.None;
  4952. attributeIndex += 1;
  4953. m_xmlAttribute[attributeIndex].nameHashCode = 0;
  4954. m_xmlAttribute[attributeIndex].valueType = TagType.None;
  4955. m_xmlAttribute[attributeIndex].valueHashCode = 0;
  4956. m_xmlAttribute[attributeIndex].valueStartIndex = 0;
  4957. m_xmlAttribute[attributeIndex].valueLength = 0;
  4958. }
  4959. }
  4960. else if (tagType == TagType.StringValue)
  4961. {
  4962. // Compute HashCode value for the named tag.
  4963. if (chars[i] != 34)
  4964. {
  4965. m_xmlAttribute[attributeIndex].valueHashCode = (m_xmlAttribute[attributeIndex].valueHashCode << 5) + m_xmlAttribute[attributeIndex].valueHashCode ^ chars[i];
  4966. m_xmlAttribute[attributeIndex].valueLength += 1;
  4967. }
  4968. else
  4969. {
  4970. //m_xmlAttribute[attributeIndex].valueHashCode = -1;
  4971. attributeFlag = 2;
  4972. tagType = TagType.None;
  4973. attributeIndex += 1;
  4974. m_xmlAttribute[attributeIndex].nameHashCode = 0;
  4975. m_xmlAttribute[attributeIndex].valueType = TagType.None;
  4976. m_xmlAttribute[attributeIndex].valueHashCode = 0;
  4977. m_xmlAttribute[attributeIndex].valueStartIndex = 0;
  4978. m_xmlAttribute[attributeIndex].valueLength = 0;
  4979. }
  4980. }
  4981. }
  4982. }
  4983. if (chars[i] == 61) // '='
  4984. attributeFlag = 1;
  4985. // Compute HashCode for the name of the attribute
  4986. if (attributeFlag == 0 && chars[i] == 32)
  4987. {
  4988. if (isTagSet) return false;
  4989. isTagSet = true;
  4990. attributeFlag = 2;
  4991. tagType = TagType.None;
  4992. attributeIndex += 1;
  4993. m_xmlAttribute[attributeIndex].nameHashCode = 0;
  4994. m_xmlAttribute[attributeIndex].valueType = TagType.None;
  4995. m_xmlAttribute[attributeIndex].valueHashCode = 0;
  4996. m_xmlAttribute[attributeIndex].valueStartIndex = 0;
  4997. m_xmlAttribute[attributeIndex].valueLength = 0;
  4998. }
  4999. if (attributeFlag == 0)
  5000. m_xmlAttribute[attributeIndex].nameHashCode = (m_xmlAttribute[attributeIndex].nameHashCode << 3) - m_xmlAttribute[attributeIndex].nameHashCode + chars[i];
  5001. if (attributeFlag == 2 && chars[i] == 32)
  5002. attributeFlag = 0;
  5003. }
  5004. if (!isValidHtmlTag)
  5005. {
  5006. return false;
  5007. }
  5008. //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);
  5009. //for (int i = 0; i < attributeIndex + 1; i++)
  5010. // 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));
  5011. // Special handling of the no parsing tag </noparse> </NOPARSE> tag
  5012. if (tag_NoParsing && (m_xmlAttribute[0].nameHashCode != 53822163 && m_xmlAttribute[0].nameHashCode != 49429939))
  5013. return false;
  5014. else if (m_xmlAttribute[0].nameHashCode == 53822163 || m_xmlAttribute[0].nameHashCode == 49429939)
  5015. {
  5016. tag_NoParsing = false;
  5017. return true;
  5018. }
  5019. // Color <#FFF> 3 Hex values (short form)
  5020. if (m_htmlTag[0] == 35 && tagCharCount == 4)
  5021. {
  5022. m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
  5023. m_colorStack.Add(m_htmlColor);
  5024. return true;
  5025. }
  5026. // Color <#FFF7> 4 Hex values with alpha (short form)
  5027. else if (m_htmlTag[0] == 35 && tagCharCount == 5)
  5028. {
  5029. m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
  5030. m_colorStack.Add(m_htmlColor);
  5031. return true;
  5032. }
  5033. // Color <#FF00FF>
  5034. else if (m_htmlTag[0] == 35 && tagCharCount == 7) // if Tag begins with # and contains 7 characters.
  5035. {
  5036. m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
  5037. m_colorStack.Add(m_htmlColor);
  5038. return true;
  5039. }
  5040. // Color <#FF00FF00> with alpha
  5041. else if (m_htmlTag[0] == 35 && tagCharCount == 9) // if Tag begins with # and contains 9 characters.
  5042. {
  5043. m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
  5044. m_colorStack.Add(m_htmlColor);
  5045. return true;
  5046. }
  5047. else
  5048. {
  5049. float value = 0;
  5050. switch (m_xmlAttribute[0].nameHashCode)
  5051. {
  5052. case 98: // <b>
  5053. case 66: // <B>
  5054. m_style |= FontStyles.Bold;
  5055. m_fontStyleStack.Add(FontStyles.Bold);
  5056. m_fontWeightInternal = 700;
  5057. m_fontWeightStack.Add(700);
  5058. return true;
  5059. case 427: // </b>
  5060. case 395: // </B>
  5061. if ((m_fontStyle & FontStyles.Bold) != FontStyles.Bold)
  5062. {
  5063. m_fontWeightInternal = m_fontWeightStack.Remove();
  5064. if (m_fontStyleStack.Remove(FontStyles.Bold) == 0)
  5065. m_style &= ~FontStyles.Bold;
  5066. }
  5067. return true;
  5068. case 105: // <i>
  5069. case 73: // <I>
  5070. m_style |= FontStyles.Italic;
  5071. m_fontStyleStack.Add(FontStyles.Italic);
  5072. return true;
  5073. case 434: // </i>
  5074. case 402: // </I>
  5075. if (m_fontStyleStack.Remove(FontStyles.Italic) == 0)
  5076. m_style &= ~FontStyles.Italic;
  5077. return true;
  5078. case 115: // <s>
  5079. case 83: // <S>
  5080. m_style |= FontStyles.Strikethrough;
  5081. m_fontStyleStack.Add(FontStyles.Strikethrough);
  5082. if (m_xmlAttribute[1].nameHashCode == 281955 || m_xmlAttribute[1].nameHashCode == 192323)
  5083. {
  5084. m_strikethroughColor = HexCharsToColor(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength);
  5085. m_strikethroughColor.a = m_htmlColor.a < m_strikethroughColor.a ? (byte)(m_htmlColor.a) : (byte)(m_strikethroughColor .a);
  5086. }
  5087. else
  5088. m_strikethroughColor = m_htmlColor;
  5089. m_strikethroughColorStack.Add(m_strikethroughColor);
  5090. return true;
  5091. case 444: // </s>
  5092. case 412: // </S>
  5093. if ((m_fontStyle & FontStyles.Strikethrough) != FontStyles.Strikethrough)
  5094. {
  5095. if (m_fontStyleStack.Remove(FontStyles.Strikethrough) == 0)
  5096. m_style &= ~FontStyles.Strikethrough;
  5097. }
  5098. return true;
  5099. case 117: // <u>
  5100. case 85: // <U>
  5101. m_style |= FontStyles.Underline;
  5102. m_fontStyleStack.Add(FontStyles.Underline);
  5103. if (m_xmlAttribute[1].nameHashCode == 281955 || m_xmlAttribute[1].nameHashCode == 192323)
  5104. {
  5105. m_underlineColor = HexCharsToColor(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength);
  5106. m_underlineColor.a = m_htmlColor.a < m_underlineColor.a ? (byte)(m_htmlColor.a) : (byte)(m_underlineColor.a);
  5107. }
  5108. else
  5109. m_underlineColor = m_htmlColor;
  5110. m_underlineColorStack.Add(m_underlineColor);
  5111. return true;
  5112. case 446: // </u>
  5113. case 414: // </U>
  5114. if ((m_fontStyle & FontStyles.Underline) != FontStyles.Underline)
  5115. {
  5116. m_underlineColor = m_underlineColorStack.Remove();
  5117. if (m_fontStyleStack.Remove(FontStyles.Underline) == 0)
  5118. m_style &= ~FontStyles.Underline;
  5119. }
  5120. return true;
  5121. case 43045: // <mark=#FF00FF80>
  5122. case 30245: // <MARK>
  5123. m_style |= FontStyles.Highlight;
  5124. m_fontStyleStack.Add(FontStyles.Highlight);
  5125. m_highlightColor = HexCharsToColor(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength);
  5126. m_highlightColor.a = m_htmlColor.a < m_highlightColor.a ? (byte)(m_htmlColor.a) : (byte)(m_highlightColor.a);
  5127. m_highlightColorStack.Add(m_highlightColor);
  5128. return true;
  5129. case 155892: // </mark>
  5130. case 143092: // </MARK>
  5131. if ((m_fontStyle & FontStyles.Highlight) != FontStyles.Highlight)
  5132. {
  5133. m_highlightColor = m_highlightColorStack.Remove();
  5134. if (m_fontStyleStack.Remove(FontStyles.Highlight) == 0)
  5135. m_style &= ~FontStyles.Highlight;
  5136. }
  5137. return true;
  5138. case 6552: // <sub>
  5139. case 4728: // <SUB>
  5140. m_fontScaleMultiplier *= m_currentFontAsset.fontInfo.SubSize > 0 ? m_currentFontAsset.fontInfo.SubSize : 1;
  5141. m_baselineOffsetStack.Push(m_baselineOffset);
  5142. m_baselineOffset += m_currentFontAsset.fontInfo.SubscriptOffset * m_fontScale * m_fontScaleMultiplier;
  5143. m_fontStyleStack.Add(FontStyles.Subscript);
  5144. m_style |= FontStyles.Subscript;
  5145. return true;
  5146. case 22673: // </sub>
  5147. case 20849: // </SUB>
  5148. if ((m_style & FontStyles.Subscript) == FontStyles.Subscript)
  5149. {
  5150. if (m_fontScaleMultiplier < 1)
  5151. {
  5152. //m_baselineOffset -= m_currentFontAsset.fontInfo.SubscriptOffset * m_fontScale * m_fontScaleMultiplier;
  5153. m_baselineOffset = m_baselineOffsetStack.Pop();
  5154. m_fontScaleMultiplier /= m_currentFontAsset.fontInfo.SubSize > 0 ? m_currentFontAsset.fontInfo.SubSize : 1;
  5155. }
  5156. if (m_fontStyleStack.Remove(FontStyles.Subscript) == 0)
  5157. m_style &= ~FontStyles.Subscript;
  5158. }
  5159. return true;
  5160. case 6566: // <sup>
  5161. case 4742: // <SUP>
  5162. m_fontScaleMultiplier *= m_currentFontAsset.fontInfo.SubSize > 0 ? m_currentFontAsset.fontInfo.SubSize : 1;
  5163. m_baselineOffsetStack.Push(m_baselineOffset);
  5164. m_baselineOffset += m_currentFontAsset.fontInfo.SuperscriptOffset * m_fontScale * m_fontScaleMultiplier;
  5165. m_fontStyleStack.Add(FontStyles.Superscript);
  5166. m_style |= FontStyles.Superscript;
  5167. return true;
  5168. case 22687: // </sup>
  5169. case 20863: // </SUP>
  5170. if ((m_style & FontStyles.Superscript) == FontStyles.Superscript)
  5171. {
  5172. if (m_fontScaleMultiplier < 1)
  5173. {
  5174. //m_baselineOffset -= m_currentFontAsset.fontInfo.SuperscriptOffset * m_fontScale * m_fontScaleMultiplier;
  5175. m_baselineOffset = m_baselineOffsetStack.Pop();
  5176. m_fontScaleMultiplier /= m_currentFontAsset.fontInfo.SubSize > 0 ? m_currentFontAsset.fontInfo.SubSize : 1;
  5177. }
  5178. if (m_fontStyleStack.Remove(FontStyles.Superscript) == 0)
  5179. m_style &= ~FontStyles.Superscript;
  5180. }
  5181. return true;
  5182. case -330774850: // <font-weight>
  5183. case 2012149182: // <FONT-WEIGHT>
  5184. value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength);
  5185. if (value == -9999) return false;
  5186. if ((m_fontStyle & FontStyles.Bold) == FontStyles.Bold)
  5187. {
  5188. // Nothing happens since Bold is forced on the text.
  5189. //m_fontWeight = 700;
  5190. return true;
  5191. }
  5192. // Remove bold style
  5193. m_style &= ~FontStyles.Bold;
  5194. switch ((int)value)
  5195. {
  5196. case 100:
  5197. m_fontWeightInternal = 100;
  5198. break;
  5199. case 200:
  5200. m_fontWeightInternal = 200;
  5201. break;
  5202. case 300:
  5203. m_fontWeightInternal = 300;
  5204. break;
  5205. case 400:
  5206. m_fontWeightInternal = 400;
  5207. break;
  5208. case 500:
  5209. m_fontWeightInternal = 500;
  5210. break;
  5211. case 600:
  5212. m_fontWeightInternal = 600;
  5213. break;
  5214. case 700:
  5215. m_fontWeightInternal = 700;
  5216. m_style |= FontStyles.Bold;
  5217. break;
  5218. case 800:
  5219. m_fontWeightInternal = 800;
  5220. break;
  5221. case 900:
  5222. m_fontWeightInternal = 900;
  5223. break;
  5224. }
  5225. m_fontWeightStack.Add(m_fontWeightInternal);
  5226. return true;
  5227. case -1885698441: // </font-weight>
  5228. case 457225591: // </FONT-WEIGHT>
  5229. m_fontWeightInternal = m_fontWeightStack.Remove();
  5230. if (m_fontWeightInternal == 400) m_style &= ~FontStyles.Bold;
  5231. return true;
  5232. case 6380: // <pos=000.00px> <pos=0em> <pos=50%>
  5233. case 4556: // <POS>
  5234. value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength);
  5235. if (value == -9999) return false;
  5236. switch (tagUnits)
  5237. {
  5238. case TagUnits.Pixels:
  5239. //if (m_xmlAttribute[1].nameHashCode == 275917) //
  5240. //{
  5241. // // left = 3774683
  5242. // // right= 136703040
  5243. // if (m_xmlAttribute [1].valueHashCode == 136703040)
  5244. // {
  5245. // // track the endindex so we can return to this character.
  5246. // Debug.Log ("align=right startIndex" + endIndex);
  5247. // }
  5248. //}
  5249. m_xAdvance = value;
  5250. //m_isIgnoringAlignment = true;
  5251. return true;
  5252. case TagUnits.FontUnits:
  5253. m_xAdvance = value * m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
  5254. //m_isIgnoringAlignment = true;
  5255. return true;
  5256. case TagUnits.Percentage:
  5257. m_xAdvance = m_marginWidth * value / 100;
  5258. //if (m_xmlAttribute[1].nameHashCode == 275917) //
  5259. //{
  5260. // //Debug.Log ("align tag.");
  5261. // // left = 3774683
  5262. // // right= 136703040
  5263. // if (m_xmlAttribute [1].valueHashCode == 136703040)
  5264. // {
  5265. // // track the endindex so we can return to this character.
  5266. // SaveWordWrappingState (ref m_SavedAlignment, endIndex, m_characterCount);
  5267. // }
  5268. //}
  5269. //m_isIgnoringAlignment = true;
  5270. return true;
  5271. }
  5272. return false;
  5273. case 22501: // </pos>
  5274. case 20677: // </POS>
  5275. /*
  5276. // Should retrun the index of where the tag started and adjust xAdvance.
  5277. if (m_isParsingText)
  5278. {
  5279. if (m_SavedAlignment.previous_WordBreak != 0)
  5280. {
  5281. float current_xAdvance = m_xAdvance;
  5282. endIndex = RestoreWordWrappingState (ref m_SavedAlignment);
  5283. m_characterCount -= 1;
  5284. m_xAdvance -= current_xAdvance - m_xAdvance;
  5285. }
  5286. m_SavedAlignment.previous_WordBreak = 0;
  5287. m_isIgnoringAlignment = false;
  5288. }
  5289. */
  5290. m_isIgnoringAlignment = false;
  5291. return true;
  5292. case 16034505: // <voffset>
  5293. case 11642281: // <VOFFSET>
  5294. value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength);
  5295. if (value == -9999) return false;
  5296. switch (tagUnits)
  5297. {
  5298. case TagUnits.Pixels:
  5299. m_baselineOffset = value;
  5300. return true;
  5301. case TagUnits.FontUnits:
  5302. m_baselineOffset = value * m_fontScale * m_fontAsset.fontInfo.Ascender;
  5303. return true;
  5304. case TagUnits.Percentage:
  5305. //m_baselineOffset = m_marginHeight * val / 100;
  5306. return false;
  5307. }
  5308. return false;
  5309. case 54741026: // </voffset>
  5310. case 50348802: // </VOFFSET>
  5311. m_baselineOffset = 0;
  5312. return true;
  5313. case 43991: // <page>
  5314. case 31191: // <PAGE>
  5315. // This tag only works when Overflow - Page mode is used.
  5316. if (m_overflowMode == TextOverflowModes.Page)
  5317. {
  5318. m_xAdvance = 0 + tag_LineIndent + tag_Indent;
  5319. m_lineOffset = 0;
  5320. m_pageNumber += 1;
  5321. m_isNewPage = true;
  5322. }
  5323. return true;
  5324. // <BR> tag is now handled inline where it is replaced by a linefeed or \n.
  5325. //case 544: // <BR>
  5326. //case 800: // <br>
  5327. // m_forceLineBreak = true;
  5328. // return true;
  5329. case 43969: // <nobr>
  5330. case 31169: // <NOBR>
  5331. m_isNonBreakingSpace = true;
  5332. return true;
  5333. case 156816: // </nobr>
  5334. case 144016: // </NOBR>
  5335. m_isNonBreakingSpace = false;
  5336. return true;
  5337. case 45545: // <size=>
  5338. case 32745: // <SIZE>
  5339. value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength);
  5340. if (value == -9999) return false;
  5341. switch (tagUnits)
  5342. {
  5343. case TagUnits.Pixels:
  5344. if (m_htmlTag[5] == 43) // <size=+00>
  5345. {
  5346. m_currentFontSize = m_fontSize + value;
  5347. m_sizeStack.Add(m_currentFontSize);
  5348. m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
  5349. return true;
  5350. }
  5351. else if (m_htmlTag[5] == 45) // <size=-00>
  5352. {
  5353. m_currentFontSize = m_fontSize + value;
  5354. m_sizeStack.Add(m_currentFontSize);
  5355. m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
  5356. return true;
  5357. }
  5358. else // <size=00.0>
  5359. {
  5360. m_currentFontSize = value;
  5361. m_sizeStack.Add(m_currentFontSize);
  5362. m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
  5363. return true;
  5364. }
  5365. case TagUnits.FontUnits:
  5366. m_currentFontSize = m_fontSize * value;
  5367. m_sizeStack.Add(m_currentFontSize);
  5368. m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
  5369. return true;
  5370. case TagUnits.Percentage:
  5371. m_currentFontSize = m_fontSize * value / 100;
  5372. m_sizeStack.Add(m_currentFontSize);
  5373. m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
  5374. return true;
  5375. }
  5376. return false;
  5377. case 158392: // </size>
  5378. case 145592: // </SIZE>
  5379. m_currentFontSize = m_sizeStack.Remove();
  5380. m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
  5381. return true;
  5382. case 41311: // <font=xx>
  5383. case 28511: // <FONT>
  5384. //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);
  5385. int fontHashCode = m_xmlAttribute[0].valueHashCode;
  5386. int materialAttributeHashCode = m_xmlAttribute[1].nameHashCode;
  5387. int materialHashCode = m_xmlAttribute[1].valueHashCode;
  5388. // Special handling for <font=default> or <font=Default>
  5389. if (fontHashCode == 764638571 || fontHashCode == 523367755)
  5390. {
  5391. m_currentFontAsset = m_materialReferences[0].fontAsset;
  5392. m_currentMaterial = m_materialReferences[0].material;
  5393. m_currentMaterialIndex = 0;
  5394. //Debug.Log("<font=Default> assigning Font Asset [" + m_currentFontAsset.name + "] with Material [" + m_currentMaterial.name + "].");
  5395. m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
  5396. m_materialReferenceStack.Add(m_materialReferences[0]);
  5397. return true;
  5398. }
  5399. TMP_FontAsset tempFont;
  5400. Material tempMaterial;
  5401. // HANDLE NEW FONT ASSET
  5402. if (MaterialReferenceManager.TryGetFontAsset(fontHashCode, out tempFont))
  5403. {
  5404. //if (tempFont != m_currentFontAsset)
  5405. //{
  5406. // //Debug.Log("Assigning Font Asset: " + tempFont.name);
  5407. // m_currentFontAsset = tempFont;
  5408. // m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
  5409. //}
  5410. }
  5411. else
  5412. {
  5413. // Load Font Asset
  5414. tempFont = Resources.Load<TMP_FontAsset>(TMP_Settings.defaultFontAssetPath + new string(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength));
  5415. if (tempFont == null)
  5416. return false;
  5417. // Add new reference to the font asset as well as default material to the MaterialReferenceManager
  5418. MaterialReferenceManager.AddFontAsset(tempFont);
  5419. }
  5420. // HANDLE NEW MATERIAL
  5421. if (materialAttributeHashCode == 0 && materialHashCode == 0)
  5422. {
  5423. // No material specified then use default font asset material.
  5424. m_currentMaterial = tempFont.material;
  5425. m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFont, m_materialReferences, m_materialReferenceIndexLookup);
  5426. m_materialReferenceStack.Add(m_materialReferences[m_currentMaterialIndex]);
  5427. }
  5428. else if (materialAttributeHashCode == 103415287 || materialAttributeHashCode == 72669687) // using material attribute
  5429. {
  5430. if (MaterialReferenceManager.TryGetMaterial(materialHashCode, out tempMaterial))
  5431. {
  5432. m_currentMaterial = tempMaterial;
  5433. m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFont, m_materialReferences, m_materialReferenceIndexLookup);
  5434. m_materialReferenceStack.Add(m_materialReferences[m_currentMaterialIndex]);
  5435. }
  5436. else
  5437. {
  5438. // Load new material
  5439. tempMaterial = Resources.Load<Material>(TMP_Settings.defaultFontAssetPath + new string(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength));
  5440. if (tempMaterial == null)
  5441. return false;
  5442. // Add new reference to this material in the MaterialReferenceManager
  5443. MaterialReferenceManager.AddFontMaterial(materialHashCode, tempMaterial);
  5444. m_currentMaterial = tempMaterial;
  5445. m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFont, m_materialReferences, m_materialReferenceIndexLookup);
  5446. m_materialReferenceStack.Add(m_materialReferences[m_currentMaterialIndex]);
  5447. }
  5448. }
  5449. else
  5450. return false;
  5451. m_currentFontAsset = tempFont;
  5452. m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
  5453. return true;
  5454. case 154158: // </font>
  5455. case 141358: // </FONT>
  5456. {
  5457. MaterialReference materialReference = m_materialReferenceStack.Remove();
  5458. m_currentFontAsset = materialReference.fontAsset;
  5459. m_currentMaterial = materialReference.material;
  5460. m_currentMaterialIndex = materialReference.index;
  5461. m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
  5462. return true;
  5463. }
  5464. case 103415287: // <material="material name">
  5465. case 72669687: // <MATERIAL>
  5466. materialHashCode = m_xmlAttribute[0].valueHashCode;
  5467. // Special handling for <material=default> or <material=Default>
  5468. if (materialHashCode == 764638571 || materialHashCode == 523367755)
  5469. {
  5470. // Check if material font atlas texture matches that of the current font asset.
  5471. //if (m_currentFontAsset.atlas.GetInstanceID() != m_currentMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID()) return false;
  5472. m_currentMaterial = m_materialReferences[0].material;
  5473. m_currentMaterialIndex = 0;
  5474. m_materialReferenceStack.Add(m_materialReferences[0]);
  5475. return true;
  5476. }
  5477. // Check if material
  5478. if (MaterialReferenceManager.TryGetMaterial(materialHashCode, out tempMaterial))
  5479. {
  5480. // Check if material font atlas texture matches that of the current font asset.
  5481. //if (m_currentFontAsset.atlas.GetInstanceID() != tempMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID()) return false;
  5482. m_currentMaterial = tempMaterial;
  5483. m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, m_currentFontAsset, m_materialReferences, m_materialReferenceIndexLookup);
  5484. m_materialReferenceStack.Add(m_materialReferences[m_currentMaterialIndex]);
  5485. }
  5486. else
  5487. {
  5488. // Load new material
  5489. tempMaterial = Resources.Load<Material>(TMP_Settings.defaultFontAssetPath + new string(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength));
  5490. if (tempMaterial == null)
  5491. return false;
  5492. // Check if material font atlas texture matches that of the current font asset.
  5493. //if (m_currentFontAsset.atlas.GetInstanceID() != tempMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID()) return false;
  5494. // Add new reference to this material in the MaterialReferenceManager
  5495. MaterialReferenceManager.AddFontMaterial(materialHashCode, tempMaterial);
  5496. m_currentMaterial = tempMaterial;
  5497. m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, m_currentFontAsset , m_materialReferences, m_materialReferenceIndexLookup);
  5498. m_materialReferenceStack.Add(m_materialReferences[m_currentMaterialIndex]);
  5499. }
  5500. return true;
  5501. case 374360934: // </material>
  5502. case 343615334: // </MATERIAL>
  5503. {
  5504. //if (m_currentMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID() != m_materialReferenceStack.PreviousItem().material.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID())
  5505. // return false;
  5506. MaterialReference materialReference = m_materialReferenceStack.Remove();
  5507. m_currentMaterial = materialReference.material;
  5508. m_currentMaterialIndex = materialReference.index;
  5509. return true;
  5510. }
  5511. case 320078: // <space=000.00>
  5512. case 230446: // <SPACE>
  5513. value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength);
  5514. if (value == -9999) return false;
  5515. switch (tagUnits)
  5516. {
  5517. case TagUnits.Pixels:
  5518. m_xAdvance += value;
  5519. return true;
  5520. case TagUnits.FontUnits:
  5521. m_xAdvance += value * m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
  5522. return true;
  5523. case TagUnits.Percentage:
  5524. // Not applicable
  5525. return false;
  5526. }
  5527. return false;
  5528. case 276254: // <alpha=#FF>
  5529. case 186622: // <ALPHA>
  5530. if (m_xmlAttribute[0].valueLength != 3) return false;
  5531. m_htmlColor.a = (byte)(HexToInt(m_htmlTag[7]) * 16 + HexToInt(m_htmlTag[8]));
  5532. return true;
  5533. case 1750458: // <a name=" ">
  5534. return false;
  5535. case 426: // </a>
  5536. return true;
  5537. case 43066: // <link="name">
  5538. case 30266: // <LINK>
  5539. if (m_isParsingText && !m_isCalculatingPreferredValues)
  5540. {
  5541. int index = m_textInfo.linkCount;
  5542. if (index + 1 > m_textInfo.linkInfo.Length)
  5543. TMP_TextInfo.Resize(ref m_textInfo.linkInfo, index + 1);
  5544. m_textInfo.linkInfo[index].textComponent = this;
  5545. m_textInfo.linkInfo[index].hashCode = m_xmlAttribute[0].valueHashCode;
  5546. m_textInfo.linkInfo[index].linkTextfirstCharacterIndex = m_characterCount;
  5547. m_textInfo.linkInfo[index].linkIdFirstCharacterIndex = startIndex + m_xmlAttribute[0].valueStartIndex;
  5548. m_textInfo.linkInfo[index].linkIdLength = m_xmlAttribute[0].valueLength;
  5549. m_textInfo.linkInfo[index].SetLinkID(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength);
  5550. }
  5551. return true;
  5552. case 155913: // </link>
  5553. case 143113: // </LINK>
  5554. if (m_isParsingText && !m_isCalculatingPreferredValues)
  5555. {
  5556. if (m_textInfo.linkCount < m_textInfo.linkInfo.Length)
  5557. {
  5558. m_textInfo.linkInfo[m_textInfo.linkCount].linkTextLength = m_characterCount - m_textInfo.linkInfo[m_textInfo.linkCount].linkTextfirstCharacterIndex;
  5559. m_textInfo.linkCount += 1;
  5560. }
  5561. }
  5562. return true;
  5563. case 275917: // <align=>
  5564. case 186285: // <ALIGN>
  5565. switch (m_xmlAttribute[0].valueHashCode)
  5566. {
  5567. case 3774683: // <align=left>
  5568. m_lineJustification = TextAlignmentOptions.Left;
  5569. m_lineJustificationStack.Add(m_lineJustification);
  5570. return true;
  5571. case 136703040: // <align=right>
  5572. m_lineJustification = TextAlignmentOptions.Right;
  5573. m_lineJustificationStack.Add(m_lineJustification);
  5574. return true;
  5575. case -458210101: // <align=center>
  5576. m_lineJustification = TextAlignmentOptions.Center;
  5577. m_lineJustificationStack.Add(m_lineJustification);
  5578. return true;
  5579. case -523808257: // <align=justified>
  5580. m_lineJustification = TextAlignmentOptions.Justified;
  5581. m_lineJustificationStack.Add(m_lineJustification);
  5582. return true;
  5583. case 122383428: // <align=flush>
  5584. m_lineJustification = TextAlignmentOptions.Flush;
  5585. m_lineJustificationStack.Add(m_lineJustification);
  5586. return true;
  5587. }
  5588. return false;
  5589. case 1065846: // </align>
  5590. case 976214: // </ALIGN>
  5591. m_lineJustification = m_lineJustificationStack.Remove();
  5592. return true;
  5593. case 327550: // <width=xx>
  5594. case 237918: // <WIDTH>
  5595. value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength);
  5596. if (value == -9999) return false;
  5597. switch (tagUnits)
  5598. {
  5599. case TagUnits.Pixels:
  5600. m_width = value;
  5601. break;
  5602. case TagUnits.FontUnits:
  5603. return false;
  5604. //break;
  5605. case TagUnits.Percentage:
  5606. m_width = m_marginWidth * value / 100;
  5607. break;
  5608. }
  5609. return true;
  5610. case 1117479: // </width>
  5611. case 1027847: // </WIDTH>
  5612. m_width = -1;
  5613. return true;
  5614. // STYLE tag is now handled inline and replaced by its definition.
  5615. //case 322689: // <style="name">
  5616. //case 233057: // <STYLE>
  5617. // TMP_Style style = TMP_StyleSheet.GetStyle(m_xmlAttribute[0].valueHashCode);
  5618. // if (style == null) return false;
  5619. // m_styleStack.Add(style.hashCode);
  5620. // // Parse Style Macro
  5621. // for (int i = 0; i < style.styleOpeningTagArray.Length; i++)
  5622. // {
  5623. // if (style.styleOpeningTagArray[i] == 60)
  5624. // {
  5625. // if (ValidateHtmlTag(style.styleOpeningTagArray, i + 1, out i) == false) return false;
  5626. // }
  5627. // }
  5628. // return true;
  5629. //case 1112618: // </style>
  5630. //case 1022986: // </STYLE>
  5631. // style = TMP_StyleSheet.GetStyle(m_xmlAttribute[0].valueHashCode);
  5632. // if (style == null)
  5633. // {
  5634. // // Get style from the Style Stack
  5635. // int styleHashCode = m_styleStack.CurrentItem();
  5636. // style = TMP_StyleSheet.GetStyle(styleHashCode);
  5637. // m_styleStack.Remove();
  5638. // }
  5639. // if (style == null) return false;
  5640. // //// Parse Style Macro
  5641. // for (int i = 0; i < style.styleClosingTagArray.Length; i++)
  5642. // {
  5643. // if (style.styleClosingTagArray[i] == 60)
  5644. // ValidateHtmlTag(style.styleClosingTagArray, i + 1, out i);
  5645. // }
  5646. // return true;
  5647. case 281955: // <color> <color=#FF00FF> or <color=#FF00FF00>
  5648. case 192323: // <COLOR=#FF00FF>
  5649. // <color=#FFF> 3 Hex (short hand)
  5650. if (m_htmlTag[6] == 35 && tagCharCount == 10)
  5651. {
  5652. m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
  5653. m_colorStack.Add(m_htmlColor);
  5654. return true;
  5655. }
  5656. // <color=#FFF7> 4 Hex (short hand)
  5657. else if (m_htmlTag[6] == 35 && tagCharCount == 11)
  5658. {
  5659. m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
  5660. m_colorStack.Add(m_htmlColor);
  5661. return true;
  5662. }
  5663. // <color=#FF00FF> 3 Hex pairs
  5664. if (m_htmlTag[6] == 35 && tagCharCount == 13)
  5665. {
  5666. m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
  5667. m_colorStack.Add(m_htmlColor);
  5668. return true;
  5669. }
  5670. // <color=#FF00FF00> 4 Hex pairs
  5671. else if (m_htmlTag[6] == 35 && tagCharCount == 15)
  5672. {
  5673. m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
  5674. m_colorStack.Add(m_htmlColor);
  5675. return true;
  5676. }
  5677. // <color=name>
  5678. switch (m_xmlAttribute[0].valueHashCode)
  5679. {
  5680. case 125395: // <color=red>
  5681. m_htmlColor = Color.red;
  5682. m_colorStack.Add(m_htmlColor);
  5683. return true;
  5684. case 3573310: // <color=blue>
  5685. m_htmlColor = Color.blue;
  5686. m_colorStack.Add(m_htmlColor);
  5687. return true;
  5688. case 117905991: // <color=black>
  5689. m_htmlColor = Color.black;
  5690. m_colorStack.Add(m_htmlColor);
  5691. return true;
  5692. case 121463835: // <color=green>
  5693. m_htmlColor = Color.green;
  5694. m_colorStack.Add(m_htmlColor);
  5695. return true;
  5696. case 140357351: // <color=white>
  5697. m_htmlColor = Color.white;
  5698. m_colorStack.Add(m_htmlColor);
  5699. return true;
  5700. case 26556144: // <color=orange>
  5701. m_htmlColor = new Color32(255, 128, 0, 255);
  5702. m_colorStack.Add(m_htmlColor);
  5703. return true;
  5704. case -36881330: // <color=purple>
  5705. m_htmlColor = new Color32(160, 32, 240, 255);
  5706. m_colorStack.Add(m_htmlColor);
  5707. return true;
  5708. case 554054276: // <color=yellow>
  5709. m_htmlColor = Color.yellow;
  5710. m_colorStack.Add(m_htmlColor);
  5711. return true;
  5712. }
  5713. return false;
  5714. case 100149144: //<gradient>
  5715. case 69403544: // <GRADIENT>
  5716. int gradientPresetHashCode = m_xmlAttribute[0].valueHashCode;
  5717. TMP_ColorGradient tempColorGradientPreset;
  5718. // Check if Color Gradient Preset has already been loaded.
  5719. if (MaterialReferenceManager.TryGetColorGradientPreset(gradientPresetHashCode, out tempColorGradientPreset))
  5720. {
  5721. m_colorGradientPreset = tempColorGradientPreset;
  5722. }
  5723. else
  5724. {
  5725. // Load Color Gradient Preset
  5726. if (tempColorGradientPreset == null)
  5727. {
  5728. tempColorGradientPreset = Resources.Load<TMP_ColorGradient>(TMP_Settings.defaultColorGradientPresetsPath + new string(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength));
  5729. }
  5730. if (tempColorGradientPreset == null)
  5731. return false;
  5732. MaterialReferenceManager.AddColorGradientPreset(gradientPresetHashCode, tempColorGradientPreset);
  5733. m_colorGradientPreset = tempColorGradientPreset;
  5734. }
  5735. m_colorGradientStack.Add(m_colorGradientPreset);
  5736. // TODO : Add support for defining preset in the tag itself
  5737. return true;
  5738. case 371094791: // </gradient>
  5739. case 340349191: // </GRADIENT>
  5740. m_colorGradientPreset = m_colorGradientStack.Remove();
  5741. return true;
  5742. case 1983971: // <cspace=xx.x>
  5743. case 1356515: // <CSPACE>
  5744. value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength);
  5745. if (value == -9999) return false;
  5746. switch (tagUnits)
  5747. {
  5748. case TagUnits.Pixels:
  5749. m_cSpacing = value;
  5750. break;
  5751. case TagUnits.FontUnits:
  5752. m_cSpacing = value;
  5753. m_cSpacing *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
  5754. break;
  5755. case TagUnits.Percentage:
  5756. return false;
  5757. }
  5758. return true;
  5759. case 7513474: // </cspace>
  5760. case 6886018: // </CSPACE>
  5761. if (!m_isParsingText) return true;
  5762. // Adjust xAdvance to remove extra space from last character.
  5763. if (m_characterCount > 0)
  5764. {
  5765. m_xAdvance -= m_cSpacing;
  5766. m_textInfo.characterInfo[m_characterCount - 1].xAdvance = m_xAdvance;
  5767. }
  5768. m_cSpacing = 0;
  5769. return true;
  5770. case 2152041: // <mspace=xx.x>
  5771. case 1524585: // <MSPACE>
  5772. value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength);
  5773. if (value == -9999) return false;
  5774. switch (tagUnits)
  5775. {
  5776. case TagUnits.Pixels:
  5777. m_monoSpacing = value;
  5778. break;
  5779. case TagUnits.FontUnits:
  5780. m_monoSpacing = value;
  5781. m_monoSpacing *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
  5782. break;
  5783. case TagUnits.Percentage:
  5784. return false;
  5785. }
  5786. return true;
  5787. case 7681544: // </mspace>
  5788. case 7054088: // </MSPACE>
  5789. m_monoSpacing = 0;
  5790. return true;
  5791. case 280416: // <class="name">
  5792. return false;
  5793. case 1071884: // </color>
  5794. case 982252: // </COLOR>
  5795. m_htmlColor = m_colorStack.Remove();
  5796. return true;
  5797. case 2068980: // <indent=10px> <indent=10em> <indent=50%>
  5798. case 1441524: // <INDENT>
  5799. value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength);
  5800. if (value == -9999) return false;
  5801. switch (tagUnits)
  5802. {
  5803. case TagUnits.Pixels:
  5804. tag_Indent = value;
  5805. break;
  5806. case TagUnits.FontUnits:
  5807. tag_Indent = value;
  5808. tag_Indent *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
  5809. break;
  5810. case TagUnits.Percentage:
  5811. tag_Indent = m_marginWidth * value / 100;
  5812. break;
  5813. }
  5814. m_indentStack.Add(tag_Indent);
  5815. m_xAdvance = tag_Indent;
  5816. return true;
  5817. case 7598483: // </indent>
  5818. case 6971027: // </INDENT>
  5819. tag_Indent = m_indentStack.Remove();
  5820. //m_xAdvance = tag_Indent;
  5821. return true;
  5822. case 1109386397: // <line-indent>
  5823. case -842656867: // <LINE-INDENT>
  5824. value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength);
  5825. if (value == -9999) return false;
  5826. switch (tagUnits)
  5827. {
  5828. case TagUnits.Pixels:
  5829. tag_LineIndent = value;
  5830. break;
  5831. case TagUnits.FontUnits:
  5832. tag_LineIndent = value;
  5833. tag_LineIndent *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
  5834. break;
  5835. case TagUnits.Percentage:
  5836. tag_LineIndent = m_marginWidth * value / 100;
  5837. break;
  5838. }
  5839. m_xAdvance += tag_LineIndent;
  5840. return true;
  5841. case -445537194: // </line-indent>
  5842. case 1897386838: // </LINE-INDENT>
  5843. tag_LineIndent = 0;
  5844. return true;
  5845. case 2246877: // <sprite=x>
  5846. case 1619421: // <SPRITE>
  5847. int spriteAssetHashCode = m_xmlAttribute[0].valueHashCode;
  5848. TMP_SpriteAsset tempSpriteAsset;
  5849. m_spriteIndex = -1;
  5850. // CHECK TAG FORMAT
  5851. if (m_xmlAttribute[0].valueType == TagType.None || m_xmlAttribute[0].valueType == TagType.NumericalValue)
  5852. {
  5853. // No Sprite Asset is assigned to the text object
  5854. if (m_spriteAsset != null)
  5855. {
  5856. m_currentSpriteAsset = m_spriteAsset;
  5857. }
  5858. else if (m_defaultSpriteAsset != null)
  5859. {
  5860. m_currentSpriteAsset = m_defaultSpriteAsset;
  5861. }
  5862. else if (m_defaultSpriteAsset == null)
  5863. {
  5864. if (TMP_Settings.defaultSpriteAsset != null)
  5865. m_defaultSpriteAsset = TMP_Settings.defaultSpriteAsset;
  5866. else
  5867. m_defaultSpriteAsset = Resources.Load<TMP_SpriteAsset>("Sprite Assets/Default Sprite Asset");
  5868. m_currentSpriteAsset = m_defaultSpriteAsset;
  5869. }
  5870. // No valid sprite asset available
  5871. if (m_currentSpriteAsset == null)
  5872. return false;
  5873. }
  5874. else
  5875. {
  5876. // A Sprite Asset has been specified
  5877. if (MaterialReferenceManager.TryGetSpriteAsset(spriteAssetHashCode, out tempSpriteAsset))
  5878. {
  5879. m_currentSpriteAsset = tempSpriteAsset;
  5880. }
  5881. else
  5882. {
  5883. // Load Sprite Asset
  5884. if (tempSpriteAsset == null)
  5885. {
  5886. tempSpriteAsset = Resources.Load<TMP_SpriteAsset>(TMP_Settings.defaultSpriteAssetPath + new string(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength));
  5887. }
  5888. if (tempSpriteAsset == null)
  5889. return false;
  5890. //Debug.Log("Loading & assigning new Sprite Asset: " + tempSpriteAsset.name);
  5891. MaterialReferenceManager.AddSpriteAsset(spriteAssetHashCode, tempSpriteAsset);
  5892. m_currentSpriteAsset = tempSpriteAsset;
  5893. }
  5894. }
  5895. // Handling of <sprite=index> legacy tag format.
  5896. if (m_xmlAttribute[0].valueType == TagType.NumericalValue) // <sprite=index>
  5897. {
  5898. int index = (int)ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength);
  5899. if (index == -9999) return false;
  5900. // Check to make sure sprite index is valid
  5901. if (index > m_currentSpriteAsset.spriteInfoList.Count - 1) return false;
  5902. m_spriteIndex = index;
  5903. }
  5904. m_spriteColor = s_colorWhite;
  5905. m_tintSprite = false;
  5906. // Handle Sprite Tag Attributes
  5907. for (int i = 0; i < m_xmlAttribute.Length && m_xmlAttribute[i].nameHashCode != 0; i++)
  5908. {
  5909. //Debug.Log("Attribute[" + i + "].nameHashCode=" + m_xmlAttribute[i].nameHashCode + " Value:" + ConvertToFloat(m_htmlTag, m_xmlAttribute[i].valueStartIndex, m_xmlAttribute[i].valueLength));
  5910. int nameHashCode = m_xmlAttribute[i].nameHashCode;
  5911. int index = 0;
  5912. switch (nameHashCode)
  5913. {
  5914. case 43347: // <sprite name="">
  5915. case 30547: // <SPRITE NAME="">
  5916. m_currentSpriteAsset = TMP_SpriteAsset.SearchForSpriteByHashCode(m_currentSpriteAsset, m_xmlAttribute[i].valueHashCode, true, out index);
  5917. if (index == -1) return false;
  5918. m_spriteIndex = index;
  5919. break;
  5920. case 295562: // <sprite index=>
  5921. case 205930: // <SPRITE INDEX=>
  5922. index = (int)ConvertToFloat(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength);
  5923. if (index == -9999) return false;
  5924. // Check to make sure sprite index is valid
  5925. if (index > m_currentSpriteAsset.spriteInfoList.Count - 1) return false;
  5926. m_spriteIndex = index;
  5927. break;
  5928. case 45819: // tint
  5929. case 33019: // TINT
  5930. m_tintSprite = ConvertToFloat(m_htmlTag, m_xmlAttribute[i].valueStartIndex, m_xmlAttribute[i].valueLength) != 0;
  5931. break;
  5932. case 281955: // color=#FF00FF80
  5933. case 192323: // COLOR
  5934. m_spriteColor = HexCharsToColor(m_htmlTag, m_xmlAttribute[i].valueStartIndex, m_xmlAttribute[i].valueLength);
  5935. break;
  5936. case 39505: // anim="0,16,12" start, end, fps
  5937. case 26705: // ANIM
  5938. //Debug.Log("Start: " + m_xmlAttribute[i].valueStartIndex + " Length: " + m_xmlAttribute[i].valueLength);
  5939. int paramCount = GetAttributeParameters(m_htmlTag, m_xmlAttribute[i].valueStartIndex, m_xmlAttribute[i].valueLength, ref m_attributeParameterValues);
  5940. if (paramCount != 3) return false;
  5941. m_spriteIndex = (int)m_attributeParameterValues[0];
  5942. if (m_isParsingText)
  5943. {
  5944. // TODO : fix this!
  5945. //if (m_attributeParameterValues[0] > m_currentSpriteAsset.spriteInfoList.Count - 1 || m_attributeParameterValues[1] > m_currentSpriteAsset.spriteInfoList.Count - 1)
  5946. // return false;
  5947. spriteAnimator.DoSpriteAnimation(m_characterCount, m_currentSpriteAsset, m_spriteIndex, (int)m_attributeParameterValues[1], (int)m_attributeParameterValues[2]);
  5948. }
  5949. break;
  5950. //case 45545: // size
  5951. //case 32745: // SIZE
  5952. // break;
  5953. default:
  5954. if (nameHashCode != 2246877 && nameHashCode != 1619421)
  5955. return false;
  5956. break;
  5957. }
  5958. }
  5959. if (m_spriteIndex == -1) return false;
  5960. // Material HashCode for the Sprite Asset is the Sprite Asset Hash Code
  5961. m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentSpriteAsset.material, m_currentSpriteAsset, m_materialReferences, m_materialReferenceIndexLookup);
  5962. m_textElementType = TMP_TextElementType.Sprite;
  5963. return true;
  5964. case 730022849: // <lowercase>
  5965. case 514803617: // <LOWERCASE>
  5966. m_style |= FontStyles.LowerCase;
  5967. m_fontStyleStack.Add(FontStyles.LowerCase);
  5968. return true;
  5969. case -1668324918: // </lowercase>
  5970. case -1883544150: // </LOWERCASE>
  5971. if (m_fontStyleStack.Remove(FontStyles.LowerCase) == 0)
  5972. m_style &= ~FontStyles.LowerCase;
  5973. return true;
  5974. case 13526026: // <allcaps>
  5975. case 9133802: // <ALLCAPS>
  5976. case 781906058: // <uppercase>
  5977. case 566686826: // <UPPERCASE>
  5978. m_style |= FontStyles.UpperCase;
  5979. m_fontStyleStack.Add(FontStyles.UpperCase);
  5980. return true;
  5981. case 52232547: // </allcaps>
  5982. case 47840323: // </ALLCAPS>
  5983. case -1616441709: // </uppercase>
  5984. case -1831660941: // </UPPERCASE>
  5985. if (m_fontStyleStack.Remove(FontStyles.UpperCase) == 0)
  5986. m_style &= ~FontStyles.UpperCase;
  5987. return true;
  5988. case 766244328: // <smallcaps>
  5989. case 551025096: // <SMALLCAPS>
  5990. m_style |= FontStyles.SmallCaps;
  5991. m_fontStyleStack.Add(FontStyles.SmallCaps);
  5992. return true;
  5993. case -1632103439: // </smallcaps>
  5994. case -1847322671: // </SMALLCAPS>
  5995. if (m_fontStyleStack.Remove(FontStyles.SmallCaps) == 0)
  5996. m_style &= ~FontStyles.SmallCaps;
  5997. return true;
  5998. case 2109854: // <margin=00.0> <margin=00em> <margin=50%>
  5999. case 1482398: // <MARGIN>
  6000. value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); // px
  6001. if (value == -9999) return false;
  6002. m_marginLeft = value;
  6003. switch (tagUnits)
  6004. {
  6005. case TagUnits.Pixels:
  6006. // Default behavior
  6007. break;
  6008. case TagUnits.FontUnits:
  6009. m_marginLeft *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
  6010. break;
  6011. case TagUnits.Percentage:
  6012. m_marginLeft = (m_marginWidth - (m_width != -1 ? m_width : 0)) * m_marginLeft / 100;
  6013. break;
  6014. }
  6015. m_marginLeft = m_marginLeft >= 0 ? m_marginLeft : 0;
  6016. m_marginRight = m_marginLeft;
  6017. return true;
  6018. case 7639357: // </margin>
  6019. case 7011901: // </MARGIN>
  6020. m_marginLeft = 0;
  6021. m_marginRight = 0;
  6022. return true;
  6023. case 1100728678: // <margin-left=xx.x>
  6024. case -855002522: // <MARGIN-LEFT>
  6025. value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); // px
  6026. if (value == -9999) return false;
  6027. m_marginLeft = value;
  6028. switch (tagUnits)
  6029. {
  6030. case TagUnits.Pixels:
  6031. // Default behavior
  6032. break;
  6033. case TagUnits.FontUnits:
  6034. m_marginLeft *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
  6035. break;
  6036. case TagUnits.Percentage:
  6037. m_marginLeft = (m_marginWidth - (m_width != -1 ? m_width : 0)) * m_marginLeft / 100;
  6038. break;
  6039. }
  6040. m_marginLeft = m_marginLeft >= 0 ? m_marginLeft : 0;
  6041. return true;
  6042. case -884817987: // <margin-right=xx.x>
  6043. case -1690034531: // <MARGIN-RIGHT>
  6044. value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength); // px
  6045. if (value == -9999) return false;
  6046. m_marginRight = value;
  6047. switch (tagUnits)
  6048. {
  6049. case TagUnits.Pixels:
  6050. // Default behavior
  6051. break;
  6052. case TagUnits.FontUnits:
  6053. m_marginRight *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
  6054. break;
  6055. case TagUnits.Percentage:
  6056. m_marginRight = (m_marginWidth - (m_width != -1 ? m_width : 0)) * m_marginRight / 100;
  6057. break;
  6058. }
  6059. m_marginRight = m_marginRight >= 0 ? m_marginRight : 0;
  6060. return true;
  6061. case 1109349752: // <line-height=xx.x>
  6062. case -842693512: // <LINE-HEIGHT>
  6063. value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength);
  6064. if (value == -9999 || value == 0) return false;
  6065. m_lineHeight = value;
  6066. switch (tagUnits)
  6067. {
  6068. case TagUnits.Pixels:
  6069. //m_lineHeight = value;
  6070. break;
  6071. case TagUnits.FontUnits:
  6072. m_lineHeight *= m_fontAsset.fontInfo.LineHeight * m_fontScale;
  6073. break;
  6074. case TagUnits.Percentage:
  6075. m_lineHeight = m_fontAsset.fontInfo.LineHeight * m_lineHeight / 100 * m_fontScale;
  6076. break;
  6077. }
  6078. return true;
  6079. case -445573839: // </line-height>
  6080. case 1897350193: // </LINE-HEIGHT>
  6081. m_lineHeight = TMP_Math.FLOAT_UNSET;
  6082. return true;
  6083. case 15115642: // <noparse>
  6084. case 10723418: // <NOPARSE>
  6085. tag_NoParsing = true;
  6086. return true;
  6087. case 1913798: // <action>
  6088. case 1286342: // <ACTION>
  6089. int actionID = m_xmlAttribute[0].valueHashCode;
  6090. if (m_isParsingText)
  6091. {
  6092. m_actionStack.Add(actionID);
  6093. Debug.Log("Action ID: [" + actionID + "] First character index: " + m_characterCount);
  6094. }
  6095. //if (m_isParsingText)
  6096. //{
  6097. // TMP_Action action = TMP_Action.GetAction(m_xmlAttribute[0].valueHashCode);
  6098. //}
  6099. return true;
  6100. case 7443301: // </action>
  6101. case 6815845: // </ACTION>
  6102. if (m_isParsingText)
  6103. {
  6104. Debug.Log("Action ID: [" + m_actionStack.CurrentItem() + "] Last character index: " + (m_characterCount - 1));
  6105. }
  6106. m_actionStack.Remove();
  6107. return true;
  6108. case 315682: // <scale=xx.x>
  6109. case 226050: // <SCALE=xx.x>
  6110. value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength);
  6111. if (value == -9999) return false;
  6112. m_FXMatrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(value, 1, 1));
  6113. m_isFXMatrixSet = true;
  6114. return true;
  6115. case 1105611: // </scale>
  6116. case 1015979: // </SCALE>
  6117. m_isFXMatrixSet = false;
  6118. return true;
  6119. case 2227963: // <rotate=xx.x>
  6120. case 1600507: // <ROTATE=xx.x>
  6121. // TODO: Add ability to use Random Rotation
  6122. value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength);
  6123. if (value == -9999) return false;
  6124. m_FXMatrix = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0, 0, value), Vector3.one);
  6125. m_isFXMatrixSet = true;
  6126. return true;
  6127. case 7757466: // </rotate>
  6128. case 7130010: // </ROTATE>
  6129. m_isFXMatrixSet = false;
  6130. return true;
  6131. case 317446: // <table>
  6132. case 227814: // <TABLE>
  6133. switch (m_xmlAttribute[1].nameHashCode)
  6134. {
  6135. case 327550: // width
  6136. float tableWidth = ConvertToFloat(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength);
  6137. switch (tagUnits)
  6138. {
  6139. case TagUnits.Pixels:
  6140. Debug.Log("Table width = " + tableWidth + "px.");
  6141. break;
  6142. case TagUnits.FontUnits:
  6143. Debug.Log("Table width = " + tableWidth + "em.");
  6144. break;
  6145. case TagUnits.Percentage:
  6146. Debug.Log("Table width = " + tableWidth + "%.");
  6147. break;
  6148. }
  6149. break;
  6150. }
  6151. return true;
  6152. case 1107375: // </table>
  6153. case 1017743: // </TABLE>
  6154. return true;
  6155. case 926: // <tr>
  6156. case 670: // <TR>
  6157. return true;
  6158. case 3229: // </tr>
  6159. case 2973: // </TR>
  6160. return true;
  6161. case 916: // <th>
  6162. case 660: // <TH>
  6163. // Set style to bold and center alignment
  6164. return true;
  6165. case 3219: // </th>
  6166. case 2963: // </TH>
  6167. return true;
  6168. case 912: // <td>
  6169. case 656: // <TD>
  6170. // Style options
  6171. for (int i = 1; i < m_xmlAttribute.Length && m_xmlAttribute[i].nameHashCode != 0; i++)
  6172. {
  6173. switch (m_xmlAttribute[i].nameHashCode)
  6174. {
  6175. case 327550: // width
  6176. float tableWidth = ConvertToFloat(m_htmlTag, m_xmlAttribute[i].valueStartIndex, m_xmlAttribute[i].valueLength);
  6177. switch (tagUnits)
  6178. {
  6179. case TagUnits.Pixels:
  6180. Debug.Log("Table width = " + tableWidth + "px.");
  6181. break;
  6182. case TagUnits.FontUnits:
  6183. Debug.Log("Table width = " + tableWidth + "em.");
  6184. break;
  6185. case TagUnits.Percentage:
  6186. Debug.Log("Table width = " + tableWidth + "%.");
  6187. break;
  6188. }
  6189. break;
  6190. case 275917: // align
  6191. switch (m_xmlAttribute[i].valueHashCode)
  6192. {
  6193. case 3774683: // left
  6194. Debug.Log("TD align=\"left\".");
  6195. break;
  6196. case 136703040: // right
  6197. Debug.Log("TD align=\"right\".");
  6198. break;
  6199. case -458210101: // center
  6200. Debug.Log("TD align=\"center\".");
  6201. break;
  6202. case -523808257: // justified
  6203. Debug.Log("TD align=\"justified\".");
  6204. break;
  6205. }
  6206. break;
  6207. }
  6208. }
  6209. return true;
  6210. case 3215: // </td>
  6211. case 2959: // </TD>
  6212. return true;
  6213. }
  6214. }
  6215. return false;
  6216. }
  6217. }
  6218. }