public override string render()
        {
            StringBuilder result = new StringBuilder();

            // validate borders for each cell.
            // (borders may be changed because of cell merging)
            validateAllMergedCellBorders();
            // set default char format for each cell.
            if (_defaultCharFormat != null)
            {
                for (int i = 0; i < _rowCount; i++)
                {
                    for (int j = 0; j < _colCount; j++)
                    {
                        if (_cells[i][j].IsMerged &&
                            _cells[i][j].MergeInfo.Representative != _cells[i][j])
                        {
                            continue;
                        }
                        if (_cells[i][j].DefaultCharFormat != null)
                        {
                            _cells[i][j].DefaultCharFormat.copyFrom(_defaultCharFormat);
                        }
                    }
                }
            }

            float topMargin = _margins[Direction.Top] - _fontSize;

            if (_startNewPage || topMargin > 0)
            {
                result.Append(@"{\pard");
                if (_startNewPage)
                {
                    result.Append(@"\pagebb");
                }
                if (_margins[Direction.Top] >= 0)
                {
                    result.Append(@"\sl-" + RtfUtility.pt2Twip(topMargin));
                }
                else
                {
                    result.Append(@"\sl-1");
                }
                result.AppendLine(@"\slmult0\par}");
            }

            int colAcc;

            for (int i = 0; i < _rowCount; i++)
            {
                colAcc = 0;
                result.Append(@"{\trowd\trgaph" +
                              string.Format(@"\trpaddl{0}\trpaddt{1}\trpaddr{2}\trpaddb{3}",
                                            RtfUtility.pt2Twip(CellPadding[i][Direction.Left]),
                                            RtfUtility.pt2Twip(CellPadding[i][Direction.Top]),
                                            RtfUtility.pt2Twip(CellPadding[i][Direction.Right]),
                                            RtfUtility.pt2Twip(CellPadding[i][Direction.Bottom])));
                switch (_alignment)
                {
                case Align.Left:
                    result.Append(@"\trql");
                    break;

                case Align.Right:
                    result.Append(@"\trqr");
                    break;

                case Align.Center:
                    result.Append(@"\trqc");
                    break;

                case Align.FullyJustify:
                    result.Append(@"\trqj");
                    break;
                }
                result.AppendLine();
                if (_margins[Direction.Left] >= 0)
                {
                    result.AppendLine(@"\trleft" + RtfUtility.pt2Twip(_margins[Direction.Left]));
                    colAcc = RtfUtility.pt2Twip(_margins[Direction.Left]);
                }
                if (_rowHeight[i] > 0)
                {
                    result.Append(@"\trrh" + RtfUtility.pt2Twip(_rowHeight[i]));
                }
                if (_rowKeepInSamePage[i])
                {
                    result.Append(@"\trkeep");
                }
                if (i < _titleRowCount)
                {
                    result.Append(@"\trhdr");
                }
                result.AppendLine();

                for (int j = 0; j < _colCount; j++)
                {
                    if (_cells[i][j].IsMerged && !_cells[i][j].IsBeginOfColSpan)
                    {
                        continue;
                    }
                    float nextCellLeftBorderClearance = j < _colCount - 1 ? cell(i, j + 1).OuterLeftBorderClearance : 0;
                    colAcc += RtfUtility.pt2Twip(cell(i, j).Width);
                    int colRightPos = colAcc;
                    if (nextCellLeftBorderClearance < 0)
                    {
                        colRightPos += RtfUtility.pt2Twip(nextCellLeftBorderClearance);
                        colRightPos  = colRightPos == 0 ? 1 : colRightPos;
                    }

                    // Borders
                    for (Direction d = Direction.Top; d <= Direction.Left; d++)
                    {
                        Border bdr = cell(i, j).Borders[d];
                        if (bdr.Style != BorderStyle.None)
                        {
                            result.Append(@"\clbrdr");
                            switch (d)
                            {
                            case Direction.Top:
                                result.Append("t");
                                break;

                            case Direction.Right:
                                result.Append("r");
                                break;

                            case Direction.Bottom:
                                result.Append("b");
                                break;

                            case Direction.Left:
                                result.Append("l");
                                break;
                            }
                            result.Append(@"\brdrw" + RtfUtility.pt2Twip(bdr.Width));
                            result.Append(@"\brdr");
                            switch (bdr.Style)
                            {
                            case BorderStyle.Single:
                                result.Append("s");
                                break;

                            case BorderStyle.Dotted:
                                result.Append("dot");
                                break;

                            case BorderStyle.Dashed:
                                result.Append("dash");
                                break;

                            case BorderStyle.Double:
                                result.Append("db");
                                break;

                            default:
                                throw new Exception("Unkown border style");
                            }
                            result.Append(@"\brdrcf" + bdr.Color.Value);
                        }
                    }

                    // Cell background colour
                    if (cell(i, j).BackgroundColour != null)
                    {
                        result.Append(string.Format(@"\clcbpat{0}", cell(i, j).BackgroundColour.Value));                                      // cell.BackGroundColor overrides others
                    }
                    else if (i == 0 && HeaderBackgroundColour != null)
                    {
                        result.Append(string.Format(@"\clcbpat{0}", HeaderBackgroundColour.Value));                                                // header
                    }
                    else if (RowBackgroundColour != null && (RowAltBackgroundColour == null || i % 2 == 0))
                    {
                        result.Append(string.Format(@"\clcbpat{0}", RowBackgroundColour.Value));                                                                                     // row colour
                    }
                    else if (RowBackgroundColour != null && RowAltBackgroundColour != null && i % 2 != 0)
                    {
                        result.Append(string.Format(@"\clcbpat{0}", RowAltBackgroundColour.Value));                                                                                   // alt row colour
                    }
                    if (_cells[i][j].IsMerged && _cells[i][j].MergeInfo.RowSpan > 1)
                    {
                        if (_cells[i][j].IsBeginOfRowSpan)
                        {
                            result.Append(@"\clvmgf");
                        }
                        else
                        {
                            result.Append(@"\clvmrg");
                        }
                    }
                    switch (_cells[i][j].AlignmentVertical)
                    {
                    case AlignVertical.Top:
                        result.Append(@"\clvertalt");
                        break;

                    case AlignVertical.Middle:
                        result.Append(@"\clvertalc");
                        break;

                    case AlignVertical.Bottom:
                        result.Append(@"\clvertalb");
                        break;
                    }
                    result.AppendLine(@"\cellx" + colRightPos);
                }

                for (int j = 0; j < _colCount; j++)
                {
                    if (!_cells[i][j].IsMerged || _cells[i][j].IsBeginOfColSpan)
                    {
                        result.Append(_cells[i][j].render());
                    }
                }

                result.AppendLine(@"\row}");
            }

            if (_margins[Direction.Bottom] >= 0)
            {
                result.Append(@"\sl-" + RtfUtility.pt2Twip(_margins[Direction.Bottom]) + @"\slmult");
            }

            return(result.ToString());
        }
        /// <summary>
        /// Indirect use only.
        /// See if two borders are equal.
        /// </summary>
        /// <param name="obj">Border object to be compared with.</param>
        /// <returns>True if the two borders are equal; false otherwise.</returns>
        public override bool Equals(object obj)
        {
            Border bdr = (Border)obj;

            return(this.Style == bdr.Style && this.Width == bdr.Width);
        }