using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Drawing.Drawing2D;
namespace System.Drawing.Html
{
/// <summary>
/// Represents a CSS Box of text or replaced elements.
/// </summary>
/// <remarks>
/// The Box can contains other boxes, that's the way that the CSS Tree
/// is composed.
///
/// To know more about boxes visit CSS spec:
/// http://www.w3.org/TR/CSS21/box.html
/// </remarks>
public class CssBox
{
#region Static
/// <summary>
/// An empty box with empty values.
/// </summary>
internal readonly static CssBox Empty;
/// <summary>
/// Table of 'css-property' => .NET property
/// </summary>
internal static Dictionary<string, PropertyInfo> _properties;
/// <summary>
/// Dictionary of default values
/// </summary>
private static Dictionary<string, string> _defaults;
/// <summary>
/// Hosts all inhertiable properties
/// </summary>
private static List<PropertyInfo> _inheritables;
/// <summary>
/// Hosts css properties
/// </summary>
private static List<PropertyInfo> _cssproperties;
/// <summary>
/// Static constructor and initialization
/// </summary>
static CssBox()
{
#region Initialize _properties, _inheritables and _defaults Dictionaries
_properties = new Dictionary<string, PropertyInfo>();
_defaults = new Dictionary<string, string>();
_inheritables = new List<PropertyInfo>();
_cssproperties = new List<PropertyInfo>();
PropertyInfo[] props = typeof(CssBox).GetProperties();
for (int i = 0; i < props.Length; i++)
{
CssPropertyAttribute att = Attribute.GetCustomAttribute(props[i], typeof(CssPropertyAttribute)) as CssPropertyAttribute;
if (att != null)
{
_properties.Add(att.Name, props[i]);
_defaults.Add(att.Name, GetDefaultValue(props[i]));
_cssproperties.Add(props[i]);
CssPropertyInheritedAttribute inh = Attribute.GetCustomAttribute(props[i], typeof(CssPropertyInheritedAttribute)) as CssPropertyInheritedAttribute;
if (inh != null)
{
_inheritables.Add(props[i]);
}
}
}
#endregion
Empty = new CssBox();
}
/// <summary>
/// Gets the default value of the specified css property
/// </summary>
/// <param name="prop"></param>
/// <returns></returns>
private static string GetDefaultValue(PropertyInfo prop)
{
DefaultValueAttribute att = Attribute.GetCustomAttribute(prop, typeof(DefaultValueAttribute)) as DefaultValueAttribute;
if (att == null) return string.Empty;
string s = Convert.ToString(att.Value);
return string.IsNullOrEmpty(s) ? string.Empty : s;
}
#endregion
#region CSS Fields
private string _backgroundColor;
private string _backgroundGradient;
private string _backgroundGradientAngle;
private string _BackgroundImage;
private string _backgroundRepeat;
private string _borderTopWidth;
private string _borderRightWidth;
private string _borderBottomWidth;
private string _borderLeftWidth;
private string _borderWidth;
private string _borderTopColor;
private string _borderRightColor;
private string _borderBottomColor;
private string _borderLeftColor;
private string _borderColor;
private string _borderTopStyle;
private string _borderRightStyle;
private string _borderBottomStyle;
private string _borderLeftStyle;
private string _borderStyle;
private string _borderBottom;
private string _borderLeft;
private string _borderRight;
private string _borderTop;
private string _borderSpacing;
private string _borderCollapse;
private string _border;
private string _bottom;
private string _color;
private string _cornerNWRadius;
private string _cornerNERadius;
private string _cornerSERadius;
private string _cornerSWRadius;
private string _cornerRadius;
private string _emptyCells;
private string _direction;
private string _display;
private string _font;
private string _fontFamily;
private string _fontSize;
private string _fontStyle;
private string _fontVariant;
private string _fontWeight;
private string _float;
private string _height;
private string _marginBottom;
private string _marginLeft;
private string _marginRight;
private string _marginTop;
private string _margin;
private string _left;
private string _lineHeight;
private string _listStyleType;
private string _listStyleImage;
private string _listStylePosition;
private string _listStyle;
private string _paddingLeft;
private string _paddingBottom;
private string _paddingRight;
private string _paddingTop;
private string _padding;
private string _right;
private string _text;
private string _textAlign;
private string _textDecoration;
private string _textIndent;
private string _top;
private string _position;
private string _verticalAlign;
private string _width;
private string _wordSpacing;
private string _whiteSpace;
#endregion
#region Fields
/// <summary>
/// Do not use or alter this flag
/// </summary>
/// <remarks>
/// Flag that indicates that CssTable algorithm already made fixes on it.
/// </remarks>
internal bool TableFixed;
private List<CssBoxWord> _boxWords;
private List<CssBox> _boxes;
private CssBox _parentBox;
private bool _wordsSizeMeasured;
private SizeF _size;
private PointF _location;
private List<CssLineBox> _lineBoxes;
private List<CssLineBox> _parentLineBoxes;
private float _fontAscent = float.NaN;
private float _fontDescent = float.NaN;
private float _fontLineSpacing = float.NaN;
private HtmlTag _htmltag;
private Dictionary<CssLineBox, RectangleF> _rectangles = null;
protected InitialContainer _initialContainer = null;
private CssBox _listItemBox;
private CssLineBox _firstHostingLineBox;
private CssLineBox _lastHostingLineBox;
#endregion
#region Ctor
protected CssBox()
{
_boxWords = new List<CssBoxWord>();
_boxes = new List<CssBox>();
_lineBoxes = new List<CssLineBox>();
_parentLineBoxes = new List<CssLineBox>();
_rectangles = new Dictionary<CssLineBox, RectangleF>();
#region Initialize properties with default values
foreach (string prop in _properties.Keys)
{
_properties[prop].SetValue(this, _defaults[prop], null);
}
#endregion
}
public CssBox(CssBox parentBox)
: this()
{
ParentBox = parentBox;
}
internal CssBox(CssBox parentBox, HtmlTag tag)
: this(parentBox)
{
_htmltag = tag;
}
#endregion
#region CSS Properties
#region Visual Formatting
#region Border
#region Border Width
[CssProperty("border-bottom-width")]
[DefaultValue("medium")]
public string BorderBottomWidth
{
get { return _borderBottomWidth; }
set { _borderBottomWidth = value; }
}
[CssProperty("border-left-width")]
[DefaultValue("medium")]
public string BorderLeftWidth
{
get { return _borderLeftWidth; }
set { _borderLeftWidth = value; }
}
[CssProperty("border-right-width")]
[DefaultValue("medium")]
public string BorderRightWidth
{
get { return _borderRightWidth; }
set { _borderRightWidth = value; }
}
[CssProperty("border-top-width")]
[DefaultValue("medium")]
public string BorderTopWidth
{
get { return _borderTopWidth; }
set { _borderTopWidth = value; }
}
[CssProperty("border-width")]
[DefaultValue("")]
public string BorderWidth
{
get { return _borderWidth; }
set
{
_borderWidth = value;
string[] values = CssValue.SplitValues(value);
switch (values.Length)
{
case 1:
BorderTopWidth = BorderLeftWidth = BorderRightWidth = BorderBottomWidth = values[0];
break;
case 2:
BorderTopWidth = BorderBottomWidth = values[0];
BorderLeftWidth = BorderRightWidth = values[1];
break;
case 3:
BorderTopWidth = values[0];
BorderLeftWidth = BorderRightWidth = values[1];
BorderBottomWidth = values[2];
break;
case 4:
BorderTopWidth = values[0];
BorderRightWidth = values[1];
BorderBottomWidth = values[2];
BorderLeftWidth = values[3];
break;
default:
break;
}
}
}
#endregion
#region Border Style
[CssProperty("border-bottom-style")]
[DefaultValue("none")]
public string BorderBottomStyle
{
get { return _borderBottomStyle; }
set { _borderBottomStyle = value; }
}
[CssProperty("border-left-style")]
[DefaultValue("none")]
public string BorderLeftStyle
{
get { return _borderLeftStyle; }
set { _borderLeftStyle = value; }
}
[CssProperty("border-right-style")]
[DefaultValue("none")]
public string BorderRightStyle
{
get { return _borderRightStyle; }
set { _borderRightStyle = value; }
}
[CssProperty("border-style")]
[DefaultValue("")]
public string BorderStyle
{
get { return _borderStyle; }
set
{
_borderStyle = value;
string[] values = CssValue.SplitValues(value);
switch (values.Length)
{
case 1:
BorderTopStyle = BorderLeftStyle = BorderRightStyle = BorderBottomStyle = values[0];
break;
case 2:
BorderTopStyle = BorderBottomStyle = values[0];
BorderLeftStyle = BorderRightStyle = values[1];
break;
case 3:
BorderTopStyle = values[0];
BorderLeftStyle = BorderRightStyle = values[1];
BorderBottomStyle = values[2];
break;
case 4:
BorderTopStyle = values[0];
BorderRightStyle = values[1];
BorderBottomStyle = values[2];
BorderLeftStyle = values[3];
break;
default:
break;
}
}
}
[CssProperty("border-top-style")]
[DefaultValue("none")]
public string BorderTopStyle
{
get { return _borderTopStyle; }
set { _borderTopStyle = value; }
}
#endregion
#region Border Color
[CssProperty("border-color")]
[DefaultValue("black")]
public string BorderColor
{
get { return _borderColor; }
set
{
_borderColor = value;
MatchCollection colors = Parser.Match(Parser.CssColors, value);
string[] values = new string[colors.Count];
for (int i = 0; i < values.Length; i++)
values[i] = colors[i].Value;
switch (values.Length)
{
case 1:
BorderTopColor = BorderLeftColor = BorderRightColor = BorderBottomColor = values[0];
break;
case 2:
BorderTopColor = BorderBottomColor = values[0];
BorderLeftColor = BorderRightColor = values[1];
break;
case 3:
BorderTopColor = values[0];
BorderLeftColor = BorderRightColor = values[1];
BorderBottomColor = values[2];
break;
case 4:
BorderTopColor = values[0];
BorderRightColor = values[1];
BorderBottomColor = values[2];
BorderLeftColor = values[3];
break;
default:
break;
}
}
}
[CssProperty("border-bottom-color")]
[DefaultValue("black")]
public string BorderBottomColor
{
get { return _borderBottomColor; }
set { _borderBottomColor = value; }
}
[CssProperty("border-left-color")]
[DefaultValue("black")]
public string BorderLeftColor
{
get { return _borderLeftColor; }
set { _borderLeftColor = value; }
}
[CssProperty("border-right-color")]
[DefaultValue("black")]
public string BorderRightColor
{
get { return _borderRightColor; }
set { _borderRightColor = value; }
}
[CssProperty("border-top-color")]
[DefaultValue("black")]
public string BorderTopColor
{
get { return _borderTopColor; }
set { _borderTopColor = value; }
}
#endregion
#region Border ShortHands
[CssProperty("border")]
[DefaultValue("")]
public string Border
{
get { return _border; }
set
{
_border = value;
string borderWidth = Parser.Search(Parser.CssBorderWidth, value);
string borderStyle = Parser.Search(Parser.CssBorderStyle, value);
string borderColor = Parser.Search(Parser.CssColors, value);
if (borderWidth != null) BorderWidth = borderWidth;
if (borderStyle != null) BorderStyle = borderStyle;
if (borderColor != null) BorderColor = borderColor;
}
}
[CssProperty("border-bottom")]
[DefaultValue("")]
public string BorderBottom
{
get { return _borderBottom; }
set
{
_borderBottom = value;
string borderWidth = Parser.Search(Parser.CssBorderWidth, value);
string borderStyle = Parser.Search(Parser.CssBorderStyle, value);
string borderColor = Parser.Search(Parser.CssColors, value);
if (borderWidth != null) BorderBottomWidth = borderWidth;
if (borderStyle != null) BorderBottomStyle = borderStyle;
if (borderColor != null) BorderBottomColor = borderColor;
}
}
[CssProperty("border-left")]
[DefaultValue("")]
public string BorderLeft
{
get { return _borderLeft; }
set
{
_borderLeft = value;
string borderWidth = Parser.Search(Parser.CssBorderWidth, value);
string borderStyle = Parser.Search(Parser.CssBorderStyle, value);
string borderColor = Parser.Search(Parser.CssColors, value);
if (borderWidth != null) BorderLeftWidth = borderWidth;
if (borderStyle != null) BorderLeftStyle = borderStyle;
if (borderColor != null) BorderLeftColor = borderColor;
}
}
[CssProperty("border-right")]
[DefaultValue("")]
public string BorderRight
{
get { return _borderRight; }
set
{
_borderRight = value;
string borderWidth = Parser.Search(Parser.CssBorderWidth, value);
string borderStyle = Parser.Search(Parser.CssBorderStyle, value);
string borderColor = Parser.Search(Parser.CssColors, value);
if (borderWidth != null) BorderRightWidth = borderWidth;
if (borderStyle != null) BorderRightStyle = borderStyle;
if (borderColor != null) BorderRightColor = borderColor;
}
}
[CssProperty("border-top")]
[DefaultValue("")]
public string BorderTop
{
get { return _borderTop; }
set
{
_borderTop = value;
string borderWidth = Parser.Search(Parser.CssBorderWidth, value);
string borderStyle = Parser.Search(Parser.CssBorderStyle, value);
string borderColor = Parser.Search(Parser.CssColors, value);
if (borderWidth != null) BorderTopWidth = borderWidth;
if (borderStyle != null) BorderTopStyle = borderStyle;
if (borderColor != null) BorderTopColor = borderColor;
}
}
#endregion
#region Table borders
[CssProperty("border-spacing")]
[DefaultValue("0")]
[CssPropertyInherited()]
public string BorderSpacing
{
get { return _borderSpacing; }
set { _borderSpacing = value; }
}
[CssProperty("border-collapse")]
[DefaultValue("separate")]
[CssPropertyInherited()]
public string BorderCollapse
{
get { return _borderCollapse; }
set { _borderCollapse = value; }
}
#endregion
#region Rounded corners
[CssProperty("corner-radius")]
[DefaultValue("0")]
public string CornerRadius
{
get { return _cornerRadius; }
set
{
MatchCollection r = Parser.Match(Parser.CssLength, value);
switch (r.Count)
{
case 1:
CornerNERadius = r[0].Value;
CornerNWRadius = r[0].Value;
CornerSERadius = r[0].Value;
CornerSWRadius = r[0].Value;
break;
case 2:
CornerNERadius = r[0].Value;
CornerNWRadius = r[0].Value;
CornerSERadius = r[1].Value;
CornerSWRadius = r[1].Value;
break;
case 3:
CornerNERadius = r[0].Value;
CornerNWRadius = r[1].Value;
CornerSERadius = r[2].Value;
break;
case 4:
CornerNERadius = r[0].Value;
CornerNWRadius = r[1].Value;
CornerSERadius = r[2].Value;
CornerSWRadius = r[3].Value;
break;
}
_cornerRadius = value;
}
}
[CssProperty("corner-nw-radius")]
[DefaultValue("0")]
public string CornerNWRadius
{
get { return _cornerNWRadius; }
set { _cornerNWRadius = value; }
}
[CssProperty("corner-ne-radius")]
[DefaultValue("0")]
public string CornerNERadius
{
get { return _cornerNERadius; }
set { _cornerNERadius = value; }
}
[CssProperty("corner-se-radius")]
[DefaultValue("0")]
public string CornerSERadius
{
get { return _cornerSERadius; }
set { _cornerSERadius = value; }
}
[CssProperty("corner-sw-radius")]
[DefaultValue("0")]
public string CornerSWRadius
{
get { return _cornerSWRadius; }
set { _cornerSWRadius = value; }
}
#endregion
#endregion
#region Margin
[CssProperty("margin")]
[DefaultValue("")]
public string Margin
{
get { return _margin; }
set
{
_margin = value;
string[] values = CssValue.SplitValues(value);
switch (values.Length)
{
case 1:
MarginTop = MarginLeft = MarginRight = MarginBottom = values[0];
break;
case 2:
MarginTop = MarginBottom = values[0];
MarginLeft = MarginRight = values[1];
break;
case 3:
MarginTop = values[0];
MarginLeft = MarginRight = values[1];
MarginBottom = values[2];
break;
case 4:
MarginTop = values[0];
MarginRight = values[1];
MarginBottom = values[2];
MarginLeft = values[3];
break;
default:
break;
}
}
}
[CssProperty("margin-bottom")]
[DefaultValue("0")]
public string MarginBottom
{
get { return _marginBottom; }
set { _marginBottom = value; }
}
[CssProperty("margin-left")]
[DefaultValue("0")]
public string MarginLeft
{
get { return _marginLeft; }
set { _marginLeft = value; }
}
[CssProperty("margin-right")]
[DefaultValue("0")]
public string MarginRight
{
get { return _marginRight; }
set { _marginRight = value; }
}
[CssProperty("margin-top")]
[DefaultValue("0")]
public string MarginTop
{
get { return _marginTop; }
set { _marginTop = value; }
}
#endregion
#region Padding
[CssProperty("padding")]
[DefaultValue("")]
public string Padding
{
get { return _padding; }
set
{
_padding = value;
string[] values = CssValue.SplitValues(value);
switch (values.Length)
{
case 1:
PaddingTop = PaddingLeft = PaddingRight = PaddingBottom = values[0];
break;
case 2:
PaddingTop = PaddingBottom = values[0];
PaddingLeft = PaddingRight = values[1];
break;
case 3:
PaddingTop = values[0];
PaddingLeft = PaddingRight = values[1];
PaddingBottom = values[2];
break;
case 4:
PaddingTop = values[0];
PaddingRight = values[1];
PaddingBottom = values[2];
PaddingLeft = values[3];
break;
default:
break;
}
}
}
[CssProperty("padding-bottom")]
[DefaultValue("0")]
public string PaddingBottom
{
get { return _paddingBottom; }
set { _paddingBottom = value; _actualPaddingBottom = float.NaN; }
}
[CssProperty("padding-left")]
[DefaultValue("0")]
public string PaddingLeft
{
get { return _paddingLeft; }
set { _paddingLeft = value; _actualPaddingLeft = float.NaN; }
}
[CssProperty("padding-right")]
[DefaultValue("0")]
public string PaddingRight
{
get { return _paddingRight; }
set { _paddingRight = value; _actualPaddingRight = float.NaN; }
}
[CssProperty("padding-top")]
[DefaultValue("0")]
public string PaddingTop
{
get { return _paddingTop; }
set { _paddingTop = value; _actualPaddingTop = float.NaN; }
}
#endregion
#region Bounds
[CssProperty("left")]
[DefaultValue("auto")]
public string Left
{
get { return _left; }
set { _left = value; }
}
[CssProperty("top")]
[DefaultValue("auto")]
public string Top
{
get { return _top; }
set { _top = value; }
}
//[CssProperty("right")]
//[DefaultValue("auto")]
//public string Right
//{
// get { return _right; }
// set { _right = value; }
//}
//[CssProperty("bottom")]
//[DefaultValue("auto")]
//public string Bottom
//{
// get { return _bottom; }
// set { _bottom = value; }
//}
[CssProperty("width")]
[DefaultValue("auto")]
public string Width
{
get { return _width; }
set { _width = value; }
}
[CssProperty("height")]
[DefaultValue("auto")]
public string Height
{
get { return _height; }
set { _height = value; }
}
#endregion
#endregion
#region Colors and Backgrounds
[CssProperty("background-color")]
[DefaultValue("transparent")]
public string BackgroundColor
{
get { return _backgroundColor; }
set { _backgroundColor = value; }
}
[CssProperty("background-image")]
[DefaultValue("none")]
public string BackgroundImage
{
get { return _BackgroundImage; }
set { _BackgroundImage = value; }
}
[CssProperty("background-repeat")]
[DefaultValue("repeat")]
public string BackgroundRepeat
{
get { return _backgroundRepeat; }
set { _backgroundRepeat = value; }
}
[CssProperty("background-gradient")]
[DefaultValue("none")]
public string BackgroundGradient
{
get { return _backgroundGradient; }
set { _backgroundGradient = value; }
}
[CssProperty("background-gradient-angle")]
[DefaultValue("90")]
public string BackgroundGradientAngle
{
get { return _backgroundGradientAngle; }
set { _backgroundGradientAngle = value; }
}
[CssProperty("color")]
[DefaultValue("black")]
[CssPropertyInherited()]
public string Color
{
get { return _color; }
set { _color = value; _actualColor = System.Drawing.Color.Empty; }
}
[CssProperty("display")]
[DefaultValue("inline")]
public string Display
{
get { return _display; }
set { _display = value; }
}
[CssProperty("direction")]
[DefaultValue("ltr")]
public string Direction
{
get { return _direction; }
set { _direction = value; }
}
[CssProperty("empty-cells")]
[DefaultValue("show")]
[CssPropertyInherited()]
public string EmptyCells
{
get { return _emptyCells; }
set { _emptyCells = value; }
}
[CssProperty("float")]
[DefaultValue("none")]
public string Float
{
get { return _float; }
set { _float = value; }
}
[CssProperty("position")]
[DefaultValue("static")]
public string Position
{
get { return _position; }
set { _position = value; }
}
#endregion
#region Text
[CssProperty("line-height")]
[DefaultValue("normal")]
public string LineHeight
{
get { return _lineHeight; }
set { _lineHeight = NoEms(value); }
}
[CssProperty("vertical-align")]
[DefaultValue("baseline")]
[CssPropertyInherited()]
public string VerticalAlign
{
get { return _verticalAlign; }
set { _verticalAlign = value; }
}
[CssProperty("text-indent")]
[DefaultValue("0")]
[CssPropertyInherited()]
public string TextIndent
{
get { return _textIndent; }
set { _textIndent = NoEms(value); }
}
[CssProperty("text-align")]
[DefaultValue("")]
[CssPropertyInherited()]
public string TextAlign
{
get { return _textAlign; }
set { _textAlign = value; }
}
[CssProperty("text-decoration")]
[DefaultValue("")]
public string TextDecoration
{
get { return _textDecoration; }
set { _textDecoration = value; }
}
[CssProperty("white-space")]
[DefaultValue("normal")]
[CssPropertyInherited()]
public string WhiteSpace
{
get { return _whiteSpace; }
set { _whiteSpace = value; }
}
[CssProperty("word-spacing")]
[DefaultValue("normal")]
public string WordSpacing
{
get { return _wordSpacing; }
set { _wordSpacing = NoEms(value); }
}
#endregion
#region Font
[CssProperty("font")]
[DefaultValue("")]
[CssPropertyInherited()]
public string Font
{
get { return _font; }
set
{
_font = value;
int mustBePos;
string mustBe = Parser.Search(Parser.CssFontSizeAndLineHeight, value, out mustBePos);
if (!string.IsNullOrEmpty(mustBe))
{
mustBe = mustBe.Trim();
//Check for style||variant||weight on the left
string leftSide = value.Substring(0, mustBePos);
string fontStyle = Parser.Search(Parser.CssFontStyle, leftSide);
string fontVariant = Parser.Search(Parser.CssFontVariant, leftSide);
string fontWeight = Parser.Search(Parser.CssFontWeight, leftSide);
//Check for family on the right
string rightSide = value.Substring(mustBePos + mustBe.Length);
string fontFamily = rightSide.Trim(); //Parser.Search(Parser.CssFontFamily, rightSide); //TODO: Would this be right?
//Check for font-size and line-height
string fontSize = mustBe;
string lineHeight = string.Empty;
if (mustBe.Contains("/") && mustBe.Length > mustBe.IndexOf("/") + 1)
{
int slashPos = mustBe.IndexOf("/");
fontSize = mustBe.Substring(0, slashPos);
lineHeight = mustBe.Substring(slashPos + 1);
}
//Assign values p { font: 12px/14px sans-serif }
if (!string.IsNullOrEmpty(fontStyle)) FontStyle = fontStyle;
if (!string.IsNullOrEmpty(fontVariant)) FontVariant = fontVariant;
if (!string.IsNullOrEmpty(fontWeight)) FontWeight = fontWeight;
if (!string.IsNullOrEmpty(fontFamily)) FontFamily = fontFamily;
if (!string.IsNullOrEmpty(fontSize)) FontSize = fontSize;
if (!string.IsNullOrEmpty(lineHeight)) LineHeight = lineHeight;
}
else
{
// Check for: caption | icon | menu | message-box | small-caption | status-bar
//TODO: Interpret font values of: caption | icon | menu | message-box | small-caption | status-bar
}
}
}
[CssProperty("font-family")]
[DefaultValue("serif")]
[CssPropertyInherited()]
public string FontFamily
{
get { return _fontFamily; }
set
{
///HACK: Because of performance, generic font families
/// will be checked when only the generic font
/// family is given.
switch (value)
{
case CssConstants.Serif:
_fontFamily = CssDefaults.FontSerif; break;
case CssConstants.SansSerif:
_fontFamily = CssDefaults.FontSansSerif; break;
case CssConstants.Cursive:
_fontFamily = CssDefaults.FontCursive; break;
case CssConstants.Fantasy:
_fontFamily = CssDefaults.FontFantasy; break;
case CssConstants.Monospace:
_fontFamily = CssDefaults.FontMonospace; break;
default:
_fontFamily = value; break;
}
}
}
[CssProperty("font-size")]
[DefaultValue("medium")]
[CssPropertyInherited()]
public string FontSize
{
get { return _fontSize; }
set
{
string length = Parser.Search(Parser.CssLength, value);
if (length != null)
{
string computedValue = string.Empty;
CssLength len = new CssLength(length);
if (len.HasError)
{
computedValue = _defaults["font-size"];
}
else if (len.Unit == CssLength.CssUnit.Ems && ParentBox != null)
{
computedValue = len.ConvertEmToPoints(ParentBox.ActualFont.SizeInPoints).ToString();
}
else
{
computedValue = len.ToString();
}
_fontSize = computedValue;
}
else
{
_fontSize = value;
}
}
}
[CssProperty("font-style")]
[DefaultValue("normal")]
[CssPropertyInherited()]
public string FontStyle
{
get { return _fontStyle; }
set { _fontStyle = value; }
}
[CssProperty("font-variant")]
[DefaultValue("normal")]
[CssPropertyInherited()]
public string FontVariant
{
get { return _fontVariant; }
set { _fontVariant = value; }
}
[CssProperty("font-weight")]
[DefaultValue("normal")]
[CssPropertyInherited()]
public string FontWeight
{
get { return _fontWeight; }
set { _fontWeight = value; }
}
#endregion
#region Lists
[CssProperty("list-style")]
[DefaultValue("")]
[CssPropertyInherited()]
public string ListStyle
{
get { return _listStyle; }
set { _listStyle = value; }
}
[CssProperty("list-style-position")]
[DefaultValue("outside")]
[CssPropertyInherited()]
public string ListStylePosition
{
get { return _listStylePosition; }
set { _listStylePosition = value; }
}
[CssProperty("list-style-image")]
[DefaultValue("")]
[CssPropertyInherited()]
public string ListStyleImage
{
get { return _listStyleImage; }
set { _listStyleImage = value; }
}
[CssProperty("list-style-type")]
[DefaultValue("disc")]
[CssPropertyInherited()]
public string ListStyleType
{
get { return _listStyleType; }
set { _listStyleType = value; }
}
#endregion
#endregion
#region Actual Values Properties
#region Fields
private float _actualCornerNW = float.NaN;
private float _actualCornerNE = float.NaN;
private float _actualCornerSW = float.NaN;
private float _actualCornerSE = float.NaN;
private Color _actualColor = System.Drawing.Color.Empty;
private float _actualBackgroundGradientAngle = float.NaN;
private float _actualPaddingTop = float.NaN;
private float _actualPaddingBottom = float.NaN;
private float _actualPaddingRight = float.NaN;
private float _actualPaddingLeft = float.NaN;
private float _actualMarginTop = float.NaN;
private float _actualMarginBottom = float.NaN;
private float _actualMarginRight = float.NaN;
private float _actualMarginLeft = float.NaN;
private float _actualBorderTopWidth = float.NaN;
private float _actualBorderLeftWidth = float.NaN;
private float _actualBorderBottomWidth = float.NaN;
private float _actualBorderRightWidth = float.NaN;
private Color _actualBackgroundGradient = System.Drawing.Color.Empty;
private System.Drawing.Color _actualBorderTopColor = System.Drawing.Color.Empty;
private System.Drawing.Color _actualBorderLeftColor = System.Drawing.Color.Empty;
private System.Drawing.Color _actualBorderBottomColor = System.Drawing.Color.Empty;
private System.Drawing.Color _actualBorderRightColor = System.Drawing.Color.Empty;
private float _actualWordSpacing = float.NaN;
private Color _actualBackgroundColor = System.Drawing.Color.Empty;
private Font _actualFont = null;
private float _actualTextIndent = float.NaN;
private float _actualBorderSpacingHorizontal = float.NaN;
private float _actualBorderSpacingVertical = float.NaN;
#endregion
#region Boxing
#region Padding
/// <summary>
/// Gets the actual top's padding
/// </summary>
public float ActualPaddingTop
{
get
{
if (float.IsNaN(_actualPaddingTop))
{
_actualPaddingTop = CssValue.ParseLength(PaddingTop, Size.Width, this);
}
return _actualPaddingTop;
}
}
/// <summary>
/// Gets the actual padding on the left
/// </summary>
public float ActualPaddingLeft
{
get
{
if (float.IsNaN(_actualPaddingLeft))
{
_actualPaddingLeft = CssValue.ParseLength(PaddingLeft, Size.Width, this);
}
return _actualPaddingLeft;
}
}
/// <summary>
/// Gets the actual Padding of the bottom
/// </summary>
public float ActualPaddingBottom
{
get
{
if (float.IsNaN(_actualPaddingBottom))
{
_actualPaddingBottom = CssValue.ParseLength(PaddingBottom, Size.Width, this);
}
return _actualPaddingBottom;
}
}
/// <summary>
/// Gets the actual padding on the right
/// </summary>
public float ActualPaddingRight
{
get
{
if (float.IsNaN(_actualPaddingRight))
{
_actualPaddingRight = CssValue.ParseLength(PaddingRight, Size.Width, this);
}
return _actualPaddingRight;
}
}
#endregion
#region Margin
/// <summary>
/// Gets the actual top's Margin
/// </summary>
public float ActualMarginTop
{
get
{
if (float.IsNaN(_actualMarginTop))
{
if (MarginTop == CssConstants.Auto) MarginTop = "0";
_actualMarginTop = CssValue.ParseLength(MarginTop, Size.Width, this);
}
return _actualMarginTop;
}
}
/// <summary>
/// Gets the actual Margin on the left
/// </summary>
public float ActualMarginLeft
{
get
{
if (float.IsNaN(_actualMarginLeft))
{
if (MarginLeft == CssConstants.Auto) MarginLeft = "0";
_actualMarginLeft = CssValue.ParseLength(MarginLeft, Size.Width, this);
}
return _actualMarginLeft;
}
}
/// <summary>
/// Gets the actual Margin of the bottom
/// </summary>
public float ActualMarginBottom
{
get
{
if (float.IsNaN(_actualMarginBottom))
{
if (MarginBottom == CssConstants.Auto) MarginBottom = "0";
_actualMarginBottom = CssValue.ParseLength(MarginBottom, Size.Width, this);
}
return _actualMarginBottom;
}
}
/// <summary>
/// Gets the actual Margin on the right
/// </summary>
public float ActualMarginRight
{
get
{
if (float.IsNaN(_actualMarginRight))
{
if (MarginRight == CssConstants.Auto) MarginRight = "0";
_actualMarginRight = CssValue.ParseLength(MarginRight, Size.Width, this);
}
return _actualMarginRight;
}
}
#endregion
#region Border
#region Border Width
/// <summary>
/// Gets the actual top border width
/// </summary>
public float ActualBorderTopWidth
{
get
{
if (float.IsNaN(_actualBorderTopWidth))
{
_actualBorderTopWidth = CssValue.GetActualBorderWidth(BorderTopWidth, this);
if (string.IsNullOrEmpty(BorderTopStyle) || BorderTopStyle == CssConstants.None)
{
_actualBorderTopWidth = 0f;
}
}
return _actualBorderTopWidth;
}
}
/// <summary>
/// Gets the actual Left border width
/// </summary>
public float ActualBorderLeftWidth
{
get
{
if (float.IsNaN(_actualBorderLeftWidth))
{
_actualBorderLeftWidth = CssValue.GetActualBorderWidth(BorderLeftWidth, this);
if (string.IsNullOrEmpty(BorderLeftStyle) || BorderLeftStyle == CssConstants.None)
{
_actualBorderLeftWidth = 0f;
}
}
return _actualBorderLeftWidth;
}
}
/// <summary>
/// Gets the actual Bottom border width
/// </summary>
public float ActualBorderBottomWidth
{
get
{
if (float.IsNaN(_actualBorderBottomWidth))
{
_actualBorderBottomWidth = CssValue.GetActualBorderWidth(BorderBottomWidth, this);
if (string.IsNullOrEmpty(BorderBottomStyle) || BorderBottomStyle == CssConstants.None)
{
_actualBorderBottomWidth = 0f;
}
}
return _actualBorderBottomWidth;
}
}
/// <summary>
/// Gets the actual Right border width
/// </summary>
public float ActualBorderRightWidth
{
get
{
if (float.IsNaN(_actualBorderRightWidth))
{
_actualBorderRightWidth = CssValue.GetActualBorderWidth(BorderRightWidth, this);
if (string.IsNullOrEmpty(BorderRightStyle) || BorderRightStyle == CssConstants.None)
{
_actualBorderRightWidth = 0f;
}
}
return _actualBorderRightWidth;
}
}
#endregion
#region Border Color
/// <summary>
/// Gets the actual top border Color
/// </summary>
public Color ActualBorderTopColor
{
get
{
if ((_actualBorderTopColor.IsEmpty))
{
_actualBorderTopColor = CssValue.GetActualColor(BorderTopColor);
}
return _actualBorderTopColor;
}
}
/// <summary>
/// Gets the actual Left border Color
/// </summary>
public Color ActualBorderLeftColor
{
get
{
if ((_actualBorderLeftColor.IsEmpty))
{
_actualBorderLeftColor = CssValue.GetActualColor(BorderLeftColor);
}
return _actualBorderLeftColor;
}
}
/// <summary>
/// Gets the actual Bottom border Color
/// </summary>
public Color ActualBorderBottomColor
{
get
{
if ((_actualBorderBottomColor.IsEmpty))
{
_actualBorderBottomColor = CssValue.GetActualColor(BorderBottomColor);
}
return _actualBorderBottomColor;
}
}
/// <summary>
/// Gets the actual Right border Color
/// </summary>
public Color ActualBorderRightColor
{
get
{
if ((_actualBorderRightColor.IsEmpty))
{
_actualBorderRightColor = CssValue.GetActualColor(BorderRightColor);
}
return _actualBorderRightColor;
}
}
#endregion
#endregion
#region Corners
/// <summary>
/// Gets the actual lenght of the north west corner
/// </summary>
public float ActualCornerNW
{
get
{
if (float.IsNaN(_actualCornerNW))
{
_actualCornerNW = CssValue.ParseLength(CornerNWRadius, 0, this);
}
return _actualCornerNW;
}
}
/// <summary>
/// Gets the actual lenght of the north east corner
/// </summary>
public float ActualCornerNE
{
get
{
if (float.IsNaN(_actualCornerNE))
{
_actualCornerNE = CssValue.ParseLength(CornerNERadius, 0, this);
}
return _actualCornerNE;
}
}
/// <summary>
/// Gets the actual lenght of the south east corner
/// </summary>
public float ActualCornerSE
{
get
{
if (float.IsNaN(_actualCornerSE))
{
_actualCornerSE = CssValue.ParseLength(CornerSERadius, 0, this);
}
return _actualCornerSE;
}
}
/// <summary>
/// Gets the actual lenght of the south west corner
/// </summary>
public float ActualCornerSW
{
get
{
if (float.IsNaN(_actualCornerSW))
{
_actualCornerSW = CssValue.ParseLength(CornerSWRadius, 0, this);
}
return _actualCornerSW;
}
}
#endregion
#endregion
#region Layout Formatting
/// <summary>
/// Gets the actual word spacing of the word.
/// </summary>
public float ActualWordSpacing
{
get
{
if (float.IsNaN(_actualWordSpacing))
{
throw new Exception("Space must be calculated before using this property");
}
return _actualWordSpacing;
}
}
#endregion
#region Colors and Backgrounds
/// <summary>
///
/// Gets the actual color for the text.
/// </summary>
public Color ActualColor
{
get
{
if (_actualColor.IsEmpty)
{
_actualColor = CssValue.GetActualColor(Color);
}
return _actualColor;
}
}
/// <summary>
/// Gets the actual background color of the box
/// </summary>
public Color ActualBackgroundColor
{
get
{
if (_actualBackgroundColor.IsEmpty)
{
_actualBackgroundColor = CssValue.GetActualColor(BackgroundColor);
}
return _actualBackgroundColor;
}
}
/// <summary>
/// Gets the second color that creates a gradient for the background
/// </summary>
public Color ActualBackgroundGradient
{
get
{
if (_actualBackgroundGradient.IsEmpty)
{
_actualBackgroundGradient = CssValue.GetActualColor(BackgroundGradient);
}
return _actualBackgroundGradient;
}
}
/// <summary>
/// Gets the actual angle specified for the background gradient
/// </summary>
public float ActualBackgroundGradientAngle
{
get
{
if (float.IsNaN(_actualBackgroundGradientAngle))
{
_actualBackgroundGradientAngle = CssValue.ParseNumber(BackgroundGradientAngle, 360f);
}
return _actualBackgroundGradientAngle;
}
}
#endregion
#region Fonts
/// <summary>
/// Gets the actual font of the parent
/// </summary>
public Font ActualParentFont
{
get
{
if (ParentBox == null)
{
return ActualFont;
}
return ParentBox.ActualFont;
}
}
/// <summary>
/// Gets the font that should be actually used to paint the text of the box
/// </summary>
public Font ActualFont
{
get {
if (_actualFont == null)
{
if (string.IsNullOrEmpty(FontFamily)) { FontFamily = CssDefaults.FontSerif; }
if (string.IsNullOrEmpty(FontSize)) { FontSize = CssDefaults.FontSize + "pt"; }
FontStyle st = System.Drawing.FontStyle.Regular;
if (FontStyle == CssConstants.Italic || FontStyle == CssConstants.Oblique)
{
st |= System.Drawing.FontStyle.Italic;
}
if (FontWeight != CssConstants.Normal && FontWeight != CssConstants.Lighter && !string.IsNullOrEmpty(FontWeight))
{
st |= System.Drawing.FontStyle.Bold;
}
float fsize = 0f;
float parentSize = CssDefaults.FontSize;
if(ParentBox != null) parentSize = ParentBox.ActualFont.Size;
switch (FontSize)
{
case CssConstants.Medium:
fsize = CssDefaults.FontSize; break;
case CssConstants.XXSmall:
fsize = CssDefaults.FontSize - 4; break;
case CssConstants.XSmall:
fsize = CssDefaults.FontSize - 3; break;
case CssConstants.Small:
fsize = CssDefaults.FontSize - 2; break;
case CssConstants.Large:
fsize = CssDefaults.FontSize + 2; break;
case CssConstants.XLarge:
fsize = CssDefaults.FontSize + 3; break;
case CssConstants.XXLarge:
fsize = CssDefaults.FontSize + 4; break;
case CssConstants.Smaller:
fsize = parentSize - 2; break;
case CssConstants.Larger:
fsize = parentSize + 2; break;
default:
fsize = CssValue.ParseLength(FontSize, parentSize, this, parentSize, true);
break;
}
if (fsize <= 1f) fsize = CssDefaults.FontSize;
_actualFont = new Font(FontFamily, fsize, st);
}
return _actualFont;
}
}
#endregion
#region Text
/// <summary>
/// Gets the text indentation (on first line only)
/// </summary>
public float ActualTextIndent
{
get
{
if (float.IsNaN(_actualTextIndent))
{
_actualTextIndent = CssValue.ParseLength(TextIndent, Size.Width, this);
}
return _actualTextIndent;
}
}
#endregion
#region Tables
/// <summary>
/// Gets the actual horizontal border spacing for tables
/// </summary>
public float ActualBorderSpacingHorizontal
{
get
{
if (float.IsNaN(_actualBorderSpacingHorizontal))
{
MatchCollection matches = Parser.Match(Parser.CssLength, BorderSpacing);
if (matches.Count == 0)
{
_actualBorderSpacingHorizontal = 0;
}
else if (matches.Count > 0)
{
_actualBorderSpacingHorizontal = CssValue.ParseLength(matches[0].Value, 1, this);
}
}
return _actualBorderSpacingHorizontal;
}
}
/// <summary>
/// Gets the actual vertical border spacing for tables
/// </summary>
public float ActualBorderSpacingVertical
{
get
{
if (float.IsNaN(_actualBorderSpacingVertical))
{
MatchCollection matches = Parser.Match(Parser.CssLength, BorderSpacing);
if (matches.Count == 0)
{
_actualBorderSpacingVertical = 0;
}
else if (matches.Count == 1)
{
_actualBorderSpacingVertical = CssValue.ParseLength(matches[0].Value, 1, this);
}
else
{
_actualBorderSpacingVertical = CssValue.ParseLength(matches[1].Value, 1, this);
}
}
return _actualBorderSpacingVertical;
}
}
#endregion
#endregion
#region Properties
/// <summary>
/// Gets the � box
/// </summary>
public CssBox ListItemBox
{
get
{
return _listItemBox;
}
}
/// <summary>
/// Gets the width available on the box, counting padding and margin.
/// </summary>
public float AvailableWidth
{
get { return Size.Width - ActualBorderLeftWidth - ActualPaddingLeft - ActualPaddingRight - ActualBorderRightWidth; }
}
/// <summary>
/// Gets the bounds of the box
/// </summary>
public RectangleF Bounds
{
get { return new RectangleF(Location, Size); }
}
/// <summary>
/// Gets or sets the bottom of the box.
/// (When setting, alters only the Size.Height of the box)
/// </summary>
public float ActualBottom
{
get
{
return Location.Y + Size.Height;
}
set
{
Size = new SizeF(Size.Width, value - Location.Y);
}
}
/// <summary>
/// Gets the childrenn boxes of this box
/// </summary>
public List<CssBox> Boxes
{
get { return _boxes; }
}
/// <summary>
/// Gets the left of the client rectangle (Where content starts rendering)
/// </summary>
public float ClientLeft
{
get { return Location.X + ActualBorderLeftWidth + ActualPaddingLeft; }
}
/// <summary>
/// Gets the top of the client rectangle (Where content starts rendering)
/// </summary>
public float ClientTop
{
get { return Location.Y + ActualBorderTopWidth + ActualPaddingTop; }
}
/// <summary>
/// Gets the right of the client rectangle
/// </summary>
public float ClientRight
{
get { return ActualRight - ActualPaddingRight - ActualBorderRightWidth; }
}
/// <summary>
/// Gets the bottom of the client rectangle
/// </summary>
public float ClientBottom
{
get { return ActualBottom - ActualPaddingBottom - ActualBorderBottomWidth; }
}
/// <summary>
/// Gets the client rectangle
/// </summary>
public RectangleF ClientRectangle
{
get { return RectangleF.FromLTRB(ClientLeft, ClientTop, ClientRight, ClientBottom); }
}
/// <summary>
/// Gets the containing block-box of this box. (The nearest parent box with display=block)
/// </summary>
public CssBox ContainingBlock
{
get
{
if (ParentBox == null)
{
return this; //This is the initial containing block.
}
CssBox b = ParentBox;
while (
b.Display != CssConstants.Block &&
b.Display != CssConstants.Table &&
b.Display != CssConstants.TableCell &&
b.ParentBox != null)
{
b = b.ParentBox;
}
//Comment this following line to treat always superior box as block
if (b == null) throw new Exception("There's no containing block on the chain");
return b;
}
}
/// <summary>
/// Gets the font's ascent
/// </summary>
public float FontAscent
{
get
{
if (float.IsNaN(_fontAscent))
{
_fontAscent = CssLayoutEngine.GetAscent(ActualFont);
}
return _fontAscent;
}
}
/// <summary>
/// Gets the font's line spacing
/// </summary>
public float FontLineSpacing
{
get
{
if (float.IsNaN(_fontLineSpacing))
{
_fontLineSpacing = CssLayoutEngine.GetLineSpacing(ActualFont);
}
return _fontLineSpacing;
}
}
/// <summary>
/// Gets the font's descent
/// </summary>
public float FontDescent
{
get
{
if (float.IsNaN(_fontDescent))
{
_fontDescent = CssLayoutEngine.GetDescent(ActualFont);
} return _fontDescent;
}
}
/// <summary>
/// Gets the first word of the box
/// </summary>
internal CssBoxWord FirstWord
{
get { return Words[0]; }
}
/// <summary>
/// Gets or sets the first linebox where content of this box appear
/// </summary>
internal CssLineBox FirstHostingLineBox
{
get { return _firstHostingLineBox; }
set { _firstHostingLineBox = value; }
}
/// <summary>
/// Gets or sets the last linebox where content of this box appear
/// </summary>
internal CssLineBox LastHostingLineBox
{
get { return _lastHostingLineBox; }
set { _lastHostingLineBox = value; }
}
/// <summary>
/// Gets the HTMLTag that hosts this box
/// </summary>
public HtmlTag HtmlTag
{
get { return _htmltag; }
}
/// <summary>
/// Gets the InitialContainer of the Box.
/// WARNING: May be null.
/// </summary>
public InitialContainer InitialContainer
{
get { return _initialContainer; }
}
/// <summary>
/// Gets if this box represents an image
/// </summary>
public bool IsImage
{
get { return Words.Count == 1 && Words[0].IsImage; }
}
/// <summary>
/// Gets a value indicating if at least one of the corners of the box is rounded
/// </summary>
public bool IsRounded
{
get { return ActualCornerNE > 0f || ActualCornerNW > 0f || ActualCornerSE > 0f || ActualCornerSW > 0f; }
}
/// <summary>
/// Tells if the box is empty or contains just blank spaces
/// </summary>
public bool IsSpaceOrEmpty
{
get {
if ((Words.Count == 0 && Boxes.Count == 0) ||
(Words.Count == 1 && Words[0].IsSpaces) ||
Boxes.Count == 1 && Boxes[0] is CssAnonymousSpaceBlockBox) return true;
foreach (CssBoxWord word in Words)
{
if (!word.IsSpaces)
{
return false;
}
}
return true;
}
}
/// <summary>
/// Gets the last word of the box
/// </summary>
internal CssBoxWord LastWord
{
get { return Words[Words.Count - 1]; }
}
/// <summary>
/// Gets the line-boxes of this box (if block box)
/// </summary>
internal List<CssLineBox> LineBoxes
{
get { return _lineBoxes; }
}
/// <summary>
/// Gets or sets the location of the box
/// </summary>
public PointF Location
{
get { return _location; }
set { _location = value; }
}
/// <summary>
/// Gets or sets the parent box of this box
/// </summary>
public CssBox ParentBox
{
get { return _parentBox; }
set
{
//Remove from last parent
if (_parentBox != null && _parentBox.Boxes.Contains(this))
{
_parentBox.Boxes.Remove(this);
}
_parentBox = value;
//Add to new parent
if (value != null && !value.Boxes.Contains(this))
{
_parentBox.Boxes.Add(this);
_initialContainer = value.InitialContainer;
}
}
}
/// <summary>
/// Gets the linebox(es) that contains words of this box (if inline)
/// </summary>
internal List<CssLineBox> ParentLineBoxes
{
get { return _parentLineBoxes; }
}
/// <summary>
/// Gets the rectangles where this box should be painted
/// </summary>
internal Dictionary<CssLineBox, RectangleF> Rectangles
{
get
{
return _rectangles;
}
}
/// <summary>
/// Gets the right of the box. When setting, it will affect only the width of the box.
/// </summary>
public float ActualRight
{
get { return Location.X + Size.Width; }
set
{
Size = new SizeF(value - Location.X, Size.Height);
}
}
/// <summary>
/// Gets or sets the size of the box
/// </summary>
public SizeF Size
{
get { return _size; }
set { _size = value; }
}
/// <summary>
/// Gets or sets the inner text of the box
/// </summary>
public string Text
{
get { return _text; }
set { _text = value; UpdateWords(); }
}
/// <summary>
/// Gets the BoxWords of text in the box
/// </summary>
internal List<CssBoxWord> Words
{
get { return _boxWords; }
}
#endregion
#region Methods
/// <summary>
/// Sets the initial container of the box
/// </summary>
/// <param name="b"></param>
private void SetInitialContainer(InitialContainer b)
{
_initialContainer = b;
}
/// <summary>
/// Returns false if some of the boxes
/// </summary>
/// <returns></returns>
internal bool ContainsInlinesOnly()
{
foreach (CssBox b in Boxes)
{
if (b.Display != CssConstants.Inline)
{
return false;
}
}
return true;
}
/// <summary>
/// Gets the index of the box to be used on a (ordered) list
/// </summary>
/// <returns></returns>
private int GetIndexForList()
{
int index = 0;
foreach (CssBox b in ParentBox.Boxes)
{
if (b.Display == CssConstants.ListItem) index++;
if (b.Equals(this)) return index;
}
return index;
}
/// <summary>
/// Creates the <see cref="ListItemBox"/>
/// </summary>
/// <param name="g"></param>
private void CreateListItemBox(Graphics g)
{
if (Display == CssConstants.ListItem)
{
if (_listItemBox == null)
{
_listItemBox = new CssBox();
_listItemBox.InheritStyle(this, false);
_listItemBox.Display = CssConstants.Inline;
_listItemBox.SetInitialContainer(InitialContainer);
if (ParentBox != null && ListStyleType == CssConstants.Decimal)
{
_listItemBox.Text = GetIndexForList().ToString() + ".";
}
else
{
_listItemBox.Text = "�";
}
_listItemBox.MeasureBounds(g);
_listItemBox.Size = new SizeF(_listItemBox.Words[0].Width, _listItemBox.Words[0].Height);
}
_listItemBox.Words[0].Left = Location.X - _listItemBox.Size.Width - 5;
_listItemBox.Words[0].Top = Location.Y + ActualPaddingTop;// +FontAscent;
}
}
/// <summary>
/// Searches for the first word occourence inside the box, on the specified linebox
/// </summary>
/// <param name="b"></param>
/// <returns></returns>
internal CssBoxWord FirstWordOccourence(CssBox b, CssLineBox line)
{
if (b.Words.Count == 0 && b.Boxes.Count == 0)
{
return null;
}
if (b.Words.Count > 0)
{
foreach (CssBoxWord word in b.Words)
{
if (line.Words.Contains(word))
{
return word;
}
}
return null;
}
else
{
foreach (CssBox bb in b.Boxes)
{
CssBoxWord w = FirstWordOccourence(bb, line);
if (w != null)
{
return w;
}
}
return null;
}
}
/// <summary>
/// Gets the specified Attribute, returns string.Empty if no attribute specified
/// </summary>
/// <param name="attribute">Attribute to retrieve</param>
/// <returns>Attribute value or string.Empty if no attribute specified</returns>
internal string GetAttribute(string attribute)
{
return GetAttribute(attribute, string.Empty);
}
/// <summary>
/// Gets the value of the specified attribute of the source HTML tag.
/// </summary>
/// <param name="attribute">Attribute to retrieve</param>
/// <param name="defaultValue">Value to return if attribute is not specified</param>
/// <returns>Attribute value or defaultValue if no attribute specified</returns>
internal string GetAttribute(string attribute, string defaultValue)
{
if (HtmlTag == null)
{
return defaultValue;
}
if (!HtmlTag.HasAttribute(attribute))
{
return defaultValue;
}
return HtmlTag.Attributes[attribute];
}
/// <summary>
/// Gets the height of the font in the specified units
/// </summary>
/// <param name="unit"></param>
/// <returns></returns>
public float GetEmHeight()
{
//float res = Convert.ToSingle(ActualFont.Height);
//float res = ActualFont.Size * ActualFont.FontFamily.GetCellAscent(f.Style) / ActualFont.FontFamily.GetEmHeight(f.Style);
float res = ActualFont.GetHeight();
return res;
}
/// <summary>
/// Gets the previous sibling of this box.
/// </summary>
/// <returns>Box before this one on the tree. Null if its the first</returns>
private CssBox GetPreviousSibling(CssBox b)
{
if (b.ParentBox == null)
{
return null; //This is initial containing block
}
int index = b.ParentBox.Boxes.IndexOf(this);
if (index < 0) throw new Exception("Box doesn't exist on parent's Box list");
if (index == 0) return null; //This is the first sibling.
int diff = 1;
CssBox sib = b.ParentBox.Boxes[index - diff];
while ((sib.Display == CssConstants.None || sib.Position == CssConstants.Absolute) && index - diff - 1 >= 0)
{
sib = b.ParentBox.Boxes[index - ++diff];
}
return sib.Display == CssConstants.None ? null : sib;
}
/// <summary>
/// Gets the minimum width that the box can be.
/// The box can be as thin as the longest word plus padding.
/// The check is deep thru box tree.
/// </summary>
/// <returns></returns>
internal float GetMinimumWidth()
{
float maxw = 0f;
float padding = 0f;
CssBoxWord word = null;
GetMinimumWidth_LongestWord(this, ref maxw, ref word);
if (word != null)
{
GetMinimumWidth_BubblePadding(word.OwnerBox, this, ref padding);
}
return maxw + padding;
}
/// <summary>
/// Bubbles up the padding from the starting box
/// </summary>
/// <param name="box"></param>
/// <returns></returns>
private void GetMinimumWidth_BubblePadding(CssBox box, CssBox endbox, ref float sum)
{
//float padding = box.ActualMarginLeft + box.ActualBorderLeftWidth + box.ActualPaddingLeft +
// box.ActualMarginRight + box.ActualBorderRightWidth + box.ActualPaddingRight;
float padding = box.ActualBorderLeftWidth + box.ActualPaddingLeft +
box.ActualBorderRightWidth + box.ActualPaddingRight;
sum += padding;
if (!box.Equals(endbox))
{
GetMinimumWidth_BubblePadding(box.ParentBox, endbox, ref sum);
}
}
/// <summary>
/// Gets the longest word (in width) inside the box, deeply.
/// </summary>
/// <param name="b"></param>
/// <returns></returns>
private void GetMinimumWidth_LongestWord(CssBox b, ref float maxw, ref CssBoxWord word)
{
if (b.Words.Count > 0)
{
foreach (CssBoxWord w in b.Words)
{
if (w.FullWidth > maxw)
{
maxw = w.FullWidth;
word = w;
}
}
}
else
{
foreach(CssBox bb in b.Boxes)
GetMinimumWidth_LongestWord(bb, ref maxw,ref word);
}
}
/// <summary>
/// Gets the maximum bottom of the boxes inside the startBox
/// </summary>
/// <param name="startBox"></param>
/// <param name="currentMaxBottom"></param>
/// <returns></returns>
internal float GetMaximumBottom(CssBox startBox, float currentMaxBottom)
{
foreach (CssLineBox line in startBox.Rectangles.Keys)
{
currentMaxBottom = Math.Max(currentMaxBottom, startBox.Rectangles[line].Bottom);
}
foreach (CssBox b in startBox.Boxes)
{
currentMaxBottom = Math.Max(currentMaxBottom, b.ActualBottom);
currentMaxBottom = Math.Max(currentMaxBottom, GetMaximumBottom(b, currentMaxBottom));
}
return currentMaxBottom;
}
/// <summary>
/// Get the width of the box at full width (No line breaks)
/// </summary>
/// <returns></returns>
internal float GetFullWidth(Graphics g)
{
float sum = 0f;
float paddingsum = 0f;
GetFullWidth_WordsWith(this, g, ref sum, ref paddingsum);
return paddingsum + sum;
}
/// <summary>
/// Gets the longest word (in width) inside the box, deeply.
/// </summary>
/// <param name="b"></param>
/// <returns></returns>
private void GetFullWidth_WordsWith(CssBox b, Graphics g, ref float sum, ref float paddingsum)
{
if (b.Display != CssConstants.Inline)
{
sum = 0;
}
paddingsum += b.ActualBorderLeftWidth + b.ActualBorderRightWidth + b.ActualPaddingRight + b.ActualPaddingLeft;
if (b.Words.Count > 0)
{
foreach (CssBoxWord word in b.Words)
sum += word.FullWidth;
}
else
{
foreach (CssBox bb in b.Boxes)
{
GetFullWidth_WordsWith(bb, g, ref sum, ref paddingsum);
}
}
}
/// <summary>
/// Gets the next sibling of this box.
/// </summary>
/// <returns>Box after this one on the tree. Null if its the last one.</returns>
private CssBox GetNextSibling()
{
if (ParentBox == null)
{
return null; //This is initial containing block
}
int index = ParentBox.Boxes.IndexOf(this);
if (index < 0) throw new Exception("Box doesn't exist on parent's Box list");
if (index == ParentBox.Boxes.Count - 1) return null; //This is the last sibling
return ParentBox.Boxes[index + 1];
}
/// <summary>
/// Gets if this box has only inline siblings (including itself)
/// </summary>
/// <returns></returns>
internal bool HasJustInlineSiblings()
{
if (ParentBox == null)
{
return false;
}
return ParentBox.ContainsInlinesOnly();
}
/// <summary>
/// Gets the rectangles where inline box will be drawn. See Remarks for more info.
/// </summary>
/// <returns>Rectangles where content should be placed</returns>
/// <remarks>
/// Inline boxes can be splitted across different LineBoxes, that's why this method
/// Delivers a rectangle for each LineBox related to this box, if inline.
/// </remarks>
/// <summary>
/// Inherits inheritable values from parent.
/// </summary>
internal void InheritStyle()
{
InheritStyle(ParentBox, false);
}
/// <summary>
/// Inherits inheritable values from specified box.
/// </summary>
/// <param name="everything">Set to true to inherit all CSS properties instead of only the ineritables</param>
/// <param name="godfather">Box to inherit the properties</param>
internal void InheritStyle(CssBox godfather, bool everything)
{
if (godfather != null)
{
IEnumerable<PropertyInfo> pps = everything ? _cssproperties : _inheritables;
foreach (PropertyInfo prop in pps)
{
prop.SetValue(this,
prop.GetValue(godfather, null),
null);
}
}
}
/// <summary>
/// Gets the result of collapsing the vertical margins of the two boxes
/// </summary>
/// <param name="a">Superior box (checks for margin-bottom)</param>
/// <param name="b">Inferior box (checks for margin-top)</param>
/// <returns>Maximum of margins</returns>
private float MarginCollapse(CssBox a, CssBox b)
{
return Math.Max(
a == null ? 0 : a.ActualMarginBottom,
b == null ? 0 : b.ActualMarginTop);
}
/// <summary>
/// Measures the bounds of box and children, recursively.
/// </summary>
/// <param name="g">Device context to draw</param>
/// <param name="layoutRect">Rectangle containing the fragment</param>
public virtual void MeasureBounds(Graphics g)
{
if (Display == CssConstants.None) return;
RectanglesReset();
MeasureWordsSize(g);
if (Display == CssConstants.Block ||
Display == CssConstants.ListItem ||
Display == CssConstants.Table ||
Display == CssConstants.InlineTable ||
Display == CssConstants.TableCell ||
Display == CssConstants.None)
{
#region Measure Bounds
if (Display != CssConstants.TableCell)
{
CssBox prevSibling = GetPreviousSibling(this);
float left = ContainingBlock.Location.X + ContainingBlock.ActualPaddingLeft + ActualMarginLeft + ContainingBlock.ActualBorderLeftWidth;
float top =
(prevSibling == null && ParentBox != null ? ParentBox.ClientTop : 0) +
MarginCollapse(prevSibling, this) +
(prevSibling != null ? prevSibling.ActualBottom + prevSibling.ActualBorderBottomWidth : 0);
Location = new PointF(left, top);
ActualBottom = top;
}
if (Display != CssConstants.TableCell &&
Display != CssConstants.Table) //Because their width and height are set by CssTable
{
#region Set Width
//width at 100% (or auto)
float minwidth = GetMinimumWidth();
float width =
ContainingBlock.Size.Width
- ContainingBlock.ActualPaddingLeft - ContainingBlock.ActualPaddingRight
- ContainingBlock.ActualBorderLeftWidth - ContainingBlock.ActualBorderRightWidth
- ActualMarginLeft - ActualMarginRight - ActualBorderLeftWidth - ActualBorderRightWidth;
//Check width if not auto
if (Width != CssConstants.Auto && !string.IsNullOrEmpty(Width))
{
width = CssValue.ParseLength(Width, width, this);
}
if (width < minwidth) width = minwidth;
Size = new SizeF(width, Size.Height);
#endregion
}
//If we're talking about a table here..
if (Display == CssConstants.Table || Display == CssConstants.InlineTable)
{
CssTable tbl = new CssTable(this, g);
}
else if (Display != CssConstants.None)
{
//If there's just inlines, create LineBoxes
if (ContainsInlinesOnly())
{
ActualBottom = Location.Y;
CssLayoutEngine.CreateLineBoxes(g, this); //This will automatically set the bottom of this block
}
else
{
CssBox lastOne = null; // Boxes[Boxes.Count - 1];
//Treat as BlockBox
foreach (CssBox box in Boxes)
{
if (box.Display == CssConstants.None) continue;
//box.Display = CssConstants.Block; //Force to be block, according to CSS spec
box.MeasureBounds(g);
lastOne = box;
}
if (lastOne != null)
ActualBottom = Math.Max(ActualBottom, lastOne.ActualBottom + lastOne.ActualMarginBottom + ActualPaddingBottom);
}
}
#endregion
}
if (InitialContainer != null)
{
InitialContainer.MaximumSize = new SizeF(
Math.Max(InitialContainer.MaximumSize.Width, ActualRight),
Math.Max(InitialContainer.MaximumSize.Height, ActualBottom));
}
}
/// <summary>
/// Measures the word spacing
/// </summary>
/// <param name="g"></param>
private void MeasureWordSpacing(Graphics g)
{
_actualWordSpacing = CssLayoutEngine.WhiteSpace(g, this);
if (WordSpacing != CssConstants.Normal)
{
string len = Parser.Search(Parser.CssLength, WordSpacing);
_actualWordSpacing += CssValue.ParseLength(len, 1, this);
}
}
/// <summary>
/// Assigns words its width and height
/// </summary>
/// <param name="g"></param>
internal void MeasureWordsSize(Graphics g)
{
if (_wordsSizeMeasured) return;
//Measure white space if not yet done
if (float.IsNaN(_actualWordSpacing))
MeasureWordSpacing(g);
if (HtmlTag != null && HtmlTag.TagName.Equals("img", StringComparison.CurrentCultureIgnoreCase))
{
#region Measure image
CssBoxWord word = new CssBoxWord(this, CssValue.GetImage(GetAttribute("src")));
Words.Clear();
Words.Add(word);
#endregion
}
else
{
#region Measure text words
bool lastWasSpace = false;
foreach (CssBoxWord b in Words)
{
bool collapse = CssBoxWordSplitter.CollapsesWhiteSpaces(this);
if (CssBoxWordSplitter.EliminatesLineBreaks(this)) b.ReplaceLineBreaksAndTabs();
if (b.IsSpaces)
{
b.Height = FontLineSpacing;
if (b.IsTab)
{
b.Width = ActualWordSpacing * 4; //TODO: Configure tab size
}
else if (b.IsLineBreak)
{
b.Width = 0;
}
else
{
if (!(lastWasSpace && collapse))
{
b.Width = ActualWordSpacing * (collapse ? 1 : b.Text.Length);
}
}
lastWasSpace = true;
}
else
{
string word = b.Text;
CharacterRange[] measurable = { new CharacterRange(0, word.Length) };
StringFormat sf = new StringFormat();
sf.SetMeasurableCharacterRanges(measurable);
Region[] regions = g.MeasureCharacterRanges(word, ActualFont,
new RectangleF(0, 0, float.MaxValue, float.MaxValue),
sf);
SizeF s = regions[0].GetBounds(g).Size;
PointF p = regions[0].GetBounds(g).Location;
b.LastMeasureOffset = new PointF(p.X, p.Y);
b.Width = s.Width;// +p.X;
b.Height = s.Height;// +p.Y;
lastWasSpace = false;
}
}
#endregion
}
_wordsSizeMeasured = true;
}
/// <summary>
/// Ensures that the specified length is converted to pixels if necessary
/// </summary>
/// <param name="length"></param>
private string NoEms(string length)
{
CssLength len = new CssLength(length);
if (len.Unit == CssLength.CssUnit.Ems)
{
length = len.ConvertEmToPixels(GetEmHeight()).ToString();
}
return length;
}
/// <summary>
/// Deeply offsets the top of the box and its contents
/// </summary>
/// <param name="amount"></param>
internal void OffsetTop(float amount)
{
List<CssLineBox> lines = new List<CssLineBox>();
foreach (CssLineBox line in Rectangles.Keys)
lines.Add(line);
foreach (CssLineBox line in lines)
{
RectangleF r = Rectangles[line];
Rectangles[line] = new RectangleF(r.X, r.Y + amount, r.Width, r.Height);
}
foreach (CssBoxWord word in Words)
{
word.Top += amount;
}
foreach (CssBox b in Boxes)
{
b.OffsetTop(amount);
}
//TODO: Aqu� me quede: no se mueve bien todo (probar con las tablas rojas)
Location = new PointF(Location.X, Location.Y + amount);
}
/// <summary>
/// Paints the fragment
/// </summary>
/// <param name="g"></param>
public void Paint(Graphics g)
{
if (Display == CssConstants.None)
return;
if (Display == CssConstants.TableCell &&
EmptyCells == CssConstants.Hide &&
IsSpaceOrEmpty)
return;
List<RectangleF> areas = Rectangles.Count == 0 ?
new List<RectangleF>(new RectangleF[] { Bounds }) :
new List<RectangleF>(Rectangles.Values);
RectangleF[] rects = areas.ToArray();
PointF offset = InitialContainer != null ? InitialContainer.ScrollOffset : PointF.Empty;
for (int i = 0; i < rects.Length; i++)
{
RectangleF actualRect = rects[i]; actualRect.Offset(offset);
if (InitialContainer != null && HtmlTag != null && HtmlTag.TagName.Equals("a", StringComparison.CurrentCultureIgnoreCase))
{
if (InitialContainer.LinkRegions.ContainsKey(this)) InitialContainer.LinkRegions.Remove(this);
InitialContainer.LinkRegions.Add(this, actualRect);
}
PaintBackground(g, actualRect);
PaintBorder(g, actualRect, i == 0, i == rects.Length - 1);
}
if (IsImage)
{
RectangleF r = Words[0].Bounds; r.Offset(offset);
r.Height -= ActualBorderTopWidth + ActualBorderBottomWidth + ActualPaddingTop + ActualPaddingBottom;
r.Y += ActualBorderTopWidth + ActualPaddingTop;
//HACK: round rectangle only when necessary
g.DrawImage(Words[0].Image, Rectangle.Round(r));
}
else
{
Font f = ActualFont;
using (SolidBrush b = new SolidBrush(CssValue.GetActualColor(Color)))
{
foreach (CssBoxWord word in Words)
{
g.DrawString(word.Text, f, b, word.Left - word.LastMeasureOffset.X + offset.X, word.Top + offset.Y);
}
}
}
for (int i = 0; i < rects.Length; i++)
{
RectangleF actualRect = rects[i]; actualRect.Offset(offset);
PaintDecoration(g, actualRect, i == 0, i == rects.Length - 1);
}
foreach (CssBox b in Boxes)
{
b.Paint(g);
}
CreateListItemBox(g);
if (ListItemBox != null)
{
ListItemBox.Paint(g);
}
}
/// <summary>
/// Paints the border of the box
/// </summary>
/// <param name="g"></param>
private void PaintBorder(Graphics g, RectangleF rectangle, bool isFirst, bool isLast)
{
SmoothingMode smooth = g.SmoothingMode;
if (InitialContainer != null && !InitialContainer.AvoidGeometryAntialias && IsRounded)
{
g.SmoothingMode = SmoothingMode.AntiAlias;
}
//Top border
if (!(string.IsNullOrEmpty(BorderTopStyle) || BorderTopStyle == CssConstants.None))
{
using (SolidBrush b = new SolidBrush(ActualBorderTopColor))
{
if (BorderTopStyle == CssConstants.Inset) b.Color = CssDrawingHelper.Darken(ActualBorderTopColor);
g.FillPath(b, CssDrawingHelper.GetBorderPath(CssDrawingHelper.Border.Top, this, rectangle, isFirst, isLast));
}
}
if (isLast)
{
//Right Border
if (!(string.IsNullOrEmpty(BorderRightStyle) || BorderRightStyle == CssConstants.None))
{
using (SolidBrush b = new SolidBrush(ActualBorderRightColor))
{
if (BorderRightStyle == CssConstants.Outset) b.Color = CssDrawingHelper.Darken(ActualBorderRightColor);
g.FillPath(b, CssDrawingHelper.GetBorderPath(CssDrawingHelper.Border.Right, this, rectangle, isFirst, isLast));
}
}
}
//Bottom border
if (!(string.IsNullOrEmpty(BorderBottomStyle) || BorderBottomStyle == CssConstants.None))
{
using (SolidBrush b = new SolidBrush(ActualBorderBottomColor))
{
if (BorderBottomStyle == CssConstants.Outset) b.Color = CssDrawingHelper.Darken(ActualBorderBottomColor);
g.FillPath(b, CssDrawingHelper.GetBorderPath(CssDrawingHelper.Border.Bottom, this, rectangle, isFirst, isLast));
}
}
if (isFirst)
{
//Left Border
if (!(string.IsNullOrEmpty(BorderLeftStyle) || BorderLeftStyle == CssConstants.None))
{
using (SolidBrush b = new SolidBrush(ActualBorderLeftColor))
{
if (BorderLeftStyle == CssConstants.Inset) b.Color = CssDrawingHelper.Darken(ActualBorderLeftColor);
g.FillPath(b, CssDrawingHelper.GetBorderPath(CssDrawingHelper.Border.Left, this, rectangle, isFirst, isLast));
}
}
}
g.SmoothingMode = smooth;
}
/// <summary>
/// Paints the background of the box
/// </summary>
/// <param name="g"></param>
private void PaintBackground(Graphics g, RectangleF rectangle)
{
//HACK: Background rectangles are being deactivated when justifying text.
if (ContainingBlock.TextAlign == CssConstants.Justify) return;
GraphicsPath roundrect = null;
Brush b = null;
SmoothingMode smooth = g.SmoothingMode;
if (IsRounded)
{
roundrect = CssDrawingHelper.GetRoundRect(rectangle, ActualCornerNW, ActualCornerNE, ActualCornerSE, ActualCornerSW);
}
if (BackgroundGradient != CssConstants.None)
{
b = new LinearGradientBrush(rectangle, ActualBackgroundColor, ActualBackgroundGradient, ActualBackgroundGradientAngle);
}
else
{
b = new SolidBrush(ActualBackgroundColor);
}
if (InitialContainer != null && !InitialContainer.AvoidGeometryAntialias && IsRounded)
{
g.SmoothingMode = SmoothingMode.AntiAlias;
}
if (roundrect != null)
{
g.FillPath(b, roundrect);
}
else
{
g.FillRectangle(b, rectangle);
}
g.SmoothingMode = smooth;
if (roundrect != null) roundrect.Dispose();
if (b != null) b.Dispose();
}
/// <summary>
/// Paints the text decoration
/// </summary>
/// <param name="g"></param>
private void PaintDecoration(Graphics g, RectangleF rectangle, bool isFirst, bool isLast)
{
if (string.IsNullOrEmpty(TextDecoration) || TextDecoration == CssConstants.None || IsImage) return;
float desc = CssLayoutEngine.GetDescent(ActualFont);
float asc = CssLayoutEngine.GetAscent(ActualFont);
float y = 0f;
if (TextDecoration == CssConstants.Underline)
{
y = rectangle.Bottom - desc;
}
else if (TextDecoration == CssConstants.LineThrough)
{
y = rectangle.Bottom - desc - asc / 2;
}
else if (TextDecoration == CssConstants.Overline)
{
y = rectangle.Bottom - desc - asc - 2;
}
y -= ActualPaddingBottom - ActualBorderBottomWidth;
float x1 = rectangle.X;
float x2 = rectangle.Right;
if (isFirst) x1 += ActualPaddingLeft + ActualBorderLeftWidth;
if (isLast) x2 -= ActualPaddingRight + ActualBorderRightWidth;
g.DrawLine(new Pen(ActualColor), x1, y, x2, y);
}
/// <summary>
/// Offsets the rectangle of the specified linebox by the specified gap,
/// and goes deep for rectangles of children in that linebox.
/// </summary>
/// <param name="lineBox"></param>
/// <param name="gap"></param>
internal void OffsetRectangle(CssLineBox lineBox, float gap)
{
if (Rectangles.ContainsKey(lineBox))
{
RectangleF r = Rectangles[lineBox];
Rectangles[lineBox] = new RectangleF(r.X, r.Y + gap, r.Width, r.Height);
}
//foreach (Box b in Boxes)
//{
// b.OffsetRectangle(lineBox, gap);
//}
}
/// <summary>
/// Resets the <see cref="Rectangles"/> array
/// </summary>
internal void RectanglesReset()
{
_rectangles.Clear();
}
/// <summary>
/// Removes boxes that are just blank spaces
/// </summary>
internal void RemoveAnonymousSpaces()
{
for (int i = 0; i < Boxes.Count; i++)
{
if (Boxes[i] is CssAnonymousSpaceBlockBox || Boxes[i] is CssAnonymousSpaceBox)
{
Boxes.RemoveAt(i);
i--;
}
}
}
/// <summary>
/// Sets the bounds of the box
/// </summary>
/// <param name="r"></param>
public void SetBounds(Rectangle r)
{
SetBounds(new RectangleF(r.X, r.Y, r.Width, r.Height));
}
/// <summary>
/// Sets the bounds of the box
/// </summary>
/// <param name="rectangle"></param>
public void SetBounds(RectangleF rectangle)
{
Size = rectangle.Size;
Location = rectangle.Location;
}
/// <summary>
/// ToString override.
/// </summary>
/// <returns></returns>
public override string ToString()
{
string t = GetType().Name;
if (HtmlTag != null)
{
t = string.Format("<{0}>", HtmlTag.TagName);
}
if (ParentBox == null)
{
return "Initial Container";
}
else if (Display == CssConstants.Block)
{
return string.Format("{0} BlockBox {2}, Children:{1}",t, Boxes.Count, FontSize);
}
else if (Display == CssConstants.None)
{
return string.Format("{0} None", t);
}
else
{
return string.Format("{0} {2}: {1}", t, Text, Display);
}
//return base.ToString();
}
/// <summary>
/// Splits the text into words and saves the result
/// </summary>
private void UpdateWords()
{
Words.Clear();
CssBoxWordSplitter splitter = new CssBoxWordSplitter(this, Text);
splitter.SplitWords();
Words.AddRange(splitter.Words);
}
#endregion
}
}