TextObject.cs 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830
  1. using System;
  2. using System.Text;
  3. using System.Collections.Generic;
  4. using System.Drawing;
  5. using System.Drawing.Text;
  6. using System.Drawing.Drawing2D;
  7. using System.ComponentModel;
  8. using FastReport.Utils;
  9. using FastReport.Format;
  10. using FastReport.Code;
  11. using System.Windows.Forms;
  12. using System.Drawing.Design;
  13. namespace FastReport
  14. {
  15. /// <summary>
  16. /// Specifies the horizontal alignment of a text in the TextObject object.
  17. /// </summary>
  18. public enum HorzAlign
  19. {
  20. /// <summary>
  21. /// Specifies that text is aligned in the left of the layout rectangle.
  22. /// </summary>
  23. Left,
  24. /// <summary>
  25. /// Specifies that text is aligned in the center of the layout rectangle.
  26. /// </summary>
  27. Center,
  28. /// <summary>
  29. /// Specifies that text is aligned in the right of the layout rectangle.
  30. /// </summary>
  31. Right,
  32. /// <summary>
  33. /// Specifies that text is aligned in the left and right sides of the layout rectangle.
  34. /// </summary>
  35. Justify
  36. }
  37. /// <summary>
  38. /// Specifies the vertical alignment of a text in the TextObject object.
  39. /// </summary>
  40. public enum VertAlign
  41. {
  42. /// <summary>
  43. /// Specifies that text is aligned in the top of the layout rectangle.
  44. /// </summary>
  45. Top,
  46. /// <summary>
  47. /// Specifies that text is aligned in the center of the layout rectangle.
  48. /// </summary>
  49. Center,
  50. /// <summary>
  51. /// Specifies that text is aligned in the bottom of the layout rectangle.
  52. /// </summary>
  53. Bottom
  54. }
  55. /// <summary>
  56. /// The type of text renderer
  57. /// </summary>
  58. public enum TextRenderType
  59. {
  60. /// <summary>
  61. /// The default render
  62. /// </summary>
  63. Default,
  64. /// <summary>
  65. /// Render with some html tags and stable logic
  66. /// </summary>
  67. HtmlTags,
  68. /// <summary>
  69. /// Render with img tags, span etc. Experimental and unstable logic
  70. /// </summary>
  71. HtmlParagraph,
  72. /// <summary>
  73. /// Renders a text in a simplest way. For internal use only.
  74. /// </summary>
  75. Inline
  76. }
  77. /// <summary>
  78. /// The format of paragraph
  79. /// </summary>
  80. [TypeConverter(typeof(TypeConverters.FRExpandableObjectConverter))]
  81. public class ParagraphFormat
  82. {
  83. private float firstLineIndent;
  84. private float lineSpacing;
  85. private LineSpacingType lineSpacingType;
  86. private bool skipFirstLineIndent;
  87. /// <summary>
  88. /// The first line on each paragraph.
  89. /// </summary>
  90. [Browsable(true)]
  91. [DefaultValue(0f)]
  92. [TypeConverter("FastReport.TypeConverters.UnitsConverter, FastReport")]
  93. public float FirstLineIndent
  94. {
  95. get { return firstLineIndent; }
  96. set { firstLineIndent = value; }
  97. }
  98. /// <summary>
  99. /// The distance between lines, not effect if value less then 0
  100. /// </summary>
  101. [Browsable(true)]
  102. [DefaultValue(0f)]
  103. [TypeConverter("FastReport.TypeConverters.UnitsConverter, FastReport")]
  104. public float LineSpacing
  105. {
  106. get { return lineSpacing; }
  107. set { if (value >= 0) lineSpacing = value; }
  108. }
  109. /// <summary>
  110. /// The spacing type for distance between line calculation
  111. /// </summary>
  112. [Browsable(true)]
  113. [DefaultValue(LineSpacingType.Single)]
  114. public LineSpacingType LineSpacingType
  115. {
  116. get { return lineSpacingType; }
  117. set { lineSpacingType = value; }
  118. }
  119. /// <summary>
  120. /// The value for a multiplication line height for adding spacing
  121. /// </summary>
  122. [Browsable(true)]
  123. [DefaultValue(0f)]
  124. public float LineSpacingMultiple
  125. {
  126. get { return lineSpacing / 100f; }
  127. set { if (value >= 0) lineSpacing = value * 100f; }
  128. }
  129. /// <summary>
  130. /// Skip the line indent in the first paragraph, for broken paragraphs
  131. /// </summary>
  132. [Browsable(false)]
  133. [DefaultValue(false)]
  134. public bool SkipFirstLineIndent
  135. {
  136. get { return skipFirstLineIndent; }
  137. set { skipFirstLineIndent = value; }
  138. }
  139. /// <summary>
  140. /// clone with new scale;
  141. /// </summary>
  142. /// <param name="scale"></param>
  143. /// <returns></returns>
  144. internal ParagraphFormat MultipleScale(float scale)
  145. {
  146. ParagraphFormat clone = new ParagraphFormat();
  147. clone.lineSpacingType = lineSpacingType;
  148. if (LineSpacingType == LineSpacingType.Multiple)
  149. clone.lineSpacing = lineSpacing;
  150. else
  151. clone.lineSpacing = lineSpacing * scale;
  152. clone.firstLineIndent = firstLineIndent * scale;
  153. clone.skipFirstLineIndent = skipFirstLineIndent;
  154. return clone;
  155. }
  156. internal void Assign(ParagraphFormat p)
  157. {
  158. lineSpacingType = p.lineSpacingType;
  159. lineSpacing = p.lineSpacing;
  160. firstLineIndent = p.firstLineIndent;
  161. skipFirstLineIndent = p.skipFirstLineIndent;
  162. }
  163. public override bool Equals(object obj)
  164. {
  165. ParagraphFormat format = obj as ParagraphFormat;
  166. return format != null &&
  167. firstLineIndent == format.firstLineIndent &&
  168. lineSpacing == format.lineSpacing &&
  169. lineSpacingType == format.lineSpacingType &&
  170. skipFirstLineIndent == format.skipFirstLineIndent;
  171. }
  172. public override int GetHashCode()
  173. {
  174. unchecked
  175. {
  176. int hashCode = -1051315095;
  177. hashCode = hashCode * -1521134295 + firstLineIndent.GetHashCode();
  178. hashCode = hashCode * -1521134295 + lineSpacing.GetHashCode();
  179. hashCode = hashCode * -1521134295 + lineSpacingType.GetHashCode();
  180. hashCode = hashCode * -1521134295 + skipFirstLineIndent.GetHashCode();
  181. return hashCode;
  182. }
  183. }
  184. }
  185. /// <summary>
  186. /// The spacing type between lines
  187. /// </summary>
  188. public enum LineSpacingType
  189. {
  190. /// <summary>
  191. /// Single spacing, not effect from LineSpacing
  192. /// </summary>
  193. Single,
  194. /// <summary>
  195. /// Minimal spacing in exactly size
  196. /// </summary>
  197. AtLeast,
  198. /// <summary>
  199. /// The specific distance between the lines, for some exports, does not work if the distance value is too small.
  200. /// </summary>
  201. Exactly,
  202. /// <summary>
  203. /// The calculated distance between lines, for some exports, does not work if the distance value is too small.
  204. /// </summary>
  205. Multiple
  206. }
  207. /// <summary>
  208. /// Specifies the behavior of the <b>AutoShrink</b> feature of <b>TextObject</b>.
  209. /// </summary>
  210. public enum AutoShrinkMode
  211. {
  212. /// <summary>
  213. /// AutoShrink is disabled.
  214. /// </summary>
  215. None,
  216. /// <summary>
  217. /// AutoShrink decreases the <b>Font.Size</b> property of the <b>TextObject</b>.
  218. /// </summary>
  219. FontSize,
  220. /// <summary>
  221. /// AutoShrink decreases the <b>FontWidthRatio</b> property of the <b>TextObject</b>.
  222. /// </summary>
  223. FontWidth
  224. }
  225. /// <summary>
  226. /// Specifies the behavior of the <b>MergeMode</b> feature of <b>TextObject</b>.
  227. /// </summary>
  228. [TypeConverter(typeof(FastReport.TypeConverters.FlagConverter))]
  229. [Flags]
  230. public enum MergeMode
  231. {
  232. /// <summary>
  233. /// Merge is disabled.
  234. /// </summary>
  235. None = 0,
  236. /// <summary>
  237. /// Allows horizontal merging.
  238. /// </summary>
  239. Horizontal = 1,
  240. /// <summary>
  241. /// Allows vertical merging.
  242. /// </summary>
  243. Vertical = 2,
  244. }
  245. /// <summary>
  246. /// Represents the Text object that may display one or several text lines.
  247. /// </summary>
  248. /// <remarks>
  249. /// Specify the object's text in the <see cref="TextObjectBase.Text">Text</see> property.
  250. /// Text may contain expressions and data items, for example: "Today is [Date]". When report
  251. /// is running, all expressions are calculated and replaced with actual values, so the text
  252. /// would be "Today is 01.01.2008".
  253. /// <para/>The symbols used to find expressions in a text are set in the
  254. /// <see cref="TextObjectBase.Brackets">Brackets</see> property. You also may disable expressions
  255. /// using the <see cref="TextObjectBase.AllowExpressions">AllowExpressions</see> property.
  256. /// <para/>To format an expression value, use the <see cref="Format"/> property.
  257. /// </remarks>
  258. public partial class TextObject : TextObjectBase
  259. {
  260. #region Fields
  261. private MergeMode mergeMode;
  262. private bool autoWidth;
  263. private HorzAlign horzAlign;
  264. private VertAlign vertAlign;
  265. private int angle;
  266. private bool rightToLeft;
  267. private bool wordWrap;
  268. private bool underlines;
  269. private Font font;
  270. private FillBase textFill;
  271. private TextOutline textOutline;
  272. private StringTrimming trimming;
  273. private float fontWidthRatio;
  274. private float firstTabOffset;
  275. private float tabWidth;
  276. private FloatCollection tabPositions;
  277. private bool clip;
  278. private ConditionCollection highlight;
  279. private bool wysiwyg;
  280. private float lineHeight;
  281. private bool forceJustify;
  282. private TextRenderType textRenderType;
  283. private AutoShrinkMode autoShrink;
  284. private float autoShrinkMinSize;
  285. private float paragraphOffset;
  286. private FillBase savedTextFill;
  287. private Font savedFont;
  288. private string savedText;
  289. private FormatBase savedFormat;
  290. private InlineImageCache inlineImageCache;
  291. private ParagraphFormat paragraphFormat;
  292. private bool preserveLastLineSpace;
  293. #endregion
  294. #region Properties
  295. /// <summary>
  296. /// Gets or sets a paragraph format for a new html rendering type, not for others rendering
  297. /// </summary>
  298. [Category("Appearance")]
  299. public ParagraphFormat ParagraphFormat
  300. {
  301. get { return paragraphFormat; }
  302. set { paragraphFormat = value; }
  303. }
  304. /// <summary>
  305. /// Gets or sets a value that determines if the text object should handle its width automatically.
  306. /// </summary>
  307. [DefaultValue(false)]
  308. [Category("Behavior")]
  309. public bool AutoWidth
  310. {
  311. get { return autoWidth; }
  312. set { autoWidth = value; }
  313. }
  314. /// <summary>
  315. /// Gets or sets a value that indicates whether the font size should shrink to
  316. /// display the longest text line without word wrap.
  317. /// </summary>
  318. /// <remarks>
  319. /// To limit the minimum size, use the <see cref="AutoShrinkMinSize"/> property.
  320. /// </remarks>
  321. [DefaultValue(AutoShrinkMode.None)]
  322. [Category("Behavior")]
  323. public AutoShrinkMode AutoShrink
  324. {
  325. get { return autoShrink; }
  326. set { autoShrink = value; }
  327. }
  328. /// <summary>
  329. /// Gets or sets the minimum size of font (or minimum width ratio) if the <see cref="AutoShrink"/>
  330. /// mode is on.
  331. /// </summary>
  332. /// <remarks>
  333. /// This property determines the minimum font size (in case the <see cref="AutoShrink"/> property is set to
  334. /// <b>FontSize</b>), or the minimum font width ratio (if <b>AutoShrink</b> is set to <b>FontWidth</b>).
  335. /// <para/>The default value is 0, that means no limits.
  336. /// </remarks>
  337. [DefaultValue(0f)]
  338. [Category("Behavior")]
  339. public float AutoShrinkMinSize
  340. {
  341. get { return autoShrinkMinSize; }
  342. set { autoShrinkMinSize = value; }
  343. }
  344. /// <summary>
  345. /// Gets or sets the horizontal alignment of a text in the TextObject object.
  346. /// </summary>
  347. [DefaultValue(HorzAlign.Left)]
  348. [Category("Appearance")]
  349. public HorzAlign HorzAlign
  350. {
  351. get { return horzAlign; }
  352. set { horzAlign = value; }
  353. }
  354. /// <summary>
  355. /// Gets or sets the vertical alignment of a text in the TextObject object.
  356. /// </summary>
  357. [DefaultValue(VertAlign.Top)]
  358. [Category("Appearance")]
  359. public VertAlign VertAlign
  360. {
  361. get { return vertAlign; }
  362. set { vertAlign = value; }
  363. }
  364. /// <summary>
  365. /// Gets or sets the text angle, in degrees.
  366. /// </summary>
  367. [DefaultValue(0)]
  368. [Category("Appearance")]
  369. [Editor("FastReport.TypeEditors.AngleEditor, FastReport", typeof(UITypeEditor))]
  370. public int Angle
  371. {
  372. get { return angle; }
  373. set { angle = value; }
  374. }
  375. /// <summary>
  376. /// Gets or sets a value that indicates whether the component should draw right-to-left for RTL languages.
  377. /// </summary>
  378. [DefaultValue(false)]
  379. [Category("Behavior")]
  380. public bool RightToLeft
  381. {
  382. get { return rightToLeft; }
  383. set { rightToLeft = value; }
  384. }
  385. /// <summary>
  386. /// Gets or sets a value that indicates if lines are automatically word-wrapped.
  387. /// </summary>
  388. [DefaultValue(true)]
  389. [Category("Behavior")]
  390. public bool WordWrap
  391. {
  392. get { return wordWrap; }
  393. set { wordWrap = value; }
  394. }
  395. /// <summary>
  396. /// Gets or sets a value that determines if the text object will underline each text line.
  397. /// </summary>
  398. [DefaultValue(false)]
  399. [Category("Appearance")]
  400. public bool Underlines
  401. {
  402. get { return underlines; }
  403. set { underlines = value; }
  404. }
  405. /// <summary>
  406. /// Gets or sets the font settings for this object.
  407. /// </summary>
  408. [Category("Appearance")]
  409. public Font Font
  410. {
  411. get { return font; }
  412. set
  413. {
  414. font = value;
  415. if (!String.IsNullOrEmpty(Style))
  416. Style = "";
  417. }
  418. }
  419. /// <summary>
  420. /// Gets or sets a collection of TAB symbol positions, in pixels. Negative values will not affect this property.
  421. /// </summary>
  422. /// <remarks>Use collection methods to add or remove TAB positions.</remarks>
  423. public FloatCollection TabPositions
  424. {
  425. get { return tabPositions; }
  426. set
  427. {
  428. if (value == null)
  429. tabPositions.Clear();
  430. else
  431. tabPositions = value;
  432. }
  433. }
  434. /// <summary>
  435. /// Gets or sets the fill color used to draw a text.
  436. /// </summary>
  437. /// <remarks>
  438. /// Default fill is <see cref="SolidFill"/>. You may specify other fill types, for example:
  439. /// <code>
  440. /// text1.TextFill = new HatchFill(Color.Black, Color.White, HatchStyle.Cross);
  441. /// </code>
  442. /// Use the <see cref="TextColor"/> property to set the solid text color.
  443. /// </remarks>
  444. [Category("Appearance")]
  445. [Editor("FastReport.TypeEditors.FillEditor, FastReport", typeof(UITypeEditor))]
  446. public FillBase TextFill
  447. {
  448. get { return textFill; }
  449. set
  450. {
  451. if (value == null)
  452. throw new ArgumentNullException("TextFill");
  453. textFill = value;
  454. if (!String.IsNullOrEmpty(Style))
  455. Style = "";
  456. }
  457. }
  458. /// <summary>
  459. /// Gets or sets the text outline.
  460. /// </summary>
  461. [Category("Appearance")]
  462. [Editor("FastReport.TypeEditors.OutlineEditor, FastReport", typeof(UITypeEditor))]
  463. public TextOutline TextOutline
  464. {
  465. get { return textOutline; }
  466. set
  467. {
  468. if (value == null)
  469. throw new ArgumentNullException("TextOutline");
  470. textOutline = value;
  471. if (!String.IsNullOrEmpty(Style))
  472. Style = "";
  473. }
  474. }
  475. /// <summary>
  476. /// Gets or sets the text color in a simple manner.
  477. /// </summary>
  478. /// <remarks>
  479. /// This property can be used in a report script to change the text color of the object. It is
  480. /// equivalent to: <code>textObject1.TextFill = new SolidFill(color);</code>
  481. /// </remarks>
  482. [Browsable(false)]
  483. public Color TextColor
  484. {
  485. get { return TextFill is SolidFill ? (TextFill as SolidFill).Color : Color.Black; }
  486. set { TextFill = new SolidFill(value); }
  487. }
  488. /// <summary>
  489. /// Gets or sets the string trimming options.
  490. /// </summary>
  491. [DefaultValue(StringTrimming.None)]
  492. [Category("Behavior")]
  493. public StringTrimming Trimming
  494. {
  495. get { return trimming; }
  496. set { trimming = value; }
  497. }
  498. /// <summary>
  499. /// Gets or sets the width ratio of the font.
  500. /// </summary>
  501. /// <remarks>
  502. /// Default value is 1. To make a font wider, set a value grether than 1; to make a font narrower,
  503. /// set a value less than 1.
  504. /// </remarks>
  505. [DefaultValue(1f)]
  506. [Category("Appearance")]
  507. public float FontWidthRatio
  508. {
  509. get { return fontWidthRatio; }
  510. set
  511. {
  512. if (value > 0)
  513. fontWidthRatio = value;
  514. else
  515. fontWidthRatio = 1;
  516. }
  517. }
  518. /// <summary>
  519. /// Gets or sets the height of single text line, in pixels.
  520. /// </summary>
  521. [DefaultValue(0f)]
  522. [Category("Appearance")]
  523. public float LineHeight
  524. {
  525. get { return lineHeight; }
  526. set { lineHeight = value; }
  527. }
  528. /// <summary>
  529. /// Gets or sets the offset of the first TAB symbol. Negative value will not affect this property.
  530. /// </summary>
  531. [DefaultValue(0f)]
  532. [Category("Appearance")]
  533. //[TypeConverter("FastReport.TypeConverters.UnitsConverter, FastReport")]
  534. public float FirstTabOffset
  535. {
  536. get { return firstTabOffset; }
  537. set { if (value >= 0) firstTabOffset = value; }
  538. }
  539. /// <summary>
  540. /// Gets or sets the width of TAB symbol, in pixels. Negative values will not affect this property.
  541. /// </summary>
  542. [DefaultValue(58f)]
  543. [Category("Appearance")]
  544. public float TabWidth
  545. {
  546. get { return tabWidth; }
  547. set { if (value >= 0) tabWidth = value; }
  548. }
  549. /// <summary>
  550. /// Gets or sets a value that indicates if text should be clipped inside the object's bounds.
  551. /// </summary>
  552. [DefaultValue(true)]
  553. [Category("Behavior")]
  554. public bool Clip
  555. {
  556. get { return clip; }
  557. set { clip = value; }
  558. }
  559. /// <summary>
  560. /// Gets the collection of conditional highlight attributes.
  561. /// </summary>
  562. /// <remarks>
  563. /// Conditional highlight is used to change the visual appearance of the Text object
  564. /// depending on some condition(s). For example, you may highlight negative values displayed by
  565. /// the Text object with red color. To do this, add the highlight condition:
  566. /// <code>
  567. /// TextObject text1;
  568. /// HighlightCondition highlight = new HighlightCondition();
  569. /// highlight.Expression = "Value &lt; 0";
  570. /// highlight.Fill = new SolidFill(Color.Red);
  571. /// highlight.ApplyFill = true;
  572. /// text1.Highlight.Add(highlight);
  573. /// </code>
  574. /// </remarks>
  575. [Category("Data")]
  576. [Editor("FastReport.TypeEditors.HighlightEditor, FastReport", typeof(UITypeEditor))]
  577. public ConditionCollection Highlight
  578. {
  579. get { return highlight; }
  580. }
  581. /// <summary>
  582. /// Gets or sets a value that indicates if the text object should display its contents similar to the printout.
  583. /// </summary>
  584. [DefaultValue(false)]
  585. [Category("Behavior")]
  586. public bool Wysiwyg
  587. {
  588. get { return wysiwyg; }
  589. set { wysiwyg = value; }
  590. }
  591. /// <summary>
  592. /// Forces justify for the last text line.
  593. /// </summary>
  594. [Browsable(false)]
  595. public bool ForceJustify
  596. {
  597. get { return forceJustify; }
  598. set { forceJustify = value; }
  599. }
  600. /// <summary>
  601. /// Allows handling html tags in the text.
  602. /// </summary>
  603. /// <remarks>
  604. /// The following html tags can be used in the object's text: &lt;b&gt;, &lt;i&gt;, &lt;u&gt;,
  605. /// &lt;strike&gt;, &lt;sub&gt;, &lt;sup&gt;, &lt;/b&gt;, &lt;/i&gt;, &lt;/u&gt;,
  606. /// &lt;/strike&gt;, &lt;/sub&gt;, &lt;/sup&gt;,
  607. /// &lt;font color=&amp;...&amp;&gt;, &lt;/font&gt;. Font size cannot
  608. /// be changed due to limitations in the rendering engine.
  609. /// </remarks>
  610. [DefaultValue(false)]
  611. [Category("Behavior")]
  612. [Browsable(false)]
  613. [Obsolete("This method is deprecated please use TextRenderer")]
  614. public bool HtmlTags
  615. {
  616. get
  617. {
  618. return HasHtmlTags;
  619. }
  620. set { textRenderType = value ? TextRenderType.HtmlTags : TextRenderType.Default; }
  621. }
  622. /// <summary>
  623. /// Indicates handling html tags in the text.
  624. /// </summary>
  625. /// <remarks>To set the value use the TextRenderer property.</remarks>
  626. [DefaultValue(false)]
  627. [Category("Behavior")]
  628. [Browsable(false)]
  629. public bool HasHtmlTags
  630. {
  631. get
  632. {
  633. switch (textRenderType)
  634. {
  635. case TextRenderType.HtmlTags:
  636. case TextRenderType.HtmlParagraph:
  637. return true;
  638. default:
  639. return false;
  640. }
  641. }
  642. }
  643. /// <summary>
  644. /// The type of text render
  645. /// </summary>
  646. /// /// <remarks>
  647. /// The following html tags can be used in the object's text: &lt;b&gt;, &lt;i&gt;, &lt;u&gt;,
  648. /// &lt;strike&gt;, &lt;sub&gt;, &lt;sup&gt;, &lt;/b&gt;, &lt;/i&gt;, &lt;/u&gt;,
  649. /// &lt;/strike&gt;, &lt;/sub&gt;, &lt;/sup&gt;,
  650. /// &lt;font color=&amp;...&amp;&gt;, &lt;/font&gt;. Font size cannot
  651. /// be changed due to limitations in the rendering engine.
  652. /// </remarks>
  653. [DefaultValue(TextRenderType.Default)]
  654. [Category("Behavior")]
  655. public TextRenderType TextRenderType
  656. {
  657. get { return textRenderType; }
  658. set { textRenderType = value; }
  659. }
  660. /// <summary>
  661. /// Gets or sets the paragraph offset, in pixels. For HtmlParagraph use ParagraphFormat.FirstLineIndent.
  662. /// </summary>
  663. [DefaultValue(0f)]
  664. [Category("Appearance")]
  665. [TypeConverter("FastReport.TypeConverters.UnitsConverter, FastReport")]
  666. public float ParagraphOffset
  667. {
  668. get { return paragraphOffset; }
  669. set { paragraphOffset = value; }
  670. }
  671. internal bool IsAdvancedRendererNeeded
  672. {
  673. get { return HorzAlign == HorzAlign.Justify || Wysiwyg || LineHeight != 0 || HasHtmlTags; }
  674. }
  675. internal bool PreserveLastLineSpace { get { return preserveLastLineSpace; } set { preserveLastLineSpace = value; } }
  676. /// <summary>
  677. /// Cache for inline images
  678. /// </summary>
  679. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  680. public InlineImageCache InlineImageCache
  681. {
  682. get
  683. {
  684. if (inlineImageCache == null)
  685. inlineImageCache = new InlineImageCache();
  686. return inlineImageCache;
  687. }
  688. }
  689. /// <summary>
  690. /// Gets or sets a value indicating whether the text should be merged with other nearby text objects.
  691. /// </summary>
  692. [DefaultValue(MergeMode.None)]
  693. [Category("Behavior")]
  694. [Editor("FastReport.TypeEditors.FlagsEditor, FastReport", typeof(UITypeEditor))]
  695. public MergeMode MergeMode
  696. {
  697. get { return mergeMode; }
  698. set { mergeMode = value; }
  699. }
  700. #endregion
  701. #region Private Methods
  702. private void DrawUnderlines(FRPaintEventArgs e)
  703. {
  704. if (!Underlines || Angle != 0)
  705. return;
  706. IGraphics g = e.Graphics;
  707. float lineHeight = LineHeight == 0 ? Font.GetHeight() * DrawUtils.ScreenDpiFX : LineHeight;
  708. lineHeight *= e.ScaleY;
  709. float curY = AbsTop * e.ScaleY + lineHeight + 1;
  710. Pen pen = e.Cache.GetPen(Border.Color, Border.Width * e.ScaleY, DashStyle.Solid);
  711. while (curY < AbsBottom * e.ScaleY)
  712. {
  713. g.DrawLine(pen, AbsLeft * e.ScaleX, curY, AbsRight * e.ScaleY, curY);
  714. curY += lineHeight;
  715. }
  716. }
  717. private SizeF CalcSize()
  718. {
  719. Report report = Report;
  720. if (String.IsNullOrEmpty(Text) || report == null)
  721. return new SizeF(0, 0);
  722. Font font = report.GraphicCache.GetFont(Font.FontFamily, Font.Size * 96f / DrawUtils.ScreenDpi, Font.Style);
  723. float width = 0;
  724. if (WordWrap)
  725. {
  726. if (Angle == 90 || Angle == 270)
  727. width = Height - Padding.Vertical;
  728. else
  729. width = Width - Padding.Horizontal;
  730. }
  731. IGraphics g = report.MeasureGraphics;
  732. IGraphicsState state = g.Save();
  733. try
  734. {
  735. if (report.TextQuality != TextQuality.Default)
  736. g.TextRenderingHint = report.GetTextQuality();
  737. if (TextRenderType == TextRenderType.HtmlParagraph)
  738. {
  739. if (width == 0)
  740. width = 100000;
  741. using (HtmlTextRenderer htmlRenderer = GetHtmlTextRenderer(g, new RectangleF(0, 0, width, 100000), 1, 1))
  742. {
  743. float height = htmlRenderer.CalcHeight();
  744. width = htmlRenderer.CalcWidth();
  745. width += Padding.Horizontal + 1;
  746. if (LineHeight == 0 || this.PreserveLastLineSpace)
  747. height += Padding.Vertical + 1;
  748. return new SizeF(width, height);
  749. }
  750. }
  751. #if CROSSPLATFORM && !SKIA
  752. // in FR.Core we use AdvancedTextRenderer only if needed (IsAdvancedRendererNeeded) or if it's not Windows
  753. if (IsAdvancedRendererNeeded || !Config.IsWindows)
  754. #else
  755. if (IsAdvancedRendererNeeded)
  756. #endif
  757. {
  758. if (width == 0)
  759. width = 100000;
  760. AdvancedTextRenderer renderer = new AdvancedTextRenderer(Text, g, font, Brushes.Black, Pens.Black,
  761. new RectangleF(0, 0, width, 100000), GetStringFormat(report.GraphicCache, 0),
  762. HorzAlign, VertAlign, LineHeight, Angle, FontWidthRatio, false, Wysiwyg, HasHtmlTags, false, 96f / DrawUtils.ScreenDpi,
  763. 96f / DrawUtils.ScreenDpi, InlineImageCache);
  764. float height = renderer.CalcHeight();
  765. width = renderer.CalcWidth();
  766. width += Padding.Horizontal + 1;
  767. //if (LineHeight == 0)
  768. height += Padding.Vertical + 1;
  769. return new SizeF(width, height);
  770. }
  771. else
  772. {
  773. if (FontWidthRatio != 1)
  774. width /= FontWidthRatio;
  775. SizeF size = g.MeasureString(Text, font, new SizeF(width, 100000));
  776. size.Width += Padding.Horizontal + 1;
  777. size.Height += Padding.Vertical + 1;
  778. return size;
  779. }
  780. }
  781. finally
  782. {
  783. g.Restore(state);
  784. }
  785. }
  786. private float InternalCalcWidth()
  787. {
  788. bool saveWordWrap = WordWrap;
  789. WordWrap = false;
  790. float result = 0;
  791. try
  792. {
  793. SizeF size = CalcSize();
  794. result = size.Width;
  795. }
  796. finally
  797. {
  798. WordWrap = saveWordWrap;
  799. }
  800. return result;
  801. }
  802. private float InternalCalcHeight()
  803. {
  804. return CalcSize().Height;
  805. }
  806. private string BreakTextHtml(out bool endOnEnter, out float excessiveHeight)
  807. {
  808. excessiveHeight = 0;
  809. endOnEnter = false;
  810. ForceJustify = false;
  811. if (String.IsNullOrEmpty(Text))
  812. return "";
  813. string result = null;
  814. Report report = Report;
  815. if (report == null)
  816. return "";
  817. StringFormat format = GetStringFormat(report.GraphicCache, StringFormatFlags.LineLimit);
  818. RectangleF textRect = new RectangleF(0, 0, Width - Padding.Horizontal, Height - Padding.Vertical);
  819. if (textRect.Height <= 0)
  820. return result;
  821. int charactersFitted;
  822. IGraphics g = report.MeasureGraphics;
  823. IGraphicsState state = g.Save();
  824. if (report.TextQuality != TextQuality.Default)
  825. g.TextRenderingHint = report.GetTextQuality();
  826. try
  827. {
  828. using (HtmlTextRenderer htmlRenderer = GetHtmlTextRenderer(g, 1, 1, textRect, format))
  829. {
  830. htmlRenderer.CalcHeight(out charactersFitted);
  831. if (charactersFitted == 0)
  832. return null;
  833. Text = HtmlTextRenderer.BreakHtml(Text, charactersFitted, out result, out endOnEnter);
  834. excessiveHeight = Height - Padding.Vertical - GetHtmlTextRenderer(g, 1, 1, textRect, format).CalcHeight();
  835. if (HorzAlign == HorzAlign.Justify && !endOnEnter && result != "")
  836. {
  837. if (Text.EndsWith(" "))
  838. Text = Text.TrimEnd(' ');
  839. ForceJustify = true;
  840. }
  841. }
  842. }
  843. finally
  844. {
  845. g.Restore(state);
  846. }
  847. return result;
  848. }
  849. private string BreakText()
  850. {
  851. ForceJustify = false;
  852. if (String.IsNullOrEmpty(Text))
  853. return "";
  854. string result = null;
  855. Report report = Report;
  856. if (report == null)
  857. return "";
  858. Font font = report.GraphicCache.GetFont(Font.FontFamily, Font.Size * 96f / DrawUtils.ScreenDpi, Font.Style);
  859. StringFormat format = GetStringFormat(report.GraphicCache, StringFormatFlags.LineLimit);
  860. RectangleF textRect = new RectangleF(0, 0, Width - Padding.Horizontal, Height - Padding.Vertical);
  861. if (textRect.Height < 0)
  862. return null;
  863. int charactersFitted;
  864. int linesFilled;
  865. IGraphics g = report.MeasureGraphics;
  866. IGraphicsState state = g.Save();
  867. try
  868. {
  869. if (report.TextQuality != TextQuality.Default)
  870. g.TextRenderingHint = report.GetTextQuality();
  871. AdvancedTextRenderer.StyleDescriptor htmlStyle = null;
  872. if (IsAdvancedRendererNeeded)
  873. {
  874. AdvancedTextRenderer renderer = new AdvancedTextRenderer(Text, g, font, Brushes.Black, Pens.Black,
  875. textRect, format, HorzAlign, VertAlign, LineHeight, Angle, FontWidthRatio, false, Wysiwyg, HasHtmlTags, false, 96f / DrawUtils.ScreenDpi,
  876. 96f / DrawUtils.ScreenDpi, InlineImageCache);
  877. renderer.CalcHeight(out charactersFitted, out htmlStyle);
  878. if (charactersFitted == 0)
  879. linesFilled = 0;
  880. else
  881. linesFilled = 2;
  882. }
  883. else
  884. {
  885. g.MeasureString(Text, font, textRect.Size, format, out charactersFitted, out linesFilled);
  886. }
  887. if (linesFilled == 0)
  888. return null;
  889. if (linesFilled == 1)
  890. {
  891. // check if there is enough space for one line
  892. float lineHeight = g.MeasureString("Wg", font).Height;
  893. if (textRect.Height < lineHeight)
  894. return null;
  895. }
  896. if (charactersFitted < Text.Length)
  897. result = Text.Substring(charactersFitted);
  898. else
  899. result = "";
  900. Text = Text.Substring(0, charactersFitted);
  901. if (HorzAlign == HorzAlign.Justify && !Text.EndsWith("\n") && result != "")
  902. {
  903. if (Text.EndsWith(" "))
  904. Text = Text.Substring(0, Text.Length - 1);
  905. ForceJustify = true;
  906. }
  907. if (HasHtmlTags && htmlStyle != null && result != "")
  908. result = htmlStyle.ToString() + result;
  909. }
  910. finally
  911. {
  912. g.Restore(state);
  913. }
  914. return result;
  915. }
  916. private void ProcessAutoShrink()
  917. {
  918. if (TextRenderType == TextRenderType.HtmlParagraph)
  919. return;
  920. if (String.IsNullOrEmpty(Text))
  921. return;
  922. if (AutoShrink == AutoShrinkMode.FontSize)
  923. {
  924. while (CalcWidth() > Width - 1 && Font.Size > AutoShrinkMinSize && Font.Size > 1)
  925. {
  926. Font = new Font(Font.FontFamily, Font.Size - 1, Font.Style);
  927. }
  928. }
  929. else if (AutoShrink == AutoShrinkMode.FontWidth)
  930. {
  931. FontWidthRatio = 1;
  932. float ratio = Converter.DecreasePrecision((Width - 1) / CalcWidth(), 2) - 0.01f;
  933. if (ratio < 1)
  934. FontWidthRatio = Math.Max(ratio, AutoShrinkMinSize);
  935. }
  936. }
  937. private string MakeParagraphOffset(string text)
  938. {
  939. // fixed issue 2823
  940. FirstTabOffset = ParagraphOffset;
  941. string[] lines = text.Split('\n');
  942. for (int i = 0; i < lines.Length; i++)
  943. {
  944. if (!lines[i].StartsWith("\t"))
  945. lines[i] = "\t" + lines[i];
  946. }
  947. return String.Join("\n", lines);
  948. }
  949. #endregion
  950. #region Protected Methods
  951. /// <inheritdoc/>
  952. protected override void DeserializeSubItems(FRReader reader)
  953. {
  954. if (String.Compare(reader.ItemName, "Highlight", true) == 0)
  955. reader.Read(Highlight);
  956. else
  957. base.DeserializeSubItems(reader);
  958. }
  959. #endregion
  960. #region Public Methods
  961. /// <summary>
  962. /// Returns StringFormat object.
  963. /// </summary>
  964. /// <param name="cache">Report graphic cache.</param>
  965. /// <param name="flags">StringFormat flags.</param>
  966. /// <returns>StringFormat object.</returns>
  967. public StringFormat GetStringFormat(GraphicCache cache, StringFormatFlags flags)
  968. {
  969. return GetStringFormat(cache, flags, 1);
  970. }
  971. internal StringFormat GetStringFormat(GraphicCache cache, StringFormatFlags flags, float scale)
  972. {
  973. StringAlignment align = StringAlignment.Near;
  974. if (HorzAlign == HorzAlign.Center)
  975. align = StringAlignment.Center;
  976. else if (HorzAlign == HorzAlign.Right)
  977. align = StringAlignment.Far;
  978. StringAlignment lineAlign = StringAlignment.Near;
  979. if (VertAlign == VertAlign.Center)
  980. lineAlign = StringAlignment.Center;
  981. else if (VertAlign == VertAlign.Bottom)
  982. lineAlign = StringAlignment.Far;
  983. if (RightToLeft)
  984. flags |= StringFormatFlags.DirectionRightToLeft;
  985. if (!WordWrap)
  986. flags |= StringFormatFlags.NoWrap;
  987. if (!Clip)
  988. flags |= StringFormatFlags.NoClip;
  989. if (TabPositions.Count > 0)
  990. {
  991. FloatCollection tabPositions = new FloatCollection();
  992. foreach (var i in TabPositions)
  993. tabPositions.Add((float)i * scale);
  994. return cache.GetStringFormat(align, lineAlign, Trimming, flags, firstTabOffset * scale, tabPositions,
  995. 48 * scale);
  996. }
  997. return cache.GetStringFormat(align, lineAlign, Trimming, flags, firstTabOffset * scale, tabWidth * scale);
  998. }
  999. /// <inheritdoc/>
  1000. public override void Assign(Base source)
  1001. {
  1002. base.Assign(source);
  1003. TextObject src = source as TextObject;
  1004. AutoWidth = src.AutoWidth;
  1005. HorzAlign = src.HorzAlign;
  1006. VertAlign = src.VertAlign;
  1007. Angle = src.Angle;
  1008. RightToLeft = src.RightToLeft;
  1009. WordWrap = src.WordWrap;
  1010. Underlines = src.Underlines;
  1011. Font = src.Font;
  1012. TextFill = src.TextFill.Clone();
  1013. TextOutline.Assign(src.TextOutline);
  1014. Trimming = src.Trimming;
  1015. FontWidthRatio = src.FontWidthRatio;
  1016. FirstTabOffset = src.FirstTabOffset;
  1017. TabWidth = src.TabWidth;
  1018. TabPositions.Assign(src.TabPositions);
  1019. Clip = src.Clip;
  1020. Highlight.Assign(src.Highlight);
  1021. Wysiwyg = src.Wysiwyg;
  1022. LineHeight = src.LineHeight;
  1023. TextRenderType = src.TextRenderType;
  1024. AutoShrink = src.AutoShrink;
  1025. AutoShrinkMinSize = src.AutoShrinkMinSize;
  1026. ParagraphOffset = src.ParagraphOffset;
  1027. inlineImageCache = src.inlineImageCache;
  1028. PreserveLastLineSpace = src.PreserveLastLineSpace;
  1029. paragraphFormat.Assign(src.paragraphFormat);
  1030. MergeMode = src.MergeMode;
  1031. }
  1032. /// <summary>
  1033. /// Returns an instance of html text renderer.
  1034. /// </summary>
  1035. /// <param name="scale">Scale ratio.</param>
  1036. /// <param name="fontScale">Font scale ratio.</param>
  1037. /// <returns>The html text renderer.</returns>
  1038. public HtmlTextRenderer GetHtmlTextRenderer(float scale, float fontScale)
  1039. {
  1040. return GetHtmlTextRenderer(Report.MeasureGraphics, scale, fontScale);
  1041. }
  1042. internal HtmlTextRenderer GetHtmlTextRenderer(IGraphics g, float scale, float fontScale)
  1043. {
  1044. StringFormat format = GetStringFormat(Report.GraphicCache, 0, scale);
  1045. RectangleF textRect = new RectangleF(
  1046. (AbsLeft + Padding.Left) * scale,
  1047. (AbsTop + Padding.Top) * scale,
  1048. (Width - Padding.Horizontal) * scale,
  1049. (Height - Padding.Vertical) * scale);
  1050. return GetHtmlTextRenderer(g, scale, fontScale, textRect, format);
  1051. }
  1052. internal HtmlTextRenderer GetHtmlTextRenderer(IGraphics g, RectangleF textRect, float scale, float fontScale)
  1053. {
  1054. StringFormat format = GetStringFormat(Report.GraphicCache, 0, fontScale);
  1055. return GetHtmlTextRenderer(g, scale, fontScale, textRect, format);
  1056. }
  1057. internal HtmlTextRenderer GetHtmlTextRenderer(IGraphics g, float scale, float fontScale, RectangleF textRect, StringFormat format)
  1058. {
  1059. return GetHtmlTextRenderer(Text, g, fontScale, scale, fontScale, textRect, format, false);
  1060. }
  1061. internal HtmlTextRenderer GetHtmlTextRenderer(string text, IGraphics g, float formatScale, float scale, float fontScale,
  1062. RectangleF textRect, StringFormat format, bool isPrinting)
  1063. {
  1064. #if true
  1065. HtmlTextRenderer.RendererContext context;
  1066. context.text = text;
  1067. context.g = g;
  1068. context.font = font.FontFamily;
  1069. context.size = font.Size;
  1070. context.style = font.Style; // no keep
  1071. context.color = TextColor; // no keep
  1072. context.underlineColor = textOutline.Color;
  1073. context.rect = textRect;
  1074. context.underlines = Underlines;
  1075. context.format = format; // no keep
  1076. context.horzAlign = horzAlign;
  1077. context.vertAlign = vertAlign;
  1078. context.paragraphFormat = ParagraphFormat.MultipleScale(formatScale);
  1079. context.forceJustify = ForceJustify;
  1080. context.scale = scale * 96f / DrawUtils.ScreenDpi;
  1081. context.fontScale = fontScale * 96f / DrawUtils.ScreenDpi;
  1082. context.cache = InlineImageCache;
  1083. context.isPrinting = isPrinting;
  1084. context.isDifferentTabPositions = TabPositions.Count > 0;
  1085. context.keepLastLineSpace = this.PreserveLastLineSpace;
  1086. return new HtmlTextRenderer(context);
  1087. #else
  1088. bool isDifferentTabPositions = TabPositions.Count > 0;
  1089. return new HtmlTextRenderer(text, g, font.FontFamily, font.Size, font.Style, TextColor,
  1090. textOutline.Color, textRect, Underlines,
  1091. format, horzAlign, vertAlign, ParagraphFormat.MultipleScale(formatScale), ForceJustify,
  1092. scale * 96f / DrawUtils.ScreenDpi, fontScale * 96f / DrawUtils.ScreenDpi, InlineImageCache,
  1093. isPrinting, isDifferentTabPositions);
  1094. #endif
  1095. }
  1096. /// <summary>
  1097. /// Draws a text.
  1098. /// </summary>
  1099. /// <param name="e">Paint event data.</param>
  1100. public void DrawText(FRPaintEventArgs e)
  1101. {
  1102. string text = GetDisplayText();
  1103. if (!String.IsNullOrEmpty(text))
  1104. {
  1105. IGraphics g = e.Graphics;
  1106. RectangleF textRect = new RectangleF(
  1107. (AbsLeft + Padding.Left) * e.ScaleX,
  1108. (AbsTop + Padding.Top) * e.ScaleY,
  1109. (Width - Padding.Horizontal) * e.ScaleX,
  1110. (Height - Padding.Vertical) * e.ScaleY);
  1111. if (ParagraphOffset != 0 && IsDesigning)
  1112. text = MakeParagraphOffset(text);
  1113. StringFormat format = GetStringFormat(e.Cache, 0, e.ScaleX);
  1114. Font font = e.Cache.GetFont(Font.FontFamily,
  1115. IsPrinting ? Font.Size : Font.Size * e.ScaleX * 96f / DrawUtils.ScreenDpi,
  1116. Font.Style);
  1117. Brush textBrush = null;
  1118. if (TextFill is SolidFill)
  1119. textBrush = e.Cache.GetBrush((TextFill as SolidFill).Color);
  1120. else
  1121. textBrush = TextFill.CreateBrush(textRect, e.ScaleX, e.ScaleY);
  1122. Pen outlinePen = null;
  1123. if (textOutline.Enabled)
  1124. outlinePen = e.Cache.GetPen(textOutline.Color, textOutline.Width * e.ScaleX, textOutline.Style);
  1125. Report report = Report;
  1126. if (report != null && report.TextQuality != TextQuality.Default)
  1127. g.TextRenderingHint = report.GetTextQuality();
  1128. if (textRect.Width > 0 && textRect.Height > 0)
  1129. {
  1130. switch (TextRenderType)
  1131. {
  1132. case TextRenderType.Inline:
  1133. g.DrawString(text, font, textBrush, textRect.X, textRect.Y, StringFormat.GenericTypographic);
  1134. break;
  1135. case TextRenderType.HtmlParagraph:
  1136. try
  1137. {
  1138. using (HtmlTextRenderer htmlRenderer = GetHtmlTextRenderer(text, e.Graphics, e.ScaleX,
  1139. IsPrinting ? 1 : e.ScaleX, IsPrinting ? 1 / (96f / DrawUtils.ScreenDpi) : e.ScaleX, textRect, format, IsPrinting))
  1140. {
  1141. htmlRenderer.Draw();
  1142. }
  1143. }
  1144. catch
  1145. {
  1146. textBrush.Dispose();
  1147. textBrush = null;
  1148. }
  1149. break;
  1150. default:
  1151. if (IsAdvancedRendererNeeded)
  1152. {
  1153. // use advanced rendering
  1154. AdvancedTextRenderer advancedRenderer = new AdvancedTextRenderer(text, g, font, textBrush,
  1155. outlinePen, textRect, format, HorzAlign, VertAlign, LineHeight * e.ScaleY, Angle,
  1156. FontWidthRatio, ForceJustify, Wysiwyg, HasHtmlTags, false,
  1157. e.ScaleX * 96f / DrawUtils.ScreenDpi,
  1158. IsPrinting ? 1 : e.ScaleX * 96f / DrawUtils.ScreenDpi, InlineImageCache, IsPrinting);
  1159. advancedRenderer.Draw();
  1160. }
  1161. else
  1162. {
  1163. // use simple rendering
  1164. if (Angle == 0 && FontWidthRatio == 1)
  1165. {
  1166. if (outlinePen == null)
  1167. {
  1168. if (WordWrap)
  1169. format.Trimming = StringTrimming.Word;
  1170. g.DrawString(text, font, textBrush, textRect, format);
  1171. }
  1172. else
  1173. {
  1174. GraphicsPath path = new GraphicsPath();
  1175. path.AddString(text, font.FontFamily, Convert.ToInt32(font.Style),
  1176. g.DpiY * font.Size / 72, textRect, format);
  1177. IGraphicsState state = g.Save();
  1178. g.SetClip(textRect);
  1179. //g.FillPath(textBrush, path);
  1180. //regime for text output with drawbehind
  1181. if (TextOutline.DrawBehind)
  1182. {
  1183. g.DrawPath(outlinePen, path);
  1184. g.FillPath(textBrush, path);
  1185. }
  1186. else //without. default
  1187. {
  1188. g.FillAndDrawPath(outlinePen, textBrush, path);
  1189. }
  1190. g.Restore(state);
  1191. }
  1192. }
  1193. else
  1194. StandardTextRenderer.Draw(text, g, font, textBrush, outlinePen, textRect, format, Angle,
  1195. FontWidthRatio);
  1196. }
  1197. DrawUnderlines(e);
  1198. break;
  1199. }
  1200. }
  1201. if (!(TextFill is SolidFill))
  1202. {
  1203. textBrush.Dispose();
  1204. }
  1205. }
  1206. }
  1207. /// <inheritdoc/>
  1208. public override void Draw(FRPaintEventArgs e)
  1209. {
  1210. base.Draw(e);
  1211. DrawText(e);
  1212. DrawMarkers(e);
  1213. Border.Draw(e, new RectangleF(AbsLeft, AbsTop, Width, Height));
  1214. DrawDesign(e);
  1215. }
  1216. /// <inheritdoc/>
  1217. public override void ApplyStyle(Style style)
  1218. {
  1219. if (style.ApplyTextFill)
  1220. TextFill = style.TextFill.Clone();
  1221. if (style.ApplyFont)
  1222. Font = style.Font;
  1223. base.ApplyStyle(style);
  1224. }
  1225. /// <inheritdoc/>
  1226. public override void SaveStyle()
  1227. {
  1228. base.SaveStyle();
  1229. savedTextFill = TextFill;
  1230. savedFont = Font;
  1231. }
  1232. /// <inheritdoc/>
  1233. public override void RestoreStyle()
  1234. {
  1235. base.RestoreStyle();
  1236. TextFill = savedTextFill;
  1237. Font = savedFont;
  1238. }
  1239. /// <inheritdoc/>
  1240. public override void Serialize(FRWriter writer)
  1241. {
  1242. if (writer.SerializeTo == SerializeTo.Preview && AutoWidth)
  1243. {
  1244. WordWrap = false;
  1245. float width = CalcSize().Width;
  1246. if ((Anchor & AnchorStyles.Right) != 0 || HorzAlign == HorzAlign.Right)
  1247. Left = Right - width;
  1248. if (HorzAlign == HorzAlign.Center)
  1249. Left += Width / 2 - width / 2;
  1250. Width = width;
  1251. }
  1252. TextObject c = writer.DiffObject as TextObject;
  1253. base.Serialize(writer);
  1254. if (c == null)
  1255. return; // RichObject here
  1256. if (AutoWidth != c.AutoWidth)
  1257. writer.WriteBool("AutoWidth", AutoWidth);
  1258. if (AutoShrink != c.AutoShrink)
  1259. writer.WriteValue("AutoShrink", AutoShrink);
  1260. if (FloatDiff(AutoShrinkMinSize, c.AutoShrinkMinSize))
  1261. writer.WriteFloat("AutoShrinkMinSize", AutoShrinkMinSize);
  1262. if (HorzAlign != c.HorzAlign)
  1263. writer.WriteValue("HorzAlign", HorzAlign);
  1264. if (VertAlign != c.VertAlign)
  1265. writer.WriteValue("VertAlign", VertAlign);
  1266. if (Angle != c.Angle)
  1267. writer.WriteInt("Angle", Angle);
  1268. if (RightToLeft != c.RightToLeft)
  1269. writer.WriteBool("RightToLeft", RightToLeft);
  1270. if (WordWrap != c.WordWrap)
  1271. writer.WriteBool("WordWrap", WordWrap);
  1272. if (Underlines != c.Underlines)
  1273. writer.WriteBool("Underlines", Underlines);
  1274. if ((writer.SerializeTo != SerializeTo.Preview || !Font.Equals(c.Font)) && writer.ItemName != "inherited")
  1275. writer.WriteValue("Font", Font);
  1276. TextFill.Serialize(writer, "TextFill", c.TextFill);
  1277. if (TextOutline != null)
  1278. TextOutline.Serialize(writer, "TextOutline", c.TextOutline);
  1279. if (Trimming != c.Trimming)
  1280. writer.WriteValue("Trimming", Trimming);
  1281. if (FontWidthRatio != c.FontWidthRatio)
  1282. writer.WriteFloat("FontWidthRatio", FontWidthRatio);
  1283. if (FirstTabOffset != c.FirstTabOffset)
  1284. writer.WriteFloat("FirstTabOffset", FirstTabOffset);
  1285. if (TabWidth != c.TabWidth)
  1286. writer.WriteFloat("TabWidth", TabWidth);
  1287. if (TabPositions.Count > 0)
  1288. writer.WriteValue("TabPositions", TabPositions);
  1289. if (Clip != c.Clip)
  1290. writer.WriteBool("Clip", Clip);
  1291. if (Wysiwyg != c.Wysiwyg)
  1292. writer.WriteBool("Wysiwyg", Wysiwyg);
  1293. if (LineHeight != c.LineHeight)
  1294. writer.WriteFloat("LineHeight", LineHeight);
  1295. if (TextRenderType != c.TextRenderType)
  1296. writer.WriteValue("TextRenderType", TextRenderType);
  1297. if (ParagraphOffset != c.ParagraphOffset)
  1298. writer.WriteFloat("ParagraphOffset", ParagraphOffset);
  1299. if (ForceJustify != c.ForceJustify)
  1300. writer.WriteBool("ForceJustify", ForceJustify);
  1301. if (MergeMode != c.MergeMode)
  1302. writer.WriteValue("MergeMode", MergeMode);
  1303. if (writer.SerializeTo != SerializeTo.Preview)
  1304. {
  1305. if (Style != c.Style)
  1306. writer.WriteStr("Style", Style);
  1307. if (Highlight.Count > 0)
  1308. writer.Write(Highlight);
  1309. }
  1310. if (ParagraphFormat.FirstLineIndent != 0)
  1311. writer.WriteFloat("ParagraphFormat.FirstLineIndent", ParagraphFormat.FirstLineIndent);
  1312. if (ParagraphFormat.LineSpacing > 0)
  1313. writer.WriteFloat("ParagraphFormat.LineSpacing", ParagraphFormat.LineSpacing);
  1314. if (ParagraphFormat.LineSpacingType != LineSpacingType.Single)
  1315. writer.WriteValue("ParagraphFormat.LineSpacingType", ParagraphFormat.LineSpacingType);
  1316. if (ParagraphFormat.SkipFirstLineIndent)
  1317. writer.WriteBool("ParagraphFormat.SkipFirstLineIndent", ParagraphFormat.SkipFirstLineIndent);
  1318. StringBuilder sb = null;
  1319. if (InlineImageCache != null && writer.BlobStore != null && HasHtmlTags == true)
  1320. foreach (InlineImageCache.CacheItem item in InlineImageCache.AllItems())
  1321. {
  1322. if (item.Src.StartsWith("data:")) continue;
  1323. if (sb == null)
  1324. sb = new StringBuilder();
  1325. sb.Append(writer.BlobStore.AddOrUpdate(item.Stream, item.Src))
  1326. .Append(',');
  1327. }
  1328. if (sb != null)
  1329. {
  1330. sb.Length--;
  1331. writer.WriteStr("InlineImageCacheIndexes", sb.ToString());
  1332. }
  1333. }
  1334. /// <inheritdoc/>
  1335. public override void Deserialize(FRReader reader)
  1336. {
  1337. base.Deserialize(reader);
  1338. TextFill.Deserialize(reader, "TextFill");
  1339. if (reader.BlobStore != null)
  1340. {
  1341. string indexes = reader.ReadStr("InlineImageCacheIndexes");
  1342. if (indexes != "null" && !String.IsNullOrEmpty(indexes))
  1343. {
  1344. string[] arr = indexes.Split(',');
  1345. foreach (string index in arr)
  1346. {
  1347. int val = 0;
  1348. if (Int32.TryParse(index, out val))
  1349. {
  1350. if (val >= 0 && val < reader.BlobStore.Count)
  1351. {
  1352. InlineImageCache.CacheItem it = new InlineImageCache.CacheItem();
  1353. it.Set(reader.BlobStore.Get(val));
  1354. InlineImageCache.Set(reader.BlobStore.GetSource(val), it);
  1355. }
  1356. }
  1357. }
  1358. }
  1359. }
  1360. switch (reader.DeserializeFrom)
  1361. {
  1362. case SerializeTo.Undo:
  1363. case SerializeTo.Preview:
  1364. case SerializeTo.Clipboard:
  1365. // skip
  1366. break;
  1367. default:
  1368. if (!reader.HasProperty("Font") && reader.ItemName != "inherited")
  1369. {
  1370. string creatorVersion = reader.Root.GetProp("ReportInfo.CreatorVersion");
  1371. if (!String.IsNullOrEmpty(creatorVersion))
  1372. {
  1373. try
  1374. {
  1375. string[] versions = creatorVersion.Split('.');
  1376. int major = 0;
  1377. if (Int32.TryParse(versions[0], out major))
  1378. {
  1379. if (major < 2016)
  1380. {
  1381. Font = new Font("Arial", 10);
  1382. }
  1383. }
  1384. }
  1385. catch
  1386. {
  1387. }
  1388. }
  1389. }
  1390. break;
  1391. }
  1392. }
  1393. public override void InitializeComponent()
  1394. {
  1395. base.InitializeComponent();
  1396. TextFill.InitializeComponent();
  1397. }
  1398. public override void FinalizeComponent()
  1399. {
  1400. base.FinalizeComponent();
  1401. TextFill.FinalizeComponent();
  1402. }
  1403. internal void ApplyCondition(HighlightCondition c)
  1404. {
  1405. if (c.ApplyBorder)
  1406. Border = c.Border.Clone();
  1407. if (c.ApplyFill)
  1408. Fill = c.Fill.Clone();
  1409. if (c.ApplyTextFill)
  1410. TextFill = c.TextFill.Clone();
  1411. if (c.ApplyFont)
  1412. Font = c.Font;
  1413. Visible = c.Visible;
  1414. }
  1415. #endregion
  1416. #region Report Engine
  1417. /// <inheritdoc/>
  1418. public override string[] GetExpressions()
  1419. {
  1420. List<string> expressions = new List<string>();
  1421. expressions.AddRange(base.GetExpressions());
  1422. if (AllowExpressions && !String.IsNullOrEmpty(Brackets))
  1423. {
  1424. string[] brackets = Brackets.Split(',');
  1425. // collect expressions found in the text
  1426. expressions.AddRange(CodeUtils.GetExpressions(Text, brackets[0], brackets[1]));
  1427. }
  1428. // add highlight conditions
  1429. foreach (HighlightCondition condition in Highlight)
  1430. {
  1431. expressions.Add(condition.Expression);
  1432. }
  1433. return expressions.ToArray();
  1434. }
  1435. /// <inheritdoc/>
  1436. public override void SaveState()
  1437. {
  1438. base.SaveState();
  1439. savedText = Text;
  1440. savedTextFill = TextFill;
  1441. savedFont = Font;
  1442. savedFormat = Format;
  1443. }
  1444. /// <inheritdoc/>
  1445. public override void RestoreState()
  1446. {
  1447. base.RestoreState();
  1448. Text = savedText;
  1449. TextFill = savedTextFill;
  1450. Font = savedFont;
  1451. Format = savedFormat;
  1452. }
  1453. /// <summary>
  1454. /// Calculates the object's width.
  1455. /// </summary>
  1456. /// <returns>The width, in pixels.</returns>
  1457. public float CalcWidth()
  1458. {
  1459. if (Angle == 90 || Angle == 270)
  1460. return InternalCalcHeight();
  1461. return InternalCalcWidth();
  1462. }
  1463. /// <inheritdoc/>
  1464. public override float CalcHeight()
  1465. {
  1466. if (Angle == 90 || Angle == 270)
  1467. return InternalCalcWidth();
  1468. return InternalCalcHeight();
  1469. }
  1470. /// <inheritdoc/>
  1471. public override void GetData()
  1472. {
  1473. base.GetData();
  1474. // process expressions
  1475. if (AllowExpressions)
  1476. {
  1477. if (!String.IsNullOrEmpty(Brackets))
  1478. {
  1479. string[] brackets = Brackets.Split(',');
  1480. FindTextArgs args = new FindTextArgs();
  1481. args.Text = new FastString(Text);
  1482. args.OpenBracket = brackets[0];
  1483. args.CloseBracket = brackets[1];
  1484. int expressionIndex = 0;
  1485. while (args.StartIndex < args.Text.Length)
  1486. {
  1487. string expression = CodeUtils.GetExpression(args, false);
  1488. if (expression == null)
  1489. break;
  1490. //if (!Report.IsCompileNeeded)
  1491. //{
  1492. // expression = Text;
  1493. //}
  1494. string formattedValue = CalcAndFormatExpression(expression, expressionIndex);
  1495. args.Text.Remove(args.StartIndex, args.EndIndex - args.StartIndex);
  1496. args.Text.Insert(args.StartIndex, formattedValue);
  1497. args.StartIndex += formattedValue.Length;
  1498. expressionIndex++;
  1499. }
  1500. Text = args.Text.ToString();
  1501. }
  1502. }
  1503. // process highlight
  1504. Variant varValue = new Variant(Value);
  1505. foreach (HighlightCondition condition in Highlight)
  1506. {
  1507. try
  1508. {
  1509. object val = Report.Calc(condition.Expression, varValue);
  1510. if (val != null && (bool)val == true)
  1511. {
  1512. ApplyCondition(condition);
  1513. break;
  1514. }
  1515. }
  1516. catch (Exception e)
  1517. {
  1518. throw new Exception(Name + ": " + Res.Get("Messages,ErrorInHighlightCondition") + ": " + condition.Expression, e.InnerException);
  1519. }
  1520. }
  1521. // make paragraph offset
  1522. if (ParagraphOffset != 0)
  1523. Text = MakeParagraphOffset(Text);
  1524. // process AutoShrink
  1525. ProcessAutoShrink();
  1526. }
  1527. /// <inheritdoc/>
  1528. public override bool Break(BreakableComponent breakTo, out float excessiveHeight)
  1529. {
  1530. excessiveHeight = 0;
  1531. switch (TextRenderType)
  1532. {
  1533. case TextRenderType.HtmlParagraph:
  1534. bool endOnEnter;
  1535. string breakTextHtml = BreakTextHtml(out endOnEnter, out excessiveHeight);
  1536. if (breakTextHtml != null && breakTo != null)
  1537. {
  1538. (breakTo as TextObject).Text = breakTextHtml;
  1539. if (!endOnEnter)
  1540. (breakTo as TextObject).ParagraphFormat.SkipFirstLineIndent = true;
  1541. }
  1542. return breakTextHtml != null;
  1543. default:
  1544. string breakText = BreakText();
  1545. if (breakText != null && breakTo != null)
  1546. (breakTo as TextObject).Text = breakText;
  1547. return breakText != null;
  1548. }
  1549. }
  1550. /// <inheritdoc/>
  1551. public override bool Break(BreakableComponent breakTo)
  1552. {
  1553. float excessiveHeight = 0;
  1554. return Break(breakTo, out excessiveHeight);
  1555. }
  1556. internal IEnumerable<PictureObject> GetPictureFromHtmlText(AdvancedTextRenderer renderer)
  1557. {
  1558. if (renderer == null)
  1559. {
  1560. using (Bitmap b = new Bitmap(1, 1))
  1561. using (IGraphics g = new GdiGraphics(b))
  1562. {
  1563. RectangleF textRect = new RectangleF(
  1564. (AbsLeft + Padding.Left),
  1565. (AbsTop + Padding.Top),
  1566. (Width - Padding.Horizontal),
  1567. (Height - Padding.Vertical));
  1568. StringFormat format = GetStringFormat(Report.GraphicCache, StringFormatFlags.LineLimit);
  1569. renderer = new AdvancedTextRenderer(Text, g, Font, Brushes.Black, Pens.Black,
  1570. textRect, format, HorzAlign, VertAlign, LineHeight, Angle, FontWidthRatio,
  1571. ForceJustify, Wysiwyg, HasHtmlTags, false, 1, 1,
  1572. InlineImageCache);
  1573. foreach (PictureObject obj in GetPictureFromHtmlText(renderer))
  1574. yield return obj;
  1575. }
  1576. }
  1577. else
  1578. {
  1579. RectangleF textRect = renderer.DisplayRect;
  1580. foreach (AdvancedTextRenderer.Paragraph paragraph in renderer.Paragraphs)
  1581. foreach (AdvancedTextRenderer.Line line in paragraph.Lines)
  1582. foreach (AdvancedTextRenderer.Word word in line.Words)
  1583. foreach (AdvancedTextRenderer.Run run in word.Runs)
  1584. if (run is AdvancedTextRenderer.RunImage)
  1585. {
  1586. AdvancedTextRenderer.RunImage runImage = run as AdvancedTextRenderer.RunImage;
  1587. PictureObject obj = new PictureObject();
  1588. float left = runImage.Left - textRect.Left;
  1589. float top = runImage.Top - textRect.Top;
  1590. float width =
  1591. runImage.Left + runImage.Width > textRect.Right ?
  1592. textRect.Right - (left < 0 ? textRect.Left : runImage.Left) :
  1593. (
  1594. runImage.Left < textRect.Left ?
  1595. runImage.Left + runImage.Width - textRect.Left :
  1596. runImage.Width
  1597. );
  1598. float height =
  1599. runImage.Top + runImage.Height > textRect.Bottom ?
  1600. textRect.Bottom - (top < 0 ? textRect.Top : runImage.Top) :
  1601. (
  1602. runImage.Top < textRect.Top ?
  1603. runImage.Top + runImage.Height - textRect.Top :
  1604. runImage.Height
  1605. );
  1606. if (left < 0 || top < 0 || width < runImage.Width || height < runImage.Height)
  1607. {
  1608. Bitmap bmp = new Bitmap((int)width, (int)height);
  1609. using (Graphics g = Graphics.FromImage(bmp))
  1610. {
  1611. g.DrawImage(runImage.Image, new PointF(
  1612. left < 0 ? left : 0,
  1613. top < 0 ? top : 0
  1614. ));
  1615. }
  1616. obj.Image = bmp;
  1617. obj.Left = (left < 0 ? textRect.Left : runImage.Left) / renderer.Scale;
  1618. obj.Top = (top < 0 ? textRect.Top : runImage.Top) / renderer.Scale;
  1619. obj.Width = width / renderer.Scale;
  1620. obj.Height = height / renderer.Scale;
  1621. obj.SizeMode = PictureBoxSizeMode.StretchImage;
  1622. }
  1623. else
  1624. {
  1625. obj.Image = runImage.Image;
  1626. obj.Left = runImage.Left / renderer.Scale;
  1627. obj.Top = runImage.Top / renderer.Scale;
  1628. obj.Width = runImage.Width / renderer.Scale;
  1629. obj.Height = runImage.Height / renderer.Scale;
  1630. obj.SizeMode = PictureBoxSizeMode.StretchImage;
  1631. }
  1632. yield return obj;
  1633. }
  1634. }
  1635. }
  1636. #endregion
  1637. /// <summary>
  1638. /// Initializes a new instance of the <see cref="TextObject"/> class with default settings.
  1639. /// </summary>
  1640. public TextObject()
  1641. {
  1642. paragraphFormat = new ParagraphFormat();
  1643. wordWrap = true;
  1644. font = DrawUtils.DefaultReportFont;
  1645. textFill = new SolidFill(Color.Black);
  1646. textOutline = new TextOutline();
  1647. trimming = StringTrimming.None;
  1648. fontWidthRatio = 1;
  1649. tabWidth = 58;
  1650. tabPositions = new FloatCollection();
  1651. clip = true;
  1652. highlight = new ConditionCollection();
  1653. FlagSerializeStyle = false;
  1654. SetFlags(Flags.HasSmartTag, true);
  1655. preserveLastLineSpace = false;
  1656. }
  1657. }
  1658. }