2
0

TextStyle.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using QuestPDF.Helpers;
  5. using QuestPDF.Skia;
  6. using QuestPDF.Skia.Text;
  7. namespace QuestPDF.Infrastructure
  8. {
  9. public record TextStyle
  10. {
  11. internal const float NormalLineHeightCalculatedFromFontMetrics = 0;
  12. internal int Id { get; set; }
  13. internal Color? Color { get; set; }
  14. internal Color? BackgroundColor { get; set; }
  15. internal Color? DecorationColor { get; set; }
  16. internal string[]? FontFamilies { get; set; }
  17. internal float? Size { get; set; }
  18. internal float? LineHeight { get; set; }
  19. internal float? LetterSpacing { get; set; }
  20. internal float? WordSpacing { get; set; }
  21. internal FontWeight? FontWeight { get; set; }
  22. internal FontPosition? FontPosition { get; set; }
  23. internal bool? IsItalic { get; set; }
  24. internal bool? HasStrikethrough { get; set; }
  25. internal bool? HasUnderline { get; set; }
  26. internal bool? HasOverline { get; set; }
  27. internal TextStyleConfiguration.TextDecorationStyle? DecorationStyle { get; set; }
  28. internal float? DecorationThickness { get; set; }
  29. internal TextDirection? Direction { get; set; }
  30. public static TextStyle Default { get; } = new()
  31. {
  32. Id = 0
  33. };
  34. internal static TextStyle LibraryDefault { get; } = new()
  35. {
  36. Id = 1,
  37. Color = Colors.Black,
  38. BackgroundColor = Colors.Transparent,
  39. DecorationColor = Colors.Black,
  40. FontFamilies = new[] { Fonts.Lato },
  41. Size = 12,
  42. LineHeight = NormalLineHeightCalculatedFromFontMetrics,
  43. LetterSpacing = 0,
  44. WordSpacing = 0f,
  45. FontWeight = Infrastructure.FontWeight.Normal,
  46. FontPosition = Infrastructure.FontPosition.Normal,
  47. IsItalic = false,
  48. HasStrikethrough = false,
  49. HasUnderline = false,
  50. HasOverline = false,
  51. DecorationStyle = TextStyleConfiguration.TextDecorationStyle.Solid,
  52. DecorationThickness = 1f,
  53. Direction = TextDirection.Auto
  54. };
  55. internal static TextStyle ParagraphSpacing { get; } = LibraryDefault with
  56. {
  57. Id = 2,
  58. Size = 0,
  59. LineHeight = 1
  60. };
  61. private SkTextStyle? SkTextStyleCache;
  62. internal SkTextStyle GetSkTextStyle()
  63. {
  64. if (SkTextStyleCache != null)
  65. return SkTextStyleCache;
  66. var fontFamilyTexts = FontFamilies.Select(x => new SkText(x)).ToList();
  67. SkTextStyleCache = new SkTextStyle(new TextStyleConfiguration
  68. {
  69. FontSize = CalculateTargetFontSize(),
  70. FontWeight = (TextStyleConfiguration.FontWeights?)FontWeight ?? TextStyleConfiguration.FontWeights.Normal,
  71. IsItalic = IsItalic ?? false,
  72. FontFamilies = GetFontFamilyPointers(fontFamilyTexts),
  73. ForegroundColor = Color ?? Colors.Black,
  74. BackgroundColor = BackgroundColor ?? Colors.Transparent,
  75. DecorationColor = DecorationColor ?? Colors.Black,
  76. DecorationType = CreateDecoration(),
  77. DecorationMode = TextStyleConfiguration.TextDecorationMode.Through,
  78. DecorationStyle = DecorationStyle ?? TextStyleConfiguration.TextDecorationStyle.Solid,
  79. DecorationThickness = DecorationThickness ?? 1,
  80. LineHeight = LineHeight ?? NormalLineHeightCalculatedFromFontMetrics,
  81. LetterSpacing = (LetterSpacing ?? 0) * (Size ?? 1),
  82. WordSpacing = (WordSpacing ?? 0) * (Size ?? 1),
  83. BaselineOffset = CalculateBaselineOffset(),
  84. });
  85. fontFamilyTexts.ForEach(x => x.Dispose());
  86. return SkTextStyleCache;
  87. IntPtr[] GetFontFamilyPointers(IList<SkText> texts)
  88. {
  89. var result = new IntPtr[TextStyleConfiguration.FONT_FAMILIES_LENGTH];
  90. for (var i = 0; i < Math.Min(result.Length, texts.Count); i++)
  91. result[i] = texts[i].Instance;
  92. return result;
  93. }
  94. TextStyleConfiguration.TextDecoration CreateDecoration()
  95. {
  96. var result = TextStyleConfiguration.TextDecoration.NoDecoration;
  97. if (HasUnderline == true)
  98. result |= TextStyleConfiguration.TextDecoration.Underline;
  99. if (HasStrikethrough == true)
  100. result |= TextStyleConfiguration.TextDecoration.LineThrough;
  101. if (HasOverline == true)
  102. result |= TextStyleConfiguration.TextDecoration.Overline;
  103. return result;
  104. }
  105. float CalculateTargetFontSize()
  106. {
  107. var fontSize = Size ?? 0;
  108. if (FontPosition is Infrastructure.FontPosition.Subscript or Infrastructure.FontPosition.Superscript)
  109. return fontSize * 0.6f;
  110. return fontSize;
  111. }
  112. float CalculateBaselineOffset()
  113. {
  114. if (FontPosition == Infrastructure.FontPosition.Subscript)
  115. return Size.Value * 0.25f;
  116. if (FontPosition == Infrastructure.FontPosition.Superscript)
  117. return -Size.Value * 0.35f;
  118. return 0;
  119. }
  120. }
  121. }
  122. }