HtmlTextRenderer.cs 119 KB

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