/// <summary>
/// Performs a parsing pass over a tbody to read information about column width and rowspan attributes. Information read about width
/// attributes is stored in the reference ArrayList parameter columnStarts, which contains a list of all starting
/// positions of all columns in the table, ordered from left to right. Row spans are taken into consideration when
/// computing column starts
/// </summary>
/// <param name="htmlTbodyElement">
/// XmlElement representing Html tbody whose structure is to be analyzed
/// </param>
/// <param name="columnStarts">
/// ArrayList of type double which contains the function output. If analysis fails, this parameter is set to null
/// </param>
/// <param name="tableWidth">
/// Current width of the table. This is used to determine if a new column when added to the end of table should
/// come after the last column in the table or is actually splitting the last column in two. If it is only splitting
/// the last column it should inherit row span for that column
/// </param>
/// <returns>
/// Calculated width of a tbody.
/// In case of non-analizable column width structure return 0;
/// </returns>
private static double AnalyzeTbodyStructure(XmlElement htmlTbodyElement, IList columnStarts, IList activeRowSpans, double tableWidth, CssStylesheet stylesheet)
{
// Parameter validation
Debug.Assert(htmlTbodyElement.LocalName.ToLower() == "tbody");
Debug.Assert(columnStarts != null);
double tbodyWidth = 0;
bool columnWidthsAvailable = true;
if (!htmlTbodyElement.HasChildNodes())
{
return tbodyWidth;
}
// Set active row spans to 0 - thus ignoring row spans crossing tbody boundaries
ClearActiveRowSpans(activeRowSpans);
IXmlNode htmlChildNode = htmlTbodyElement.FirstChild;
// Analyze tr elements
while (htmlChildNode != null && columnWidthsAvailable)
{
switch (htmlChildNode.LocalName.ToLower())
{
case "tr":
double trWidth = AnalyzeTRStructure((XmlElement)htmlChildNode, columnStarts, activeRowSpans, tbodyWidth, stylesheet);
if (trWidth > tbodyWidth)
{
tbodyWidth = trWidth;
}
break;
case "td":
columnWidthsAvailable = false; // interrupt the analisys
break;
default:
break;
}
htmlChildNode = htmlChildNode.NextSibling;
}
// Set active row spans to 0 - thus ignoring row spans crossing tbody boundaries
ClearActiveRowSpans(activeRowSpans);
return columnWidthsAvailable ? tbodyWidth : 0;
}