using System.Text; using System.Text.RegularExpressions; using UnityEngine; namespace Wizard; public static class RubyText { private enum eSubscriptMode { NORMAL, SUBSCRIPT, SUPERSCRIPT, RUBYSTART, RUBYEND } private const string rubStartStr = "[rub<"; private const string rubEndStr = ">]"; private const string rubTagEndStr = "[/rub]"; private static Color mInvisible = new Color(0f, 0f, 0f, 0f); private static float mAlpha = 1f; private static Color32 s_c0; private static Color32 s_c1; private static BetterList mColors = new BetterList(); private static float[] mBoldOffset = new float[8] { -0.25f, 0f, 0.25f, 0f, 0f, -0.25f, 0f, 0.25f }; private static bool IsSpace(int ch) { if (ch != 32 && ch != 8202 && ch != 8203) { return ch == 8201; } return true; } public static string ReplaceDotTagToRubyTag(string text) { return Regex.Replace(text, "(\\[dot\\])(.+?)(\\[\\/dot\\])", (Match m) => ConvertRubyTagForDotText(m.Groups[2].Value)); } public static string RemoveRubyTag(string text) { return Regex.Replace(Regex.Replace(text, "\\[rub<.*?>\\]", ""), "\\[/rub\\]", ""); } private static string ConvertRubyTagForDotText(string text) { StringBuilder stringBuilder = new StringBuilder(); foreach (char c in text) { stringBuilder.Append($"[rub<・>]{c}[/rub]"); } return stringBuilder.ToString(); } public static bool ParseSymbol(string text, ref int index, BetterList colors, bool premultiply, ref int sub, ref bool bold, ref bool italic, ref bool underline, ref bool strike, ref bool ignoreColor) { float rubyTotalAdvanceRaw = 0f; float charWithRubyTotalAdvance = 0f; bool isDot = false; return ParseSymbol(text, ref index, colors, premultiply, ref sub, ref bold, ref italic, ref underline, ref strike, ref ignoreColor, ref rubyTotalAdvanceRaw, ref charWithRubyTotalAdvance, isRuby: false, ref isDot); } private static bool ParseSymbol(string text, ref int index, BetterList colors, bool premultiply, ref int sub, ref bool bold, ref bool italic, ref bool underline, ref bool strike, ref bool ignoreColor, ref float rubyTotalAdvanceRaw, ref float charWithRubyTotalAdvance, bool isRuby, ref bool isDot) { int length = text.Length; if (index + 1 < length && text.Substring(index, ">]".Length) == ">]") { if (isRuby) { sub = 4; } index += ">]".Length; return true; } if (index + 3 > length || text[index] != '[') { return false; } if (text[index + 2] == ']') { if (text[index + 1] == '-') { if (colors != null && colors.size > 1) { colors.RemoveAt(colors.size - 1); } index += 3; return true; } switch (text.Substring(index, 3)) { case "[1]": case "[2]": case "[3]": case "[4]": case "[5]": index += 3; return true; case "[b]": bold = true; index += 3; return true; case "[i]": italic = true; index += 3; return true; case "[u]": underline = true; index += 3; return true; case "[s]": strike = true; index += 3; return true; case "[c]": ignoreColor = true; index += 3; return true; } } if (index + 4 > length) { return false; } if (text[index + 3] == ']') { switch (text.Substring(index, 4)) { case "[/b]": bold = false; index += 4; return true; case "[/i]": italic = false; index += 4; return true; case "[/u]": underline = false; index += 4; return true; case "[/s]": strike = false; index += 4; return true; case "[/c]": ignoreColor = false; index += 4; return true; } char ch = text[index + 1]; char ch2 = text[index + 2]; if (NGUIText.IsHex(ch) && NGUIText.IsHex(ch2)) { mAlpha = (float)((NGUIMath.HexToDecimal(ch) << 4) | NGUIMath.HexToDecimal(ch2)) / 255f; index += 4; return true; } } if (index + 5 > length) { return false; } if (text[index + 4] == ']') { switch (text.Substring(index, 5)) { case "[sub]": sub = 1; index += 5; return true; case "[sup]": sub = 2; index += 5; return true; } } if (text[index + 4] == '<') { string text2 = text.Substring(index, 5); if (text2 != null && text2 == "[rub<") { index += "[rub<".Length; bool flag = false; rubyTotalAdvanceRaw = 0f; int num = 0; StringBuilder stringBuilder = new StringBuilder(); for (int i = index; i + ">]".Length < length; i++) { char c = text[i]; if (c == '\n') { continue; } if (text.Substring(i, ">]".Length) == ">]") { break; } num++; if (!flag && IsFadeTagStart(text, i)) { flag = true; } if (flag) { if (c == ']') { flag = false; } } else { int prev = ((i > 0) ? text[i - 1] : '\0'); rubyTotalAdvanceRaw += NGUIText.finalSpacingX + NGUIText.GetGlyph(c, prev).advance; stringBuilder.Append(c); } } if (isRuby) { bool flag2 = false; charWithRubyTotalAdvance = 0f; for (int j = index + num + ">]".Length; j < length; j++) { char c2 = text[j]; if (c2 == '\n') { continue; } if (j + "[/rub]".Length <= length && text.Substring(j, "[/rub]".Length) == "[/rub]") { break; } if (!flag2 && IsFadeTagStart(text, j)) { flag2 = true; } if (flag2) { if (c2 == ']') { flag2 = false; } } else { int prev2 = ((j > 0) ? text[j - 1] : '\0'); charWithRubyTotalAdvance += NGUIText.finalSpacingX + NGUIText.GetGlyph(c2, prev2).advance; } } if (stringBuilder.ToString() == "・") { isDot = true; } else { isDot = false; } sub = 3; } else { if (length > index + num + ">]".Length) { index += num + ">]".Length; } sub = 0; } return true; } } if (index + 6 > length) { return false; } if (text[index + 5] == ']') { switch (text.Substring(index, 6)) { case "[/sub]": sub = 0; index += 6; return true; case "[/sup]": sub = 0; index += 6; return true; case "[/rub]": sub = 0; index += 6; return true; case "[/url]": index += 6; return true; } } if (text[index + 1] == 'u' && text[index + 2] == 'r' && text[index + 3] == 'l' && text[index + 4] == '=') { int num2 = text.IndexOf(']', index + 4); if (num2 != -1) { index = num2 + 1; return true; } index = text.Length; return true; } if (index + 8 > length) { return false; } if (text[index + 7] == ']') { Color color = NGUIText.ParseColor24(text, index + 1); if (NGUIText.EncodeColor24(color) != text.Substring(index + 1, 6).ToUpper()) { return false; } if (colors != null) { color.a = colors[colors.size - 1].a; if (premultiply && color.a != 1f) { color = Color.Lerp(mInvisible, color, color.a); } colors.Add(color); } index += 8; return true; } if (index + 10 > length) { return false; } if (text[index + 9] == ']') { Color color2 = NGUIText.ParseColor32(text, index + 1); if (NGUIText.EncodeColor32(color2) != text.Substring(index + 1, 8).ToUpper()) { return false; } if (colors != null) { if (premultiply && color2.a != 1f) { color2 = Color.Lerp(mInvisible, color2, color2.a); } colors.Add(color2); } index += 10; return true; } return false; } private static bool IsFadeTagStart(string text, int offset) { if (offset + 3 >= text.Length) { return false; } if (text[offset] == '[' && text[offset + 3] == ']' && NGUIText.IsHex(text[offset + 1]) && NGUIText.IsHex(text[offset + 2])) { return true; } return false; } public static void PrintWithRuby(string text, BetterList verts, BetterList uvs, BetterList cols, UILabel uiLabel = null) { if (string.IsNullOrEmpty(text)) { return; } UICurveLabel component = uiLabel.GetComponent(); if (component != null) { component.Init(text); } int size = verts.size; NGUIText.Prepare(text); mColors.Add(Color.white); mAlpha = 1f; int num = 0; int prev = 0; float num2 = 0f; float num3 = 0f; float num4 = 0f; float num5 = NGUIText.finalSize; Color a = NGUIText.tint * NGUIText.gradientBottom; Color b = NGUIText.tint * NGUIText.gradientTop; Color32 color = NGUIText.tint; int length = text.Length; Rect rect = default(Rect); float num6 = 0f; float num7 = 0f; float num8 = num5 * NGUIText.pixelDensity; bool flag = false; int sub = 0; bool bold = false; bool italic = false; bool underline = false; bool strike = false; bool ignoreColor = false; float num9 = 0f; float num10 = 0f; if (NGUIText.bitmapFont != null) { rect = NGUIText.bitmapFont.uvRect; num6 = rect.width / (float)NGUIText.bitmapFont.texWidth; num7 = rect.height / (float)NGUIText.bitmapFont.texHeight; } float num11 = 0f; float rubyTotalAdvanceRaw = 0f; float charWithRubyTotalAdvance = 0f; bool flag2 = false; bool isRuby = uiLabel.IsRuby; float num12 = NGUIText.fontScale * (float)NGUIText.fontSize * uiLabel.RubyMargin; float num13 = NGUIText.fontScale * (float)NGUIText.fontSize * uiLabel.DotMargin; bool isDot = false; for (int i = 0; i < length; i++) { num = text[i]; num9 = num2; if (num == 10) { if (num2 > num4) { num4 = num2; } if (NGUIText.alignment != NGUIText.Alignment.Left) { NGUIText.Align(verts, size, CalcAlignPrintedWidth(num2, num10, isRuby)); size = verts.size; } num2 = 0f; num3 += NGUIText.finalLineHeight; prev = 0; if (isRuby) { num11 = 0f; num10 = 0f; } continue; } if (num < 32) { prev = num; continue; } if (NGUIText.encoding && ParseSymbol(text, ref i, mColors, NGUIText.premultiply, ref sub, ref bold, ref italic, ref underline, ref strike, ref ignoreColor, ref rubyTotalAdvanceRaw, ref charWithRubyTotalAdvance, isRuby, ref isDot)) { Color color2; if (ignoreColor) { color2 = mColors[mColors.size - 1]; color2.a *= mAlpha * NGUIText.tint.a; } else { color2 = NGUIText.tint * mColors[mColors.size - 1]; color2.a *= mAlpha; } color = color2; int j = 0; for (int num14 = mColors.size - 2; j < num14; j++) { color2.a *= mColors[j].a; } if (NGUIText.gradient) { a = NGUIText.gradientBottom * color2; b = NGUIText.gradientTop * color2; } i--; continue; } BMSymbol bMSymbol = (NGUIText.useSymbols ? NGUIText.GetSymbol(text, i, length) : null); float num15; float num16; float num18; float num17; if (bMSymbol != null) { num15 = num2 + (float)bMSymbol.offsetX * NGUIText.fontScale; num16 = num15 + (float)bMSymbol.width * NGUIText.fontScale; num17 = 0f - (num3 + (float)bMSymbol.offsetY * NGUIText.fontScale); num18 = num17 - (float)bMSymbol.height * NGUIText.fontScale; if (Mathf.RoundToInt(num2 + (float)bMSymbol.advance * NGUIText.fontScale) > NGUIText.regionWidth) { if (num2 == 0f) { return; } if (NGUIText.alignment != NGUIText.Alignment.Left && size < verts.size) { NGUIText.Align(verts, size, CalcAlignPrintedWidth(num2, num10, isRuby)); size = verts.size; } num15 -= num2; num16 -= num2; num18 -= NGUIText.finalLineHeight; num17 -= NGUIText.finalLineHeight; num2 = 0f; num3 += NGUIText.finalLineHeight; num9 = 0f; } verts.Add(new Vector3(num15, num18)); verts.Add(new Vector3(num15, num17)); verts.Add(new Vector3(num16, num17)); verts.Add(new Vector3(num16, num18)); num2 += NGUIText.finalSpacingX + (float)bMSymbol.advance * NGUIText.fontScale; i += bMSymbol.length - 1; prev = 0; if (uvs != null) { Rect uvRect = bMSymbol.uvRect; float xMin = uvRect.xMin; float yMin = uvRect.yMin; float xMax = uvRect.xMax; float yMax = uvRect.yMax; uvs.Add(new Vector2(xMin, yMin)); uvs.Add(new Vector2(xMin, yMax)); uvs.Add(new Vector2(xMax, yMax)); uvs.Add(new Vector2(xMax, yMin)); } if (cols == null) { continue; } if (NGUIText.symbolStyle == NGUIText.SymbolStyle.Colored) { for (int k = 0; k < 4; k++) { cols.Add(color); } continue; } Color32 item = Color.white; item.a = color.a; for (int l = 0; l < 4; l++) { cols.Add(item); } continue; } NGUIText.GlyphInfo glyph = NGUIText.GetGlyph(num, prev); if (glyph == null) { continue; } prev = num; float num19 = uiLabel.RubyScale; float num20 = num12; if ((sub == 3 || sub == 4) && uiLabel.IsDot && isDot) { num19 = uiLabel.DotScale; num20 = num13; } switch (sub) { case 1: glyph.v0.x *= 0.75f; glyph.v0.y *= 0.75f; glyph.v1.x *= 0.75f; glyph.v1.y *= 0.75f; glyph.v0.y -= NGUIText.fontScale * (float)NGUIText.fontSize * 0.4f; glyph.v1.y -= NGUIText.fontScale * (float)NGUIText.fontSize * 0.4f; break; case 2: glyph.v0.x *= 0.75f; glyph.v0.y *= 0.75f; glyph.v1.x *= 0.75f; glyph.v1.y *= 0.75f; glyph.v0.y += NGUIText.fontScale * (float)NGUIText.fontSize * 0.05f; glyph.v1.y += NGUIText.fontScale * (float)NGUIText.fontSize * 0.05f; break; case 3: { glyph.v0.x *= num19; glyph.v0.y *= num19; glyph.v1.x *= num19; glyph.v1.y *= num19; glyph.v0.y += num20; glyph.v1.y += num20; float num21 = (num19 * rubyTotalAdvanceRaw - charWithRubyTotalAdvance) / 2f; glyph.v0.x -= num11 + num21; glyph.v1.x -= num11 + num21; flag2 = false; break; } case 4: if (!flag2) { flag2 = true; num11 += rubyTotalAdvanceRaw * num19; } glyph.v0.x -= num11; glyph.v1.x -= num11; break; case 0: if (isRuby) { glyph.v0.x -= num11; glyph.v1.x -= num11; } break; } if (component != null) { num3 = component.GetTargetCharacterHeight(i); num15 = glyph.v0.x + num2; num18 = glyph.v0.y - num3; num16 = glyph.v1.x + num2; num17 = glyph.v1.y - num3; } else { num15 = glyph.v0.x + num2; num18 = glyph.v0.y - num3; num16 = glyph.v1.x + num2; num17 = glyph.v1.y - num3; } float num22 = glyph.advance; if (NGUIText.finalSpacingX < 0f) { num22 += NGUIText.finalSpacingX; } if (Mathf.RoundToInt(num2 - num10 + num22) > NGUIText.regionWidth) { if (num2 == 0f) { return; } if (NGUIText.alignment != NGUIText.Alignment.Left && size < verts.size) { NGUIText.Align(verts, size, CalcAlignPrintedWidth(num2, num10, isRuby)); size = verts.size; } num15 -= num2; num16 -= num2; num18 -= NGUIText.finalLineHeight; num17 -= NGUIText.finalLineHeight; num2 = 0f; num3 += NGUIText.finalLineHeight; num9 = 0f; } if (IsSpace(num)) { if (underline) { num = 95; } else if (strike) { num = 45; } } switch (sub) { case 0: case 4: num2 += NGUIText.finalSpacingX + glyph.advance; break; case 1: case 2: num2 += (NGUIText.finalSpacingX + glyph.advance) * 0.75f; break; case 3: { float num23 = (NGUIText.finalSpacingX + glyph.advance) * num19; num2 += num23; num10 += num23; break; } } if (IsSpace(num)) { continue; } if (uvs != null) { if (NGUIText.bitmapFont != null) { glyph.u0.x = rect.xMin + num6 * glyph.u0.x; glyph.u2.x = rect.xMin + num6 * glyph.u2.x; glyph.u0.y = rect.yMax - num7 * glyph.u0.y; glyph.u2.y = rect.yMax - num7 * glyph.u2.y; glyph.u1.x = glyph.u0.x; glyph.u1.y = glyph.u2.y; glyph.u3.x = glyph.u2.x; glyph.u3.y = glyph.u0.y; } int m = 0; for (int num24 = ((!bold) ? 1 : 4); m < num24; m++) { uvs.Add(glyph.u0); uvs.Add(glyph.u1); uvs.Add(glyph.u2); uvs.Add(glyph.u3); } } if (cols != null) { if (glyph.channel == 0 || glyph.channel == 15) { if (NGUIText.gradient) { float num25 = num8 + glyph.v0.y / NGUIText.fontScale; float num26 = num8 + glyph.v1.y / NGUIText.fontScale; num25 /= num8; num26 /= num8; s_c0 = Color.Lerp(a, b, num25); s_c1 = Color.Lerp(a, b, num26); int n = 0; for (int num27 = ((!bold) ? 1 : 4); n < num27; n++) { cols.Add(s_c0); cols.Add(s_c1); cols.Add(s_c1); cols.Add(s_c0); } } else { int num28 = 0; for (int num29 = (bold ? 16 : 4); num28 < num29; num28++) { cols.Add(color); } } } else { Color color3 = color; color3 *= 0.49f; switch (glyph.channel) { case 1: color3.b += 0.51f; break; case 2: color3.g += 0.51f; break; case 4: color3.r += 0.51f; break; case 8: color3.a += 0.51f; break; } Color32 item2 = color3; int num30 = 0; for (int num31 = (bold ? 16 : 4); num30 < num31; num30++) { cols.Add(item2); } } } if (!bold) { if (!italic) { if (component != null) { Vector2[] array = component.SetTargetCharacterRotation(i, ref num15, ref num18, ref num16, ref num17); verts.Add(new Vector3(array[0].x, array[0].y)); verts.Add(new Vector3(array[1].x, array[1].y)); verts.Add(new Vector3(array[2].x, array[2].y)); verts.Add(new Vector3(array[3].x, array[3].y)); } else { verts.Add(new Vector3(num15, num18)); verts.Add(new Vector3(num15, num17)); verts.Add(new Vector3(num16, num17)); verts.Add(new Vector3(num16, num18)); } } else { float num32 = (float)NGUIText.fontSize * 0.1f * ((num17 - num18) / (float)NGUIText.fontSize); verts.Add(new Vector3(num15 - num32, num18)); verts.Add(new Vector3(num15 + num32, num17)); verts.Add(new Vector3(num16 + num32, num17)); verts.Add(new Vector3(num16 - num32, num18)); } } else { for (int num33 = 0; num33 < 4; num33++) { float num34 = mBoldOffset[num33 * 2]; float num35 = mBoldOffset[num33 * 2 + 1]; float num36 = (italic ? ((float)NGUIText.fontSize * 0.1f * ((num17 - num18) / (float)NGUIText.fontSize)) : 0f); verts.Add(new Vector3(num15 + num34 - num36, num18 + num35)); verts.Add(new Vector3(num15 + num34 + num36, num17 + num35)); verts.Add(new Vector3(num16 + num34 + num36, num17 + num35)); verts.Add(new Vector3(num16 + num34 - num36, num18 + num35)); } } if (!(underline || strike)) { continue; } NGUIText.GlyphInfo glyph2 = NGUIText.GetGlyph(strike ? 45 : 95, prev); if (glyph2 == null) { continue; } if (uvs != null) { if (NGUIText.bitmapFont != null) { glyph2.u0.x = rect.xMin + num6 * glyph2.u0.x; glyph2.u2.x = rect.xMin + num6 * glyph2.u2.x; glyph2.u0.y = rect.yMax - num7 * glyph2.u0.y; glyph2.u2.y = rect.yMax - num7 * glyph2.u2.y; } float x = (glyph2.u0.x + glyph2.u2.x) * 0.5f; int num37 = 0; for (int num38 = ((!bold) ? 1 : 4); num37 < num38; num37++) { uvs.Add(new Vector2(x, glyph2.u0.y)); uvs.Add(new Vector2(x, glyph2.u2.y)); uvs.Add(new Vector2(x, glyph2.u2.y)); uvs.Add(new Vector2(x, glyph2.u0.y)); } } if (flag && strike) { num18 = (0f - num3 + glyph2.v0.y) * 0.75f; num17 = (0f - num3 + glyph2.v1.y) * 0.75f; } else { num18 = 0f - num3 + glyph2.v0.y; num17 = 0f - num3 + glyph2.v1.y; } if (bold) { for (int num39 = 0; num39 < 4; num39++) { float num40 = mBoldOffset[num39 * 2]; float num41 = mBoldOffset[num39 * 2 + 1]; verts.Add(new Vector3(num9 + num40, num18 + num41)); verts.Add(new Vector3(num9 + num40, num17 + num41)); verts.Add(new Vector3(num2 + num40, num17 + num41)); verts.Add(new Vector3(num2 + num40, num18 + num41)); } } else { verts.Add(new Vector3(num9, num18)); verts.Add(new Vector3(num9, num17)); verts.Add(new Vector3(num2, num17)); verts.Add(new Vector3(num2, num18)); } if (NGUIText.gradient) { float num42 = num8 + glyph2.v0.y / NGUIText.fontScale; float num43 = num8 + glyph2.v1.y / NGUIText.fontScale; num42 /= num8; num43 /= num8; s_c0 = Color.Lerp(a, b, num42); s_c1 = Color.Lerp(a, b, num43); int num44 = 0; for (int num45 = ((!bold) ? 1 : 4); num44 < num45; num44++) { cols.Add(s_c0); cols.Add(s_c1); cols.Add(s_c1); cols.Add(s_c0); } } else { int num46 = 0; for (int num47 = (bold ? 16 : 4); num46 < num47; num46++) { cols.Add(color); } } } if (NGUIText.alignment != NGUIText.Alignment.Left && size < verts.size) { NGUIText.Align(verts, size, CalcAlignPrintedWidth(num2, num10, isRuby)); size = verts.size; } mColors.Clear(); } private static float CalcAlignPrintedWidth(float textWidth, float rubyTextWidth, bool isRuby) { float num = textWidth - NGUIText.finalSpacingX; if (isRuby) { num -= rubyTextWidth; } return num; } }