// 处理一个矩形区域 int DoRect( Graphics g, XmlNode nodeContainer, RectParam rect_def, bool bRemainPage, Hashtable macro_table, RectGroup rect_group, ref List<Page> pages, out string strError) { strError = ""; int nRet = 0; Padding padding = new Padding(0, 0, 0, 0); string strPadding = DomUtil.GetAttr(nodeContainer, "padding"); if (String.IsNullOrEmpty(strPadding) == false) { nRet = GetPadding(strPadding, out padding, out strError); if (nRet == -1) { strError = "元素<" + nodeContainer.Name + ">中padding属性值 '" + strPadding + "' 格式错误: " + strError; return -1; } } rect_def.Padding = padding; List<PrintLine> lines = new List<PrintLine>(); // 将一个容器元素下级的全部内容切割为Line数组 nRet = Process(g, rect_def, nodeContainer, macro_table, rect_group, ref lines, out strError); if (nRet == -1) return -1; SetLastLine(lines); // 组装到Page中 int iPage = 0; Page current_page = null; if (pages.Count > iPage) current_page = pages[iPage]; else { current_page = new Page(); pages.Add(current_page); } float current_height = 0; for (int i = 0; i < lines.Count; i++) { PrintLine line = lines[i]; if (current_height + line.Height > rect_def.Height - rect_def.Padding.Vertical && current_page.Lines.Count > 0 // 至少有一个行 && bRemainPage == false) { // 新增一页 current_height = 0; iPage++; if (pages.Count > iPage) current_page = pages[iPage]; else { current_page = new Page(); pages.Add(current_page); } } // line.X += rect_def.X + rect_def.Padding.Left; line.Y += rect_def.Y + rect_def.Padding.Top + current_height; current_page.Lines.Add(line); current_height += line.Height; } return iPage; }
// parameters: // state ParagraphFirst 是否为首次处理一个<p> int Process( Graphics g, RectParam rect_def, XmlNode node, Hashtable macro_table, RectGroup rect_group, ref List<PrintLine> lines, out string strError) { strError = ""; int nRet = 0; if (node.NodeType == XmlNodeType.Element && node.Name == "br") { SetLastLine(lines); Color color; Font font = GetNodeFont(node, out color); ParagraphFormat format = GetNodeParagraphFormat(node); try { nRet = BuildLines(g, rect_def, "\r\n", font, color, format, ref lines, out strError); if (nRet == -1) return -1; } finally { font.Dispose(); } return 0; } int nStartLines = lines.Count; int nLinesLimit = -1; ParagraphGroup p_group = null; // <p>的开头,触发一下换行 if (node.NodeType == XmlNodeType.Element && node.Name == "p") { SetLastLine(lines); Color color; Font font = GetNodeFont(node, out color); ParagraphFormat format = GetNodeParagraphFormat(node); nLinesLimit = (int)format.MaxLines; p_group = new ParagraphGroup(); p_group.Format = format; rect_group.Paragraphs.Add(p_group); try { nRet = BuildLines(g, rect_def, null, font, color, format, ref lines, out strError); if (nRet == -1) return -1; } finally { font.Dispose(); } } for (int i = 0; i < node.ChildNodes.Count; i++) { XmlNode child = node.ChildNodes[i]; if (child.NodeType == XmlNodeType.Text) { string strText = child.Value; strText = strText.Replace("\n", "\r"); strText = strText.Replace("\r", ""); if (macro_table != null) { strText = StringUtil.MacroString(macro_table, strText); } Color color; Font font = GetNodeFont(node, out color); ParagraphFormat format = GetNodeParagraphFormat(node); try { nRet = BuildLines(g, rect_def, strText, font, color, format, ref lines, out strError); if (nRet == -1) return -1; } finally { font.Dispose(); } } if (child.NodeType == XmlNodeType.Element) { int x_delta = 0; int y_delta = 0; RectParam current_rect_def = rect_def; if (child.Name == "p") { // 2012/4/23 // 让<p>的padding属性起作用 ParagraphFormat format = GetNodeParagraphFormat(child); current_rect_def = new RectParam(rect_def); current_rect_def.Padding = AddPadding(current_rect_def.Padding, format.Padding); x_delta = format.Padding.Left; y_delta = format.Padding.Top; } int nStartLine = 0; if (lines != null) nStartLine = lines.Count; nRet = Process( g, current_rect_def, child, macro_table, rect_group, ref lines, out strError); if (nRet == -1) return -1; // 对新增的行进行平移 if (x_delta != 0 || y_delta != 0) { for (int j = nStartLine; j < lines.Count; j++) { PrintLine line = lines[j]; // line.X += x_delta; line.Y += y_delta; } } } } // 删除多余的行 if (nLinesLimit != -1) { // TODO 如果发生切断,是不是最后要加... ? while (lines.Count > nStartLines + nLinesLimit) { lines.RemoveAt(lines.Count - 1); } } if (p_group != null) { for (int i = nStartLines; i < lines.Count; i++) { p_group.Lines.Add(lines[i]); } } return 0; }
// parameters: // height 分页以前的单页允许高度 // bIsHeaderFooter 是否保持不增加page int DoColumns( Graphics g, XmlNode nodeDocument, float x, float y, float width, float height, bool bIsHeaderFooter, Hashtable macro_table, string strHeaderCondition, ref List<Page> pages, out string strError) { strError = ""; List<RectParam> rects = new List<RectParam>(); // 列出根下面的<Column>元素 XmlNodeList nodes = nodeDocument.SelectNodes("column"); for (int i = 0; i < nodes.Count; i++) { XmlNode node = nodes[i]; // 获得矩形参数 RectParam rect = new RectParam(); rect.WidthString = DomUtil.GetAttr(node, "width"); rects.Add(rect); } // 分配宽度。固定宽度剩下以后的,就是auto的平分 float rest = width; // 剩下的宽度 // 1) 处理数字宽度 int nAutoCount = 0; for (int i = 0; i < rects.Count; i++) { RectParam rect = rects[i]; string strWidth = rect.WidthString; if (StringUtil.IsPureNumber(strWidth) == true) { rect.Width = (float)Convert.ToDouble(strWidth); rest -= rect.Width; } else { if (string.Compare(strWidth, "auto", true) != 0) { strError = "<column>元素的width属性值 '"+strWidth+"' 格式错误"; return -1; } rect.Width = -1; nAutoCount++; } } // 2) 处理auto宽度 if (nAutoCount > 0) { float nAverWidth = rest / nAutoCount; if (nAverWidth < 0) nAverWidth = 0; for (int i = 0; i < rects.Count; i++) { RectParam rect = rects[i]; if (rect.Width == -1) rect.Width = nAverWidth; } } // 3)填充 X Y Height float start_x = x; for (int i = 0; i < rects.Count; i++) { RectParam rect = rects[i]; rect.X = start_x; start_x += rect.Width; rect.Y = y; rect.Height = height; // 一页内最大高度 } List<RectGroup> rect_groups = new List<RectGroup>(); for (int i = 0; i < nodes.Count; i++) { XmlNode node = nodes[i]; if (bIsHeaderFooter == true) { string strStyle = DomUtil.GetAttr(node, "style"); if (StringUtil.IsInList("hidewhenonepage", strStyle) == true && StringUtil.IsInList("onlyonepage", strHeaderCondition) == true) continue; if (StringUtil.IsInList("hidewhenfirstpage", strStyle) == true && StringUtil.IsInList("firstpage", strHeaderCondition) == true) continue; if (StringUtil.IsInList("hidewhentailpage", strStyle) == true && StringUtil.IsInList("tailpage", strHeaderCondition) == true) continue; } // 获得矩形参数 RectParam rect = rects[i]; RectGroup rect_group = new RectGroup(); rect_groups.Add(rect_group); int nRet = DoRect( g, node, rect, bIsHeaderFooter, macro_table, rect_group, ref pages, out strError); if (nRet == -1) return -1; } if (bIsHeaderFooter == false) { // 处理valign=bottom的<p> for (int i = 0; i < nodes.Count; i++) { XmlNode node = nodes[i]; // 获得矩形参数 RectParam rect = rects[i]; RectGroup rect_group = rect_groups[i]; for (int j = rect_group.Paragraphs.Count - 1; j >= 0; j--) { ParagraphGroup p_group = rect_group.Paragraphs[j]; if (p_group.Format.VertAlign == "bottom") { ResetLines(pages, rect, p_group.Lines); } else break; // 只要中间不连续,就中断 } } } return 0; }