protectedoverridevoidUpdateGeometry() { if (font != null) { base.UpdateGeometry(); } }
readonly UIVertex[] m_TempVerts = new UIVertex[4]; protectedoverridevoidOnPopulateMesh(VertexHelper toFill) { if (font == null) return;
// We don't care if we the font Texture changes while we are doing our Update. // The end result of cachedTextGenerator will be valid for this instance. // Otherwise we can get issues like Case 619238. m_DisableFontTextureRebuiltCallback = true;
Vector2 extents = rectTransform.rect.size;
var settings = GetGenerationSettings(extents); cachedTextGenerator.PopulateWithErrors(text, settings, gameObject);
// Apply the offset to the vertices IList<UIVertex> verts = cachedTextGenerator.verts; float unitsPerPixel = 1 / pixelsPerUnit; int vertCount = verts.Count;
// We have no verts to process just return (case 1037923) if (vertCount <= 0) { toFill.Clear(); return; }
Vector2 roundingOffset = new Vector2(verts[0].position.x, verts[0].position.y) * unitsPerPixel; roundingOffset = PixelAdjustPoint(roundingOffset) - roundingOffset; toFill.Clear(); if (roundingOffset != Vector2.zero) { for (int i = 0; i < vertCount; ++i) { int tempVertsIndex = i & 3; m_TempVerts[tempVertsIndex] = verts[i]; m_TempVerts[tempVertsIndex].position *= unitsPerPixel; m_TempVerts[tempVertsIndex].position.x += roundingOffset.x; m_TempVerts[tempVertsIndex].position.y += roundingOffset.y; if (tempVertsIndex == 3) toFill.AddUIVertexQuad(m_TempVerts); } } else { for (int i = 0; i < vertCount; ++i) { int tempVertsIndex = i & 3; m_TempVerts[tempVertsIndex] = verts[i]; m_TempVerts[tempVertsIndex].position *= unitsPerPixel; if (tempVertsIndex == 3) toFill.AddUIVertexQuad(m_TempVerts); } }
publicstaticclassFontUpdateTracker { static Dictionary<Font, HashSet<Text>> m_Tracked = new Dictionary<Font, HashSet<Text>>();
publicstaticvoidTrackText(Text t) { if (t.font == null) return;
HashSet<Text> exists; m_Tracked.TryGetValue(t.font, out exists); if (exists == null) { // The textureRebuilt event is global for all fonts, so we add our delegate the first time we register *any* Text if (m_Tracked.Count == 0) Font.textureRebuilt += RebuildForFont;
exists = new HashSet<Text>(); m_Tracked.Add(t.font, exists); } exists.Add(t); }
privatestaticvoidRebuildForFont(Font f) { HashSet<Text> texts; m_Tracked.TryGetValue(f, out texts);
if (texts == null) return;
foreach (var text in texts) text.FontTextureChanged(); }
publicstaticvoidUntrackText(Text t) { if (t.font == null) return;
HashSet<Text> texts; m_Tracked.TryGetValue(t.font, out texts);
if (texts == null) return;
texts.Remove(t);
if (texts.Count == 0) { m_Tracked.Remove(t.font);
// There is a global textureRebuilt event for all fonts, so once the last Text reference goes away, remove our delegate if (m_Tracked.Count == 0) Font.textureRebuilt -= RebuildForFont; } } }
首先,类中定义了一个 Dictionary<Font, HashSet<Text>>,用于分别储存每种字体对应的文本对象。在 TrackText() 方法中,会将 Text 对象注册进 m_Tracked 中。当字体的纹理更新时,会调用 RebuildForFont() 方法,遍历所有注册进来的 Text 对象,调用其 FontTextureChanged() 方法。
///<summary> /// Called by the FontUpdateTracker when the texture associated with a font is modified. ///</summary> publicvoidFontTextureChanged() { // Only invoke if we are not destroyed. if (!this) return;
if (m_DisableFontTextureRebuiltCallback) return;
cachedTextGenerator.Invalidate();
if (!IsActive()) return;
// this is a bit hacky, but it is currently the // cleanest solution.... // if we detect the font texture has changed and are in a rebuild loop // we just regenerate the verts for the new UV's if (CanvasUpdateRegistry.IsRebuildingGraphics() || CanvasUpdateRegistry.IsRebuildingLayout()) UpdateGeometry(); else { SetAllDirty(); } }