/// <summary> /// Ctor: initialize immutable instance. /// </summary> public FontCacheKey(IdeoFamily family, IdeoScript script, float size, FontStyle style) { this.family = family; this.script = script; this.size = (int)(100F * size); this.style = style; }
/// <summary> /// Measures the display rectangle of a single character. /// </summary> public static SizeF MeasureChar(Graphics g, IdeoFamily fam, char c, float size) { // TO-DO: actually invoke g.MeasureString for non-Hanzi characters // I.e., regular and half-width alphabetical and digits FontTray ftray = getFont(fam, IdeoScript.Simp, size, FontStyle.Regular); return(new SizeF(ftray.DisplayWidth, ftray.DisplayHeight)); }
/// <summary> /// Gets the font with the desired parameters for measuring or drawing text. Works from cache. /// </summary> private static FontTray getFont(IdeoFamily fam, IdeoScript script, float size, FontStyle style) { // If font's already in cache, great: use that. FontCacheKey fck = new FontCacheKey(fam, script, size, style); if (fontCache.ContainsKey(fck)) { return(fontCache[fck]); } // First time someone request a font like this. Instantiate and cache it. FontTray ftray = createFont(fam, script, size, style); fontCache[fck] = ftray; return(ftray); }
/// <summary> /// <para>Gets the size of a Hanzi's display rectangle, if using the font with the provided parameters.</para> /// <para>Expensive (instantiates and destroys font).</para> /// </summary> public static SizeF GetCharSize(IdeoFamily fam, float size) { FontTray ftray = null; try { // Font family and script do not matter // Whole point of this class is to make sure the display rectangles // for any family and script are standardized. ftray = createFont(fam, IdeoScript.Simp, size, FontStyle.Regular); return(new SizeF(ftray.DisplayWidth, ftray.DisplayHeight)); } finally { ftray.Font.Dispose(); } }
/// <summary> /// Returns a coverage info provider for the specified font family. /// </summary> public static IFontCoverage GetFontCoverage(IdeoFamily fam) { if (fam == IdeoFamily.Noto) { return(new FontCoverageFull()); } else if (fam == IdeoFamily.ArphicKai) { return(cvrArphic); } else if (fam == IdeoFamily.WinKai) { return(new CvrBinary(winCoverage)); } else { throw new Exception("Forgotten family: " + fam.ToString()); } }
/// <summary> /// Gets the font with the desired parameters for measuring or drawing text. Works from cache. /// </summary> private static FontTray getFont(IdeoFamily fam, IdeoScript script, float size, FontStyle style) { // If font's already in cache, great: use that. FontCacheKey fck = new FontCacheKey(fam, script, size, style); if (fontCache.ContainsKey(fck)) return fontCache[fck]; // First time someone request a font like this. Instantiate and cache it. FontTray ftray = createFont(fam, script, size, style); fontCache[fck] = ftray; return ftray; }
/// <summary> /// Actually instantiates a specific font (based on family, script, size and style). /// </summary> private static FontTray createFont(IdeoFamily fam, IdeoScript script, float size, FontStyle style) { FontTray ftray = null; float height = size * 4F / 3F; height *= scale; // If a system font is requested, instantiate if (fam == IdeoFamily.WinKai) { if (script == IdeoScript.Simp) { ftray = new FontTray( new Font(winFontNameSimp, size, style), 0, -0.05F, height * 0.9F, height); if (ftray.Font.Name != winFontNameSimp) throw new Exception("Requested font not available: " + winFontNameSimp); } else { ftray = new FontTray( new Font(winFontNameTrad, size, style), 0, -0.05F, height * 0.9F, height); if (ftray.Font.Name != winFontNameTrad) throw new Exception("Requested font not available: " + winFontNameTrad); } return ftray; } // If a private font is requested, find font face in private collection and instantiate foreach (FontFamily ff in fonts.Families) { if (fam == IdeoFamily.ArphicKai && script == IdeoScript.Trad && ff.Name == "AR PL UKai TW") ftray = new FontTray( new Font(ff, size, style), -0.08798828125F * height, -0.05F, height * 0.9F, height); // Alternative names below for name of HDZB_75: First shows up on Win8, second on Win7. else if (fam == IdeoFamily.ArphicKai && script == IdeoScript.Simp && (ff.Name == "䡡湄楮札䍓ⵆ潮瑳" || ff.Name == "汉鼎简中楷")) ftray = new FontTray( new Font(ff, size, style), 0, -0.05F, height * 0.9F, height); else if (fam == IdeoFamily.Noto && script == IdeoScript.Trad && ff.Name == "Noto Sans T Chinese Light") ftray = new FontTray( new Font(ff, size * 0.85F, style), height * 0.075F, height * 0.025F, height * 0.9F, height); else if (fam == IdeoFamily.Noto && script == IdeoScript.Simp && ff.Name == "Noto Sans S Chinese Light") ftray = new FontTray( new Font(ff, size * 0.85F, style), height * 0.075F, height * 0.025F, height * 0.9F, height); if (ftray != null) break; } if (ftray == null) throw new Exception("Requested font not available."); return ftray; }
/// <summary> /// Measures the display rectangle of a string. /// </summary> public static SizeF MeasureString(Graphics g, IdeoFamily fam, string text, float size) { // TO-DO: actually invoke g.MeasureString for non-Hanzi characters // I.e., regular and half-width alphabetical and digits FontTray ftray = getFont(fam, IdeoScript.Simp, size, FontStyle.Regular); float width = ((float)text.Length) * ftray.DisplayWidth; return new SizeF(width, ftray.DisplayHeight); }
/// <summary> /// Returns a coverage info provider for the specified font family. /// </summary> public static IFontCoverage GetFontCoverage(IdeoFamily fam) { if (fam == IdeoFamily.Noto) return new FontCoverageFull(); else if (fam == IdeoFamily.ArphicKai) return cvrArphic; else if (fam == IdeoFamily.WinKai) return new CvrBinary(winCoverage); else throw new Exception("Forgotten family: " + fam.ToString()); }
/// <summary> /// <para>Gets the size of a Hanzi's display rectangle, if using the font with the provided parameters.</para> /// <para>Expensive (instantiates and destroys font).</para> /// </summary> public static SizeF GetCharSize(IdeoFamily fam, float size) { FontTray ftray = null; try { // Font family and script do not matter // Whole point of this class is to make sure the display rectangles // for any family and script are standardized. ftray = createFont(fam, IdeoScript.Simp, size, FontStyle.Regular); return new SizeF(ftray.DisplayWidth, ftray.DisplayHeight); } finally { ftray.Font.Dispose(); } }
/// <summary> /// Draws a Hanzi string in the desired font. /// </summary> public static void DrawString(Graphics g, string text, PointF loc, Brush b, IdeoFamily fam, IdeoScript script, float size, FontStyle style) { // Font tray for requested font FontTray ftray = getFont(fam, script, size, style); // Substitute font - only for Arphic simplified FontTray ftraySubst = null; if (fam == IdeoFamily.ArphicKai && script == IdeoScript.Simp) ftraySubst = getFont(fam, IdeoScript.Trad, size, style); // Where to draw - font-specific adjustment float x = loc.X; float y = loc.Y; // TO-DO: actually invoke g.MeasureString for non-Hanzi characters // I.e., regular and half-width alphabetical and digits StringFormat sf = StringFormat.GenericTypographic; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; for (int i = 0; i != text.Length; ++i) { string chr = text.Substring(i, 1); // Get coverage info about character ArphicSimpCoverage asp = ArphicSimpCoverage.SimpCovers; char c = chr[0]; bool tofu = false; if (fam == IdeoFamily.ArphicKai) tofu = (script == IdeoScript.Trad && !cvrArphic.GetCoverage(c).HasFlag(FontCoverageFlags.Trad)) || (script == IdeoScript.Simp && (asp = getArphicCoverageSimp(c)) == ArphicSimpCoverage.None); // Draw tofu is must be if (tofu) { using (Pen p = new Pen(Color.Gray)) { p.DashStyle = DashStyle.Dot; g.SmoothingMode = SmoothingMode.None; g.DrawRectangle(p, x, y, ftray.DisplayWidth, ftray.DisplayHeight); g.SmoothingMode = SmoothingMode.AntiAlias; g.DrawLine(p, x, y, x + ftray.DisplayWidth, y + ftray.DisplayHeight); g.DrawLine(p, x + ftray.DisplayWidth, y, x, y + ftray.DisplayHeight); } } // Draw with substitute string else if (asp == ArphicSimpCoverage.CanSubstitute) g.DrawString(chr, ftraySubst.Font, b, new PointF(x + ftraySubst.HorizOfs, y + ftraySubst.VertOfs), sf); // Draw with requested string else g.DrawString(chr, ftray.Font, b, new PointF(x + ftray.HorizOfs, y + ftray.VertOfs), sf); x += ftray.DisplayWidth; } }
/// <summary> /// Actually instantiates a specific font (based on family, script, size and style). /// </summary> private static FontTray createFont(IdeoFamily fam, IdeoScript script, float size, FontStyle style) { FontTray ftray = null; float height = size * 4F / 3F; height *= scale; // If a system font is requested, instantiate if (fam == IdeoFamily.WinKai) { if (script == IdeoScript.Simp) { ftray = new FontTray( new Font(winFontNameSimp, size, style), 0, -0.05F, height * 0.9F, height); if (ftray.Font.Name != winFontNameSimp) { throw new Exception("Requested font not available: " + winFontNameSimp); } } else { ftray = new FontTray( new Font(winFontNameTrad, size, style), 0, -0.05F, height * 0.9F, height); if (ftray.Font.Name != winFontNameTrad) { throw new Exception("Requested font not available: " + winFontNameTrad); } } return(ftray); } // If a private font is requested, find font face in private collection and instantiate foreach (FontFamily ff in fonts.Families) { if (fam == IdeoFamily.ArphicKai && script == IdeoScript.Trad && ff.Name == "AR PL UKai TW") { ftray = new FontTray( new Font(ff, size, style), -0.08798828125F * height, -0.05F, height * 0.9F, height); } // Alternative names below for name of HDZB_75: First shows up on Win8, second on Win7. else if (fam == IdeoFamily.ArphicKai && script == IdeoScript.Simp && (ff.Name == "䡡湄楮札䍓ⵆ潮瑳" || ff.Name == "汉鼎简中楷")) { ftray = new FontTray( new Font(ff, size, style), 0, -0.05F, height * 0.9F, height); } else if (fam == IdeoFamily.Noto && script == IdeoScript.Trad && ff.Name == "Noto Sans T Chinese Light") { ftray = new FontTray( new Font(ff, size * 0.85F, style), height * 0.075F, height * 0.025F, height * 0.9F, height); } else if (fam == IdeoFamily.Noto && script == IdeoScript.Simp && ff.Name == "Noto Sans S Chinese Light") { ftray = new FontTray( new Font(ff, size * 0.85F, style), height * 0.075F, height * 0.025F, height * 0.9F, height); } if (ftray != null) { break; } } if (ftray == null) { throw new Exception("Requested font not available."); } return(ftray); }
/// <summary> /// Draws a Hanzi string in the desired font. /// </summary> public static void DrawString(Graphics g, string text, PointF loc, Brush b, IdeoFamily fam, IdeoScript script, float size, FontStyle style) { // Font tray for requested font FontTray ftray = getFont(fam, script, size, style); // Substitute font - only for Arphic simplified FontTray ftraySubst = null; if (fam == IdeoFamily.ArphicKai && script == IdeoScript.Simp) { ftraySubst = getFont(fam, IdeoScript.Trad, size, style); } // Where to draw - font-specific adjustment float x = loc.X; float y = loc.Y; // TO-DO: actually invoke g.MeasureString for non-Hanzi characters // I.e., regular and half-width alphabetical and digits StringFormat sf = StringFormat.GenericTypographic; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; for (int i = 0; i != text.Length; ++i) { string chr = text.Substring(i, 1); // Get coverage info about character ArphicSimpCoverage asp = ArphicSimpCoverage.SimpCovers; char c = chr[0]; bool tofu = false; if (fam == IdeoFamily.ArphicKai) { tofu = (script == IdeoScript.Trad && !cvrArphic.GetCoverage(c).HasFlag(FontCoverageFlags.Trad)) || (script == IdeoScript.Simp && (asp = getArphicCoverageSimp(c)) == ArphicSimpCoverage.None); } // Draw tofu is must be if (tofu) { using (Pen p = new Pen(Color.Gray)) { p.DashStyle = DashStyle.Dot; g.SmoothingMode = SmoothingMode.None; g.DrawRectangle(p, x, y, ftray.DisplayWidth, ftray.DisplayHeight); g.SmoothingMode = SmoothingMode.AntiAlias; g.DrawLine(p, x, y, x + ftray.DisplayWidth, y + ftray.DisplayHeight); g.DrawLine(p, x + ftray.DisplayWidth, y, x, y + ftray.DisplayHeight); } } // Draw with substitute string else if (asp == ArphicSimpCoverage.CanSubstitute) { g.DrawString(chr, ftraySubst.Font, b, new PointF(x + ftraySubst.HorizOfs, y + ftraySubst.VertOfs), sf); } // Draw with requested string else { g.DrawString(chr, ftray.Font, b, new PointF(x + ftray.HorizOfs, y + ftray.VertOfs), sf); } x += ftray.DisplayWidth; } }
/// <summary> /// Sets the font family for Hanzi characters in lookup results and char picker. /// </summary> public static void SetZhoContentFontFamily(IdeoFamily fam) { zhoContentFontFamily = fam; }