// System.Drawing.Common 在 Linux 上不受支持。Point、Size、Color、SystemColors 等框架自带(System.Drawing.Primitives),
// 这里只补上学生代码会用到、框架里又没有的类型。字体只记录名称和样式,真正的渲染在浏览器里完成。
// 注意:框架的 System.Drawing.dll 门面把 Font 等转发到 System.Drawing.Common,编译学生代码时不能引用它。
using System;
namespace System.Drawing;
public enum ContentAlignment
{
TopLeft = 1,
TopCenter = 2,
TopRight = 4,
MiddleLeft = 16,
MiddleCenter = 32,
MiddleRight = 64,
BottomLeft = 256,
BottomCenter = 512,
BottomRight = 1024,
}
[Flags]
public enum FontStyle
{
Regular = 0,
Bold = 1,
Italic = 2,
Underline = 4,
Strikeout = 8,
}
public enum GraphicsUnit
{
World = 0,
Display = 1,
Pixel = 2,
Point = 3,
Inch = 4,
Document = 5,
Millimeter = 6,
}
public sealed class FontFamily
{
public FontFamily(string name) => Name = name;
public string Name { get; }
public override string ToString() => $"[FontFamily: Name={Name}]";
}
public sealed class Font : IDisposable, ICloneable
{
public Font(string familyName, float emSize)
: this(familyName, emSize, FontStyle.Regular, GraphicsUnit.Point) { }
public Font(string familyName, float emSize, FontStyle style)
: this(familyName, emSize, style, GraphicsUnit.Point) { }
public Font(string familyName, float emSize, GraphicsUnit unit)
: this(familyName, emSize, FontStyle.Regular, unit) { }
public Font(string familyName, float emSize, FontStyle style, GraphicsUnit unit)
{
if (emSize <= 0 || float.IsNaN(emSize) || float.IsInfinity(emSize))
throw new ArgumentException($"“emSize”的值“{emSize}”无效。“emSize”应大于 0 且小于或等于 System.Single.MaxValue。", nameof(emSize));
Name = string.IsNullOrWhiteSpace(familyName) ? "Microsoft Sans Serif" : familyName;
Size = emSize;
Style = style;
Unit = unit;
}
public Font(string familyName, float emSize, FontStyle style, GraphicsUnit unit, byte gdiCharSet)
: this(familyName, emSize, style, unit) => GdiCharSet = gdiCharSet;
public Font(string familyName, float emSize, FontStyle style, GraphicsUnit unit, byte gdiCharSet, bool gdiVerticalFont)
: this(familyName, emSize, style, unit, gdiCharSet) { }
public Font(FontFamily family, float emSize) : this(family.Name, emSize) { }
public Font(FontFamily family, float emSize, FontStyle style) : this(family.Name, emSize, style) { }
public Font(Font prototype, FontStyle newStyle) : this(prototype.Name, prototype.Size, newStyle, prototype.Unit) { }
public string Name { get; }
public float Size { get; }
public FontStyle Style { get; }
public GraphicsUnit Unit { get; }
public byte GdiCharSet { get; } = 1;
public FontFamily FontFamily => new(Name);
public bool Bold => (Style & FontStyle.Bold) != 0;
public bool Italic => (Style & FontStyle.Italic) != 0;
public bool Underline => (Style & FontStyle.Underline) != 0;
public bool Strikeout => (Style & FontStyle.Strikeout) != 0;
/// 按 96 DPI 换算成磅
public float SizeInPoints => Unit switch
{
GraphicsUnit.Pixel => Size * 72f / 96f,
GraphicsUnit.Inch => Size * 72f,
GraphicsUnit.Millimeter => Size * 72f / 25.4f,
GraphicsUnit.Document => Size * 72f / 300f,
_ => Size,
};
/// 大致的行高(像素),中文字体约为字号的 1.33 倍
public int Height => (int)Math.Ceiling(SizeInPoints * 96f / 72f * 1.14f);
public object Clone() => new Font(Name, Size, Style, Unit, GdiCharSet);
public void Dispose() { }
public override string ToString() => $"[Font: Name={Name}, Size={Size}, Units={(int)Unit}, GdiCharSet={GdiCharSet}, GdiVerticalFont=False]";
public override bool Equals(object? obj) =>
obj is Font other && other.Name == Name && other.Size == Size && other.Style == Style && other.Unit == Unit;
public override int GetHashCode() => HashCode.Combine(Name, Size, Style, Unit);
}