private void resizeAndParse(string textToRender, int maxWidth, bool parseHTML) { if (_reader != null) _reader = null; _reader = new HTMLParser(textToRender, parseHTML); _href.Clear(); _images.Clear(); if (maxWidth < 0) { _width = 0; } else { if (maxWidth == 0) { getTextDimensions(_reader, Data.ASCIIText.MaxWidth, 0, out _width, out _height); } else { getTextDimensions(_reader, maxWidth, 0, out _width, out _height); } } if (_texture != null) { _texture.Dispose(); _texture = null; } }
Texture2D writeTexture(GraphicsDevice graphics, HTMLParser reader, int width, int height) { if (_width == 0) // empty text string return new Texture2D(graphics, 1, 1); Color[] resultData = new Color[width * height]; // for (int i = 0; i < resultData.Length; i++) // resultData[i] = Color.LimeGreen; int dy = 0, lineheight = 0; unsafe { fixed (Color* rPtr = resultData) { int[] alignedTextX = new int[3]; List<HTMLParser_Atom>[] alignedAtoms = new List<HTMLParser_Atom>[3]; for (int i = 0; i < 3; i++) alignedAtoms[i] = new List<HTMLParser_Atom>(); for (int i = 0; i < reader.Length; i++) { HTMLParser_Atom atom = reader.Atoms[i]; alignedAtoms[(int)atom.Alignment].Add(atom); if (atom.IsThisAtomALineBreak || (i == reader.Length - 1)) { // write left aligned text. int dx; if (alignedAtoms[0].Count > 0) { alignedTextX[0] = dx = 0; writeTexture_Line(alignedAtoms[0], rPtr, ref dx, dy, width, height, ref lineheight, true); } // centered text. We need to get the width first. Do this by drawing the line with var draw = false. if (alignedAtoms[1].Count > 0) { dx = 0; writeTexture_Line(alignedAtoms[1], rPtr, ref dx, dy, width, height, ref lineheight, false); alignedTextX[1] = dx = width / 2 - dx / 2; writeTexture_Line(alignedAtoms[1], rPtr, ref dx, dy, width, height, ref lineheight, true); } // right aligned text. if (alignedAtoms[2].Count > 0) { dx = 0; writeTexture_Line(alignedAtoms[2], rPtr, ref dx, dy, width, height, ref lineheight, false); alignedTextX[2] = dx = width - dx; writeTexture_Line(alignedAtoms[2], rPtr, ref dx, dy, width, height,ref lineheight, true); } // get HREF regions for html. getHREFRegions(_href, alignedAtoms, alignedTextX, dy); // clear the aligned text lists so we can fill them up in our next pass. for (int j = 0; j < 3; j++) { alignedAtoms[j].Clear(); } dy += lineheight; } } } } Texture2D result = new Texture2D(graphics, width, height, false, SurfaceFormat.Color); result.SetData<Color>(resultData); return result; }
void getTextDimensions(HTMLParser reader, int maxwidth, int maxheight, out int width, out int height) { width = 0; height = 0; int lineheight = 0; int widestline = 0; int descenderheight = 0; List<HTMLParser_Atom> word = new List<HTMLParser_Atom>(); int additionalwidth = 0; // for italic + outlined characters, which need a little more room for their slant/outline. int word_width = 0; for (int i = 0; i < reader.Length; ++i) { word_width += reader.Atoms[i].Width; additionalwidth -= reader.Atoms[i].Width; if (additionalwidth < 0) additionalwidth = 0; if (lineheight < reader.Atoms[i].Height) lineheight = reader.Atoms[i].Height; if (reader.Atoms[i].IsThisAtomALineBreak) { if (width + additionalwidth > widestline) widestline = width + additionalwidth; height += lineheight; descenderheight = 0; lineheight = 0; width = 0; } else { word.Add(reader.Atoms[i]); // we may need to add additional width for special style characters. if (reader.Atoms[i] is HTMLParser_AtomCharacter) { HTMLParser_AtomCharacter atom = (HTMLParser_AtomCharacter)reader.Atoms[i]; UniFont font = UniText.Fonts[(int)atom.Font]; UniCharacter ch = UniText.Fonts[(int)atom.Font].GetCharacter(atom.Character); // italic characters need a little extra width if they are at the end of the line. if (atom.Style_IsItalic) additionalwidth = font.Height / 2; if (atom.Style_IsOutlined) additionalwidth += 1; if (ch.YOffset + ch.Height - lineheight > descenderheight) descenderheight = ch.YOffset + ch.Height - lineheight; } if (reader.Atoms[i].Alignment != enumHTMLAlignments.Left) widestline = maxwidth; if (i == reader.Length - 1 || reader.Atoms[i + 1].CanBreakAtThisAtom) { // Now make sure this line can fit the word. if (width + word_width + additionalwidth <= maxwidth) { // it can fit! width += word_width + additionalwidth; word_width = 0; word.Clear(); // if this word is followed by a space, does it fit? If not, drop it entirely and insert \n after the word. if (!(i == reader.Length - 1) && reader.Atoms[i + 1].IsThisAtomABreakingSpace) { int charwidth = reader.Atoms[i + 1].Width; if (width + charwidth <= maxwidth) { // we can fit an extra space here. width += charwidth; i++; } else { // can't fit an extra space on the end of the line. replace the space with a \n. ((HTMLParser_AtomCharacter)reader.Atoms[i + 1]).Character = '\n'; } } } else { // this word cannot fit in the current line. if ((width > 0) && (i - word.Count >= 0)) { // if this is the last word in a line. Replace the last space character with a line break // and back up to the beginning of this word. if (reader.Atoms[i - word.Count].IsThisAtomABreakingSpace) { ((HTMLParser_AtomCharacter)reader.Atoms[i - word.Count]).Character = '\n'; i = i - word.Count - 1; } else { reader.Atoms.Insert(i - word.Count, new HTMLParser_AtomCharacter('\n')); i = i - word.Count; } word.Clear(); word_width = 0; } else { // this is the only word on the line and we will need to split it. // first back up until we've reached the reduced the size of the word // so that it fits on one line, and split it there. int iWordWidth = word_width; for (int j = word.Count - 1; j >= 1; j--) { int iDashWidth = UniText.Fonts[(int)word[j].Font].GetCharacter('-').Width; if (iWordWidth + iDashWidth <= maxwidth) { reader.Atoms.Insert(i - (word.Count - j) + 1, new HTMLParser_AtomCharacter('\n')); reader.Atoms.Insert(i - (word.Count - j) + 1, new HTMLParser_AtomCharacter('-')); break; } iWordWidth -= word[j].Width; } i -= word.Count + 2; if (i < 0) i = -1; word.Clear(); width = 0; word_width = 0; } } } } } width += additionalwidth; height += lineheight + descenderheight; if (widestline > width) width = widestline; }