SvgElementStyle.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Text;
  5. using System.Reflection;
  6. using System.ComponentModel;
  7. using Svg.DataTypes;
  8. using System.Text.RegularExpressions;
  9. using System.Linq;
  10. #pragma warning disable
  11. namespace Svg
  12. {
  13. public partial class SvgElement
  14. {
  15. private bool _dirty;
  16. /// <summary>
  17. /// Gets or sets a value indicating whether this element's <see cref="Path"/> is dirty.
  18. /// </summary>
  19. /// <value>
  20. /// <c>true</c> if the path is dirty; otherwise, <c>false</c>.
  21. /// </value>
  22. protected virtual bool IsPathDirty
  23. {
  24. get { return this._dirty; }
  25. set { this._dirty = value; }
  26. }
  27. /// <summary>
  28. /// Force recreation of the paths for the element and it's children.
  29. /// </summary>
  30. public void InvalidateChildPaths()
  31. {
  32. this.IsPathDirty = true;
  33. foreach (SvgElement element in this.Children)
  34. {
  35. element.InvalidateChildPaths();
  36. }
  37. }
  38. protected static float FixOpacityValue(float value)
  39. {
  40. const float max = 1.0f;
  41. const float min = 0.0f;
  42. return Math.Min(Math.Max(value, min), max);
  43. }
  44. /// <summary>
  45. /// Gets or sets the fill <see cref="SvgPaintServer"/> of this element.
  46. /// </summary>
  47. [SvgAttribute("fill", true)]
  48. public virtual SvgPaintServer Fill
  49. {
  50. get
  51. {
  52. if (this.Attributes["fill"] == null)
  53. return SvgColourServer.NotSet;
  54. else
  55. return (SvgPaintServer)this.Attributes["fill"];
  56. }
  57. set { this.Attributes["fill"] = value; }
  58. }
  59. /// <summary>
  60. /// Gets or sets the <see cref="SvgPaintServer"/> to be used when rendering a stroke around this element.
  61. /// </summary>
  62. [SvgAttribute("stroke", true)]
  63. public virtual SvgPaintServer Stroke
  64. {
  65. get { return (SvgPaintServer)this.Attributes["stroke"]; }
  66. set { this.Attributes["stroke"] = value; }
  67. }
  68. [SvgAttribute("fill-rule", true)]
  69. public virtual SvgFillRule FillRule
  70. {
  71. get
  72. {
  73. if (this.Attributes["fill-rule"] == null)
  74. return SvgFillRule.NonZero;
  75. else
  76. return (SvgFillRule)this.Attributes["fill-rule"];
  77. }
  78. set { this.Attributes["fill-rule"] = value; }
  79. }
  80. /// <summary>
  81. /// Gets or sets the opacity of this element's <see cref="Fill"/>.
  82. /// </summary>
  83. [SvgAttribute("fill-opacity", true)]
  84. public virtual float FillOpacity
  85. {
  86. get
  87. {
  88. if (this.Attributes["fill-opacity"] == null)
  89. return 1.0f;
  90. else
  91. return (float)this.Attributes["fill-opacity"];
  92. }
  93. set { this.Attributes["fill-opacity"] = FixOpacityValue(value); }
  94. }
  95. /// <summary>
  96. /// Gets or sets the width of the stroke (if the <see cref="Stroke"/> property has a valid value specified.
  97. /// </summary>
  98. [SvgAttribute("stroke-width", true)]
  99. public virtual SvgUnit StrokeWidth
  100. {
  101. get
  102. {
  103. if (this.Attributes["stroke-width"] == null)
  104. return new SvgUnit(1.0f);
  105. else
  106. return (SvgUnit)this.Attributes["stroke-width"];
  107. }
  108. set { this.Attributes["stroke-width"] = value; }
  109. }
  110. [SvgAttribute("stroke-linecap", true)]
  111. public virtual SvgStrokeLineCap StrokeLineCap
  112. {
  113. get
  114. {
  115. if (this.Attributes["stroke-linecap"] == null)
  116. return SvgStrokeLineCap.Butt;
  117. else
  118. return (SvgStrokeLineCap)this.Attributes["stroke-linecap"];
  119. }
  120. set { this.Attributes["stroke-linecap"] = value; }
  121. }
  122. [SvgAttribute("stroke-linejoin", true)]
  123. public virtual SvgStrokeLineJoin StrokeLineJoin
  124. {
  125. get
  126. {
  127. if (this.Attributes["stroke-linejoin"] == null)
  128. return SvgStrokeLineJoin.Miter;
  129. else
  130. return (SvgStrokeLineJoin)this.Attributes["stroke-linejoin"];
  131. }
  132. set { this.Attributes["stroke-linejoin"] = value; }
  133. }
  134. [SvgAttribute("stroke-miterlimit", true)]
  135. public virtual float StrokeMiterLimit
  136. {
  137. get
  138. {
  139. if (this.Attributes["stroke-miterlimit"] == null)
  140. return 4f;
  141. else
  142. return (float)this.Attributes["stroke-miterlimit"];
  143. }
  144. set { this.Attributes["stroke-miterlimit"] = value; }
  145. }
  146. [SvgAttribute("stroke-dasharray", true)]
  147. public virtual SvgUnitCollection StrokeDashArray
  148. {
  149. get { return this.Attributes["stroke-dasharray"] as SvgUnitCollection; }
  150. set { this.Attributes["stroke-dasharray"] = value; }
  151. }
  152. [SvgAttribute("stroke-dashoffset", true)]
  153. public virtual SvgUnit StrokeDashOffset
  154. {
  155. get
  156. {
  157. if (this.Attributes["stroke-dashoffset"] == null)
  158. return SvgUnit.Empty;
  159. else
  160. return (SvgUnit)this.Attributes["stroke-dashoffset"];
  161. }
  162. set { this.Attributes["stroke-dashoffset"] = value; }
  163. }
  164. /// <summary>
  165. /// Gets or sets the opacity of the stroke, if the <see cref="Stroke"/> property has been specified. 1.0 is fully opaque; 0.0 is transparent.
  166. /// </summary>
  167. [SvgAttribute("stroke-opacity", true)]
  168. public virtual float StrokeOpacity
  169. {
  170. get
  171. {
  172. if (this.Attributes["stroke-opacity"] == null)
  173. return 1.0f;
  174. else
  175. return (float)this.Attributes["stroke-opacity"];
  176. }
  177. set { this.Attributes["stroke-opacity"] = FixOpacityValue(value); }
  178. }
  179. /// <summary>
  180. /// Gets or sets the colour of the gradient stop.
  181. /// </summary>
  182. [SvgAttribute("stop-color", true)]
  183. [TypeConverter(typeof(SvgPaintServerFactory))]
  184. public virtual SvgPaintServer StopColor
  185. {
  186. get { return this.Attributes["stop-color"] as SvgPaintServer; }
  187. set { this.Attributes["stop-color"] = value; }
  188. }
  189. /// <summary>
  190. /// Gets or sets the opacity of the element. 1.0 is fully opaque; 0.0 is transparent.
  191. /// </summary>
  192. [SvgAttribute("opacity", true)]
  193. public virtual float Opacity
  194. {
  195. get
  196. {
  197. if (this.Attributes["opacity"] == null)
  198. return 1.0f;
  199. else
  200. return (float)this.Attributes["opacity"];
  201. }
  202. set { this.Attributes["opacity"] = FixOpacityValue(value); }
  203. }
  204. /// <summary>
  205. /// Refers to the AnitAlias rendering of shapes.
  206. /// </summary>
  207. [SvgAttribute("shape-rendering")]
  208. public virtual SvgShapeRendering ShapeRendering
  209. {
  210. get { return this.Attributes.GetInheritedAttribute<SvgShapeRendering>("shape-rendering"); }
  211. set { this.Attributes["shape-rendering"] = value; }
  212. }
  213. /// <summary>
  214. /// Gets or sets the text anchor.
  215. /// </summary>
  216. [SvgAttribute("text-anchor", true)]
  217. public virtual SvgTextAnchor TextAnchor
  218. {
  219. get { return this.Attributes.GetInheritedAttribute<SvgTextAnchor>("text-anchor"); }
  220. set { this.Attributes["text-anchor"] = value; this.IsPathDirty = true; }
  221. }
  222. /// <summary>
  223. /// Specifies dominant-baseline positioning of text.
  224. /// </summary>
  225. [SvgAttribute("baseline-shift", true)]
  226. public virtual string BaselineShift
  227. {
  228. get { return this.Attributes.GetInheritedAttribute<string>("baseline-shift"); }
  229. set { this.Attributes["baseline-shift"] = value; this.IsPathDirty = true; }
  230. }
  231. /// <summary>
  232. /// Indicates which font family is to be used to render the text.
  233. /// </summary>
  234. [SvgAttribute("font-family", true)]
  235. public virtual string FontFamily
  236. {
  237. get { return this.Attributes["font-family"] as string; }
  238. set { this.Attributes["font-family"] = value; this.IsPathDirty = true; }
  239. }
  240. /// <summary>
  241. /// Refers to the size of the font from baseline to baseline when multiple lines of text are set solid in a multiline layout environment.
  242. /// </summary>
  243. [SvgAttribute("font-size", true)]
  244. public virtual SvgUnit FontSize
  245. {
  246. get
  247. {
  248. if (this.Attributes["font-size"] == null)
  249. return SvgUnit.Empty;
  250. else
  251. return (SvgUnit)this.Attributes["font-size"];
  252. }
  253. set { this.Attributes["font-size"] = value; this.IsPathDirty = true; }
  254. }
  255. /// <summary>
  256. /// Refers to the style of the font.
  257. /// </summary>
  258. [SvgAttribute("font-style", true)]
  259. public virtual SvgFontStyle FontStyle
  260. {
  261. get
  262. {
  263. if (this.Attributes["font-style"] == null)
  264. return SvgFontStyle.All;
  265. else
  266. return (SvgFontStyle)this.Attributes["font-style"];
  267. }
  268. set { this.Attributes["font-style"] = value; this.IsPathDirty = true; }
  269. }
  270. /// <summary>
  271. /// Refers to the varient of the font.
  272. /// </summary>
  273. [SvgAttribute("font-variant", true)]
  274. public virtual SvgFontVariant FontVariant
  275. {
  276. get
  277. {
  278. if (this.Attributes["font-variant"] == null)
  279. return SvgFontVariant.Inherit;
  280. else
  281. return (SvgFontVariant)this.Attributes["font-variant"];
  282. }
  283. set { this.Attributes["font-variant"] = value; this.IsPathDirty = true; }
  284. }
  285. /// <summary>
  286. /// Refers to the boldness of the font.
  287. /// </summary>
  288. [SvgAttribute("text-decoration", true)]
  289. public virtual SvgTextDecoration TextDecoration
  290. {
  291. get
  292. {
  293. if (this.Attributes["text-decoration"] == null)
  294. return SvgTextDecoration.Inherit;
  295. else
  296. return (SvgTextDecoration)this.Attributes["text-decoration"];
  297. }
  298. set { this.Attributes["text-decoration"] = value; this.IsPathDirty = true; }
  299. }
  300. /// <summary>
  301. /// Refers to the boldness of the font.
  302. /// </summary>
  303. [SvgAttribute("font-weight", true)]
  304. public virtual SvgFontWeight FontWeight
  305. {
  306. get
  307. {
  308. if (this.Attributes["font-weight"] == null)
  309. return SvgFontWeight.Inherit;
  310. else
  311. return (SvgFontWeight)this.Attributes["font-weight"];
  312. }
  313. set { this.Attributes["font-weight"] = value; this.IsPathDirty = true; }
  314. }
  315. private enum FontParseState
  316. {
  317. fontStyle,
  318. fontVariant,
  319. fontWeight,
  320. fontSize,
  321. fontFamilyNext,
  322. fontFamilyCurr
  323. }
  324. /// <summary>
  325. /// Set all font information.
  326. /// </summary>
  327. [SvgAttribute("font", true)]
  328. public virtual string Font
  329. {
  330. get { return ((this.Attributes["font"] ?? string.Empty) as string); }
  331. set
  332. {
  333. var state = FontParseState.fontStyle;
  334. var parts = value.Split(' ');
  335. SvgFontStyle fontStyle;
  336. SvgFontVariant fontVariant;
  337. SvgFontWeight fontWeight;
  338. SvgUnit fontSize;
  339. bool success;
  340. string[] sizes;
  341. string part;
  342. for (int i = 0; i < parts.Length; i++)
  343. {
  344. part = parts[i];
  345. success = false;
  346. while (!success)
  347. {
  348. switch (state)
  349. {
  350. case FontParseState.fontStyle:
  351. success = Enums.TryParse<SvgFontStyle>(part, out fontStyle);
  352. if (success) this.FontStyle = fontStyle;
  353. state++;
  354. break;
  355. case FontParseState.fontVariant:
  356. success = Enums.TryParse<SvgFontVariant>(part, out fontVariant);
  357. if (success) this.FontVariant = fontVariant;
  358. state++;
  359. break;
  360. case FontParseState.fontWeight:
  361. success = Enums.TryParse<SvgFontWeight>(part, out fontWeight);
  362. if (success) this.FontWeight = fontWeight;
  363. state++;
  364. break;
  365. case FontParseState.fontSize:
  366. sizes = part.Split('/');
  367. try
  368. {
  369. fontSize = (SvgUnit)(new SvgUnitConverter().ConvertFromInvariantString(sizes[0]));
  370. success = true;
  371. this.FontSize = fontSize;
  372. }
  373. catch { }
  374. state++;
  375. break;
  376. case FontParseState.fontFamilyNext:
  377. state++;
  378. success = true;
  379. break;
  380. }
  381. }
  382. switch (state)
  383. {
  384. case FontParseState.fontFamilyNext:
  385. this.FontFamily = string.Join(" ", parts, i + 1, parts.Length - (i + 1));
  386. i = int.MaxValue - 2;
  387. break;
  388. case FontParseState.fontFamilyCurr:
  389. this.FontFamily = string.Join(" ", parts, i, parts.Length - (i));
  390. i = int.MaxValue - 2;
  391. break;
  392. }
  393. }
  394. this.Attributes["font"] = value;
  395. this.IsPathDirty = true;
  396. }
  397. }
  398. /// <summary>
  399. /// Get the font information based on data stored with the text object or inherited from the parent.
  400. /// </summary>
  401. /// <returns></returns>
  402. internal IFontDefn GetFont(ISvgRenderer renderer)
  403. {
  404. // Get the font-size
  405. float fontSize;
  406. var fontSizeUnit = this.FontSize;
  407. if (fontSizeUnit == SvgUnit.None || fontSizeUnit == SvgUnit.Empty)
  408. {
  409. fontSize = 1.0f;
  410. }
  411. else
  412. {
  413. fontSize = fontSizeUnit.ToDeviceValue(renderer, UnitRenderingType.Vertical, this);
  414. }
  415. var family = ValidateFontFamily(this.FontFamily, this.OwnerDocument);
  416. var sFaces = family as IEnumerable<SvgFontFace>;
  417. if (sFaces == null)
  418. {
  419. var fontStyle = System.Drawing.FontStyle.Regular;
  420. // Get the font-weight
  421. switch (this.FontWeight)
  422. {
  423. //Note: Bold is not listed because it is = W700.
  424. case SvgFontWeight.Bolder:
  425. case SvgFontWeight.W600:
  426. case SvgFontWeight.W700:
  427. case SvgFontWeight.W800:
  428. case SvgFontWeight.W900:
  429. fontStyle |= System.Drawing.FontStyle.Bold;
  430. break;
  431. }
  432. // Get the font-style
  433. switch (this.FontStyle)
  434. {
  435. case SvgFontStyle.Italic:
  436. case SvgFontStyle.Oblique:
  437. fontStyle |= System.Drawing.FontStyle.Italic;
  438. break;
  439. }
  440. // Get the text-decoration
  441. switch (this.TextDecoration)
  442. {
  443. case SvgTextDecoration.LineThrough:
  444. fontStyle |= System.Drawing.FontStyle.Strikeout;
  445. break;
  446. case SvgTextDecoration.Underline:
  447. fontStyle |= System.Drawing.FontStyle.Underline;
  448. break;
  449. }
  450. var ff = family as FontFamily;
  451. if (!ff.IsStyleAvailable(fontStyle))
  452. {
  453. // Do Something
  454. }
  455. // Get the font-family
  456. return new GdiFontDefn(new System.Drawing.Font(ff, fontSize, fontStyle, System.Drawing.GraphicsUnit.Pixel));
  457. }
  458. else
  459. {
  460. var font = sFaces.First().Parent as SvgFont;
  461. if (font == null)
  462. {
  463. var uri = sFaces.First().Descendants().OfType<SvgFontFaceUri>().First().ReferencedElement;
  464. font = OwnerDocument.IdManager.GetElementById(uri) as SvgFont;
  465. }
  466. return new SvgFontDefn(font, fontSize, OwnerDocument.Ppi);
  467. }
  468. }
  469. public static object ValidateFontFamily(string fontFamilyList, SvgDocument doc)
  470. {
  471. // Split font family list on "," and then trim start and end spaces and quotes.
  472. var fontParts = (fontFamilyList ?? string.Empty).Split(',').Select(fontName => fontName.Trim(new[] { '"', ' ', '\'' }));
  473. var families = FastReport.FontManager.AllFamilies;
  474. Func<FontFamily, bool> getFamily;
  475. FontFamily family;
  476. IEnumerable<SvgFontFace> sFaces;
  477. // Find a the first font that exists in the list of installed font families.
  478. //styles from IE get sent through as lowercase.
  479. foreach (var f in fontParts)
  480. {
  481. if (doc.FontDefns().TryGetValue(f, out sFaces)) return sFaces;
  482. getFamily = new Func<FontFamily, bool>(ff => string.Equals(ff.Name, f, StringComparison.OrdinalIgnoreCase));
  483. family = families.FirstOrDefault(getFamily);
  484. if (family != null) return family;
  485. switch (f.ToLower())
  486. {
  487. case "serif":
  488. return System.Drawing.FontFamily.GenericSerif;
  489. case "sans-serif":
  490. return System.Drawing.FontFamily.GenericSansSerif;
  491. case "monospace":
  492. return System.Drawing.FontFamily.GenericMonospace;
  493. }
  494. }
  495. // No valid font family found from the list requested.
  496. return System.Drawing.FontFamily.GenericSansSerif;
  497. }
  498. }
  499. }
  500. #pragma warning restore