HtmlTextRenderer.cs 114 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Drawing.Drawing2D;
  5. using System.Text;
  6. namespace FastReport.Utils
  7. {
  8. public class HtmlTextRenderer : IDisposable
  9. {
  10. #region Definitions
  11. /// <summary>
  12. /// Context of HTML rendering
  13. /// It is better to put this structure instead of class' private fields.
  14. /// For future optimization. Then we can avoid constructor with dozen arguments
  15. /// </summary>
  16. public struct RendererContext
  17. {
  18. internal string text;
  19. internal IGraphics g;
  20. internal FontFamily font;
  21. internal float size;
  22. internal FontStyle style; // no keep
  23. internal Color color; // no keep
  24. internal Color underlineColor;
  25. internal RectangleF rect;
  26. internal bool underlines;
  27. internal StringFormat format; // no keep
  28. internal HorzAlign horzAlign;
  29. internal VertAlign vertAlign;
  30. internal ParagraphFormat paragraphFormat;
  31. internal bool forceJustify;
  32. internal float scale;
  33. internal float fontScale;
  34. internal InlineImageCache cache;
  35. internal bool isPrinting;
  36. internal bool isDifferentTabPositions;
  37. internal bool keepLastLineSpace; // Classic objects need false, translated objects need true
  38. }
  39. #endregion
  40. #region Internal Fields
  41. public static readonly System.Globalization.CultureInfo CultureInfo = System.Globalization.CultureInfo.InvariantCulture;
  42. #endregion Internal Fields
  43. #region Private Fields
  44. private const char SOFT_ENTER = '\u2028';
  45. private List<RectangleFColor> backgrounds;
  46. private InlineImageCache cache;
  47. private RectangleF displayRect;
  48. private bool everUnderlines;
  49. private FontFamily font;
  50. private float fontLineHeight;
  51. private float scale;
  52. private bool forceJustify;
  53. private StringFormat format;
  54. private IGraphics graphics;
  55. private HorzAlign horzAlign;
  56. private ParagraphFormat paragraphFormat;
  57. private List<HtmlTextRenderer.Paragraph> paragraphs;
  58. private bool rightToLeft;
  59. private float size;
  60. private List<LineFColor> strikeouts;
  61. private string text;
  62. private Color underlineColor;
  63. private List<LineFColor> underlines;
  64. private VertAlign vertAlign;
  65. private StyleDescriptor initalStyle;
  66. private float fontScale;
  67. private FastString cacheString = new FastString(100);
  68. private bool isPrinting;
  69. private bool isDifferentTabPositions;
  70. internal bool keepLastSpace = false;
  71. #endregion Private Fields
  72. #region Public Properties
  73. public IEnumerable<RectangleFColor> Backgrounds { get { return backgrounds; } }
  74. public RectangleF DisplayRect { get { return displayRect; } }
  75. public float Scale { get { return scale; } }
  76. public float FontScale { get { return fontScale; } set { fontScale = value; } }
  77. public HorzAlign HorzAlign { get { return horzAlign; } }
  78. public ParagraphFormat ParagraphFormat { get { return paragraphFormat; } }
  79. public IEnumerable<Paragraph> Paragraphs { get { return paragraphs; } }
  80. public bool RightToLeft
  81. {
  82. get { return rightToLeft; }
  83. }
  84. public IEnumerable<LineFColor> Stikeouts { get { return strikeouts; } }
  85. public float[] TabPositions
  86. {
  87. get
  88. {
  89. float firstTabStop;
  90. return format.GetTabStops(out firstTabStop);
  91. }
  92. }
  93. public float TabSize
  94. {
  95. get
  96. {
  97. // re fix tab offset #2823 sorry linux users, on linux firstTab is firstTab not tabSizes[0]
  98. float[] tabSizes = TabPositions;
  99. if (tabSizes.Length > 1)
  100. return tabSizes[1];
  101. return 0;
  102. }
  103. }
  104. public float TabOffset
  105. {
  106. get
  107. {
  108. // re fix tab offset #2823 sorry linux users, on linux firstTab is firstTab not tabSizes[0]
  109. float[] tabSizes = TabPositions;
  110. if (tabSizes.Length > 0)
  111. return tabSizes[0];
  112. return 0;
  113. }
  114. }
  115. public IEnumerable<LineFColor> Underlines { get { return underlines; } }
  116. public bool WordWrap
  117. {
  118. get { return (format.FormatFlags & StringFormatFlags.NoWrap) == 0; }
  119. }
  120. #endregion Public Properties
  121. ////TODO this is a problem with dotnet, because typographic width
  122. ////float width_dotnet = 2.7f;
  123. #region Public Constructors
  124. /// <summary>
  125. /// Contexted version of HTML renderer
  126. /// </summary>
  127. /// <param name="context"></param>
  128. public HtmlTextRenderer(RendererContext context)
  129. {
  130. this.text = context.text;
  131. this.graphics = context.g;
  132. this.font = context.font;
  133. this.size = context.size;
  134. this.underlineColor = context.underlineColor;
  135. this.displayRect = context.rect;
  136. this.everUnderlines = context.underlines;
  137. this.format = context.format;
  138. this.horzAlign = context.horzAlign;
  139. this.vertAlign = context.vertAlign;
  140. this.paragraphFormat = context.paragraphFormat;
  141. this.forceJustify = context.forceJustify;
  142. this.scale = context.scale;
  143. this.fontScale = context.fontScale;
  144. this.cache = context.cache;
  145. this.isPrinting = context.isPrinting;
  146. this.isDifferentTabPositions = context.isDifferentTabPositions;
  147. this.keepLastSpace = context.keepLastLineSpace;
  148. paragraphs = new List<HtmlTextRenderer.Paragraph>();
  149. rightToLeft = (context.format.FormatFlags & StringFormatFlags.DirectionRightToLeft) == StringFormatFlags.DirectionRightToLeft;
  150. // Dispose it
  151. this.format = StringFormat.GenericTypographic.Clone() as StringFormat;
  152. if (RightToLeft)
  153. this.format.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
  154. float firstTab;
  155. float[] tabs = context.format.GetTabStops(out firstTab);
  156. this.format.SetTabStops(firstTab, tabs);
  157. this.format.Alignment = StringAlignment.Near;
  158. this.format.LineAlignment = StringAlignment.Near;
  159. this.format.Trimming = StringTrimming.None;
  160. this.format.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.None;
  161. //FFormat.DigitSubstitutionMethod = StringDigitSubstitute.User;
  162. //FFormat.DigitSubstitutionLanguage = 0;
  163. this.format.FormatFlags |= StringFormatFlags.NoClip | StringFormatFlags.FitBlackBox | StringFormatFlags.LineLimit;
  164. //FFormat.FormatFlags |= StringFormatFlags.NoFontFallback;
  165. backgrounds = new List<RectangleFColor>();
  166. this.underlines = new List<LineFColor>();
  167. strikeouts = new List<LineFColor>();
  168. //FDisplayRect.Width -= width_dotnet * scale;
  169. initalStyle = new StyleDescriptor(context.style, context.color, BaseLine.Normal, this.font, this.size * this.fontScale);
  170. using (Font f = initalStyle.GetFont())
  171. {
  172. fontLineHeight = f.GetHeight(graphics.Graphics);
  173. }
  174. StringFormatFlags saveFlags = this.format.FormatFlags;
  175. StringTrimming saveTrimming = this.format.Trimming;
  176. // if word wrap is set, ignore trimming
  177. if (WordWrap)
  178. this.format.Trimming = StringTrimming.Word;
  179. SplitToParagraphs(text);
  180. AdjustParagraphLines();
  181. // restore original values
  182. displayRect = context.rect;
  183. this.format.FormatFlags = saveFlags;
  184. this.format.Trimming = saveTrimming;
  185. }
  186. public HtmlTextRenderer(string text, IGraphics g, FontFamily font, float size,
  187. FontStyle style, Color color, Color underlineColor, RectangleF rect, bool underlines,
  188. StringFormat format, HorzAlign horzAlign, VertAlign vertAlign,
  189. ParagraphFormat paragraphFormat, bool forceJustify, float scale, float fontScale, InlineImageCache cache, bool isPrinting = false, bool isDifferentTabPositions = false)
  190. {
  191. this.cache = cache;
  192. this.scale = scale;
  193. this.fontScale = fontScale;
  194. paragraphs = new List<HtmlTextRenderer.Paragraph>();
  195. this.text = text;
  196. graphics = g;
  197. this.font = font;
  198. displayRect = rect;
  199. rightToLeft = (format.FormatFlags & StringFormatFlags.DirectionRightToLeft) == StringFormatFlags.DirectionRightToLeft;
  200. // Dispose it
  201. this.format = StringFormat.GenericTypographic.Clone() as StringFormat;
  202. if (RightToLeft)
  203. this.format.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
  204. float firstTab;
  205. float[] tabs = format.GetTabStops(out firstTab);
  206. this.format.SetTabStops(firstTab, tabs);
  207. this.format.Alignment = StringAlignment.Near;
  208. this.format.LineAlignment = StringAlignment.Near;
  209. this.format.Trimming = StringTrimming.None;
  210. this.format.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.None;
  211. this.underlineColor = underlineColor;
  212. //FFormat.DigitSubstitutionMethod = StringDigitSubstitute.User;
  213. //FFormat.DigitSubstitutionLanguage = 0;
  214. this.format.FormatFlags |= StringFormatFlags.NoClip | StringFormatFlags.FitBlackBox | StringFormatFlags.LineLimit;
  215. //FFormat.FormatFlags |= StringFormatFlags.NoFontFallback;
  216. this.horzAlign = horzAlign;
  217. this.vertAlign = vertAlign;
  218. this.paragraphFormat = paragraphFormat;
  219. this.font = font;
  220. this.size = size;
  221. this.isPrinting = isPrinting;
  222. this.isDifferentTabPositions = isDifferentTabPositions;
  223. everUnderlines = underlines;
  224. backgrounds = new List<RectangleFColor>();
  225. this.underlines = new List<LineFColor>();
  226. strikeouts = new List<LineFColor>();
  227. //FDisplayRect.Width -= width_dotnet * scale;
  228. initalStyle = new StyleDescriptor(style, color, BaseLine.Normal, this.font, this.size * this.fontScale);
  229. using (Font f = initalStyle.GetFont())
  230. {
  231. fontLineHeight = f.GetHeight(g.Graphics);
  232. }
  233. this.forceJustify = forceJustify;
  234. StringFormatFlags saveFlags = this.format.FormatFlags;
  235. StringTrimming saveTrimming = this.format.Trimming;
  236. // if word wrap is set, ignore trimming
  237. if (WordWrap)
  238. this.format.Trimming = StringTrimming.Word;
  239. SplitToParagraphs(text);
  240. AdjustParagraphLines();
  241. // restore original values
  242. displayRect = rect;
  243. this.format.FormatFlags = saveFlags;
  244. this.format.Trimming = saveTrimming;
  245. }
  246. #endregion Public Constructors
  247. #region Public Methods
  248. public void AddUnknownWord(List<CharWithIndex> w, Paragraph paragraph, StyleDescriptor style, int charIndex, ref Line line, ref Word word, ref float width)
  249. {
  250. if (w[0].Char == ' ')
  251. {
  252. if (word == null || word.Type == WordType.Normal)
  253. {
  254. word = new Word(this, line, WordType.WhiteSpace);
  255. line.Words.Add(word);
  256. }
  257. Run r = new RunText(this, word, style, w, width, charIndex);
  258. word.Runs.Add(r);
  259. width += r.Width;
  260. if (width > displayRect.Width)
  261. line = WrapLine(paragraph, line, charIndex, displayRect.Width, ref width);
  262. }
  263. else
  264. {
  265. if (word == null || word.Type != WordType.Normal)
  266. {
  267. word = new Word(this, line, WordType.Normal);
  268. line.Words.Add(word);
  269. }
  270. Run r = new RunText(this, word, style, w, width, charIndex);
  271. word.Runs.Add(r);
  272. width += r.Width;
  273. if (width > displayRect.Width)
  274. line = WrapLine(paragraph, line, charIndex, displayRect.Width, ref width);
  275. }
  276. }
  277. public float CalcHeight()
  278. {
  279. int charsFit = 0;
  280. return CalcHeight(out charsFit);
  281. }
  282. public float CalcHeight(out int charsFit)
  283. {
  284. charsFit = -1;
  285. float height = 0;
  286. float displayHeight = displayRect.Height;
  287. float lineSpacing = 0;
  288. foreach (Paragraph paragraph in paragraphs)
  289. {
  290. foreach (Line line in paragraph.Lines)
  291. {
  292. line.CalcMetrics();
  293. height += line.Height;
  294. if (charsFit < 0 && height > displayHeight)
  295. {
  296. charsFit = line.OriginalCharIndex;
  297. }
  298. height += lineSpacing = line.LineSpacing;
  299. }
  300. }
  301. if(!keepLastSpace) // It looks like TextProcessors keep this value for every line.
  302. height -= lineSpacing;
  303. if (charsFit < 0)
  304. charsFit = text.Length;
  305. return height;
  306. }
  307. public float CalcWidth()
  308. {
  309. float width = 0;
  310. foreach (Paragraph paragraph in paragraphs)
  311. {
  312. foreach (Line line in paragraph.Lines)
  313. {
  314. if (width < line.Width)
  315. width = line.Width;
  316. }
  317. }
  318. return width;
  319. }
  320. #endregion Public Methods
  321. #region Internal Methods
  322. /// <summary>
  323. /// Returns splited string
  324. /// </summary>
  325. /// <param name="text">text for splitting</param>
  326. /// <param name="charactersFitted">index of first character of second string</param>
  327. /// <param name="result">second part of string</param>
  328. /// <param name="endOnEnter">returns true if ends on enter</param>
  329. /// <returns>first part of string</returns>
  330. internal static string BreakHtml(string text, int charactersFitted, out string result, out bool endOnEnter)
  331. {
  332. endOnEnter = false;
  333. Stack<SimpleFastReportHtmlElement> elements = new Stack<SimpleFastReportHtmlElement>();
  334. SimpleFastReportHtmlReader reader = new SimpleFastReportHtmlReader(text);
  335. while (reader.IsNotEOF)
  336. {
  337. if (reader.Position >= charactersFitted)
  338. {
  339. StringBuilder firstPart = new StringBuilder();
  340. if (reader.Character.Char == SOFT_ENTER)
  341. firstPart.Append(text.Substring(0, reader.LastPosition));
  342. else
  343. firstPart.Append(text.Substring(0, reader.Position));
  344. foreach (SimpleFastReportHtmlElement el in elements)
  345. {
  346. SimpleFastReportHtmlElement el2 = new SimpleFastReportHtmlElement(el.name, true);
  347. firstPart.Append(el2.ToString());
  348. }
  349. SimpleFastReportHtmlElement[] arr = elements.ToArray();
  350. StringBuilder secondPart = new StringBuilder();
  351. for (int i = arr.Length - 1; i >= 0; i--)
  352. secondPart.Append(arr[i].ToString());
  353. secondPart.Append(text.Substring(reader.Position));
  354. endOnEnter = reader.Character.Char == '\n';
  355. result = secondPart.ToString();
  356. return firstPart.ToString();
  357. }
  358. if (!reader.Read())
  359. {
  360. if (reader.Element.isEnd)
  361. {
  362. int enumIndex = 1;
  363. using (Stack<SimpleFastReportHtmlElement>.Enumerator enumerator = elements.GetEnumerator())
  364. {
  365. while (enumerator.MoveNext())
  366. {
  367. SimpleFastReportHtmlElement el = enumerator.Current;
  368. if (el.name == reader.Element.name)
  369. {
  370. for (int i = 0; i < enumIndex; i++)
  371. elements.Pop();
  372. break;
  373. }
  374. else
  375. enumIndex++;
  376. }
  377. }
  378. }
  379. else if (!reader.Element.IsSelfClosed) elements.Push(reader.Element);
  380. }
  381. }
  382. result = "";
  383. return text;
  384. }
  385. internal void Draw()
  386. {
  387. // set clipping
  388. IGraphicsState state = graphics.Save();
  389. //RectangleF rect = new RectangleF(FDisplayRect.Location, SizeF.Add(FDisplayRect.Size, new SizeF(width_dotnet, 0)));
  390. //FGraphics.SetClip(rect, CombineMode.Intersect);
  391. graphics.SetClip(displayRect, CombineMode.Intersect);
  392. // reset alignment
  393. //StringAlignment saveAlign = FFormat.Alignment;
  394. //StringAlignment saveLineAlign = FFormat.LineAlignment;
  395. //FFormat.Alignment = StringAlignment.Near;
  396. //FFormat.LineAlignment = StringAlignment.Near;
  397. //if (FRightToLeft)
  398. // foreach (RectangleFColor rect in FBackgrounds)
  399. // using (Brush brush = new SolidBrush(rect.Color))
  400. // FGraphics.FillRectangle(brush, rect.Left - rect.Width, rect.Top, rect.Width, rect.Height);
  401. //else
  402. foreach (RectangleFColor rect in backgrounds)
  403. using (Brush brush = new SolidBrush(rect.Color))
  404. graphics.FillRectangle(brush, rect.Left, rect.Top, rect.Width, rect.Height);
  405. foreach (Paragraph p in paragraphs)
  406. foreach (Line l in p.Lines)
  407. {
  408. //#if DEBUG
  409. // FGraphics.DrawRectangle(Pens.Blue, FDisplayRect.Left, l.Top, FDisplayRect.Width, l.Height);
  410. //#endif
  411. foreach (Word w in l.Words)
  412. switch (w.Type)
  413. {
  414. case WordType.Normal:
  415. foreach (Run r in w.Runs)
  416. {
  417. r.Draw();
  418. }
  419. break;
  420. }
  421. }
  422. //if (RightToLeft)
  423. //{
  424. // foreach (LineFColor line in FUnderlines)
  425. // using (Pen pen = new Pen(line.Color, line.Width))
  426. // FGraphics.DrawLine(pen, 2 * line.Left - line.Right, line.Top, line.Left, line.Top);
  427. // foreach (LineFColor line in FStrikeouts)
  428. // using (Pen pen = new Pen(line.Color, line.Width))
  429. // FGraphics.DrawLine(pen, 2 * line.Left - line.Right, line.Top, line.Left, line.Top);
  430. //}
  431. //else
  432. //{
  433. foreach (LineFColor line in underlines)
  434. using (Pen pen = new Pen(line.Color, line.Width))
  435. graphics.DrawLine(pen, line.Left, line.Top, line.Right, line.Top);
  436. foreach (LineFColor line in strikeouts)
  437. using (Pen pen = new Pen(line.Color, line.Width))
  438. graphics.DrawLine(pen, line.Left, line.Top, line.Right, line.Top);
  439. //}
  440. // restore alignment and clipping
  441. //FFormat.Alignment = saveAlign;
  442. //FFormat.LineAlignment = saveLineAlign;
  443. graphics.Restore(state);
  444. }
  445. #endregion Internal Methods
  446. #region Private Methods
  447. private void AdjustParagraphLines()
  448. {
  449. // calculate text height
  450. float height = 0;
  451. height = CalcHeight();
  452. // calculate Y offset
  453. float offsetY = displayRect.Top;
  454. if (vertAlign == VertAlign.Center)
  455. offsetY += (displayRect.Height - height) / 2;
  456. else if (vertAlign == VertAlign.Bottom)
  457. offsetY += (displayRect.Height - height) - 1;
  458. for (int i = 0; i < paragraphs.Count; i++)
  459. {
  460. Paragraph paragraph = paragraphs[i];
  461. paragraph.AlignLines(i == paragraphs.Count - 1 && forceJustify);
  462. // adjust line tops
  463. foreach (Line line in paragraph.Lines)
  464. {
  465. line.Top = offsetY;
  466. line.MakeUnderlines();
  467. line.MakeStrikeouts();
  468. line.MakeBackgrounds();
  469. offsetY += line.Height + line.LineSpacing;
  470. }
  471. }
  472. }
  473. private void CssStyle(StyleDescriptor style, Dictionary<string, string> dict)
  474. {
  475. if (dict == null)
  476. return;
  477. string tStr;
  478. if (dict.TryGetValue("font-size", out tStr))
  479. {
  480. if (EndsWith(tStr, "px"))
  481. try { style.Size = fontScale * 0.75f * Single.Parse(tStr.Substring(0, tStr.Length - 2), CultureInfo); } catch { }
  482. else if (EndsWith(tStr, "pt"))
  483. try { style.Size = fontScale * Single.Parse(tStr.Substring(0, tStr.Length - 2), CultureInfo); } catch { }
  484. else if (EndsWith(tStr, "em"))
  485. try { style.Size *= Single.Parse(tStr.Substring(0, tStr.Length - 2), CultureInfo); } catch { }
  486. }
  487. if (dict.TryGetValue("font-family", out tStr))
  488. style.Font = new FontFamily(tStr);
  489. if (dict.TryGetValue("color", out tStr))
  490. {
  491. if (StartsWith(tStr, "#"))
  492. try { style.Color = Color.FromArgb((int)(0xFF000000 + uint.Parse(tStr.Substring(1), System.Globalization.NumberStyles.HexNumber))); } catch { }
  493. else if (StartsWith(tStr, "rgba"))
  494. {
  495. int i1 = tStr.IndexOf('(');
  496. int i2 = tStr.IndexOf(')');
  497. string[] strs = tStr.Substring(i1 + 1, i2 - i1 - 1).Split(',');
  498. if (strs.Length == 4)
  499. {
  500. float r, g, b, a;
  501. try
  502. {
  503. r = Single.Parse(strs[0], CultureInfo);
  504. g = Single.Parse(strs[1], CultureInfo);
  505. b = Single.Parse(strs[2], CultureInfo);
  506. a = Single.Parse(strs[3], CultureInfo);
  507. style.Color = Color.FromArgb((int)(a * 0xFF), (int)r, (int)g, (int)b);
  508. }
  509. catch { }
  510. }
  511. }
  512. else if (StartsWith(tStr, "rgb"))
  513. {
  514. int i1 = tStr.IndexOf('(');
  515. int i2 = tStr.IndexOf(')');
  516. string[] strs = tStr.Substring(i1 + 1, i2 - i1 - 1).Split(',');
  517. if (strs.Length == 3)
  518. {
  519. float r, g, b;
  520. try
  521. {
  522. r = Single.Parse(strs[0], CultureInfo);
  523. g = Single.Parse(strs[1], CultureInfo);
  524. b = Single.Parse(strs[2], CultureInfo);
  525. style.Color = Color.FromArgb((int)r, (int)g, (int)b);
  526. }
  527. catch { }
  528. }
  529. }
  530. else style.Color = Color.FromName(tStr);
  531. }
  532. if (dict.TryGetValue("background-color", out tStr))
  533. {
  534. if (StartsWith(tStr, "#"))
  535. try { style.BackgroundColor = Color.FromArgb((int)(0xFF000000 + uint.Parse(tStr.Substring(1), System.Globalization.NumberStyles.HexNumber))); } catch { }
  536. else if (StartsWith(tStr, "rgba"))
  537. {
  538. int i1 = tStr.IndexOf('(');
  539. int i2 = tStr.IndexOf(')');
  540. string[] strs = tStr.Substring(i1 + 1, i2 - i1 - 1).Split(',');
  541. if (strs.Length == 4)
  542. {
  543. float r, g, b, a;
  544. try
  545. {
  546. r = Single.Parse(strs[0], CultureInfo);
  547. g = Single.Parse(strs[1], CultureInfo);
  548. b = Single.Parse(strs[2], CultureInfo);
  549. a = Single.Parse(strs[3], CultureInfo);
  550. style.BackgroundColor = Color.FromArgb((int)(a * 0xFF), (int)r, (int)g, (int)b);
  551. }
  552. catch { }
  553. }
  554. }
  555. else if (StartsWith(tStr, "rgb"))
  556. {
  557. int i1 = tStr.IndexOf('(');
  558. int i2 = tStr.IndexOf(')');
  559. string[] strs = tStr.Substring(i1 + 1, i2 - i1 - 1).Split(',');
  560. if (strs.Length == 3)
  561. {
  562. float r, g, b;
  563. try
  564. {
  565. r = Single.Parse(strs[0], CultureInfo);
  566. g = Single.Parse(strs[1], CultureInfo);
  567. b = Single.Parse(strs[2], CultureInfo);
  568. style.BackgroundColor = Color.FromArgb((int)r, (int)g, (int)b);
  569. }
  570. catch { }
  571. }
  572. }
  573. else style.BackgroundColor = Color.FromName(tStr);
  574. }
  575. }
  576. private bool EndsWith(string str1, string str2)
  577. {
  578. int len1 = str1.Length;
  579. int len2 = str2.Length;
  580. if (len1 < len2) return false;
  581. switch (len2)
  582. {
  583. case 0: return true;
  584. case 1: return str1[len1 - 1] == str2[len2 - 1];
  585. case 2: return str1[len1 - 1] == str2[len2 - 1] && str1[len1 - 2] == str2[len2 - 2];
  586. case 3: return str1[len1 - 1] == str2[len2 - 1] && str1[len1 - 2] == str2[len2 - 2] && str1[len1 - 3] == str2[len2 - 3];
  587. case 4: return str1[len1 - 1] == str2[len2 - 1] && str1[len1 - 2] == str2[len2 - 2] && str1[len1 - 3] == str2[len2 - 3] && str1[len1 - 4] == str2[len2 - 4];
  588. default: return str1.EndsWith(str2);
  589. }
  590. }
  591. private float GetTabPosition(float pos)
  592. {
  593. float tabOffset = TabOffset;
  594. float tabSize = TabSize;
  595. int tabPosition = (int)((pos - tabOffset) / tabSize);
  596. if (pos < tabOffset)
  597. return tabOffset;
  598. return (tabPosition + 1) * tabSize + tabOffset;
  599. }
  600. private float GetTabPosition(float pos, int tabIndex)
  601. {
  602. float tabOffset = 0;
  603. float tabSize;
  604. float firstTabOffset;
  605. float[] tabsPos = format.GetTabStops(out firstTabOffset);
  606. if (tabIndex <= 1)
  607. {
  608. tabOffset = TabOffset;
  609. tabSize = TabSize;
  610. }
  611. else
  612. {
  613. for (int i = 0; i < tabIndex; i++)
  614. {
  615. tabOffset += tabsPos[i];
  616. }
  617. tabSize = tabsPos[tabIndex];
  618. }
  619. int tabPosition = (int)((pos - tabOffset) / tabSize);
  620. if (pos < tabOffset)
  621. return tabOffset;
  622. return (tabPosition + 1) * tabSize + tabOffset;
  623. }
  624. private void SplitToParagraphs(string text)
  625. {
  626. Stack<SimpleFastReportHtmlElement> elements = new Stack<SimpleFastReportHtmlElement>();
  627. SimpleFastReportHtmlReader reader = new SimpleFastReportHtmlReader(this.text);
  628. List<CharWithIndex> currentWord = new List<CharWithIndex>();
  629. float width = paragraphFormat.SkipFirstLineIndent ? 0 : paragraphFormat.FirstLineIndent;
  630. Paragraph paragraph = new Paragraph(this);
  631. int charIndex = 0;
  632. int tabIndex = 0;
  633. Line line = new Line(this, paragraph, charIndex);
  634. paragraph.Lines.Add(line);
  635. paragraphs.Add(paragraph);
  636. Word word = null;
  637. StyleDescriptor style = new StyleDescriptor(initalStyle);
  638. //bool softReturn = false;
  639. //CharWithIndex softReturnChar = new CharWithIndex();
  640. while (reader.IsNotEOF)
  641. {
  642. if (reader.Read())
  643. {
  644. switch (reader.Character.Char)
  645. {
  646. case ' ':
  647. if (word == null)
  648. {
  649. word = new Word(this, line, WordType.WhiteSpace);
  650. line.Words.Add(word);
  651. }
  652. if (word.Type == WordType.WhiteSpace)
  653. currentWord.Add(reader.Character);
  654. else
  655. {
  656. if (currentWord.Count > 0)
  657. {
  658. Run r = new RunText(this, word, style, currentWord, width, charIndex);
  659. word.Runs.Add(r);
  660. currentWord.Clear();
  661. width += r.Width;
  662. if (width > displayRect.Width)
  663. line = WrapLine(paragraph, line, charIndex, displayRect.Width, ref width);
  664. }
  665. currentWord.Add(reader.Character);
  666. word = new Word(this, line, WordType.WhiteSpace);
  667. line.Words.Add(word);
  668. charIndex = reader.LastPosition;
  669. }
  670. break;
  671. case '\t':
  672. if (word != null)
  673. {
  674. if (currentWord.Count > 0)
  675. {
  676. Run r = new RunText(this, word, style, currentWord, width, charIndex);
  677. word.Runs.Add(r);
  678. currentWord.Clear();
  679. width += r.Width;
  680. if (width > displayRect.Width)
  681. line = WrapLine(paragraph, line, charIndex, displayRect.Width, ref width);
  682. }
  683. }
  684. else
  685. {
  686. if (currentWord.Count > 0)
  687. {
  688. AddUnknownWord(currentWord, paragraph, style, charIndex, ref line, ref word, ref width);
  689. }
  690. }
  691. charIndex = reader.LastPosition;
  692. word = new Word(this, line, WordType.Tab);
  693. Run tabRun = new RunText(this, word, style, new List<CharWithIndex>(new CharWithIndex[] { reader.Character }), width, charIndex);
  694. word.Runs.Add(tabRun);
  695. float width2 = GetTabPosition(width);
  696. if (isDifferentTabPositions)
  697. {
  698. width2 = GetTabPosition(width, tabIndex);
  699. }
  700. if (width2 < width) width2 = width;
  701. if (line.Words.Count > 0 && width2 > displayRect.Width)
  702. {
  703. tabRun.Left = 0;
  704. line = new Line(this, paragraph, charIndex);
  705. tabIndex = 0;
  706. paragraph.Lines.Add(line);
  707. width = 0;
  708. width2 = GetTabPosition(width);
  709. if (isDifferentTabPositions)
  710. {
  711. width2 = GetTabPosition(width, tabIndex);
  712. }
  713. }
  714. tabIndex++;
  715. line.Words.Add(word);
  716. tabRun.Width = width2 - width;
  717. width = width2;
  718. word = null;
  719. break;
  720. case SOFT_ENTER://soft enter
  721. if (word != null)
  722. {
  723. if (currentWord.Count > 0)
  724. {
  725. Run r = new RunText(this, word, style, currentWord, width, charIndex);
  726. word.Runs.Add(r);
  727. currentWord.Clear();
  728. width += r.Width;
  729. if (width > displayRect.Width)
  730. line = WrapLine(paragraph, line, charIndex, displayRect.Width, ref width);
  731. }
  732. }
  733. else
  734. {
  735. if (currentWord.Count > 0)
  736. {
  737. AddUnknownWord(currentWord, paragraph, style, charIndex, ref line, ref word, ref width);
  738. }
  739. }
  740. charIndex = reader.Position;
  741. //currentWord.Append(' ')
  742. //RunText runText = new RunText(this, word, style, new List<CharWithIndex>(new CharWithIndex[] { reader.Character }), width, charIndex);
  743. //runText.Width = 0;
  744. //word.Runs.Add(runText);
  745. line = new Line(this, paragraph, charIndex);
  746. word = null;
  747. width = 0;
  748. currentWord.Clear();
  749. paragraph.Lines.Add(line);
  750. break;
  751. case '\n':
  752. if (word != null)
  753. {
  754. if (currentWord.Count > 0)
  755. {
  756. Run r = new RunText(this, word, style, currentWord, width, charIndex);
  757. word.Runs.Add(r);
  758. currentWord.Clear();
  759. width += r.Width;
  760. if (width > displayRect.Width)
  761. line = WrapLine(paragraph, line, charIndex, displayRect.Width, ref width);
  762. }
  763. }
  764. else
  765. {
  766. if (currentWord.Count > 0)
  767. {
  768. AddUnknownWord(currentWord, paragraph, style, charIndex, ref line, ref word, ref width);
  769. }
  770. }
  771. charIndex = reader.Position;
  772. paragraph = new Paragraph(this);
  773. paragraphs.Add(paragraph);
  774. line = new Line(this, paragraph, charIndex);
  775. word = null;
  776. width = paragraphFormat.FirstLineIndent;
  777. paragraph.Lines.Add(line);
  778. break;
  779. case '\r'://ignore
  780. break;
  781. default:
  782. if (word == null)
  783. {
  784. word = new Word(this, line, WordType.Normal);
  785. line.Words.Add(word);
  786. }
  787. if (word.Type == WordType.Normal)
  788. currentWord.Add(reader.Character);
  789. else
  790. {
  791. if (currentWord.Count > 0)
  792. {
  793. Run r = new RunText(this, word, style, currentWord, width, charIndex);
  794. word.Runs.Add(r);
  795. currentWord.Clear();
  796. width += r.Width;
  797. if (width > displayRect.Width)
  798. line = WrapLine(paragraph, line, charIndex, displayRect.Width, ref width);
  799. }
  800. currentWord.Add(reader.Character);
  801. word = new Word(this, line, WordType.Normal);
  802. line.Words.Add(word);
  803. charIndex = reader.LastPosition;
  804. }
  805. break;
  806. }
  807. }
  808. else
  809. {
  810. StyleDescriptor newStyle = new StyleDescriptor(initalStyle);
  811. SimpleFastReportHtmlElement element = reader.Element;
  812. if (!element.IsSelfClosed)
  813. {
  814. if (element.isEnd)
  815. {
  816. int enumIndex = 1;
  817. using (Stack<SimpleFastReportHtmlElement>.Enumerator enumerator = elements.GetEnumerator())
  818. {
  819. while (enumerator.MoveNext())
  820. {
  821. SimpleFastReportHtmlElement el = enumerator.Current;
  822. if (el.name == element.name)
  823. {
  824. for (int i = 0; i < enumIndex; i++)
  825. elements.Pop();
  826. break;
  827. }
  828. else
  829. enumIndex++;
  830. }
  831. }
  832. }
  833. else elements.Push(element);
  834. SimpleFastReportHtmlElement[] arr = elements.ToArray();
  835. for (int i = arr.Length - 1; i >= 0; i--)
  836. {
  837. SimpleFastReportHtmlElement el = arr[i];
  838. switch (el.name)
  839. {
  840. case "b":
  841. newStyle.FontStyle |= FontStyle.Bold;
  842. break;
  843. case "i":
  844. newStyle.FontStyle |= FontStyle.Italic;
  845. break;
  846. case "u":
  847. newStyle.FontStyle |= FontStyle.Underline;
  848. break;
  849. case "sub":
  850. newStyle.BaseLine = BaseLine.Subscript;
  851. break;
  852. case "sup":
  853. newStyle.BaseLine = BaseLine.Superscript;
  854. break;
  855. case "strike":
  856. newStyle.FontStyle |= FontStyle.Strikeout;
  857. break;
  858. //case "font":
  859. // {
  860. // string color = null;
  861. // string face = null;
  862. // string size = null;
  863. // if (el.Attributes != null)
  864. // {
  865. // el.Attributes.TryGetValue("color", out color);
  866. // el.Attributes.TryGetValue("face", out face);
  867. // el.Attributes.TryGetValue("size", out size);
  868. // }
  869. // if (color != null)
  870. // {
  871. // if (color.StartsWith("\"") && color.EndsWith("\""))
  872. // color = color.Substring(1, color.Length - 2);
  873. // if (color.StartsWith("#"))
  874. // {
  875. // newStyle.Color = Color.FromArgb((int)(0xFF000000 + uint.Parse(color.Substring(1), System.Globalization.NumberStyles.HexNumber)));
  876. // }
  877. // else
  878. // {
  879. // newStyle.Color = Color.FromName(color);
  880. // }
  881. // }
  882. // if (face != null)
  883. // newStyle.Font = face;
  884. // if (size != null)
  885. // {
  886. // try
  887. // {
  888. // size = size.Trim(' ');
  889. // newStyle.Size = (float)Converter.FromString(typeof(float), size) * FFontScale;
  890. // }
  891. // catch
  892. // {
  893. // newStyle.Size = FSize * FFontScale;
  894. // }
  895. // }
  896. // }
  897. // break;
  898. }
  899. CssStyle(newStyle, el.Style);
  900. }
  901. if (currentWord.Count > 0)
  902. {
  903. AddUnknownWord(currentWord, paragraph, style, charIndex, ref line, ref word, ref width);
  904. currentWord.Clear();
  905. charIndex = reader.LastPosition;
  906. }
  907. style = newStyle;
  908. }
  909. else
  910. {
  911. switch (element.name)
  912. {
  913. case "img":
  914. if (element.attributes != null && element.attributes.ContainsKey("src"))
  915. {
  916. float img_width = -1;
  917. float img_height = -1;
  918. string tStr;
  919. if (element.attributes.TryGetValue("width", out tStr))
  920. try { img_width = Single.Parse(tStr, System.Globalization.CultureInfo.InstalledUICulture); } catch { }
  921. if (element.attributes.TryGetValue("height", out tStr))
  922. try { img_height = Single.Parse(tStr, System.Globalization.CultureInfo.InstalledUICulture); } catch { }
  923. if (currentWord.Count > 0)
  924. {
  925. AddUnknownWord(currentWord, paragraph, style, charIndex, ref line, ref word, ref width);
  926. currentWord.Clear();
  927. }
  928. if (word == null || word.Type != WordType.Normal)
  929. {
  930. word = new Word(this, line, WordType.Normal);
  931. line.Words.Add(word);
  932. charIndex = reader.LastPosition;
  933. }
  934. Run r = new RunImage(this, word, element.attributes["src"], style, width, reader.LastPosition, img_width, img_height);
  935. word.Runs.Add(r);
  936. width += r.Width;
  937. if (width > displayRect.Width)
  938. line = WrapLine(paragraph, line, charIndex, displayRect.Width, ref width);
  939. }
  940. break;
  941. }
  942. }
  943. }
  944. }
  945. if (currentWord.Count > 0)
  946. {
  947. AddUnknownWord(currentWord, paragraph, style, charIndex, ref line, ref word, ref width);
  948. }
  949. }
  950. private bool StartsWith(string str1, string str2)
  951. {
  952. if (str1.Length < str2.Length) return false;
  953. switch (str2.Length)
  954. {
  955. case 0: return true;
  956. case 1: return str1[0] == str2[0];
  957. case 2: return str1[0] == str2[0] && str1[1] == str2[1];
  958. case 3: return str1[0] == str2[0] && str1[1] == str2[1] && str1[2] == str2[2];
  959. case 4: return str1[0] == str2[0] && str1[1] == str2[1] && str1[2] == str2[2] && str1[3] == str2[3];
  960. default: return str1.StartsWith(str2);
  961. }
  962. }
  963. /// <summary>
  964. /// Check the line, and if last word is able to move next line, move it.
  965. /// e.g. white space won't move to next line.
  966. /// If word is not moved return current line.
  967. /// else return new line
  968. /// </summary>
  969. /// <param name="paragraph">the paragraph for lines</param>
  970. /// <param name="line">the line with extra words</param>
  971. /// <param name="wordCharIndex">the index of start last word in this line</param>
  972. /// <param name="availableWidth">width to place words</param>
  973. /// <param name="newWidth">ref to current line width</param>
  974. /// <returns></returns>
  975. private Line WrapLine(Paragraph paragraph, Line line, int wordCharIndex, float availableWidth, ref float newWidth)
  976. {
  977. if (line.Words.Count == 0)
  978. {
  979. return line;
  980. }
  981. if (line.Words.Count == 1 && line.Words[0].Type == WordType.Normal)
  982. {
  983. Word word = line.Words[0];
  984. float width = word.Runs.Count > 0 ? word.Runs[0].Left : 0;
  985. /* Foreach runs, while run in available space next run
  986. * if run begger then space split run and generate new word and run
  987. */
  988. Word newWord = new Word(word.Renderer, line, word.Type);
  989. line.Words.Clear();
  990. line.Words.Add(newWord);
  991. foreach (Run run in word.Runs)
  992. {
  993. width += run.Width;
  994. if (width <= availableWidth || availableWidth < 0)
  995. {
  996. newWord.Runs.Add(run);
  997. run.Word = newWord;
  998. }
  999. else
  1000. {
  1001. Run secondPart = run;
  1002. while (secondPart != null)
  1003. {
  1004. Run firstPart = secondPart.Split(availableWidth - run.Left, out secondPart);
  1005. if (firstPart != null)
  1006. {
  1007. newWord.Runs.Clear();
  1008. newWord.Runs.Add(firstPart);
  1009. firstPart.Word = newWord;
  1010. }
  1011. else if (newWord.Runs.Count == 0)
  1012. {
  1013. newWord.Runs.Add(run);
  1014. run.Word = newWord;
  1015. secondPart = null;
  1016. }
  1017. if (secondPart != null)
  1018. {
  1019. line = new Line(line.Renderer, paragraph, secondPart.CharIndex);
  1020. paragraph.Lines.Add(line);
  1021. newWord = new Word(newWord.Renderer, line, newWord.Type);
  1022. line.Words.Add(newWord);
  1023. secondPart.Left = 0;
  1024. width = secondPart.Width;
  1025. secondPart.Word = newWord;
  1026. newWord.Runs.Add(secondPart);
  1027. if (width < availableWidth)
  1028. secondPart = null;
  1029. }
  1030. }
  1031. }
  1032. }
  1033. return line;
  1034. }
  1035. else
  1036. if (line.Words[line.Words.Count - 1].Type == WordType.WhiteSpace)
  1037. {
  1038. return line;
  1039. }
  1040. else
  1041. {
  1042. Word lastWord = line.Words[line.Words.Count - 1];
  1043. line.Words.RemoveAt(line.Words.Count - 1);
  1044. Line result = new Line(this, paragraph, wordCharIndex);
  1045. paragraph.Lines.Add(result);
  1046. newWidth = 0;
  1047. result.Words.Add(lastWord);
  1048. lastWord.Line = result;
  1049. foreach (Run r in lastWord.Runs)
  1050. {
  1051. r.Left = newWidth;
  1052. newWidth += r.Width;
  1053. }
  1054. return result;
  1055. }
  1056. }
  1057. #endregion Private Methods
  1058. #region Public Enums
  1059. public enum WordType
  1060. {
  1061. Normal,
  1062. WhiteSpace,
  1063. Tab,
  1064. }
  1065. #endregion Public Enums
  1066. #region Internal Enums
  1067. /// <summary>
  1068. /// Represents character placement.
  1069. /// </summary>
  1070. public enum BaseLine
  1071. {
  1072. Normal,
  1073. Subscript,
  1074. Superscript
  1075. }
  1076. #endregion Internal Enums
  1077. #region Public Structs
  1078. public struct CharWithIndex
  1079. {
  1080. #region Public Fields
  1081. public char Char;
  1082. public int Index;
  1083. #endregion Public Fields
  1084. #region Public Constructors
  1085. public CharWithIndex(char v, int fPosition)
  1086. {
  1087. this.Char = v;
  1088. this.Index = fPosition;
  1089. }
  1090. #endregion Public Constructors
  1091. }
  1092. #if READONLY_STRUCTS
  1093. public readonly struct LineFColor
  1094. #else
  1095. public struct LineFColor
  1096. #endif
  1097. {
  1098. #region Public Fields
  1099. public readonly Color Color;
  1100. public readonly float Left;
  1101. public readonly float Right;
  1102. public readonly float Top;
  1103. public readonly float Width;
  1104. #endregion Public Fields
  1105. #region Public Constructors
  1106. public LineFColor(float left, float top, float right, float width, Color color)
  1107. {
  1108. this.Left = left;
  1109. this.Top = top;
  1110. this.Right = right;
  1111. this.Width = width;
  1112. this.Color = color;
  1113. }
  1114. public LineFColor(float left, float top, float right, float width, byte R, byte G, byte B)
  1115. : this(left, top, right, width, Color.FromArgb(R, G, B))
  1116. {
  1117. }
  1118. public LineFColor(float left, float top, float right, float width, byte R, byte G, byte B, byte A)
  1119. : this(left, top, right, width, Color.FromArgb(A, R, G, B))
  1120. {
  1121. }
  1122. public LineFColor(float left, float top, float right, float width, int R, int G, int B)
  1123. : this(left, top, right, width, Color.FromArgb(R, G, B))
  1124. {
  1125. }
  1126. public LineFColor(float left, float top, float right, float width, int R, int G, int B, int A)
  1127. : this(left, top, right, width, Color.FromArgb(A, R, G, B))
  1128. {
  1129. }
  1130. #endregion Public Constructors
  1131. }
  1132. #if READONLY_STRUCTS
  1133. public readonly struct RectangleFColor
  1134. #else
  1135. public struct RectangleFColor
  1136. #endif
  1137. {
  1138. #region Public Fields
  1139. public readonly Color Color;
  1140. public readonly float Height;
  1141. public readonly float Left;
  1142. public readonly float Top;
  1143. public readonly float Width;
  1144. #endregion Public Fields
  1145. #region Public Constructors
  1146. public RectangleFColor(float left, float top, float width, float height, Color color)
  1147. {
  1148. this.Left = left;
  1149. this.Top = top;
  1150. this.Width = width;
  1151. this.Height = height;
  1152. this.Color = color;
  1153. }
  1154. public RectangleFColor(float left, float top, float width, float height, byte R, byte G, byte B)
  1155. : this(left, top, width, height, Color.FromArgb(R, G, B))
  1156. {
  1157. }
  1158. public RectangleFColor(float left, float top, float width, float height, byte R, byte G, byte B, byte A)
  1159. : this(left, top, width, height, Color.FromArgb(A, R, G, B))
  1160. {
  1161. }
  1162. public RectangleFColor(float left, float top, float width, float height, int R, int G, int B)
  1163. : this(left, top, width, height, Color.FromArgb(R, G, B))
  1164. {
  1165. }
  1166. public RectangleFColor(float left, float top, float width, float height, int R, int G, int B, int A)
  1167. : this(left, top, width, height, Color.FromArgb(A, R, G, B))
  1168. {
  1169. }
  1170. #endregion Public Constructors
  1171. }
  1172. #endregion Public Structs
  1173. #region Public Classes
  1174. public class Line
  1175. {
  1176. #region Private Fields
  1177. private float baseLine;
  1178. private float height;
  1179. private HorzAlign horzAlign;
  1180. private float lineSpacing;
  1181. private int originalCharIndex;
  1182. private Paragraph paragraph;
  1183. private HtmlTextRenderer renderer;
  1184. private float top;
  1185. private float width;
  1186. private List<Word> words;
  1187. #endregion Private Fields
  1188. #region Public Properties
  1189. public float BaseLine
  1190. {
  1191. get { return baseLine; }
  1192. set { baseLine = value; }
  1193. }
  1194. public float Height
  1195. {
  1196. get { return height; }
  1197. set { height = value; }
  1198. }
  1199. public HorzAlign HorzAlign
  1200. {
  1201. get { return horzAlign; }
  1202. }
  1203. public float LineSpacing
  1204. {
  1205. get { return lineSpacing; }
  1206. set { lineSpacing = value; }
  1207. }
  1208. public int OriginalCharIndex
  1209. {
  1210. get { return originalCharIndex; }
  1211. set { originalCharIndex = value; }
  1212. }
  1213. public Paragraph Paragraph
  1214. {
  1215. get { return paragraph; }
  1216. set { paragraph = value; }
  1217. }
  1218. public HtmlTextRenderer Renderer
  1219. {
  1220. get { return renderer; }
  1221. }
  1222. public float Top
  1223. {
  1224. get { return top; }
  1225. set
  1226. {
  1227. top = value;
  1228. foreach (Word w in Words)
  1229. {
  1230. foreach (Run r in w.Runs)
  1231. {
  1232. float shift = 0;
  1233. if (r.Style.BaseLine == HtmlTextRenderer.BaseLine.Subscript)
  1234. shift += r.Height * 0.45f;
  1235. else if (r.Style.BaseLine == HtmlTextRenderer.BaseLine.Superscript)
  1236. shift -= r.BaseLine - r.Height * 0.15f;
  1237. r.Top = top + BaseLine - r.BaseLine + shift;
  1238. }
  1239. }
  1240. }
  1241. }
  1242. public float Width
  1243. {
  1244. get
  1245. {
  1246. return width;
  1247. }
  1248. }
  1249. public List<Word> Words
  1250. {
  1251. get { return words; }
  1252. }
  1253. #endregion Public Properties
  1254. #region Public Constructors
  1255. public Line(HtmlTextRenderer renderer, Paragraph paragraph, int charIndex)
  1256. {
  1257. words = new List<Word>();
  1258. this.renderer = renderer;
  1259. this.paragraph = paragraph;
  1260. originalCharIndex = charIndex;
  1261. }
  1262. #endregion Public Constructors
  1263. #region Public Methods
  1264. public override string ToString()
  1265. {
  1266. return String.Format("Words[{0}]", Words.Count);
  1267. }
  1268. #endregion Public Methods
  1269. #region Internal Methods
  1270. internal void AlignWords(HorzAlign align)
  1271. {
  1272. horzAlign = align;
  1273. float width = CalcWidth();
  1274. float left = Words.Count > 0 && Words[0].Runs.Count > 0 ? Words[0].Runs[0].Left : 0;
  1275. width += left;
  1276. this.width = width;
  1277. switch (align)
  1278. {
  1279. case HorzAlign.Left:
  1280. break;
  1281. case HorzAlign.Right:
  1282. {
  1283. float delta = Renderer.displayRect.Width - width;
  1284. foreach (Word w in Words)
  1285. foreach (Run r in w.Runs)
  1286. r.Left += delta;
  1287. }
  1288. break;
  1289. case HorzAlign.Center:
  1290. {
  1291. float delta = (Renderer.displayRect.Width - width) / 2f;
  1292. foreach (Word w in Words)
  1293. foreach (Run r in w.Runs)
  1294. r.Left += delta;
  1295. }
  1296. break;
  1297. case HorzAlign.Justify:
  1298. {
  1299. int spaces = 0;
  1300. int tab_index = -1;
  1301. bool isWordExistAfterTab = true;
  1302. for (int i = 0; i < Words.Count - 1; i++)
  1303. {
  1304. if (isWordExistAfterTab)
  1305. {
  1306. if (Words[i].Type == WordType.WhiteSpace)
  1307. foreach (Run r in Words[i].Runs)
  1308. if (r is RunText)
  1309. spaces += (r as RunText).Text.Length;
  1310. }
  1311. else if (Words[i].Type == WordType.Normal)
  1312. isWordExistAfterTab = true;
  1313. if (Words[i].Type == WordType.Tab)
  1314. {
  1315. spaces = 0;
  1316. tab_index = i;
  1317. isWordExistAfterTab = false;
  1318. }
  1319. }
  1320. if (spaces > 0)
  1321. {
  1322. float space_width = (Renderer.displayRect.Width - width) / spaces;
  1323. for (int i = 0; i < Words.Count; i++)
  1324. {
  1325. Word w = Words[i];
  1326. if (w.Type == WordType.WhiteSpace)
  1327. foreach (Run r in w.Runs)
  1328. {
  1329. if (i > tab_index && r is RunText)
  1330. r.Width += space_width * (r as RunText).Text.Length;
  1331. r.Left = left;
  1332. left += r.Width;
  1333. }
  1334. else foreach (Run r in w.Runs)
  1335. {
  1336. r.Left = left;
  1337. left += r.Width;
  1338. }
  1339. }
  1340. }
  1341. }
  1342. break;
  1343. }
  1344. if (renderer.RightToLeft)
  1345. {
  1346. float rectRight = Renderer.displayRect.Right;
  1347. foreach (Word w in Words)
  1348. foreach (Run r in w.Runs)
  1349. r.Left = rectRight - r.Left;
  1350. }
  1351. else
  1352. {
  1353. float rectLeft = Renderer.displayRect.Left;
  1354. foreach (Word w in Words)
  1355. foreach (Run r in w.Runs)
  1356. r.Left += rectLeft;
  1357. }
  1358. }
  1359. internal void CalcMetrics()
  1360. {
  1361. baseLine = 0;
  1362. foreach (Word word in Words)
  1363. {
  1364. word.CalcMetrics();
  1365. baseLine = Math.Max(baseLine, word.BaseLine);
  1366. }
  1367. height = renderer.fontLineHeight;
  1368. float decent = 0;
  1369. foreach (Word word in Words)
  1370. {
  1371. decent = Math.Max(decent, word.Descent);
  1372. }
  1373. if (baseLine + decent > 0.01)
  1374. height = baseLine + decent;
  1375. switch (renderer.paragraphFormat.LineSpacingType)
  1376. {
  1377. case LineSpacingType.AtLeast:
  1378. if (height < renderer.paragraphFormat.LineSpacing)
  1379. lineSpacing = renderer.paragraphFormat.LineSpacing - height;
  1380. break;
  1381. case LineSpacingType.Single:
  1382. break;
  1383. case LineSpacingType.Multiple:
  1384. lineSpacing = height * (renderer.paragraphFormat.LineSpacingMultiple - 1);
  1385. break;
  1386. case LineSpacingType.Exactly:
  1387. lineSpacing = renderer.paragraphFormat.LineSpacing - height;
  1388. break;
  1389. }
  1390. }
  1391. internal void MakeBackgrounds()
  1392. {
  1393. List<RectangleFColor> list = renderer.backgrounds;
  1394. if (renderer.rightToLeft)
  1395. {
  1396. foreach (Word word in Words)
  1397. foreach (Run run in word.Runs)
  1398. if (run.Style.BackgroundColor.A > 0)
  1399. list.Add(new RectangleFColor(
  1400. run.Left - run.Width, top, run.Width, height, run.Style.BackgroundColor
  1401. ));
  1402. }
  1403. else
  1404. {
  1405. foreach (Word word in Words)
  1406. foreach (Run run in word.Runs)
  1407. if (run.Style.BackgroundColor.A > 0)
  1408. list.Add(new RectangleFColor(
  1409. run.Left, top, run.Width, height, run.Style.BackgroundColor
  1410. ));
  1411. }
  1412. }
  1413. internal void MakeEverUnderlines()
  1414. {
  1415. OwnHashSet<StyleDescriptor> styles = new OwnHashSet<StyleDescriptor>();
  1416. float size = 0;
  1417. float underline = 0;
  1418. foreach (Word word in Words)
  1419. foreach (Run run in word.Runs)
  1420. if (!styles.Contains(run.Style))
  1421. {
  1422. styles.Add(run.Style);
  1423. size += run.Style.Size;
  1424. underline += run.Descent / 2;
  1425. }
  1426. if (styles.Count == 0 || BaseLine <= 0.01)
  1427. {
  1428. using (Font ff = renderer.initalStyle.GetFont())
  1429. {
  1430. float lineSpace = ff.FontFamily.GetLineSpacing(renderer.initalStyle.FontStyle);
  1431. float ascent = ff.FontFamily.GetCellAscent(renderer.initalStyle.FontStyle);
  1432. baseLine = height * ascent / lineSpace;
  1433. float FDescent = height - baseLine;
  1434. underline = FDescent / 2;
  1435. size = ff.Size;
  1436. }
  1437. }
  1438. else
  1439. {
  1440. size /= styles.Count;
  1441. underline /= styles.Count;
  1442. }
  1443. float fixScale = Renderer.Scale / Renderer.FontScale;
  1444. renderer.underlines.Add(new LineFColor(
  1445. renderer.displayRect.Left, Top + BaseLine + underline, renderer.displayRect.Right, size * 0.1f * fixScale, renderer.underlineColor
  1446. ));
  1447. }
  1448. internal void MakeStrikeouts()
  1449. {
  1450. List<LineFColor> lines = renderer.strikeouts;
  1451. float fixScale = Renderer.Scale / Renderer.FontScale;
  1452. if (renderer.rightToLeft)
  1453. {
  1454. foreach (Word word in Words)
  1455. foreach (Run r in word.Runs)
  1456. if ((r.Style.FontStyle & FontStyle.Strikeout) == FontStyle.Strikeout)
  1457. lines.Add(new LineFColor(
  1458. r.Left - r.Width, r.Top + r.BaseLine / 3f * 2f, r.Left, r.Style.Size * 0.1f * fixScale,
  1459. r.Style.Color));
  1460. }
  1461. else
  1462. {
  1463. foreach (Word word in Words)
  1464. foreach (Run r in word.Runs)
  1465. if ((r.Style.FontStyle & FontStyle.Strikeout) == FontStyle.Strikeout)
  1466. lines.Add(new LineFColor(
  1467. r.Left, r.Top + r.BaseLine / 3f * 2f, r.Left + r.Width, r.Style.Size * 0.1f * fixScale,
  1468. r.Style.Color));
  1469. }
  1470. }
  1471. internal void MakeUnderlines()
  1472. {
  1473. if (renderer.everUnderlines)
  1474. {
  1475. MakeEverUnderlines();
  1476. return;
  1477. }
  1478. List<List<Run>> runs = new List<List<Run>>();
  1479. List<Run> currentRuns = null;
  1480. foreach (Word word in Words)
  1481. foreach (Run run in word.Runs)
  1482. {
  1483. if ((run.Style.FontStyle & FontStyle.Underline) == FontStyle.Underline)
  1484. {
  1485. if (currentRuns == null)
  1486. {
  1487. currentRuns = new List<Run>();
  1488. runs.Add(currentRuns);
  1489. }
  1490. currentRuns.Add(run);
  1491. }
  1492. else
  1493. {
  1494. currentRuns = null;
  1495. }
  1496. }
  1497. List<LineFColor> unerlines = renderer.underlines;
  1498. float fixScale = Renderer.Scale / Renderer.FontScale;
  1499. foreach (List<Run> cRuns in runs)
  1500. {
  1501. OwnHashSet<StyleDescriptor> styles = new OwnHashSet<StyleDescriptor>();
  1502. float size = 0;
  1503. float underline = 0;
  1504. foreach (Run r in cRuns)
  1505. if (!styles.Contains(r.Style))
  1506. {
  1507. styles.Add(r.Style);
  1508. size += r.Style.Size;
  1509. underline += r.Descent / 2;
  1510. }
  1511. size /= styles.Count;
  1512. underline /= styles.Count;
  1513. if (renderer.rightToLeft)
  1514. foreach (Run r in cRuns)
  1515. unerlines.Add(new LineFColor(
  1516. r.Left - r.Width, r.Top + r.BaseLine + underline, r.Left, size * 0.1f * fixScale,
  1517. r.Style.Color));
  1518. else
  1519. foreach (Run r in cRuns)
  1520. unerlines.Add(new LineFColor(
  1521. r.Left, r.Top + r.BaseLine + underline, r.Left + r.Width, size * 0.1f * fixScale,
  1522. r.Style.Color));
  1523. }
  1524. }
  1525. #endregion Internal Methods
  1526. #region Private Methods
  1527. private float CalcWidth()
  1528. {
  1529. float width = 0;
  1530. foreach (Word w in Words)
  1531. foreach (Run r in w.Runs)
  1532. width += r.Width;
  1533. Word lastWord = Words.Count > 0 ? Words[Words.Count - 1] : null;
  1534. if (lastWord != null && lastWord.Type == WordType.WhiteSpace)
  1535. {
  1536. foreach (Run r in lastWord.Runs)
  1537. width -= r.Width;
  1538. }
  1539. return width;
  1540. }
  1541. #endregion Private Methods
  1542. }
  1543. public class Paragraph
  1544. {
  1545. #region Private Fields
  1546. private List<Line> lines;
  1547. private HtmlTextRenderer renderer;
  1548. #endregion Private Fields
  1549. #region Public Properties
  1550. public List<Line> Lines
  1551. {
  1552. get { return lines; }
  1553. }
  1554. public HtmlTextRenderer Renderer
  1555. {
  1556. get { return renderer; }
  1557. }
  1558. #endregion Public Properties
  1559. #region Public Constructors
  1560. public Paragraph(HtmlTextRenderer renderer)
  1561. {
  1562. lines = new List<Line>();
  1563. this.renderer = renderer;
  1564. }
  1565. #endregion Public Constructors
  1566. #region Public Methods
  1567. public override string ToString()
  1568. {
  1569. if (Lines.Count == 0) return "Lines[0]";
  1570. StringBuilder sb = new StringBuilder();
  1571. sb.AppendFormat("Lines[{0}]", Lines.Count);
  1572. sb.Append("{");
  1573. foreach (Line line in Lines)
  1574. {
  1575. sb.Append(line);
  1576. sb.Append(",");
  1577. }
  1578. sb.Append("}");
  1579. return sb.ToString();
  1580. }
  1581. #endregion Public Methods
  1582. #region Internal Methods
  1583. internal void AlignLines(bool forceJustify)
  1584. {
  1585. for (int i = 0; i < Lines.Count; i++)
  1586. {
  1587. HorzAlign align = Renderer.horzAlign;
  1588. if (align == HorzAlign.Justify && i == Lines.Count - 1 && !forceJustify)
  1589. align = HorzAlign.Left;
  1590. Lines[i].AlignWords(align);
  1591. }
  1592. }
  1593. #endregion Internal Methods
  1594. }
  1595. public abstract class Run
  1596. {
  1597. #region Protected Fields
  1598. protected float baseLine;
  1599. protected int charIndex;
  1600. protected float descent;
  1601. protected float height;
  1602. protected float left;
  1603. protected HtmlTextRenderer renderer;
  1604. protected StyleDescriptor style;
  1605. protected float top;
  1606. //protected float FUnderline;
  1607. //protected float FUnderlineSize;
  1608. protected float width;
  1609. protected Word word;
  1610. #endregion Protected Fields
  1611. #region Public Properties
  1612. public float BaseLine
  1613. {
  1614. get { return baseLine; }
  1615. set { baseLine = value; }
  1616. }
  1617. public int CharIndex
  1618. {
  1619. get { return charIndex; }
  1620. }
  1621. public float Descent
  1622. {
  1623. get { return descent; }
  1624. set { descent = value; }
  1625. }
  1626. public float Height
  1627. {
  1628. get { return height; }
  1629. set { height = value; }
  1630. }
  1631. public float Left
  1632. {
  1633. get { return left; }
  1634. set { left = value; }
  1635. }
  1636. public HtmlTextRenderer Renderer
  1637. {
  1638. get { return renderer; }
  1639. }
  1640. public StyleDescriptor Style
  1641. {
  1642. get { return style; }
  1643. }
  1644. public float Top
  1645. {
  1646. get { return top; }
  1647. set { top = value; }
  1648. }
  1649. //public float Underline
  1650. //{
  1651. // get { return FUnderline; }
  1652. // set { FUnderline = value; }
  1653. //}
  1654. //public float UnderlineSize
  1655. //{
  1656. // get { return FUnderlineSize; }
  1657. // set { FUnderlineSize = value; }
  1658. //}
  1659. public float Width
  1660. {
  1661. get { return width; }
  1662. set { width = value; }
  1663. }
  1664. public Word Word
  1665. {
  1666. get { return word; }
  1667. set { word = value; }
  1668. }
  1669. #endregion Public Properties
  1670. #region Public Constructors
  1671. public Run(HtmlTextRenderer renderer, Word word, StyleDescriptor style, float left, int charIndex)
  1672. {
  1673. this.renderer = renderer;
  1674. this.word = word;
  1675. this.style = style;
  1676. this.left = left;
  1677. this.charIndex = charIndex;
  1678. }
  1679. #endregion Public Constructors
  1680. //public virtual void DrawBack(float top, float height)
  1681. //{
  1682. // if (FStyle.BackgroundColor.A > 0)
  1683. // {
  1684. // using (Brush brush = GetBackgroundBrush())
  1685. // FRenderer.FGraphics.FillRectangle(brush, Left, top, Width, height);
  1686. // }
  1687. //}
  1688. #region Public Methods
  1689. public abstract void Draw();
  1690. public abstract Run Split(float availableWidth, out Run secondPart);
  1691. #endregion Public Methods
  1692. #region Protected Methods
  1693. protected Brush GetBackgroundBrush()
  1694. {
  1695. return new SolidBrush(style.BackgroundColor);
  1696. }
  1697. #endregion Protected Methods
  1698. //public virtual void Draw(bool drawContents)
  1699. //{
  1700. // if ((FStyle.FontStyle & FontStyle.Underline) == FontStyle.Underline)
  1701. // {
  1702. // if (!FRenderer.FUnderLines)
  1703. // {
  1704. // float top = Top + FUnderline;
  1705. // using (Pen pen = new Pen(FStyle.Color, FUnderlineSize * 0.1f))
  1706. // if (FRenderer.FRightToLeft)
  1707. // FRenderer.FGraphics.DrawLine(pen, Left - Width, top, Left, top);
  1708. // else
  1709. // FRenderer.FGraphics.DrawLine(pen, Left, top, Left + Width, top);
  1710. // }
  1711. // }
  1712. // if ((FStyle.FontStyle & FontStyle.Strikeout) == FontStyle.Strikeout)
  1713. // {
  1714. // float top = Top + FBaseLine / 3 * 2;
  1715. // using (Pen pen = new Pen(FStyle.Color, FStyle.Size * 0.1f))
  1716. // if (FRenderer.FRightToLeft)
  1717. // FRenderer.FGraphics.DrawLine(pen, Left - Width, top, Left, top);
  1718. // else
  1719. // FRenderer.FGraphics.DrawLine(pen, Left, top, Left + Width, top);
  1720. // }
  1721. //}
  1722. }
  1723. public class RunImage : Run
  1724. {
  1725. #region Private Fields
  1726. private Image image;
  1727. private string src;
  1728. #endregion Private Fields
  1729. #region Public Properties
  1730. public Image Image { get { return image; } }
  1731. #endregion Public Properties
  1732. #region Public Constructors
  1733. public RunImage(HtmlTextRenderer renderer, Word word, string src, StyleDescriptor style, float left, int charIndex, float img_width, float img_height) : base(renderer, word, style, left, charIndex)
  1734. {
  1735. base.style = new StyleDescriptor(style);
  1736. this.src = src;
  1737. //disable for exports because img tag not support strikeouts and underlines
  1738. base.style.FontStyle &= ~(FontStyle.Strikeout | FontStyle.Underline);
  1739. image = InlineImageCache.Load(Renderer.cache, src);
  1740. Width = image.Width * Renderer.Scale;
  1741. Height = image.Height * Renderer.Scale;
  1742. if (img_height > 0)
  1743. {
  1744. if (img_width > 0)
  1745. {
  1746. Width = img_width * Renderer.Scale;
  1747. Height = img_height * Renderer.Scale;
  1748. }
  1749. else
  1750. {
  1751. Width *= img_height / image.Height;
  1752. Height = img_height * Renderer.Scale;
  1753. }
  1754. }
  1755. else if (img_width > 0)
  1756. {
  1757. Width = img_width * Renderer.Scale;
  1758. Height *= img_width / image.Width;
  1759. }
  1760. baseLine = Height;
  1761. using (Font ff = style.GetFont())
  1762. {
  1763. float height = ff.GetHeight(Renderer.graphics.Graphics);
  1764. float lineSpace = ff.FontFamily.GetLineSpacing(style.FontStyle);
  1765. float descent = ff.FontFamily.GetCellDescent(style.FontStyle);
  1766. base.descent = height * descent / lineSpace;
  1767. }
  1768. }
  1769. #endregion Public Constructors
  1770. #region Public Methods
  1771. public override void Draw()
  1772. //public override void Draw(bool drawContents)
  1773. {
  1774. //if (drawContents)
  1775. if (image != null)
  1776. {
  1777. if (renderer.rightToLeft)
  1778. renderer.graphics.DrawImage(image, new RectangleF(Left - Width, Top, Width, Height));
  1779. else
  1780. renderer.graphics.DrawImage(image, new RectangleF(Left, Top, Width, Height));
  1781. }
  1782. //base.Draw(drawContents);
  1783. }
  1784. public override Run Split(float availableWidth, out Run secondPart)
  1785. {
  1786. secondPart = this;
  1787. return null;
  1788. }
  1789. #endregion Public Methods
  1790. #region Internal Methods
  1791. public Bitmap GetBitmap(out float width, out float height)
  1792. {
  1793. width = 1;
  1794. height = 1;
  1795. if (image == null)
  1796. return new Bitmap(1, 1);
  1797. width = image.Width;
  1798. height = image.Height;
  1799. float x = 0;
  1800. float y = 0;
  1801. float scaleX = width / this.Width;
  1802. float scaleY = height / this.Height;
  1803. if (left < renderer.displayRect.Left)
  1804. {
  1805. x = -((renderer.displayRect.Left - left) * scaleX);
  1806. width += x;
  1807. }
  1808. if (top < renderer.displayRect.Top)
  1809. {
  1810. y = -((renderer.displayRect.Top - top) * scaleY);
  1811. height += y;
  1812. }
  1813. if (left + base.width > renderer.displayRect.Right)
  1814. {
  1815. width -= ((left + base.width - renderer.displayRect.Right) * scaleX);
  1816. }
  1817. if (top + base.height > renderer.displayRect.Bottom)
  1818. {
  1819. height -= ((top + base.height - renderer.displayRect.Bottom) * scaleY);
  1820. }
  1821. if (width < 1) width = 1;
  1822. if (height < 1) height = 1;
  1823. Bitmap bmp = new Bitmap((int)width, (int)height);
  1824. using (Graphics g = Graphics.FromImage(bmp))
  1825. g.DrawImage(image, new PointF(x, y));
  1826. width /= scaleX;
  1827. height /= scaleY;
  1828. return bmp;
  1829. }
  1830. #endregion Internal Methods
  1831. //public override void ToHtml(FastString sb, bool download)
  1832. //{
  1833. // if(download)
  1834. // {
  1835. // if(FImage!=null)
  1836. // {
  1837. // using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
  1838. // {
  1839. // try
  1840. // {
  1841. // using (Bitmap bmp = new Bitmap(FImage.Width, FImage.Height))
  1842. // {
  1843. // using (Graphics g = Graphics.FromImage(bmp))
  1844. // {
  1845. // g.DrawImage(FImage, Point.Empty);
  1846. // }
  1847. // bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
  1848. // }
  1849. // ms.Flush();
  1850. // sb.Append("<img src=\"data:image/png;base64,").Append(Convert.ToBase64String(ms.ToArray()))
  1851. // .Append("\" width=\"").Append(FWidth.ToString(CultureInfo)).Append("\" height=\"").Append(FHeight.ToString(CultureInfo)).Append("\"/>");
  1852. // }
  1853. // catch(Exception e)
  1854. // {
  1855. // }
  1856. // }
  1857. // }
  1858. // }else if(!String.IsNullOrEmpty(FSrc))
  1859. // {
  1860. // if (FImage != null)
  1861. // {
  1862. // sb.Append("<img src=\"").Append(FSrc).Append("\" width=\"").Append(FWidth.ToString(CultureInfo)).Append("\" height=\"").Append(FHeight.ToString(CultureInfo)).Append("\"/>");
  1863. // }
  1864. // else
  1865. // {
  1866. // sb.Append("<img src=\"").Append(FSrc).Append("\"/>");
  1867. // }
  1868. // }
  1869. //}
  1870. }
  1871. public class RunText : Run
  1872. {
  1873. #region Private Fields
  1874. private List<CharWithIndex> chars;
  1875. private string text;
  1876. #endregion Private Fields
  1877. #region Public Properties
  1878. public string Text { get { return text; } }
  1879. #endregion Public Properties
  1880. #region Public Constructors
  1881. public RunText(HtmlTextRenderer renderer, Word word, StyleDescriptor style, List<CharWithIndex> text, float left, int charIndex) : base(renderer, word, style, left, charIndex)
  1882. {
  1883. using (Font ff = style.GetFont())
  1884. {
  1885. chars = new List<CharWithIndex>(text);
  1886. this.text = GetString(text);
  1887. if (ff.FontFamily.Name == "Wingdings" || ff.FontFamily.Name == "Webdings")
  1888. {
  1889. this.text = WingdingsToUnicodeConverter.Convert(this.text);
  1890. }
  1891. if (this.text.Length > 0)
  1892. {
  1893. base.charIndex = text[0].Index;
  1894. if (word.Type == WordType.WhiteSpace)
  1895. {
  1896. //using (Font f = new Font("Consolas", 10))
  1897. width = CalcSpaceWidth(this.text, ff);
  1898. }
  1899. else
  1900. {
  1901. width = Renderer.graphics.MeasureString(this.text, ff, int.MaxValue, base.renderer.format).Width;
  1902. }
  1903. }
  1904. height = ff.GetHeight(Renderer.graphics.Graphics);
  1905. float lineSpace = ff.FontFamily.GetLineSpacing(style.FontStyle);
  1906. float ascent = ff.FontFamily.GetCellAscent(style.FontStyle);
  1907. baseLine = height * ascent / lineSpace;
  1908. descent = height - baseLine;
  1909. if (style.BaseLine == HtmlTextRenderer.BaseLine.Subscript)
  1910. descent += height * 0.45f;
  1911. }
  1912. }
  1913. #endregion Public Constructors
  1914. #region Public Methods
  1915. public float CalcSpaceWidth(string text, Font ff)
  1916. {
  1917. return Renderer.graphics.MeasureString("1" + text + "2", ff, int.MaxValue, renderer.format).Width
  1918. - Renderer.graphics.MeasureString("12", ff, int.MaxValue, renderer.format).Width;
  1919. }
  1920. public override void Draw()
  1921. //public override void Draw(bool drawContents)
  1922. {
  1923. using (Font font = style.GetFont())
  1924. using (Brush brush = GetBrush())
  1925. {
  1926. //if (drawContents)
  1927. //{
  1928. //#if DEBUG
  1929. // SizeF size = FRenderer.FGraphics.MeasureString(FText, font, int.MaxValue, FRenderer.FFormat);
  1930. // if (FRenderer.RightToLeft)
  1931. // FRenderer.FGraphics.DrawRectangle(Pens.Red, Left - size.Width, Top, size.Width, size.Height);
  1932. // else
  1933. // FRenderer.FGraphics.DrawRectangle(Pens.Red, Left, Top, size.Width, size.Height);
  1934. //#endif
  1935. renderer.graphics.DrawString(text, font, brush, Left, Top, renderer.format);
  1936. }
  1937. //}
  1938. //base.Draw(drawContents);
  1939. }
  1940. public Brush GetBrush()
  1941. {
  1942. return new SolidBrush(Style.Color);
  1943. }
  1944. public override Run Split(float availableWidth, out Run secondPart)
  1945. {
  1946. int size = chars.Count;
  1947. if (size == 0)
  1948. {
  1949. secondPart = this;
  1950. return null;
  1951. }
  1952. int from = 0;
  1953. int point = size / 2;
  1954. int to = size;
  1955. Run r = null;
  1956. while (to - from > 1)
  1957. {
  1958. List<CharWithIndex> list = new List<CharWithIndex>();
  1959. for (int i = 0; i < point; i++)
  1960. list.Add(chars[i]);
  1961. r = new RunText(renderer, word, style, list, left, charIndex);
  1962. if (r.Width > availableWidth)
  1963. {
  1964. if(point == 1)
  1965. {
  1966. // Single char width is less than availableWidth
  1967. // Give up splitting
  1968. secondPart = null;
  1969. return this;
  1970. }
  1971. to = point;
  1972. point = (to + from) / 2;
  1973. }
  1974. else
  1975. {
  1976. from = point;
  1977. point = (to + from) / 2;
  1978. }
  1979. }
  1980. if (to < 2)
  1981. {
  1982. secondPart = this;
  1983. return null;
  1984. }
  1985. else
  1986. {
  1987. List<CharWithIndex> list = new List<CharWithIndex>();
  1988. for (int i = point; i < size; i++)
  1989. list.Add(chars[i]);
  1990. secondPart = new RunText(renderer, word, style, list, left + r.Width, charIndex);
  1991. list.Clear();
  1992. for (int i = 0; i < point; i++)
  1993. list.Add(chars[i]);
  1994. r = new RunText(renderer, word, style, list, left, charIndex);
  1995. return r;
  1996. }
  1997. }
  1998. #endregion Public Methods
  1999. #region Private Methods
  2000. private string GetString(List<CharWithIndex> str)
  2001. {
  2002. renderer.cacheString.Clear();
  2003. foreach (CharWithIndex ch in str)
  2004. {
  2005. renderer.cacheString.Append(ch.Char);
  2006. }
  2007. return renderer.cacheString.ToString();
  2008. }
  2009. #endregion Private Methods
  2010. //public override void ToHtml(FastString sb, bool download)
  2011. //{
  2012. // //if (FWord.Type == WordType.Tab)
  2013. // // sb.Append("<span style=\"display:inline-block;min-width:").Append((FWidth * 0.99f).ToString(CultureInfo)).Append("px;\">");
  2014. // foreach(char ch in Text)
  2015. // {
  2016. // switch (ch)
  2017. // {
  2018. // case '"':
  2019. // sb.Append("&quot;");
  2020. // break;
  2021. // case '&':
  2022. // sb.Append("&amp;");
  2023. // break;
  2024. // case '<':
  2025. // sb.Append("&lt;");
  2026. // break;
  2027. // case '>':
  2028. // sb.Append("&gt;");
  2029. // break;
  2030. // case '\t':
  2031. // sb.Append("&Tab;");
  2032. // break;
  2033. // default:
  2034. // sb.Append(ch);
  2035. // break;
  2036. // }
  2037. // }
  2038. // //if (FWord.Type == WordType.Tab)
  2039. // // sb.Append("</span>");
  2040. //}
  2041. }
  2042. public class Word
  2043. {
  2044. #region Private Fields
  2045. private float baseLine;
  2046. private float descent;
  2047. private float height;
  2048. private Line line;
  2049. private HtmlTextRenderer renderer;
  2050. private List<Run> runs;
  2051. private WordType type;
  2052. #endregion Private Fields
  2053. #region Public Properties
  2054. public float BaseLine { get { return baseLine; } }
  2055. public float Descent { get { return descent; } }
  2056. public float Height { get { return height; } }
  2057. public Line Line
  2058. {
  2059. get { return line; }
  2060. set { line = value; }
  2061. }
  2062. public HtmlTextRenderer Renderer
  2063. {
  2064. get { return renderer; }
  2065. }
  2066. public List<Run> Runs
  2067. {
  2068. get { return runs; }
  2069. }
  2070. public WordType Type
  2071. {
  2072. get { return type; }
  2073. set { type = value; }
  2074. }
  2075. #endregion Public Properties
  2076. #region Public Constructors
  2077. public Word(HtmlTextRenderer renderer, Line line)
  2078. {
  2079. this.renderer = renderer;
  2080. runs = new List<Run>();
  2081. this.line = line;
  2082. }
  2083. public Word(HtmlTextRenderer renderer, Line line, WordType type)
  2084. {
  2085. this.renderer = renderer;
  2086. runs = new List<Run>();
  2087. this.line = line;
  2088. this.type = type;
  2089. }
  2090. #endregion Public Constructors
  2091. #region Internal Methods
  2092. internal void CalcMetrics()
  2093. {
  2094. baseLine = 0;
  2095. descent = 0;
  2096. foreach (Run run in Runs)
  2097. {
  2098. baseLine = Math.Max(baseLine, run.BaseLine);
  2099. descent = Math.Max(descent, run.Descent);
  2100. }
  2101. height = baseLine + descent;
  2102. }
  2103. #endregion Internal Methods
  2104. }
  2105. #endregion Public Classes
  2106. #region Internal Classes
  2107. internal class SimpleFastReportHtmlElement
  2108. {
  2109. #region Public Fields
  2110. public Dictionary<string, string> attributes;
  2111. public bool isSelfClosed;
  2112. public bool isEnd;
  2113. public string name;
  2114. #endregion Public Fields
  2115. #region Private Fields
  2116. private Dictionary<string, string> style;
  2117. #endregion Private Fields
  2118. #region Public Properties
  2119. public bool IsSelfClosed
  2120. {
  2121. get
  2122. {
  2123. switch (name)
  2124. {
  2125. case "img":
  2126. case "br":
  2127. return true;
  2128. default:
  2129. return isSelfClosed;
  2130. }
  2131. }
  2132. set { isSelfClosed = value; }
  2133. }
  2134. /// <summary>
  2135. /// Be care generates dictionary only one time
  2136. /// </summary>
  2137. public Dictionary<string, string> Style
  2138. {
  2139. get
  2140. {
  2141. if (style == null && attributes != null && attributes.ContainsKey("style"))
  2142. {
  2143. string styleString = attributes["style"];
  2144. style = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
  2145. foreach (string kv in styleString.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
  2146. {
  2147. string[] strs = kv.Split(':');
  2148. if (strs.Length == 2)
  2149. {
  2150. style[strs[0]] = strs[1];
  2151. }
  2152. }
  2153. }
  2154. return style;
  2155. }
  2156. }
  2157. #endregion Public Properties
  2158. #region Public Constructors
  2159. public SimpleFastReportHtmlElement(string name)
  2160. {
  2161. this.name = name;
  2162. }
  2163. public SimpleFastReportHtmlElement(string name, Dictionary<string, string> attributes)
  2164. {
  2165. this.name = name;
  2166. this.attributes = attributes;
  2167. }
  2168. public SimpleFastReportHtmlElement(string name, bool isEnd)
  2169. {
  2170. this.name = name;
  2171. this.isEnd = isEnd;
  2172. }
  2173. public SimpleFastReportHtmlElement(string name, bool isBegin, Dictionary<string, string> attributes)
  2174. {
  2175. this.name = name;
  2176. this.isEnd = isBegin;
  2177. this.attributes = attributes;
  2178. }
  2179. public SimpleFastReportHtmlElement(string name, bool isBegin, bool isSelfClosed)
  2180. {
  2181. this.name = name;
  2182. this.isEnd = isBegin;
  2183. this.IsSelfClosed = isSelfClosed;
  2184. }
  2185. public SimpleFastReportHtmlElement(string name, bool isBegin, bool isSelfClosed, Dictionary<string, string> attributes)
  2186. {
  2187. this.name = name;
  2188. this.isEnd = isBegin;
  2189. this.IsSelfClosed = isSelfClosed;
  2190. this.attributes = attributes;
  2191. }
  2192. #endregion Public Constructors
  2193. #region Public Methods
  2194. public override string ToString()
  2195. {
  2196. StringBuilder sb = new StringBuilder();
  2197. sb.Append("<");
  2198. if (isEnd)
  2199. sb.Append("/");
  2200. sb.Append(name);
  2201. if (attributes != null)
  2202. {
  2203. foreach (KeyValuePair<string, string> kv in attributes)
  2204. {
  2205. sb.Append(" ");
  2206. sb.Append(kv.Key);
  2207. sb.Append("=\"");
  2208. sb.Append(kv.Value);
  2209. sb.Append("\"");
  2210. }
  2211. }
  2212. if (IsSelfClosed)
  2213. sb.Append('/');
  2214. sb.Append(">");
  2215. return sb.ToString();
  2216. }
  2217. #endregion Public Methods
  2218. }
  2219. internal class SimpleFastReportHtmlReader
  2220. {
  2221. #region Private Fields
  2222. private CharWithIndex @char;
  2223. private SimpleFastReportHtmlElement element;
  2224. private int lastPosition;
  2225. private int position;
  2226. private string substring;
  2227. private string text;
  2228. #endregion Private Fields
  2229. #region Public Properties
  2230. public CharWithIndex Character
  2231. {
  2232. get
  2233. {
  2234. return @char;
  2235. }
  2236. }
  2237. public SimpleFastReportHtmlElement Element
  2238. {
  2239. get
  2240. {
  2241. return element;
  2242. }
  2243. }
  2244. public bool IsEOF
  2245. {
  2246. get
  2247. {
  2248. return position >= text.Length;
  2249. }
  2250. }
  2251. public bool IsNotEOF
  2252. {
  2253. get
  2254. {
  2255. return position < text.Length;
  2256. }
  2257. }
  2258. public int LastPosition
  2259. {
  2260. get { return lastPosition; }
  2261. }
  2262. public int Position
  2263. {
  2264. get
  2265. {
  2266. return position;
  2267. }
  2268. set
  2269. {
  2270. position = value;
  2271. }
  2272. }
  2273. #endregion Public Properties
  2274. #region Public Constructors
  2275. public SimpleFastReportHtmlReader(string text)
  2276. {
  2277. this.text = text;
  2278. }
  2279. #endregion Public Constructors
  2280. #region Public Methods
  2281. public static bool IsCanBeCharacterInTagName(char c)
  2282. {
  2283. if (c == ':') return true;
  2284. if ('A' <= c && c <= 'Z') return true;
  2285. if (c == '_') return true;
  2286. if ('a' <= c && c <= 'z') return true;
  2287. if (c == '-') return true;//
  2288. if (c == '.') return true;//
  2289. if ('0' <= c && c <= '9') return true;//
  2290. if (c == '\u00B7') return true;//
  2291. if ('\u00C0' <= c && c <= '\u00D6') return true;
  2292. if ('\u00D8' <= c && c <= '\u00F6') return true;
  2293. if ('\u00F8' <= c && c <= '\u02FF') return true;
  2294. if ('\u0300' <= c && c <= '\u036F') return true;//
  2295. if ('\u0370' <= c && c <= '\u037D') return true;
  2296. if ('\u037F' <= c && c <= '\u1FFF') return true;
  2297. if ('\u200C' <= c && c <= '\u200D') return true;
  2298. if ('\u203F' <= c && c <= '\u2040') return true;//
  2299. if ('\u2070' <= c && c <= '\u218F') return true;
  2300. if ('\u2C00' <= c && c <= '\u2FEF') return true;
  2301. if ('\u3001' <= c && c <= '\uD7FF') return true;
  2302. if ('\uF900' <= c && c <= '\uFDCF') return true;
  2303. if ('\uFDF0' <= c && c <= '\uFFFD') return true;
  2304. return false;
  2305. }
  2306. public static bool IsCanBeFirstCharacterInTagName(char c)
  2307. {
  2308. if (c == ':') return true;
  2309. if ('A' <= c && c <= 'Z') return true;
  2310. if (c == '_') return true;
  2311. if ('a' <= c && c <= 'z') return true;
  2312. if ('\u00C0' <= c && c <= '\u00D6') return true;
  2313. if ('\u00D8' <= c && c <= '\u00F6') return true;
  2314. if ('\u00F8' <= c && c <= '\u02FF') return true;
  2315. if ('\u0370' <= c && c <= '\u037D') return true;
  2316. if ('\u037F' <= c && c <= '\u1FFF') return true;
  2317. if ('\u200C' <= c && c <= '\u200D') return true;
  2318. if ('\u2070' <= c && c <= '\u218F') return true;
  2319. if ('\u2C00' <= c && c <= '\u2FEF') return true;
  2320. if ('\u3001' <= c && c <= '\uD7FF') return true;
  2321. if ('\uF900' <= c && c <= '\uFDCF') return true;
  2322. if ('\uFDF0' <= c && c <= '\uFFFD') return true;
  2323. return false;
  2324. }
  2325. /// <summary>
  2326. /// Return true if read char
  2327. /// </summary>
  2328. /// <returns></returns>
  2329. public bool Read()
  2330. {
  2331. lastPosition = position;
  2332. switch ((@char = new CharWithIndex(text[position], position)).Char)
  2333. {
  2334. case '&':
  2335. if (Converter.FromHtmlEntities(text, ref position, out substring))
  2336. @char.Char = substring[0];
  2337. position++;
  2338. return true;
  2339. case '<':
  2340. element = GetElement(text, ref position);
  2341. position++;
  2342. if (element != null)
  2343. switch (element.name)
  2344. {
  2345. case "br":
  2346. @char = new CharWithIndex('\n', lastPosition);
  2347. return true;
  2348. default:
  2349. return false;
  2350. }
  2351. return true;
  2352. }
  2353. position++;
  2354. return true;
  2355. }
  2356. #endregion Public Methods
  2357. #region Private Methods
  2358. private SimpleFastReportHtmlElement GetElement(string line, ref int index)
  2359. {
  2360. int to = line.Length - 1;
  2361. int i = index + 1;
  2362. bool closed = false;
  2363. if (i <= to)
  2364. if (closed = line[i] == '/')
  2365. i++;
  2366. if (i <= to)
  2367. if (!IsCanBeFirstCharacterInTagName(line[i]))
  2368. return null;
  2369. for (i++; i <= to && line[i] != ' ' && line[i] != '>' && line[i] != '/'; i++)
  2370. {
  2371. if (!IsCanBeCharacterInTagName(line[i]))
  2372. return null;
  2373. }
  2374. if (i <= to)
  2375. {
  2376. string tagName = line.Substring(index + (closed ? 2 : 1), i - index - (closed ? 2 : 1));
  2377. Dictionary<string, string> attrs = null;
  2378. if (!IsAvailableTagName(tagName))
  2379. return null;
  2380. if (line[i] == ' ')
  2381. {
  2382. //read attributes
  2383. for (; i <= to && line[i] != '>' && line[i] != '/'; i++)
  2384. {
  2385. for (; i <= to && line[i] == ' '; i++) ;
  2386. if (line[i] == '>' || line[i] == '/') i--;
  2387. else
  2388. {
  2389. if (!IsCanBeFirstCharacterInTagName(line[i]))
  2390. return null;
  2391. int attrNameStartIndex = i;
  2392. for (i++; i <= to && line[i] != '='; i++)
  2393. if (!IsCanBeFirstCharacterInTagName(line[i]))
  2394. return null;
  2395. int attrNameEndIndex = i; //index of =
  2396. i++;
  2397. if (i <= to && line[i] == '"')
  2398. {//begin attr
  2399. int attrValueStartIndex = i + 1;
  2400. for (i++; i <= to && line[i] != '"'; i++)
  2401. {
  2402. switch (line[i])
  2403. {
  2404. case '<': return null;
  2405. case '>': return null;
  2406. }
  2407. }
  2408. if (i <= to)
  2409. {
  2410. string attrName = line.Substring(attrNameStartIndex, attrNameEndIndex - attrNameStartIndex);
  2411. string attrValue = line.Substring(attrValueStartIndex, i - attrValueStartIndex);
  2412. if (attrs == null) attrs = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
  2413. attrs[attrName] = attrValue;
  2414. }
  2415. }
  2416. }
  2417. }
  2418. }
  2419. if (i <= to)
  2420. {
  2421. if (line[i] == '>')
  2422. {
  2423. index = i;
  2424. return new SimpleFastReportHtmlElement(tagName, closed, false, attrs);
  2425. }
  2426. if (line[i] == '/' && i < to && line[i + 1] == '>')
  2427. {
  2428. index = i + 1;
  2429. return new SimpleFastReportHtmlElement(tagName, closed, true, attrs);
  2430. }
  2431. }
  2432. }
  2433. return null;
  2434. }
  2435. private bool IsAvailableTagName(string tagName)
  2436. {
  2437. switch (tagName)
  2438. {
  2439. case "b":
  2440. case "br":
  2441. case "i":
  2442. case "u":
  2443. case "sub":
  2444. case "sup":
  2445. case "img":
  2446. //case "font":
  2447. case "strike":
  2448. case "span":
  2449. return true;
  2450. }
  2451. return false;
  2452. }
  2453. #endregion Private Methods
  2454. }
  2455. /// <summary>
  2456. /// Represents a style used in HtmlTags mode. Color does not affect the equals function.
  2457. /// </summary>
  2458. public class StyleDescriptor
  2459. {
  2460. #region Private Fields
  2461. private static readonly Color DefaultColor = Color.Transparent;
  2462. private Color backgroundColor;
  2463. private BaseLine baseLine;
  2464. private Color color;
  2465. private FontFamily font;
  2466. private FontStyle fontStyle;
  2467. private float size;
  2468. #endregion Private Fields
  2469. #region Public Properties
  2470. public Color BackgroundColor
  2471. {
  2472. get { return backgroundColor; }
  2473. set { backgroundColor = value; }
  2474. }
  2475. public BaseLine BaseLine
  2476. {
  2477. get { return baseLine; }
  2478. set { baseLine = value; }
  2479. }
  2480. public Color Color
  2481. {
  2482. get { return color; }
  2483. set { color = value; }
  2484. }
  2485. public FontFamily Font
  2486. {
  2487. get { return font; }
  2488. set { font = value; }
  2489. }
  2490. public FontStyle FontStyle
  2491. {
  2492. get { return fontStyle; }
  2493. set { fontStyle = value; }
  2494. }
  2495. public float Size
  2496. {
  2497. get { return size; }
  2498. set { size = value; }
  2499. }
  2500. #endregion Public Properties
  2501. #region Public Constructors
  2502. public StyleDescriptor(FontStyle fontStyle, Color color, BaseLine baseLine, FontFamily font, float size)
  2503. {
  2504. this.fontStyle = fontStyle;
  2505. this.color = color;
  2506. this.baseLine = baseLine;
  2507. this.font = font;
  2508. this.size = size;
  2509. backgroundColor = DefaultColor;
  2510. }
  2511. public StyleDescriptor(StyleDescriptor styleDescriptor)
  2512. {
  2513. fontStyle = styleDescriptor.fontStyle;
  2514. color = styleDescriptor.color;
  2515. baseLine = styleDescriptor.baseLine;
  2516. font = styleDescriptor.font;
  2517. size = styleDescriptor.size;
  2518. backgroundColor = styleDescriptor.backgroundColor;
  2519. }
  2520. #endregion Public Constructors
  2521. #region Public Methods
  2522. public override bool Equals(object obj)
  2523. {
  2524. StyleDescriptor descriptor = obj as StyleDescriptor;
  2525. return descriptor != null &&
  2526. baseLine == descriptor.baseLine &&
  2527. font == descriptor.font &&
  2528. fontStyle == descriptor.fontStyle &&
  2529. size == descriptor.size;
  2530. }
  2531. /// <summary>
  2532. /// returns true if objects realy equals
  2533. /// </summary>
  2534. /// <param name="obj"></param>
  2535. /// <returns></returns>
  2536. public bool FullEquals(StyleDescriptor obj)
  2537. {
  2538. return obj != null && GetHashCode() == obj.GetHashCode() &&
  2539. this.Equals(obj) &&
  2540. color.Equals(obj.color) &&
  2541. backgroundColor.Equals(obj.backgroundColor);
  2542. }
  2543. public Font GetFont()
  2544. {
  2545. float fontSize = size;
  2546. if (baseLine != BaseLine.Normal)
  2547. fontSize *= 0.6f;
  2548. FontStyle fontStyle = FontStyle;
  2549. fontStyle = fontStyle & ~FontStyle.Underline & ~FontStyle.Strikeout;
  2550. return new Font(font, fontSize, fontStyle);
  2551. }
  2552. public override int GetHashCode()
  2553. {
  2554. int hashCode = -1631016721;
  2555. unchecked
  2556. {
  2557. hashCode = hashCode * -1521134295 + baseLine.GetHashCode();
  2558. hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(font.Name);
  2559. hashCode = hashCode * -1521134295 + fontStyle.GetHashCode();
  2560. hashCode = hashCode * -1521134295 + size.GetHashCode();
  2561. }
  2562. return hashCode;
  2563. }
  2564. public void ToHtml(FastString sb, bool close)
  2565. {
  2566. float fontsize = size / DrawUtils.ScreenDpiFX;
  2567. if (close)
  2568. {
  2569. sb.Append("</span>");
  2570. if ((fontStyle & FontStyle.Strikeout) == FontStyle.Strikeout) sb.Append("</strike>");
  2571. if ((fontStyle & FontStyle.Underline) == FontStyle.Underline) sb.Append("</u>");
  2572. if ((fontStyle & FontStyle.Italic) == FontStyle.Italic) sb.Append("</i>");
  2573. if ((fontStyle & FontStyle.Bold) == FontStyle.Bold) sb.Append("</b>");
  2574. switch (baseLine)
  2575. {
  2576. case BaseLine.Subscript: sb.Append("</sub>"); break;
  2577. case BaseLine.Superscript: sb.Append("</sup>"); break;
  2578. }
  2579. }
  2580. else
  2581. {
  2582. switch (baseLine)
  2583. {
  2584. case BaseLine.Subscript: sb.Append("<sub>"); break;
  2585. case BaseLine.Superscript: sb.Append("<sup>"); break;
  2586. }
  2587. if ((fontStyle & FontStyle.Bold) == FontStyle.Bold) sb.Append("<b>");
  2588. if ((fontStyle & FontStyle.Italic) == FontStyle.Italic) sb.Append("<i>");
  2589. if ((fontStyle & FontStyle.Underline) == FontStyle.Underline) sb.Append("<u>");
  2590. if ((fontStyle & FontStyle.Strikeout) == FontStyle.Strikeout) sb.Append("<strike>");
  2591. sb.Append("<span style=\"");
  2592. if (backgroundColor.A > 0) sb.Append(String.Format(CultureInfo, "background-color:rgba({0},{1},{2},{3});", backgroundColor.R, backgroundColor.G, backgroundColor.B, ((float)backgroundColor.A) / 255f));
  2593. if (color.A > 0) sb.Append(String.Format(CultureInfo, "color:rgba({0},{1},{2},{3});", color.R, color.G, color.B, ((float)color.A) / 255f));
  2594. if (font != null) { sb.Append("font-family:"); sb.Append(font.Name); sb.Append(";"); }
  2595. if (fontsize > 0) { sb.Append("font-size:"); sb.Append(fontsize.ToString(CultureInfo)); sb.Append("pt;"); }
  2596. sb.Append("\">");
  2597. }
  2598. }
  2599. #endregion Public Methods
  2600. }
  2601. private class OwnHashSet<T>
  2602. {
  2603. #if DOTNET_4
  2604. private HashSet<T> internalHashSet;
  2605. public int Count { get { return internalHashSet.Count; } }
  2606. #else
  2607. private Dictionary<T, object> internalDictionary;
  2608. private object FHashSetObject;
  2609. public int Count { get { return internalDictionary.Count; } }
  2610. #endif
  2611. public OwnHashSet()
  2612. {
  2613. #if DOTNET_4
  2614. internalHashSet = new HashSet<T>();
  2615. #else
  2616. internalDictionary = new Dictionary<T, object>();
  2617. FHashSetObject = new object();
  2618. #endif
  2619. }
  2620. public void Clear()
  2621. {
  2622. #if DOTNET_4
  2623. internalHashSet.Clear();
  2624. #else
  2625. internalDictionary.Clear();
  2626. #endif
  2627. }
  2628. public bool Contains(T value)
  2629. {
  2630. #if DOTNET_4
  2631. return internalHashSet.Contains(value);
  2632. #else
  2633. return internalDictionary.ContainsKey(value);
  2634. #endif
  2635. }
  2636. public void Add(T value)
  2637. {
  2638. #if DOTNET_4
  2639. internalHashSet.Add(value);
  2640. #else
  2641. internalDictionary.Add(value, FHashSetObject);
  2642. #endif
  2643. }
  2644. }
  2645. #endregion Internal Classes
  2646. #region IDisposable Support
  2647. private bool disposedValue = false;
  2648. protected virtual void Dispose(bool disposing)
  2649. {
  2650. if (!disposedValue)
  2651. {
  2652. if (disposing)
  2653. {
  2654. format.Dispose();
  2655. format = null;
  2656. }
  2657. disposedValue = true;
  2658. }
  2659. }
  2660. public void Dispose()
  2661. {
  2662. Dispose(true);
  2663. }
  2664. #endregion IDisposable Support
  2665. }
  2666. /// <summary>
  2667. /// Class that converts strings with Wingdings characters to Unicode strings.
  2668. /// </summary>
  2669. public static class WingdingsToUnicodeConverter
  2670. {
  2671. /// <summary>
  2672. /// Converts string with Wingdings characters to its Unicode analog.
  2673. /// </summary>
  2674. /// <param name="str">The string that should be converted.</param>
  2675. /// <returns></returns>
  2676. public static string Convert(string str)
  2677. {
  2678. char[] chars = str.ToCharArray();
  2679. for (int i = 0; i < chars.Length; i++)
  2680. {
  2681. if (chars[i] >= 0x20 && chars[i] <= 0xFF)
  2682. {
  2683. chars[i] = (char)(0xF000 + chars[i]);
  2684. }
  2685. }
  2686. return new string(chars);
  2687. }
  2688. }
  2689. }