using System; using System.Drawing; using System.Linq; namespace FastReport.Utils { internal enum MonoRendering { Undefined, Pango, Cairo } public static partial class DrawUtils { private static Font FDefaultFont; private static Font FDefaultReportFont; private static Font FDefaultTextObjectFont; private static Font FFixedFont; private static int FScreenDpi; private static float FDpiFX; private static MonoRendering FMonoRendering = MonoRendering.Undefined; public static int ScreenDpi { get { if (FScreenDpi == 0) FScreenDpi = GetDpi(); return FScreenDpi; } } public static float ScreenDpiFX { get { if (FDpiFX == 0f) FDpiFX = 96f / DrawUtils.ScreenDpi; return FDpiFX; } } private static int GetDpi() { using (Bitmap bmp = new Bitmap(1, 1)) using (Graphics g = Graphics.FromImage(bmp)) { return (int)g.DpiX; } } public static Font DefaultFont { get { if (FDefaultFont == null) { #if AVALONIA if (OperatingSystem.IsWindows()) { FDefaultFont = new Font("Segoe UI", 8.5f); } else if (OperatingSystem.IsMacOS()) { FDefaultFont = new Font("Helvetica Neue", 8.5f); } else if (OperatingSystem.IsLinux()) { FDefaultFont = new Font("Liberation Sans", 8.5f); } #else switch (System.Globalization.CultureInfo.CurrentCulture.TwoLetterISOLanguageName) { case "ja": FDefaultFont = CreateFont("MS UI Gothic", 9); break; case "zh": FDefaultFont = CreateFont("SimSun", 9); break; default: #if WPF FDefaultFont = CreateFont("Segoe UI", 8.5f); #else FDefaultFont = CreateFont("Tahoma", 8); #endif break; } #endif } return FDefaultFont; } set { FDefaultFont = value; } } public static Font DefaultReportFont { get { if (FDefaultReportFont == null) { switch (System.Globalization.CultureInfo.CurrentCulture.TwoLetterISOLanguageName) { case "ja": FDefaultReportFont = CreateFont("MS UI Gothic", 9); break; case "zh": FDefaultReportFont = CreateFont("SimSun", 9); break; default: FDefaultReportFont = CreateFont("Arial", 10); break; } } return FDefaultReportFont; } } public static Font DefaultTextObjectFont { get { if (FDefaultTextObjectFont == null) FDefaultTextObjectFont = CreateFont("Arial", 10); return FDefaultTextObjectFont; } } public static Font FixedFont { get { if (FFixedFont == null) #if WPF FFixedFont = CreateFont("Consolas", 9); #elif AVALONIA if (OperatingSystem.IsWindows()) { FFixedFont = CreateFont("Lucida Console", 9); } else if (OperatingSystem.IsMacOS()) { FFixedFont = CreateFont("PT Mono", 9); } else if (OperatingSystem.IsLinux()) { FFixedFont = CreateFont("Liberation Mono", 9); } #else FFixedFont = CreateFont("Courier New", 10); #endif return FFixedFont; } } internal static Font CreateFont(string familyName, float emSize, FontStyle style = FontStyle.Regular, GraphicsUnit unit = GraphicsUnit.Point, byte gdiCharSet = 1, bool gdiVerticalFont = false) { Font font = new Font(familyName, emSize, style, unit, gdiCharSet, gdiVerticalFont); // skia now handles Font instantiation correctly /*#if SKIA if (font.Name != familyName) { // font family not found in installed fonts, search in the user fonts font = new Font(familyName, emSize, style, unit, gdiCharSet, gdiVerticalFont, Config.PrivateFontCollection.Collection); } #endif*/ return font; } public static SizeF MeasureString(string text) { return MeasureString(text, DefaultFont); } public static SizeF MeasureString(string text, Font font) { using (Bitmap bmp = new Bitmap(1, 1)) using (StringFormat sf = new StringFormat()) { Graphics g = Graphics.FromImage(bmp); return MeasureString(g, text, font, sf); } } public static SizeF MeasureString(Graphics g, string text, Font font, StringFormat format) { return MeasureString(g, text, font, new RectangleF(0, 0, 10000, 10000), format); } public static SizeF MeasureString(Graphics g, string text, Font font, RectangleF layoutRect, StringFormat format) { if (String.IsNullOrEmpty(text)) return new SizeF(0, 0); CharacterRange[] characterRanges = { new CharacterRange(0, text.Length) }; StringFormatFlags saveFlags = format.FormatFlags; format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces; format.SetMeasurableCharacterRanges(characterRanges); Region[] regions = g.MeasureCharacterRanges(text, font, layoutRect, format); format.FormatFlags = saveFlags; RectangleF rect = regions[0].GetBounds(g); regions[0].Dispose(); return rect.Size; } internal static MonoRendering GetMonoRendering(IGraphics printerGraphics) { if (FMonoRendering == MonoRendering.Undefined) { GraphicsUnit savedUnit = printerGraphics.PageUnit; printerGraphics.PageUnit = GraphicsUnit.Point; const string s = "test string test string test string test string"; float f1 = printerGraphics.MeasureString(s, DefaultReportFont).Width; FMonoRendering = f1 > 200 ? MonoRendering.Pango : MonoRendering.Cairo; printerGraphics.PageUnit = savedUnit; } return FMonoRendering; } /// /// The method adjusts the dotted line style for the in a graphical context. /// /// Collection of values for custom dash pattern. /// Pen for lines. /// Border around the report object. /// /// If a DashPattern pattern is specified and contains elements, the method checks each element. /// If the element is less than or equal to 0, it is replaced by 1.
/// Then the resulting array of patterns is converted to the type and set as a dotted line pattern for the .
/// If the pattern is empty or not specified, /// the method sets the style of the dotted line of the equal to the style of the dotted line of the object. ///
internal static void SetPenDashPatternOrStyle(FloatCollection dashPattern, Pen pen, Border border) { if (dashPattern?.Count > 0) { for (int i = 0; i < dashPattern.Count; i++) { if (dashPattern[i] <= 0) dashPattern[i] = 1; } pen.DashPattern = dashPattern.Cast().ToArray(); } else { pen.DashStyle = border.DashStyle; } } } }