// draw = false to get the width of the line to be drawn without actually drawing anything. Useful for aligning text. private unsafe void RenderTextureLine(List <AElement> atoms, uint *rPtr, ref int x, int y, int linewidth, int maxHeight, ref int lineheight, bool draw) { for (int i = 0; i < atoms.Count; i++) { IFont font = atoms[i].Style.Font; if (lineheight < font.Height) { lineheight = font.Height; } if (lineheight < atoms[i].Height) { lineheight = atoms[i].Height; } if (draw) { if (atoms[i] is CharacterElement) { CharacterElement atom = (CharacterElement)atoms[i]; ICharacter character = font.GetCharacter(atom.Character); // HREF links should be colored white, because we will hue them at runtime. uint color = atom.Style.IsHREF ? 0xFFFFFFFF : Utility.UintFromColor(atom.Style.Color); character.WriteToBuffer(rPtr, x, y, linewidth, maxHeight, font.Baseline, atom.Style.IsBold, atom.Style.IsItalic, atom.Style.IsUnderlined, atom.Style.MustDrawnOutline, color, 0xFF000008); } else if (atoms[i] is ImageElement) { ImageElement atom = (atoms[i] as ImageElement); atom.AssociatedImage.Area = new Rectangle(x, y + ((lineheight - atom.Height) / 2), atom.Width, atom.Height); } } x += atoms[i].Width; } }
unsafe private void DoRenderBlock(BlockElement root, uint *ptr, int width, int height) { foreach (AElement element in root.Children) { int x = element.Layout_X; int y = element.Layout_Y - Ascender; // ascender is always negative. if (element is CharacterElement) { IFont font = element.Style.Font; ICharacter character = font.GetCharacter((element as CharacterElement).Character); // HREF links should be colored white, because we will hue them at runtime. uint color = element.Style.IsHREF ? 0xFFFFFFFF : Utility.UintFromColor(element.Style.Color); character.WriteToBuffer(ptr, x, y, width, height, font.Baseline, element.Style.IsBold, element.Style.IsItalic, element.Style.IsUnderlined, element.Style.MustDrawnOutline, color, 0xFF000008); // offset y by ascender for links... if (character.YOffset < 0) { y += character.YOffset; height -= character.YOffset; } } else if (element is ImageElement) { ImageElement image = (element as ImageElement); image.AssociatedImage.Area = new Rectangle(x, y, image.Width, image.Height); if (element.Style.IsHREF) { Links.AddLink(element.Style, new Rectangle(x, y, element.Width, element.Height)); image.AssociatedImage.LinkIndex = Links.Count; } } else if (element is BlockElement) { DoRenderBlock(element as BlockElement, ptr, width, height); } // set href link regions if (element.Style.IsHREF) { Links.AddLink(element.Style, new Rectangle(x, y, element.Width, element.Height)); } } }
/// <summary> /// Gets a single word of AElements to lay out. /// </summary> /// <param name="elements">The list of elements to get the word from.</param> /// <param name="start">The index in the elements list to start getting the word.</param> /// <param name="wordWidth">The width of the word of elements.</param> /// <param name="styleWidth">Italic and Outlined characters need more room for the slant/outline (Bold handled differently).</param> /// <param name="wordHeight"></param> /// <param name="ascender">Additional pixels above the top of the word. Affects dimensions of the parent if word is on the first line.</param> /// <returns></returns> List <AElement> LayoutElementsGetWord(List <AElement> elements, int start, out int wordWidth, out int styleWidth, out int wordHeight, out int ascender) { List <AElement> word = new List <AElement>(); wordWidth = 0; wordHeight = 0; styleWidth = 0; ascender = 0; for (int i = start; i < elements.Count; i++) { if (elements[i].IsThisAtomALineBreak) { return(word); } if (elements[i].CanBreakAtThisAtom) { if (word.Count > 0) { return(word); } } word.Add(elements[i]); wordWidth += elements[i].Width; styleWidth -= elements[i].Width; if (styleWidth < 0) { styleWidth = 0; } if (wordHeight < elements[i].Height) { wordHeight = elements[i].Height; } // we may need to add additional width for special style characters. if (elements[i] is CharacterElement) { CharacterElement atom = (CharacterElement)elements[i]; IFont font = atom.Style.Font; ICharacter ch = font.GetCharacter(atom.Character); // italic characters need a little extra width if they are at the end of the line. if (atom.Style.IsItalic) { styleWidth = font.Height / 2; } if (atom.Style.DrawOutline) { styleWidth += 2; if (-1 < ascender) { ascender = -1; } } if (ch.YOffset + ch.Height > wordHeight) { wordHeight = ch.YOffset + ch.Height; } if (ch.YOffset < 0 && ascender > ch.YOffset) { ascender = ch.YOffset; } } if (i == elements.Count - 1 || elements[i].CanBreakAtThisAtom) { return(word); } } return(word); }
// ====================================================================== // Old code // ====================================================================== private void DoLayoutOld(AElement root, int maxwidth, out int width, out int height, out int ascender) { // default values for out variables. width = 0; height = 0; ascender = 0; // local variables int descenderHeight = 0; int lineHeight = 0; int styleWidth = 0; // italic + outlined characters need more room for the slant/outline. int widestLine = maxwidth; // we automatically set the content to fill the specified width. int wordWidth = 0; bool firstLine = true; List <AElement> word = new List <AElement>(); List <AElement> elements = null; for (int i = 0; i < elements.Count; i++) { wordWidth += elements[i].Width; styleWidth -= elements[i].Width; if (styleWidth < 0) { styleWidth = 0; } if (lineHeight < elements[i].Height) { lineHeight = elements[i].Height; } if (elements[i].IsThisAtomALineBreak) { if (width + styleWidth > widestLine) { widestLine = width + styleWidth; } height += lineHeight; descenderHeight = 0; lineHeight = 0; width = 0; firstLine = false; } else { word.Add(elements[i]); // we may need to add additional width for special style characters. if (elements[i] is CharacterElement) { CharacterElement atom = (CharacterElement)elements[i]; IFont font = atom.Style.Font; ICharacter ch = font.GetCharacter(atom.Character); // italic characters need a little extra width if they are at the end of the line. if (atom.Style.IsItalic) { styleWidth = font.Height / 2; } if (atom.Style.MustDrawnOutline) { styleWidth += 2; } if (ch.YOffset + ch.Height - lineHeight > descenderHeight) { descenderHeight = ch.YOffset + ch.Height - lineHeight; } if (ch.YOffset < 0 && firstLine && ascender > ch.YOffset) { ascender = ch.YOffset; } } if (i == elements.Count - 1 || elements[i + 1].CanBreakAtThisAtom) { // Now make sure this line can fit the word. if (width + wordWidth + styleWidth <= maxwidth) { // it can fit! width += wordWidth + styleWidth; wordWidth = 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 == elements.Count - 1) && elements[i + 1].IsThisAtomABreakingSpace) { int charwidth = elements[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. ((CharacterElement)elements[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 (elements[i - word.Count].IsThisAtomABreakingSpace) { ((CharacterElement)elements[i - word.Count]).Character = '\n'; i = i - word.Count - 1; } else { StyleState inheritedStyle = elements[i - word.Count].Style; elements.Insert(i - word.Count, new CharacterElement(inheritedStyle, '\n')); i = i - word.Count; } word.Clear(); wordWidth = 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 = wordWidth; for (int j = word.Count - 1; j >= 1; j--) { int iDashWidth = word[j].Style.Font.GetCharacter('-').Width; if (iWordWidth + iDashWidth <= maxwidth) { StyleState inheritedStyle = elements[i - (word.Count - j) + 1].Style; elements.Insert(i - (word.Count - j) + 1, new CharacterElement(inheritedStyle, '\n')); elements.Insert(i - (word.Count - j) + 1, new CharacterElement(inheritedStyle, '-')); break; } iWordWidth -= word[j].Width; } i -= word.Count + 2; word.Clear(); width = 0; wordWidth = 0; if (i < 0) { // the texture size is too small to hold this small number of characters. This is a problem. i = -1; return; } } } } } } width += styleWidth; height += lineHeight + descenderHeight; if (widestLine > width) { width = widestLine; } }