unit DTPAdvancedRanges; interface uses DTPPrimitiveRanges, DTPUtils, DTPModules, SharedML, DocxML, DrawingMLUnitDecorator, DocxMLUnitDecorator; type RangeCollection = class(BasicRange) public function Create(); function Do();override; function Add(range: BasicRange); private range_array_: array of BasicRange; end; type ParagraphLineRange = class(BasicRange) public function Create(pg: Page); function Do();override; function AddRange(range: BasicRange); function SetAllRangeProp(pg: Page; sx: real; sy: real; ex: real; ey: real; w: real; fh: real; dh: real); function Align(jc: string); function AdjustRangeOffset(pg: Page; x_offset: real; y_offset: real); function AlignRightBound(right_bound: real); function Offset(x_offset: real; y_offset; real); private range_array_: array of BasicRange; end; type ParagraphRange = class(BasicRange) public function Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule; paragraph: P); function Calc(); function Do();override; function SetTblStyleIdAndType(style_id: string; type: string); function SetNumPages(num: integer); function RangesToLines(); function GetLastPage(): Page; function AdjustRangeOffset(pg: Page; x_offset: real; y_offset: real); function GetParagraphLineRangeArr(): array of ParagraphLineRange; function Empty(): boolean; function Offset(x: real; y: real); private function SetPPPr(var p: P); function SetPPrByStyleId(var ppr: PPr; style_id: string); function SetRRPr(var r: R; ppr_unit_decorator: PPrUnitDecorator); function SetRPrByStyleId(var rpr: RPr; style_id: string); function SetRPrByTblStyleId(var rpr: RPr; style_id: string); function SetLvlText(); function GetImageFileType(data: binary): string; function GetImageData(id: string): PdfImage; function GetParagraphLineSpace(size: real; line: integer; line_rule: string): real; function BasicRangesToParagraphLineRange(): tableArray; function UpdateTextRangeWidth(); function CheckAndAddPage(y: real; offset: real): boolean; function SplitTextToTextRange(range_arr: array of BasicRange; text: string; rpr: RPrUnitDecorator; link: string); function RAlternateContent(r: R); function RDrawing(r: R); function RFldChar(r: R; stack: Stack); function RFootnoteReference(r: R); function RFootnoteRef(r: R); function RObject(r: R); function RT(r: R; link: string); function FldSimple(fld_simple: FldSimple); function Hyperlink(hyperlink: Hyperlink); function SetLinesAlignment(); function ResetCoordinates(); function NewParagraphLineRange(): ParagraphLineRange; function BookMarkLinkToc(); function HyperlinkToToc(); function HyperlinkToTextRange(hyperlink: Hyperlink; ppr: PPrUnitDecorator); function GetXYCordinates(): array of real; function AlignRightBound(); function Init(); function OMathPara(element: OMathPara); private [weakref]docx_to_pdf_: TSDocxToPdf; [weakref]docx_components_module_: DocxComponentsModule; [weakref]paragraph_: P; [weakref]page_: Page; body_range_array_: array of BasicRange; // 正文的range bullet_range_array_: array of BasicRange; // 项目符号的range line_range_array_: array of ParagraphLineRange; hyperlink_array_: tableArray; bookmark_array_: tableArray; ppr_unit_decorator_: PPrUnitDecorator; placeholder_array_: tableArray; table_style_id_: string; table_style_type_: string; empty_: boolean; right_bound_: real; footnote_reference_hash_: hash; end; type TableRange = class(BasicRange) public function Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule; table: Tbl); function Do();override; function Calc(); function GetLastPage(): Page; function Rows(): integer; function Cols(): integer; function RowLowerBound(row: integer): real; private function CreateTableMatrix(grid_cols: array of GridColUnitDecorator; trs: array of Tr); function ComputeMatrixCells(); function ResetCoordinates(tbl_pr: TblPrUnitDecorator; grid_cols: array of GridCol); function SetTblTblPr(var table: Tbl); function SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string); function SetTrTrPr(var tr_pr: TrPr); function SetTrPrByStyleId(var tr_pr: TrPr; style_id: string); function SetTcTcPr(var tc: Tc); function SetTcPrByStyleId(var tc_pr: TcPr; style_id: string); function OverrideTcPrByTblStylePrType(var tc_pr: TcPr; type: string); private [weakref]docx_to_pdf_: TSDocxToPdf; [weakref]last_page_: Page; [weakref]docx_components_module_: DocxComponentsModule; [weakref]table_: Tbl; tbl_pr_unit_decorator_: TblPrUnitDecorator; ts_trpr_array_: array of TSTrProperty; cell_range_matrix_: array of CellRange; row_lower_bound_: hash; rows_: integer; cols_: integer; end; type CellRange = class(BasicRange) public function Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule; tc: Tc; tbl_pr: TblPr; trp: TSTrProperty); function Calc(); function Do();override; function SetPage(pg: Page); function GetLastPage(); function AlignHeight(height: real; lb: real); function SetVAlign(); function IsReComputeByCantSplit(): boolean; function IfRemoveEmptyRectangle(): boolean; function SetTop(); property Tc read tc_; private function GetCellPrType(): string; function SetBorderRange(range: BordersRange); public RemoveFlag: boolean; Row: integer; Col: integer; VMerge: integer; [weakref]TSTrPr: TSTrProperty; private [weakref]docx_to_pdf_: TSDocxToPdf; [weakref]last_page_: Page; [weakref]docx_components_module_: DocxComponentsModule; [weakref]tc_: Tc; [weakref]tbl_pr_: TblPr; tc_pr_unit_decorator_: TcPrUnitDecorator; region_array_: array of Region; // 单元格可能跨页,所以可能存在多个 top_: boolean; end; type ColumnRange = class(BasicRange) public function Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule); function AddElement(ele: Element); function Elements(): array of Element; function GetLastPage(): Page; function Do();override; private [weakref]docx_to_pdf_: TSDocxToPdf; [weakref]docx_components_module_: DocxComponentsModule; [weakref]page_: Page; elements_: array of Elements; paragraph_: P; last_y_: real; end; type MathRange = class(BasicRange) public function Create(docx_to_pdf: TSDocxToPdf; pg: Page; o_math_para: OMathPara); function Calc(); function Do();override; private [weakref]docx_to_pdf_: TSDocxToPdf; [weakref]o_math_para_: OMathPara; sub_math_range_: SubMathRange; end; type SubMathRange = class(BasicRange) public function Create(docx_to_pdf: TSDocxToPdf; pg: Page; element: OpenXmlElement; sz: real); function Do();override; function Calc(); private function MathR(r: R; sz: real; x: real; y: real): RangeCollection; function MathF(f: F; sz: real; x: real; y: real): RangeCollection; function MathRad(rad: Rad; sz: real; x: real; y: real): RangeCollection; function MathNary(nary: Nary; sz: real; x: real; y: real): RangeCollection; function MathSSup(s_sup: SSup; sz: real; x: real; y: real): RangeCollection; private [weakref]docx_to_pdf_: TSDocxToPdf; [weakref]ts_page_: Page; [weakref]openxml_element_: OpenXmlElement; range_collection_: RangeCollection; sz_: real; end; implementation function MathRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; o_math_para: OMathPara); begin class(BasicRange).Create(); docx_to_pdf_ := docx_to_pdf; o_math_para_ := o_math_para; sub_math_range_ := nil; {self.}Page := pg; end; function MathRange.Calc(); begin sub_math_range_ := new SubMathRange(docx_to_pdf_, {self.}Page, o_math_para_.OMath, 11); sub_math_range_.StartX := {self.}StartX; sub_math_range_.StartY := {self.}StartY; sub_math_range_.EndX := {self.}EndX; sub_math_range_.EndY := {self.}EndY; sub_math_range_.DynamicHeight := 100; sub_math_range_.Calc(); {self.}EndX := sub_math_range_.EndX; {self.}EndY := sub_math_range_.EndY; {self.}Width := sub_math_range_.Width; {self.}DynamicHeight := sub_math_range_.DynamicHeight; end; function MathRange.Do();override; begin sub_math_range_.Do(); end; function SubMathRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; element: OpenXmlElement; sz: real); begin class(BasicRange).Create(); docx_to_pdf_ := docx_to_pdf; ts_page_ := pg; openxml_element_ := element; {self.}Page := pg; range_collection_ := new RangeCollection(); sz_ := sz; end; function SubMathRange.Do();override; begin range_collection_.Do(); end; function SubMathRange.Calc(); begin elements := openxml_element_.Elements(); min_y := {self.}StartY; max_y := {self.}StartY; {self.}EndX := {self.}StartX; {self.}EndY := {self.}StartY; for _,element in elements do begin range := nil; if element.LocalName = "r" then range := {self.}MathR(element, sz_, {self.}EndX, {self.}EndY); else if element.LocalName = "f" then range := {self.}MathF(element, sz_, {self.}EndX, {self.}EndY); else if element.LocalName = "rad" then range := {self.}MathRad(element, sz_, {self.}EndX, {self.}EndY); else if element.LocalName = "nary" then range := {self.}MathNary(element, sz_, {self.}EndX, {self.}EndY); else if element.LocalName = "sSup" then range := {self.}MathSSup(element, sz_, {self.}EndX, {self.}EndY); if not ifObj(range) then begin echo forma("Not support <%s>\n", element.ElementName); continue; end if min_y > range.EndY then min_y := range.EndY; if max_y < range.EndY + range.DynamicHeight then max_y := range.EndY + range.DynamicHeight; {self.}EndX := range.EndX; {self.}EndY := range.EndY; {self.}Width += range.Width; range_collection_.Add(range); end range_collection_.DynamicHeight := max_y - min_y; {self.}DynamicHeight := range_collection_.DynamicHeight; end; function SubMathRange.MathSSup(s_sup: SSup; sz: real; x: real; y: real): RangeCollection; begin prange := new RangeCollection(); prange.StartX := x; prange.StartY := y; prange.EndX := x; prange.EndY := y; e_range := new SubMathRange(docx_to_pdf_, {self.}Page, s_sup.E, sz); e_range.StartX := x; e_range.StartY := y; e_range.Calc(); sup_range := new SubMathRange(docx_to_pdf_, {self.}Page, s_sup.Sup, sz * 0.4); sup_range.StartX := x + e_range.Width; sup_range.StartY := y + sz * 0.57; sup_range.Calc(); prange.Add(e_range); prange.Add(sup_range); prange.EndX := maxValue(array(e_range.EndX, sup_range.EndX)); prange.EndY := e_range.EndY; prange.Width := prange.EndX - prange.StartX; prange.DynamicHeight := e_range.DynamicHeight + sup_range.DynamicHeight * 0.5; return prange; end; function SubMathRange.MathR(r: R; sz: real; x: real; y: real): RangeCollection; begin // println("x = {}, y = {}", x, y); prange := new RangeCollection(); prange.StartX := x; prange.StartY := y; prange.EndX := x; prange.EndY := y; text := r.T.Text(); pos := 1; // println("text = {}", text); while pos <= length(text) do begin num := Utf8CharLengthFromByte(text[pos]); a_word := text[pos : pos+num-1]; if num = 1 or DTPUtils.IsChineseChar(a_word) or DTPUtils.IsChinesePunctuation(a_word) then begin word := utf8ToAnsi(a_word); font_obj := docx_to_pdf_.Font.GetCNSFont("SimSun", false, true); end else begin word := class(SymbolMapper).SymbolChr(a_word); if ifnil(word) then begin echo format("error symbol {{%s}}", a_word); word := chr(0x20); end font_obj := docx_to_pdf_.Font.GetSymbolFont(); end rpr := new RPr(); rpr.Sz.Val := sz; ts_page_.PdfPage.SetFontAndSize(font_obj, rpr.Sz.Val); word_width := ts_page_.PdfPage.TextWidth(word); text_range := new TextRange(); text_range.RPr := rpr; text_range.Text := word; text_range.Font := font_obj; text_range.StartX := prange.EndX; text_range.StartY := prange.EndY; text_range.Page := {self.}Page; text_range.EndX := text_range.StartX; text_range.EndY := text_range.StartY; text_range.Width := word_width; pos += num; prange.Add(text_range); prange.EndX += text_range.Width; prange.Width += text_range.Width; end prange.DynamicHeight := sz; return prange; end; function SubMathRange.MathF(f: F; sz: real; x: real; y: real); begin prange := new ParagraphLineRange(); prange.StartX := x; prange.StartY := y; prange.EndX := x; prange.EndY := y; den_range := new SubMathRange(docx_to_pdf_, {self.}Page, f.Den, sz); den_range.StartX := x; den_range.StartY := y; den_range.Calc(); num_range := new SubMathRange(docx_to_pdf_, {self.}Page, f.Num, sz); num_range.StartX := x; num_range.StartY := y + 1.418 * sz; num_range.Calc(); max_len := max(den_range.Width, num_range.Width); bar := max_len / 0.9; line_range := new LineRange(); line_range.StartX := x - (bar - max_len) / 2; line_range.StartY := y + 0.928 * sz; line_range.EndX := line_range.StartX; line_range.EndY := line_range.StartY; line_range.Width := bar; line_range.Page := {self.}Page; line_range.LineWidth := 0.04 * sz; prange.EndX := maxValue(array(den_range.EndX, num_range.EndX, line_range.EndX)); prange.AddRange(den_range); prange.AddRange(num_range); prange.AddRange(line_range); return prange; // TODO: delete // pg := {self.}Page.PdfPage; // pg.SetFontAndSize(font, sz); // len1 := pg.TextWidth(range1.Text); // len2 := pg.TextWidth(range2.Text); // max_len := len1 > len2 ? len1 : len2; // bar := max_len / 0.9; // pg.SetLineWidth(0.05*sz); // pg.SetRGBStroke(0, 0, 0); // x := {self.}StartX - (bar - max_len) / 2; // y := {self.}StartY + 0.928 * sz; // pg.MoveTo(x, y); // pg.LineTo(x + bar, y); // pg.Stroke(); // elements := f.Den.Elements(); // {self.}TraverseElement(elements); // elements := f.Num.Elements(); // {self.}TraverseElement(elements); // for _,element in elements do // begin // if // range1 := new TextRange(); // range1.Text := "a"; // range1.EndX := {self.}StartX; // range1.EndY := {self.}StartY; // rpr := new RPr(); // rpr.Sz.Val := sz; // range1.RPr := rpr; // range1.Page := {self.}Page; // range1.Font := font; // range1.Do(); // end // for _,element in elements do // begin // range2 := new TextRange(); // range2.Text := "b"; // range2.EndX := {self.}StartX; // range2.EndY := {self.}StartY + 1.418*sz; // rpr := new RPr(); // rpr.Sz.Val := sz; // range2.RPr := rpr; // range2.Page := {self.}Page; // range2.Font := font; // range2.Do(); // // if element.LocalName = "r" then // // begin // // range1 := new TextRange(); // // range1.Text := element.T.Text(); // // end // end end; function SubMathRange.MathRad(rad: Rad; sz: real; x: real; y: real): ParagraphLineRange; begin prange := new ParagraphLineRange(); prange.StartX := x; prange.StartY := y; prange.EndX := x; prange.EndY := y; symbol := chr(0xD6); symbol_font := docx_to_pdf_.Font.GetSymbolFont(); pg := {self.}Page.PdfPage; pg.SetFontAndSize(symbol_font, sz); symbol_range := new TextRange(); symbol_range.Text := symbol; symbol_range.EndX := x; symbol_range.EndY := y; symbol_range.Font := symbol_font; symbol_range.Width := pg.TextWidth(symbol); symbol_range.RPr := new RPr(); symbol_range.RPr.Sz.Val := sz; symbol_range.Page := {self.}Page; deg_range := new SubMathRange(docx_to_pdf_, {self.}Page, rad.Deg, sz * 0.5); deg_range.StartX := x; deg_range.StartY := y + sz * 0.57; deg_range.Calc(); e_range := new SubMathRange(docx_to_pdf_, {self.}Page, rad.E, sz); e_range.StartX := x + symbol_range.Width; e_range.StartY := y; e_range.Calc(); line_range := new LineRange(); line_range.StartX := x + symbol_range.Width * 0.9; line_range.StartY := y + sz * 0.9; line_range.EndX := line_range.StartX; line_range.EndY := line_range.StartY; line_range.Width := e_range.Width + symbol_range.Width / 3; line_range.Page := {self.}Page; line_range.LineWidth := 0.04 * sz; prange.EndX := maxValue(array(symbol_range.EndX, e_range.EndX, deg_range.EndX, line_range.EndX)); prange.AddRange(symbol_range); prange.AddRange(deg_range); prange.AddRange(e_range); prange.AddRange(line_range); return prange; // TODO: delete // range := new TextRange(); // range.Text := chr_hash_['α']; // range.EndX := {self.}StartX; // range.EndY := {self.}StartY + sz * 0.57; // range.Font := symbol_font; // range.RPr := new RPr(); // range.RPr.Sz.Val := sz / 2; // range.Page := {self.}Page; // range.Do(); // range := new TextRange(); // range.Text := "abcd"; // range.EndX := {self.}StartX + symbol_w; // range.EndY := {self.}StartY; // range.Font := font; // range.RPr := new RPr(); // range.RPr.Sz.Val := sz; // range.Page := {self.}Page; // range.Do(); // pg.SetFontAndSize(font, sz); // pg.SetLineWidth(0.04*sz); // pg.SetRGBStroke(0, 0, 0); // x := {self.}StartX + symbol_w * 0.9; // y := {self.}StartY + sz * 0.9; // pg.MoveTo(x, y); // pg.LineTo(x + pg.TextWidth(range.Text)+symbol_w/3, y); // pg.Stroke(); end; function SubMathRange.MathNary(nary: Nary; sz: real; x: real; y: real): ParagraphLineRange; begin prange := new ParagraphLineRange(); prange.StartX := x; prange.StartY := y; prange.EndX := x; prange.EndY := y; val := nary.NaryPr.Chr.Val ?: "Į"; symbol := class(SymbolMapper).SymbolChr(val); if ifnil(symbol) then raise format("error = %s", val); symbol_font := docx_to_pdf_.Font.GetSymbolFont(); pg := {self.}Page.PdfPage; pg.SetFontAndSize(symbol_font, sz * 1.5); symbol_range := new TextRange(); symbol_range.Text := symbol; symbol_range.EndX := x; symbol_range.EndY := y; symbol_range.Font := symbol_font; symbol_range.RPr := new DocxML.RPr(); symbol_range.RPr.Sz.Val := 1.5 * sz; symbol_range.Page := {self.}Page; symbol_range.Width := pg.TextWidth(symbol); if nary.NaryPr.LimLoc.Val = "subSup" then begin sup_start_x := x + symbol_range.Width * 1.2; sup_start_y := y + sz * 1.5 * 0.73; sub_start_x := x + symbol_range.Width * 0.7; sub_start_y := y - sz * 1.5 * 0.2; end // else if nary.Nary.LimLoc.Val = "undOvr" then else begin // undOvr sup_start_x := x + symbol_range.Width * 0.5; sup_start_y := y + sz * 1.5 * 0.8; sub_start_x := x; sub_start_y := y - sz * 1.5 * 0.5; end sup_range := new SubMathRange(docx_to_pdf_, {self.}Page, nary.Sup, sz * 0.7); sup_range.StartX := sup_start_x; sup_range.StartY := sup_start_y; sup_range.Calc(); sub_range := new SubMathRange(docx_to_pdf_, {self.}Page, nary.Sub, sz * 0.7); sub_range.StartX := sub_start_x; sub_range.StartY := sub_start_y; sub_range.Calc(); if nary.NaryPr.LimLoc.Val = "subSup" then begin e_start_x := x + symbol_range.Width * 0.5 + max(sup_range.Width, sub_range.Width); e_start_y := y + sz * 0.3; end else begin e_start_x := x + symbol_range.Width; e_start_y := y + sz * 0.3; end e_range := new SubMathRange(docx_to_pdf_, {self.}Page, nary.E, sz); e_range.StartX := e_start_x; e_range.StartY := e_start_y; e_range.Calc(); prange.EndX := maxValue(array(symbol_range.EndX, sup_range.EndX, sub_range.EndX, e_range.EndX)); prange.AddRange(symbol_range); prange.AddRange(sup_range); prange.AddRange(sub_range); prange.AddRange(e_range); return prange; // TODO: delete // val := nary.NaryPr.Chr.Val; // symbol := class(SymbolMapper).SymbolChr(nary.NaryPr.Chr.Val); // sz := 11; // symbol_font := docx_to_pdf_.PdfFile().GetFont("Symbol", ""); // symbol_range := new TextRange(); // symbol_range.Text := symbol; // symbol_range.EndX := {self.}StartX; // symbol_range.EndY := {self.}StartY; // symbol_range.Font := symbol_font; // symbol_range.RPr := new RPr(); // symbol_range.RPr.Sz.Val := 1.5 * sz; // symbol_range.Page := {self.}Page; // symbol_range.Do(); // pg := {self.}Page.PdfPage; // pg.SetFontAndSize(symbol_font, sz * 1.5); // symbol_w := pg.TextWidth(symbol); // font := docx_to_pdf_.PdfFile().GetFont("SimSun,Italic", "GBK-EUC-H"); // range := new TextRange(); // range.Text := chr_hash_["∞"]; // range.EndX := {self.}StartX + symbol_w / 5; // range.EndY := {self.}StartY + sz * 0.8 * 1.5; // range.Font := symbol_font; // range.RPr := new RPr(); // range.RPr.Sz.Val := sz * 0.7; // range.Page := {self.}Page; // range.Do(); // range := new TextRange(); // range.Text := "n=1"; // pg.SetFontAndSize(font, sz*0.7); // tw := pg.TextWidth(range.Text); // range.EndX := {self.}StartX + (symbol_w - tw)/2; // range.EndY := {self.}StartY - sz * 0.5 * 1.5; // range.Font := font; // range.RPr := new RPr(); // range.RPr.Sz.Val := sz * 0.7; // range.Page := {self.}Page; // range.Do(); // range := new TextRange(); // range.Text := chr_hash_["f"]; // pg.SetFontAndSize(font, sz); // tw := pg.TextWidth(range.Text); // range.EndX := {self.}StartX + symbol_w; // range.EndY := {self.}StartY + sz * 0.3; // range.Font := symbol_font; // range.RPr := new RPr(); // range.RPr.Sz.Val := sz; // range.Page := {self.}Page; // range.Do(); end; // ColumnRange function ColumnRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule); begin docx_to_pdf_ := docx_to_pdf; page_ := pg; docx_components_module_ := components; elements_ := array(); last_y_ := 0; end; function ColumnRange.AddElement(ele: Element); begin elements_[length(elements_)] := ele; end; function ColumnRange.Elements(): array of Element; begin return elements_; end; function ColumnRange.Do();override; begin x := {self.}StartX; y := {self.}StartY; for _,element in elements_ do begin range := nil; if element.LocalName = "p" then range := new ParagraphRange(docx_to_pdf_, page_, docx_components_module_, element); else if element.LocalName = "tbl" then range := new TableRange(docx_to_pdf_, page_, docx_components_module_, element); if ifnil(range) then continue; range.StartX := x; range.StartY := y; range.Width := {self.}Width; range.LowerBound := {self.}LowerBound; range.Calc(); range.Do(); y := range.EndY; page_ := range.GetLastPage(); end {self.}EndY := y; end; function ColumnRange.GetLastPage(): Page; begin return page_; end; // TableRange function TableRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: Components; table: Tbl); begin docx_to_pdf_ := docx_to_pdf; last_page_ := pg; docx_components_module_ := Components; table_ := table; ts_trpr_array_ := array(); cell_range_matrix_ := array(); row_lower_bound_ := array(); rows_ := 0; cols_ := 0; {self.}Page := last_page_; end; function TableRange.Calc(); begin {self.}SetTblTblPr(table_); tbl_pr_unit_decorator_ := new TblPrUnitDecorator(table_.TblPr); tbl_grid_unit_decorator := new TblGridUnitDecorator(table_.TblGrid); grid_cols := tbl_grid_unit_decorator.GridCols(); {self.}ResetCoordinates(tbl_pr_unit_decorator_, grid_cols); {self.}EndX := {self.}StartX; {self.}EndY := {self.}StartY; // 如果是根据内容自适应,应该计算并调整grid_cols的值 trs := table_.Trs(); rows_ := length(trs); cols_ := length(grid_cols); cell_range_matrix_ := nils(rows_, cols_); // 先构建一个矩阵 {self.}CreateTableMatrix(grid_cols, trs); // 遍历矩阵后进行计算合并 {self.}ComputeMatrixCells(); end; function TableRange.Do();override; begin for _,row in cell_range_matrix_ do begin flag := nil; for __,range in row do begin if ifnil(flag) and ifObj(range) then flag := range.IfRemoveEmptyRectangle(); if not ifObj(range) then continue; if flag <> range.IfRemoveEmptyRectangle() then begin flag := false; break; end end for __,range in row do begin if ifObj(range) then begin range.RemoveFlag := flag; range.Do(); end end end end; function TableRange.CreateTableMatrix(grid_cols: array of GridColUnitDecorator; trs: array of Tr); begin for i,tr in trs do begin {self.}SetTrTrPr(tr); tr_pr := new TrPrUnitDecorator(tr.TrPr); tc_x := {self.}EndX; tcs := tr.Tcs(); trp := new DTPUtils.TrProperty(); trp.TrPr := tr_pr; ts_trpr_array_[i] := trp; pos := 0; for j,tc in tcs do begin {self.}SetTcTcPr(tc); if i = 0 then {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "firstRow"); else if i = length(trs)-1 then {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "lastRow") else if (i + 1) % 2 = 0 then {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "band1Horz"); else {self.}OverrideTcPrByTblStylePrType(tc.TcPr, "band2Horz"); grid_span := new GridSpanUnitDecorator(tc.TcPr.GridSpan); if tc.TcPr.VMerge and tc.TcPr.VMerge <> "restart" then begin tc_x += grid_cols[pos++].W; for k:=grid_span.Val-1 downto 1 do begin cell_range_matrix_[i][pos] := 0; tc_x += grid_cols[pos++].W; end continue; end cell_range := new CellRange(docx_to_pdf_, last_page_, docx_components_module_, tc, tbl_pr_unit_decorator_, trp); cell_range.StartX := tc_x; cell_range.Width := grid_cols[pos].W; cell_range.LowerBound := {self.}LowerBound; cell_range.FixedHeight := tr_pr.TrHeight.Val; cell_range.Parent := self; cell_range.Row := i; cell_range.Col := pos; cell_range_matrix_[i][pos] := cell_range; pos++; // 水平合并的单元格,占位需要和垂直的区分 for k:=grid_span.Val-1 downto 1 do begin cell_range_matrix_[i][pos] := 0; cell_range.Width += grid_cols[pos++].W; end tc_x += cell_range.Width; end end // for i,arr in cell_range_matrix_ do // println("i = {}, arr = {}", i, arr); // println("\n"); return; end; function TableRange.ComputeMatrixCells(); begin i := 0; merge_arr := array(); vmerge_height := array(); while i < rows_ do begin j := 0; tc_y := {self.}EndY; recompute_flag := false; while j < cols_ do begin range := cell_range_matrix_[i][j]; if not ifObj(range) then begin j++; continue; end range.StartY := tc_y; range.SetPage(last_page_); range.Calc(); if range.IsReComputeByCantSplit() then begin // 调整上一行的下边界 arr := cell_range_matrix_[i-1]; for _,r in arr do begin if ifnil(r) then begin pos := i-2; while pos > 0 do begin rr := cell_range_matrix_[pos][_]; pos--; if ifnil(rr) then continue; rr.LowerBound := tc_y; break; end end if not ifnil(r) then r.LowerBound := tc_y; end last_page_ := docx_to_pdf_.PageManager[last_page_.Index + 1]; [x, y] := docx_to_pdf_.CalculateTextCoordinates(); {self.}EndY := y; j := 0; recompute_flag := true; arr := cell_range_matrix_[i]; for _,r in arr do if not ifnil(r) then r.SetTop(); break; end if range.Tc.TcPr.VMerge then begin b_merge_index := i; e_merge_index := i + 1; while ifnil(cell_range_matrix_[e_merge_index+1][j]) and e_merge_index < rows_-1 do e_merge_index++; merge_arr[e_merge_index][j] := b_merge_index; range.VMerge := e_merge_index; if ifnil(vmerge_height[e_merge_index]) or range.DynamicHeight > vmerge_height[e_merge_index] then vmerge_height[e_merge_index] := range.DynamicHeight; end j++; end if recompute_flag then continue; i_height := 0; for k,v in merge_arr[i] do begin i_height := ts_trpr_array_[i].Height; r := cell_range_matrix_[v][k]; total_height := 0; for index:=v to i-1 do total_height += ts_trpr_array_[index].Height; h := vmerge_height[i]; if h > total_height + i_height then i_height := h - total_height; else h := total_height + i_height; r.AlignHeight(h, row_lower_bound_[i-1]); r.SetVAlign(); end if i_height then ts_trpr_array_[i].Height := i_height; for _,range in cell_range_matrix_[i] do begin if not ifObj(range) or range.Tc.TcPr.VMerge then continue; range.AlignHeight(ts_trpr_array_[i].Height, row_lower_bound_[i]); range.SetVAlign(); {self.}EndY := range.EndY; last_page_ := range.GetLastPage(); row_lower_bound_[i] := range.LowerBound; end i++; end end; function TableRange.RowLowerBound(row: integer): real; begin return row_lower_bound_[row]; end; function TableRange.OverrideTcPrByTblStylePrType(var tc_pr: TcPr; type: string); begin // tc_pr应该是经过外层copy的 tbl_style_pr := docx_components_module_.GetTblStylePrByType(tbl_pr_unit_decorator_.TblStyle.Val, type); if tbl_style_pr then tc_pr.Copy(tbl_style_pr.TcPr); end; function TableRange.ResetCoordinates(tbl_pr: TblPr; grid_cols: array of GridCol); begin total_width := 0; for _,grid_col in grid_cols do total_width += grid_col.W; diff := total_width - {self.}Width; case tbl_pr.Jc.Val of "center": begin offset := diff/2; {self.}StartX -= offset; end "right": begin {self.}StartX -= diff; end end; {self.}Width := total_width; end; function TableRange.SetTblTblPr(var tbl: Tbl); begin new_tbl_pr := new TblPr(); {self.}SetTblPrByStyleId(new_tbl_pr, tbl.TblPr.TblStyle.Val); new_tbl_pr.Copy(tbl.TblPr); tbl.TblPr.Copy(new_tbl_pr); end; function TableRange.SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string); begin styles := docx_components_module_.GetStylesAdapter(); style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin based_on := style.BasedOn.Val; {self.}SetTblPrByStyleId(tbl_pr, based_on); tbl_pr.Copy(style.TblPr); end end; function TableRange.SetTrTrPr(var tr: Tr); begin new_tr_pr := new TrPr(); {self.}SetTrPrByStyleId(new_tr_pr, tbl_pr_unit_decorator_.TblStyle.Val); new_tr_pr.Copy(tr.TrPr); tr.TrPr.Copy(new_tr_pr); end; function TableRange.SetTrPrByStyleId(var tr_pr: TrPr; style_id: string); begin styles := docx_components_module_.GetStylesAdapter(); style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin based_on := style.BasedOn.Val; {self.}SetTrPrByStyleId(tr_pr, based_on); tr_pr.Copy(style.TrPr); end end; function TableRange.SetTcTcPr(var tc: Tc); begin new_tc_pr := new TcPr(); {self.}SetTcPrByStyleId(new_tc_pr, tbl_pr_unit_decorator_.TblStyle.Val); new_tc_pr.Copy(tc.TcPr); tc.TcPr.Copy(new_tc_pr); end; function TableRange.SetTcPrByStyleId(var tc_pr: TcPr; style_id: string); begin styles := docx_components_module_.GetStylesAdapter(); style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin based_on := style.BasedOn.Val; {self.}SetTcPrByStyleId(tc_pr, based_on); tc_pr.Copy(style.TcPr); end end; function TableRange.GetLastPage(): Page; begin return last_page_; end; function TableRange.Rows(): integer; begin return rows_; end; function TableRange.Cols(): integer; begin return cols_; end; // CellRange function CellRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule; tc: Tc; tbl_pr: TblPr; trp: TSTrProperty); begin docx_to_pdf_ := docx_to_pdf; last_page_ := pg; docx_components_module_ := components; tc_ := tc; tbl_pr_ := tbl_pr; region_array_ := array(); top_ := false; tc_pr_unit_decorator_ := new TcPrUnitDecorator(tc_.TcPr); {self.}TSTrPr := trp; {self.}Tc := tc; {self.}VMerge := 1; {self.}Page := last_page_; end; function CellRange.Calc(); begin region_array_ := array(); region := new DTPUtils.Region(); region.BordersRange.EndX := {self.}StartX; region.BordersRange.EndY := {self.}StartY; region.BordersRange.Width := {self.}Width; region.BordersRange.FixedHeight := {self.}FixedHeight; region.BordersRange.Page := last_page_; region.BordersRange.TcPr := tc_pr_unit_decorator_; {self.}SetBorderRange(region.BordersRange); region_array_[length(region_array_)] := region; {self.}EndX := {self.}StartX; {self.}EndY := {self.}StartY; {self.}DynamicHeight := 0; cell_x := {self.}EndX + tbl_pr_.TblCellMar.Left.W; cell_y := {self.}EndY - tbl_pr_.TblCellMar.Top.W; cell_w := {self.}Width - tbl_pr_.TblCellMar.Right.W - tbl_pr_.TblCellMar.Left.W; cell_h := {self.}FixedHeight; elements := tc_.Elements(); for _,element in elements do begin range := nil; if element.LocalName = "p" then begin range := new ParagraphRange(docx_to_pdf_, last_page_, docx_components_module_, element); range.SetTblStyleIdAndType(tbl_pr_.TblStyle.Val, {self.}GetCellPrType()); end else if element.LocalName = "tbl" then begin range := new TableRange(docx_to_pdf_, last_page_, docx_components_module_, element); continue; // TODO:表中表存在不可靠问题 end if ifObj(range) then begin range.StartX := cell_x; range.StartY := cell_y; range.Width := cell_w; range.FixedHeight := cell_h; range.LowerBound := {self.}LowerBound; range.Parent := self; range.Calc(); region.RangeArr[length(region.RangeArr)] := range; {self.}DynamicHeight += range.DynamicHeight; cell_y := range.EndY; last_page_ := range.GetLastPage(); end end {self.}EndY := cell_y - tbl_pr_.TblCellMar.Bottom.W; {self.}DynamicHeight += tbl_pr_.TblCellMar.Top.W + tbl_pr_.TblCellMar.Bottom.W; if {self.}EndY < {self.}LowerBound and not range.Empty() then begin last_page_ := docx_to_pdf_.PageManager[last_page_.Index + 1]; if ifnil(last_page_) then last_page_ := docx_to_pdf_.AddPage(); {self.}StartY := last_page_.TextPoint.Y; {self.}Calc(); end if {self.}TSTrPr.TrPr.TrHeight.HRule <> "exact" and {self.}DynamicHeight > {self.}FixedHeight then begin region.BordersRange.FixedHeight := {self.}DynamicHeight; {self.}FixedHeight := {self.}DynamicHeight; end if not {self.}Tc.TcPr.VMerge and {self.}DynamicHeight > {self.}TSTrPr.Height then {self.}TSTrPr.Height := {self.}DynamicHeight; end; function CellRange.Do();override; begin for _,region in region_array_ do begin if _ = 0 and {self.}RemoveFlag then continue; // println("Row = {}, Col = {}", {self.}Row, {self.}Col); region.BordersRange.Do(); for _,range in region.RangeArr do range.Do(); end end; function CellRange.SetPage(pg: Page); begin last_page_ := pg; {self.}Page := pg; end; function CellRange.AlignHeight(height: real; lb: real); begin region := region_array_[0]; y_lowerbound := {self.}StartY - {self.}LowerBound; surplus := height - y_lowerbound; if surplus < 1e-6 then begin region.BordersRange.DynamicHeight := height; {self.}SetBorderRange(region.BordersRange); {self.}EndY := {self.}StartY - region.BordersRange.DynamicHeight; {self.}LowerBound := {self.}StartY - height; return; end // if lb then y_lowerbound := {self.}StartY - lb; region.BordersRange.DynamicHeight := y_lowerbound; arr := region.RangeArr; region.RangeArr := array(); hash := array(region.BordersRange.Page.Index: region); last_page_ := {self.}Page; [x, y] := last_page_.OriginalTextCoordinates(); span := y - last_page_.FtrPoint.Y; while surplus > span do begin last_page_ := docx_to_pdf_.PageManager[last_page_.Index + 1]; region := new DTPUtils.Region(); region.BordersRange.EndX := {self.}StartX; region.BordersRange.EndY := y; region.BordersRange.Width := {self.}Width; region.BordersRange.DynamicHeight := span; region.BordersRange.Page := last_page_; region.BordersRange.TcPr := tc_pr_unit_decorator_; region.BordersRange.Top := true; region.BordersRange.Bottom := true; {self.}SetBorderRange(region.BordersRange); region_array_[length(region_array_)] := region; surplus -= span; hash[region.BordersRange.Page.Index] := region; end if surplus > 1e-6 then begin last_page_ := docx_to_pdf_.PageManager[last_page_.Index + 1]; region := new DTPUtils.Region(); region.BordersRange.EndX := {self.}StartX; region.BordersRange.EndY := y; region.BordersRange.Width := {self.}Width; region.BordersRange.DynamicHeight := surplus; region.BordersRange.Page := last_page_; region.BordersRange.TcPr := tc_pr_unit_decorator_; region.BordersRange.Top := true; {self.}SetBorderRange(region.BordersRange); region_array_[length(region_array_)] := region; hash[region.BordersRange.Page.Index] := region; {self.}EndY := region.BordersRange.EndY - surplus; end for _,range in arr do begin if range is class(ParagraphRange) then begin line_arr := range.GetParagraphLineRangeArr(); for _,r in line_arr do begin region := hash[r.Page.Index]; region.RangeArr[length(region.RangeArr)] := r; end end end end; function CellRange.GetLastPage(); begin return last_page_; end; function CellRange.SetVAlign(); begin val := tc_.TcPr.VAlign.Val; region := region_array_[0]; arr := region.RangeArr; if length(arr) = 0 then return; last_y := arr[length(arr)-1].EndY; offset := last_y - (region.BordersRange.EndY - region.BordersRange.DynamicHeight) - tbl_pr_.TblCellMar.Bottom.W; case val of "center": begin offset /= 2; for _,range in arr do range.AdjustRangeOffset(region.BordersRange.Page, nil, -offset); end end; end; function CellRange.IsReComputeByCantSplit(): boolean; begin if {self.}Tc.TcPr.VMerge then return false; return {self.}TSTrPr.TrPr.CantSplit and last_page_ <> {self.}Page; end; function CellRange.IfRemoveEmptyRectangle(): boolean; begin if length(region_array_) < 2 then return false; return length(region_array_[0].RangeArr) ? false : true; end; function CellRange.GetCellPrType(): string; begin if {self.}Row = 0 then return "firstRow"; else if ({self.}Row + 1) % 2 = 0 then return "band1Horz"; else return "band2Horz"; end; function CellRange.SetBorderRange(range: BordersRange); begin if top_ then range.Top := true; if ifObj(tbl_pr_.TblBorders) then begin if {self.}Row = 0 then begin if tbl_pr_.TblBorders.Top then begin if not tc_pr_unit_decorator_.TcBorders.Top then tc_pr_unit_decorator_.TcBorders.Top.Copy(tbl_pr_.TblBorders.Top); range.Top := true; end if tbl_pr_.TblBorders.InsideH and {self.}VMerge <> {self.}Parent.Rows()-1 then begin if not tc_pr_unit_decorator_.TcBorders.Bottom then tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.InsideH); range.Bottom := true; end if tbl_pr_.TblBorders.InsideV and {self.}Col <> {self.}Parent.Cols()-1 then begin if not tc_pr_unit_decorator_.TcBorders.Right then tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr_.TblBorders.InsideV); range.Right := true; end if tbl_pr_.TblBorders.Bottom and {self.}VMerge = {self.}Parent.Rows()-1 then begin if not tc_pr_unit_decorator_.TcBorders.Bottom then tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.Bottom); range.Bottom := true; end end else if {self.}Row = {self.}Parent.Rows()-1 then begin if tbl_pr_.TblBorders.Bottom then begin if not tc_pr_unit_decorator_.TcBorders.Bottom then tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.Bottom); range.Bottom := true; end if tbl_pr_.TblBorders.InsideV and {self.}Col <> {self.}Parent.Cols()-1 then begin if not tc_pr_unit_decorator_.TcBorders.Right then tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr_.TblBorders.InsideV); range.Right := true; end end else begin if tbl_pr_.TblBorders.Bottom and {self.}VMerge = {self.}Parent.Rows()-1 then begin if not tc_pr_unit_decorator_.TcBorders.Bottom then tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.Bottom); range.Bottom := true; end if tbl_pr_.TblBorders.InsideH and {self.}VMerge <> {self.}Parent.Rows()-1 then begin if not tc_pr_unit_decorator_.TcBorders.Bottom then tc_pr_unit_decorator_.TcBorders.Bottom.Copy(tbl_pr_.TblBorders.InsideH); range.Bottom := true; end if tbl_pr_.TblBorders.InsideV and {self.}Col <> {self.}Parent.Cols()-1 then begin if not tc_pr_unit_decorator_.TcBorders.Right then tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr_.TblBorders.InsideV); range.Right := true; end end if {self.}Col = 0 then begin if tbl_pr_.TblBorders.Left then begin if not tc_pr_unit_decorator_.TcBorders.Left then tc_pr_unit_decorator_.TcBorders.Left.Copy(tbl_pr_.TblBorders.Left); range.Left := true; end end if {self.}Col = {self.}Parent.Cols()-1 then begin if tbl_pr_.TblBorders.Right then begin if not tc_pr_unit_decorator_.TcBorders.Right then tc_pr_unit_decorator_.TcBorders.Right.Copy(tbl_pr_.TblBorders.Right); range.Right := true; end end end else begin range.Left := {self.}Col = 0; range.Top := {self.}Row = 0; range.Right := true; range.Bottom := true; end end; function CellRange.SetTop(); begin top_ := true; end; // RangeCollection; function RangeCollection.Create(); begin class(BasicRange).Create(); range_array_ := array(); end; function RangeCollection.Do();override; begin for _,range in range_array_ do range.Do(); end; function RangeCollection.Add(range: BasicRange); begin range_array_[length(range_array_)] := range; end; // ParagraphLineRange function ParagraphLineRange.Create(pg: Page); begin class(BasicRange).Create(); {self.}Page := pg; range_array_ := array(); end; function ParagraphLineRange.AddRange(range: BasicRange); begin range_array_[length(range_array_)] := range; end; function ParagraphLineRange.Do();override; begin for _,range in range_array_ do range.Do(); end; function ParagraphLineRange.SetAllRangeProp(pg: Page; sx: real; sy: real; ex: real; ey: real; w: real; fh: real; dh: real); begin for _,range in range_array_ do begin if not ifnil(pg) then range.Page := pg; if not ifnil(sx) then range.StartX := sx; if not ifnil(sy) then range.StartY := sy; if not ifnil(ex) then range.EndX := ex; if not ifnil(ey) then range.EndY := ey; if not ifnil(w) then range.Width := w; if not ifnil(fh) then range.FixedHeight := fh; if not ifnil(dh) then range.DynamicHeight := dh; end end; function ParagraphLineRange.Align(jc: string); begin offset := 0; first := range_array_[0]; last := range_array_[length(range_array_)-1]; case jc of "center": offset := ({self.}Width + StartX - last.EndX - last.Width) / 2; "right": offset := {self.}Width - last.EndX + first.EndX - last.Width; end; if offset <= 0 then return; for _,range in range_array_ do range.EndX += offset; end; function ParagraphLineRange.AdjustRangeOffset(pg: Page; x_offset: real; y_offset: real); begin if pg <> {self.}Page then return; for _,range in range_array_ do begin if not ifnil(x_offset) then range.EndX += x_offset; if not ifnil(y_offset) then range.EndY += y_offset; end; end; function ParagraphLineRange.AlignRightBound(right_bound: real); begin last := range_array_[length(range_array_)-1]; diff := right_bound - (last.EndX + last.Width); if diff > 1e-6 then begin avg := diff / (length(range_array_) - 1); for i:=1 to length(range_array_)-1 do range_array_[i].EndX += avg * i; end end; function ParagraphLineRange.Offset(x_offset: real; y_offset; real); begin for _,range in range_array_ do begin range.EndX += x_offset; range.EndY -= y_offset; end end; // ParagraphRange function ParagraphRange.Create(docx_to_pdf: TSDocxToPdf; pg: Page; components: DocxComponentsModule; paragraph: P); begin docx_to_pdf_ := docx_to_pdf; page_ := pg; docx_components_module_ := components; paragraph_ := paragraph; table_style_id_ := ""; table_style_type_ := ""; body_range_array_ := array(); bullet_range_array_ := array(); line_range_array_ := array(); hyperlink_array_ := array(); bookmark_array_ := array(); empty_ := false; {self.}Page := page_; footnote_reference_hash_ := array(); end; function ParagraphRange.Init(); begin body_range_array_ := array(); right_bound_ := {self.}StartX + {self.}Width; {self.}ResetCoordinates(); {self.}EndX := {self.}StartX; {self.}EndY := {self.}StartY; {self.}CheckAndAddPage({self.}EndY, ppr_unit_decorator_.Spacing.Before); {self.}EndY -= ppr_unit_decorator_.Spacing.Before; {self.}DynamicHeight += ppr_unit_decorator_.Spacing.Before; // TODO:项目符号应该单独写入 {self.}SetLvlText(); end; function ParagraphRange.Calc(): tableArray; begin // ppr.rpr是无效的,应该以ppr.pStyle为准 {self.}SetPPPr(paragraph_); ppr_unit_decorator_ := new DocxMLUnitDecorator.PPrUnitDecorator(paragraph_.PPr); {self.}Init(); if not ppr_unit_decorator_.RPr.Sz.Val then ppr_unit_decorator_.RPr.Sz.Val := docx_to_pdf_.Font.GetDefaultSz(); if paragraph_.PPr.PageBreakBefore then {self.}CheckAndAddPage({self.}LowerBound, 1); elements := paragraph_.Elements(); empty_flag := true; bookmark_id := ''; bookmark_name := ''; bookmark_flag := false; fld_stack := new DTPUtils.Stack(); for _,element in elements do begin // println("LocalName = {}", element.LocalName); if element.LocalName = "r" then begin empty_flag := false; {self.}SetRRPr(element, ppr_unit_decorator_); if element.FldChar.FldCharType = "begin" then begin fld_struct := new DTPUtils.FldStruct(); fld_stack.Push(fld_struct); end if not fld_stack.Empty() then begin {self.}RFldChar(element, fld_stack); continue; end if element.Br.Type = "page" then {self.}EndY := {self.}LowerBound; else if element.Drawing then {self.}RDrawing(element); else if element.AlternateContent then {self.}RAlternateContent(element); else if element.FootnoteReference then {self.}RFootnoteReference(element); else if element.Object then {self.}RObject(element); else if element.FootnoteRef then {self.}RFootnoteRef(element); else if element.Anchor then {self.}Hyperlink(element); // else if element.T then {self.}RT(element, bookmark_name); end else if element.LocalName = "fldSimple" then begin {self.}FldSimple(element); end else if element.LocalName = "hyperlink" then begin empty_flag := false; {self.}Hyperlink(element); end else if element.LocalName = "bookmarkStart" then begin bookmark_id := element.Id; bookmark_name := element.Name; bookmark_array_[bookmark_name] := array(); end else if element.LocalName = "bookmarkEnd" then begin bookmark_id := ''; bookmark_name := ''; end else if element.LocalName = "oMathPara" then begin {self.}OMathPara(element); end else if element.LocalName = "oMath" then begin o_math_para := new OMathPara(); o_math_para.XmlChildOMath := element; // o_math_para.OMath.Copy(element); {self.}OMathPara(o_math_para); end end if empty_flag then begin line_space := {self.}GetParagraphLineSpace(ppr_unit_decorator_.RPr.Sz.Val, ppr_unit_decorator_.Spacing.Line, ppr_unit_decorator_.Spacing.LineRule); {self.}DynamicHeight += line_space; {self.}EndY -= {self.}DynamicHeight; empty_ := true; end if placeholder_array_ then return false; {self.}RangesToLines(); if hyperlink_array_ then {self.}HyperlinkToToc(); if bookmark_array_ then {self.}BookMarkLinkToc(); return true; end; function ParagraphRange.SetNumPages(num: integer); begin text := tostring(num); last_index := length(body_range_array_); {self.}SplitTextToTextRange(body_range_array_, text, placeholder_array_[1], link); arr := array(); len := length(body_range_array_); for i:=last_index to len-1 do arr[length(arr)] := body_range_array_[i]; diff := len - last_index; for i:=len-1 downto placeholder_array_[0] do body_range_array_[i] := body_range_array_[i-diff]; k := 0; for i:=placeholder_array_[0] to placeholder_array_[0]+diff-1 do body_range_array_[i] := arr[k++]; end; function ParagraphRange.BookMarkLinkToc(); begin for name,arr in bookmark_array_ do if arr[0] then docx_to_pdf_.Toc.LinkToToc(name, arr[0].Page, arr[0].EndX, arr[0].EndY + arr[0].RPr.Sz.Val); end; function ParagraphRange.HyperlinkToToc(); begin ppr := ppr_unit_decorator_; max_size := 0; for anchor,arr in hyperlink_array_ do // 整理hyperlink发送到docx_to_pdf_ begin pg := arr[0].Page; left := {self.}StartX; right := {self.}StartX + {self.}Width; top := {self.}StartY; bottom := {self.}StartY; x := arr[0].EndX; y := arr[0].EndY; if top - {self.}GetParagraphLineSpace(arr[0].RPr.Sz.Val, ppr.Spacing.Line, ppr.Spacing.LineRule) then begin top := pg.TextPoint.Y; bottom := top; end for _,range in arr do begin if x + range.Width - {self.}StartX > {self.}Width + 1e-6 then // 换行 begin line_space := {self.}GetParagraphLineSpace(max_size, ppr.Spacing.Line, ppr.Spacing.LineRule); bottom -= line_space; max_size := 0; if range.Page <> pg then begin rect := array(left, bottom, right, top); toc := new DTPModules.Toc(ppr, rect, pg, x, y); docx_to_pdf_.Toc.AddToc(anchor, toc); pg := range.Page; bottom := {self.}StartY; end end if range.RPr.Sz.Val > max_size then max_size := range.RPr.Sz.Val; x := range.EndX + range.Width; y := range.EndY; end font_name := ppr.RPr.RFonts.EastAsia ? ppr.RPr.RFonts.EastAsia : ppr.RPr.RFonts.Ascii; font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, ppr.RPr.B, ppr.RPr.I); line_space := {self.}GetParagraphLineSpace(max_size, ppr.Spacing.Line, ppr.Spacing.LineRule); pg.PdfPage.SetFontAndSize(font_obj, max_size); bottom -= line_space; num_width := pg.PdfPage.TextWidth("." + tostring(pg.Number)); if x + num_width - {self.}StartX > {self.}Width + 1e-6 then // 换行 begin offset := (line_space - max_size) / 2 + max_size - max_size / 5; diff := {self.}EndY - {self.}LowerBound; if {self.}CheckAndAddPage({self.}EndY, line_space) then begin {self.}DynamicHeight += diff; pg := page_; rect := array(left, bottom, right, top); toc := new TSToc(ppr, rect, pg, x, y); docx_to_pdf_.Toc.AddToc(anchor, toc); bottom := {self.}StartY; end else begin bottom -= line_space; x := {self.}StartX; y := {self.}EndY - offset; {self.}EndY -= line_space; {self.}DynamicHeight += line_space; end end rect := array(left, bottom, right, top); toc := new DTPModules.Toc(ppr, rect, pg, x, y, font_obj); docx_to_pdf_.Toc.AddToc(anchor, toc); end end; function ParagraphRange.FldSimple(fld_simple: FldSimple); begin if fld_simple.Instr then begin fields := str2array(fld_simple.Instr, " "); fld_struct := new DTPUtils.FldStruct2(); for _,field in fields do begin fld := trim(field); if fld = "NUMPAGES" then fld_struct.Type.NumPages := true; else if fld = "Arabic" then fld_struct.Arabic := true; else if fld = "MERGEFORMAT" then fld_struct.MergeFormat := true; end end r := fld_simple.Rs(0); {self.}SetRRPr(r, ppr_unit_decorator_); rpr := new RPrUnitDecorator(r.RPr); if fld_struct.Type.NumPages then begin if fld_struct.Arabic then begin placeholder_array_ := array(length(body_range_array_), rpr); end end end; function ParagraphRange.Hyperlink(hyperlink: Hyperlink); begin i := length(body_range_array_); rs := hyperlink.Rs(); separate := false; stack := new DTPUtils.Stack(); for _,r in rs do begin if r.FldChar.FldCharType = "begin" then begin fld_struct := new FldStruct2(); stack.Push(fld_struct); end // if r.InstrText.Text else if r.FldChar.FldCharType = "end" then begin stack.Pop(); end else if r.FldChar.FldCharType = "separate" then begin separate := true; end else if separate then begin docx_to_pdf_.Toc.AddDocxPage(hyperlink.Anchor, r); end else if stack.Empty() then begin {self.}SetRRPr(r, ppr_unit_decorator_); r.RPr.Color.Val := nil; {self.}RT(r, hyperlink.Anchor); end end arr := array(); while i < length(body_range_array_) do begin arr[length(arr)] := body_range_array_[i]; i++; end hyperlink_array_[hyperlink.Anchor] := arr; end; function ParagraphRange.Do();override; begin for _,line_range in line_range_array_ do line_range.Do(); end; function ParagraphRange.SetTblStyleIdAndType(style_id: string; type: string); begin table_style_id_ := style_id; table_style_type_ := type; end; function ParagraphRange.NewParagraphLineRange(): ParagraphLineRange; begin line_range := new ParagraphLineRange(page_); line_range.StartX := {self.}StartX; line_range.StartY := {self.}EndY; line_range.Width := {self.}Width; return line_range; end; function ParagraphRange.UpdateTextRangeWidth(); begin head_range := body_range_array_[0]; i := 1; while i < length(body_range_array_) do begin tail_range := body_range_array_[i]; if not tail_range is class(TextRange) then begin head_range := body_range_array_[i+1]; i += 2; continue; end if not last_range is class(TextRange) then begin head_range := tail_range; i++; continue; end if head_range then begin if head_range.Type in array(1, 2) and tail_range.Type = 3 then head_range.Width += head_range.Width / 2; else if head_range.Type = 3 and tail_range.Type in array(1, 2) then head_range.Width += tail_range.Width / 2; end head_range := tail_range; i++; end end; function ParagraphRange.RangesToLines();overload; begin {self.}UpdateTextRangeWidth(); {self.}BasicRangesToParagraphLineRange(); {self.}DynamicHeight += ppr_unit_decorator_.Spacing.After; {self.}EndY -= ppr_unit_decorator_.Spacing.After; if not {self.}Empty() and ppr_unit_decorator_.PBdr.Bottom.Val = "single" then begin sect_pr := page_.SectPr; page_.PdfPage.SetLineWidth(0.05); page_.PdfPage.SetGrayStroke(0.25); page_.PdfPage.MoveTo(sect_pr.PgMar.Left, {self.}EndY); page_.PdfPage.LineTo(sect_pr.PgSz.W - sect_pr.PgMar.Right, {self.}EndY); page_.PdfPage.Stroke(); end end; function ParagraphRange.BasicRangesToParagraphLineRange(); begin ppr := ppr_unit_decorator_; line_range := {self.}NewParagraphLineRange(); i := 0; max_size := 0; max_y := 0; while i <= length(body_range_array_)-1 do begin range := body_range_array_[i]; if i = 0 then {self.}EndX += ppr.Ind.FirstLine; if range is class(TextRange) and range.RPr.Sz.Val > max_size then max_size := range.RPr.Sz.Val; if range.DynamicHeight > max_y then max_y := range.DynamicHeight; line_space := {self.}GetParagraphLineSpace(max_size, ppr.Spacing.Line, ppr.Spacing.LineRule); diff := {self.}EndY - {self.}LowerBound; if {self.}CheckAndAddPage({self.}EndY, max(line_space, range.DynamicHeight)) then {self.}DynamicHeight += diff; if_newline := {self.}EndX + range.Width - {self.}StartX > {self.}Width + 1e-6; if i = 0 then if_newline := 0; if if_newline and (range is class(TextRange)) and (AnsiToUtf8(range.Text) in array(";", ":", "。", "“", "”", "!", "?", ",")) then if_newline := 0; if if_newline and range.Width < {self.}Width then begin offset := line_space > max_y ? (line_space - max_size) / 2 + max_size - max_size / 5 : max_y; max_value := max(line_space, max_y); line_range.Page := page_; line_range.EndY := {self.}EndY - max_value; line_range.DynamicHeight := max_value; line_range.SetAllRangeProp(pg: page_, ey: {self.}EndY - offset); line_range_array_[length(line_range_array_)] := line_range; line_range := {self.}NewParagraphLineRange(); max_size := 0; max_y := 0; {self.}DynamicHeight += max_value; {self.}EndY -= max_value; {self.}EndX := {self.}StartX; // w:hanging if range is class(TextRange) then sz := range.RPr.SzCs.Val ? range.RPr.SzCs.Val : range.RPr.Sz.Val ? range.RPr.Sz.Val : docx_to_pdf_.Font.GetDefaultSz(); else sz := docx_to_pdf_.Font.GetDefaultSz(); {self.}EndX -= ppr.Ind.HangingChars ? ppr.Ind.HangingChars * sz : ppr.Ind.Hanging; continue; end range.EndX := {self.}EndX - range.StartX; {self.}EndX += range.Width; line_range.AddRange(range); i++; if i = length(body_range_array_) then begin offset := line_space > max_y ? (line_space - max_size) / 2 + max_size - max_size / 5 : max_y; max_value := max(line_space, max_y); line_range.Page := page_; line_range.EndY := {self.}EndY - max_value; line_range.DynamicHeight := max_value; line_range.SetAllRangeProp(pg: page_, ey: {self.}EndY - offset); line_range_array_[length(line_range_array_)] := line_range; {self.}DynamicHeight += max_value; {self.}EndY -= max_value; end end {self.}SetLinesAlignment(); if not {self.}Parent is class(CellRange) then {self.}AlignRightBound(); end; function ParagraphRange.SetLinesAlignment(); begin for _,line_range in line_range_array_ do line_range.Align(ppr_unit_decorator_.Jc.Val); end; function ParagraphRange.AlignRightBound(); begin len := length(line_range_array_); if len = 1 then return; for i:=0 to len-2 do line_range_array_[i].AlignRightBound(right_bound_); end; function ParagraphRange.CheckAndAddPage(y: real; offset: real): boolean; begin if y - offset < {self.}LowerBound then begin page_ := docx_to_pdf_.PageManager[page_.Index + 1]; if ifnil(page_) then page_ := docx_to_pdf_.AddPage(); {self.}EndY := page_.TextPoint.Y; return true; end return false; end; function ParagraphRange.RT(r: R; link: string); begin rpr := new RPrUnitDecorator(r.RPr); text := r.T.Text; if ifString(text) then {self.}SplitTextToTextRange(body_range_array_, text, rpr, link); end; function ParagraphRange.SplitTextToTextRange(range_arr: array of BasicRange; text: string; rpr: RPrUnitDecorator; link: string); begin pos := 1; if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz(); while pos <= length(text) do begin text_range := new TextRange(); num := DTPUtils.Utf8CharLengthFromByte(text[pos]); a_word := text[pos : pos+num-1]; if num = 1 then begin char := ord(a_word); if char >= 0x30 and char <= 0x39 then text_range.Type := 1; else if char >= 0x41 and char <= 0x5A then text_range.Type := 2; else if char >= 0x61 and char <= 0x7A then text_range.Type := 2; word := a_word; font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); end else if DTPUtils.IsChineseChar(a_word) then begin text_range.Type := 3; word := utf8ToAnsi(a_word); font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); end else if DTPUtils.IsChinesePunctuation(a_word) then begin text_range.Type := 4; word := utf8ToAnsi(a_word); font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); end else begin word := utf8ToAnsi(a_word); if word = "?" then begin word := class(SymbolMapper).ZapfDingbatsChr(a_word); if ifnil(word) then word := "u"; font_obj := docx_to_pdf_.Font.GetZapfDingbatsFont(); end else begin font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii; font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B, rpr.I); end end page_.PdfPage.SetFontAndSize(font_obj, rpr.Sz.Val); word_width := page_.PdfPage.TextWidth(word); text_range.RPr := rpr; text_range.Text := word; text_range.Font := font_obj; text_range.Width := word_width; pos += num; range_arr[length(range_arr)] := text_range; if ifarray(bookmark_array_[link]) then bookmark_array_[link] union= array(text_range); end end; function ParagraphRange.RDrawing(r: R); begin if r.Drawing._Inline then begin id := r.Drawing._Inline.Graphic.GraphicData.Pic.BlipFill.Blip.Embed; [image_type, image] := {self.}GetImageData(id); if not image then return; xfrm := new XfrmUnitDecorator(r.Drawing._Inline.Graphic.GraphicData.Pic.SpPr.Xfrm); image_range := new ImageRange(); image_range.Image := image; image_range.Type := image_type; image_range.StartX := 0; image_range.StartY := 0; image_range.Width := xfrm.Ext.CX; image_range.DynamicHeight := xfrm.Ext.CY; body_range_array_[length(body_range_array_)] := image_range; end else if r.Drawing.Anchor then begin anchor := r.Drawing.Anchor; id := anchor.Graphic.GraphicData.Pic.BlipFill.Blip.Embed; [image_type, image] := {self.}GetImageData(id); if not image then return; [x, y] := {self.}GetXYCordinates(); xfrm := new XfrmUnitDecorator(anchor.Graphic.GraphicData.Pic.SpPr.Xfrm); position_h := new PositionHUnitDecorator(anchor.PositionH); position_v := new PositionVUnitDecorator(anchor.PositionV); if position_h.RelativeFrom = "paragraph" then x := {self.}StartY; if position_v.RelativeFrom = "paragraph" then y := {self.}StartY; image_range := new ImageRange(); image_range.Image := image; image_range.Type := image_type; image_range.EndX := x + position_h.PosOffset.Text; image_range.EndY := y - position_v.PosOffset.Text - xfrm.Ext.CY; image_range.Width := xfrm.Ext.CX; image_range.DynamicHeight := xfrm.Ext.CY; image_range.Page := page_; image_range.Do(); end end; function ParagraphRange.RAlternateContent(r: R); begin anchor := r.AlternateContent.Choice.Drawing.Anchor; wsp := anchor.Graphic.GraphicData.Wsp; [x, y] := {self.}GetXYCordinates(); xfrm := new XfrmUnitDecorator(wsp.SpPr.Xfrm); position_h := new PositionHUnitDecorator(anchor.PositionH); position_v := new PositionVUnitDecorator(anchor.PositionV); if position_h.RelativeFrom = "paragraph" then x := {self.}StartY; if position_v.RelativeFrom = "paragraph" then y := {self.}StartY; x += position_h.PosOffset.Text; y -= position_v.PosOffset.Text; w := xfrm.Ext.CX; body_pr := new BodyPrUnitDecorator(wsp.BodyPr); x += body_pr.LIns; w -= (body_pr.LIns + body_pr.RIns); ps := wsp.Txbx.TxbxContent.Ps(); for _,p in ps do begin range := new ParagraphRange(docx_to_pdf_, page_, docx_components_module_, p); range.StartX := x; range.StartY := y; range.Width := w; range.Calc(); range.Do(); y := range.EndY; end end; function ParagraphRange.RFootnoteReference(r: R); begin return; id := R.FootnoteReference.Id; footnotes_adapter := docx_components_module_.GetFootnotesAdapter(); footnote := footnotes_adapter.GetFootnoteById(id); sect_pr := page_.SectPr; w := sect_pr.SectPr.PgSz.W - sect_pr.SectPr.PgMar.Right - sect_pr.SectPr.PgMar.Left; lb := 0; x := sect_pr.SectPr.PgMar.Left; y := sect_pr.SectPr.PgSz.H; arr := array(); elements := footnote.Elements(); for _,element in elements do begin if element.LocalName = "p" then begin range := new ParagraphRange(docx_to_pdf_, page_, docx_components_module_, element); range.StartX := x; range.StartY := y; range.Width := w; range.LowerBound := 0; range.Calc(); arr[length(arr)] := arr; end end rpr := new RPrUnitDecorator(r.RPr); note := docx_to_pdf_.Note; text := docx_to_pdf_.GetCurrentNoteModule().GetIndex(); i := length(body_range_array_); if ifString(text) then {self.}SplitTextToTextRange(body_range_array_, text, rpr, nil); footnote_reference_hash_[body_range_array_[i]] := arr; // range := new ParagraphRange(self, page_, docx_components_module_, ); end; function ParagraphRange.RFootnoteRef(r: R); begin return; note_module := docx_to_pdf_.GetCurrentNoteModule(); rpr := new RPrUnitDecorator(r.RPr); text := note_module.GetFootnoteOrderNumber(); if ifString(text) then {self.}SplitTextToTextRange(body_range_array_, text, rpr, nil); end; function ParagraphRange.RObject(r: R); begin id := r.Object.Shape.Imagedata.Id; [image_type, image] := {self.}GetImageData(id); if not image then return; style := r.Object.Shape.Style; style_arr := str2array(style, ";"); for _,str in style_arr do begin if startsStr("width:", str) then w := strtofloat(str[7:length(str)-2]); else if startsStr("height:", str) then h := strtofloat(str[8:length(str)-2]); end image_range := new ImageRange(); image_range.Image := image; image_range.Type := image_type; image_range.StartX := 0; image_range.StartY := 0; image_range.Width := w; image_range.DynamicHeight := h; body_range_array_[length(body_range_array_)] := image_range; end; function ParagraphRange.RFldChar(r: R; stack: Stack); begin fld_struct := stack.Pop(); if r.FldChar.FldCharType = "begin" then fld_struct.EndFld := false; else if r.FldChar.FldCharType = "end" then fld_struct.EndFld := true; else if r.FldChar.FldCharType = "separate" then fld_struct.Separate := true; instr_text := ifString(r.InstrText.Text) ? trim(r.InstrText.Text) : ""; if instr_text <> "" then begin if instr_text = "QUOTE" then fld_struct.Quote := true; else if instr_text = "\\* MERGEFORMAT" then fld_struct.MergeFormat := true; else if instr_text = "PAGE \\* Arabic \\* MERGEFORMAT" or instr_text = "PAGE \\* MERGEFORMAT" then fld_struct.PageArabicMergeFormat := true; else if instr_text = "NUMPAGES" then fld_struct.NumPages := true; else if instr_text = "\\* Arabic \\* MERGEFORMAT" then fld_struct.ArabicMergeFormat := true; else if instr_text = "NUMPAGES \\* Arabic \\* MERGEFORMAT" then fld_struct.NumPages := fld_struct.ArabicMergeFormat := true; end if fld_struct.Quote then begin if not fld_struct.EndFld and not fld_struct.Separate then begin stack.Push(fld_struct); return; end end else if fld_struct.PageArabicMergeFormat then begin if fld_struct.Separate then begin r.T.Text := tostring(page_.Number); {self.}RT(r, nil); fld_struct.PageArabicMergeFormat := false; end end else if fld_struct.ArabicMergeFormat then begin if fld_struct.Separate then begin rpr := new RPrUnitDecorator(r.RPr); numpages_index := length(body_range_array_); placeholder_array_ := array(numpages_index, rpr); fld_struct.NumPages := false; end end if not fld_struct.EndFld then begin stack.Push(fld_struct); end if ifObj(r.Drawing) then {self.}RDrawing(r); else if ifObj(r.AlternateContent) then {self.}RAlternateContent(r); else if ifObj(r.FootnoteReference) then {self.}RFootnoteReference(r); else if ifObj(r.Object) then {self.}RObject(r); end; function ParagraphRange.GetXYCordinates(): array of real; begin xml_file := docx_to_pdf_.GetCurrentXmlFile(); if xml_file = "document.xml" then begin [x, y] := page_.OriginalTextPoint(); end else begin x := page_.SectPr.PgMar.Left; if ansiContainsStr(xml_file, "footer") then y := page_.SectPr.PgMar.Bottom; else if ansiContainsStr(xml_file, "header") then y := page_.SectPr.PgSz.H - page_.SectPr.PgMar.Header; end return array(x, y); end; function ParagraphRange.GetImageData(id: string): PdfImage; begin xml_file := docx_to_pdf_.GetCurrentXmlFile(); if xml_file = "document.xml" then rels_adapter := docx_components_module_.GetDocumentRelsAdapter(); else if ansiContainsStr(xml_file, "footer") then rels_adapter := docx_components_module_.GetFtrRelsAdapter(xml_file); else if ansiContainsStr(xml_file, "header") then rels_adapter := docx_components_module_.GetHdrRelsAdapter(xml_file); rel := rels_adapter.GetRelationshipById(id); image_path := "word/" + rel.Target; image := docx_components_module_.Zip().Get(image_path); data := image.Data(); image_path := docx_to_pdf_.GetCachePath(image_path); writeFile(rwBinary(), "", image_path, 0, length(data), data); image := nil; image_type := GetImageFileType(data); case image_type of "png": image := docx_to_pdf_.PdfFile().LoadPngImageFromFile("", image_path); "jpg": image := docx_to_pdf_.PdfFile().LoadJpegImageFromFile("", image_path); "emf": image := docx_to_pdf_.PdfFile().LoadEmfImageFromFile("", image_path); "wmf": image := docx_to_pdf_.PdfFile().LoadWmfImageFromFile("", image_path); end; fileDelete("", image_path); return array(image_type, image); end; function ParagraphRange.GetImageFileType(data: binary): string; begin stream := new TMemoryStream(); size := length(data); stream.Write(data[0:size-1], size); def := array( ('name': 'png', 'position': 0, 'value': array(0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A)), ('name': 'jpg', 'position': 0, 'value': array(0xFF, 0xD8)), ('name': 'emf', 'position': 40, 'value': array(0x20, 0x45, 0x4d, 0x46)), ('name': 'wmf', 'position': 0, 'value': array(0xd7, 0xcd, 0xc6, 0x9a)), ); for i:=0 to length(def)-1 do begin value := def[i]['value']; stream.Seek(def[i]['position']); for j:=0 to length(value)-1 do begin r := 0; stream.Read(r, 1); if r <> value[j] then break; if j = length(value)-1 then return def[i]['name']; end end return ''; end; function ParagraphRange.GetParagraphLineSpace(size: real; line: integer; line_rule: string): real; begin if not line then line := 240; if line_rule = "exact" or line_rule = "atLeast" then begin lines := line / 240; return size + lines; end else begin lines := roundto(line / 240, -1); multi := ceil(size / page_.BaseSize); if (not ifnil(ppr_unit_decorator_.SnapToGrid) and not ppr_unit_decorator_.SnapToGrid) or ((ifnil(ppr_unit_decorator_.SnapToGrid) or ppr_unit_decorator_.SnapToGrid) and lines > multi) then multi *= lines; return page_.SectPr.DocGrid.LinePitch * multi; end end; function ParagraphRange.SetPPPr(var p: P); begin new_ppr := new PPr(); styles := docx_components_module_.GetStyles(); new_ppr.Copy(styles.DocDefaults.PPrDefault.PPr); new_ppr.RPr.Copy(styles.DocDefaults.RPrDefault.RPr); {self.}SetPPrByStyleId(new_ppr, table_style_id_); {self.}SetPPrByStyleId(new_ppr, p.PPr.PStyle.Val); new_ppr.Copy(p.PPr); p.PPr.Copy(new_ppr); end; function ParagraphRange.SetPPrByStyleId(var ppr: PPr; style_id: string); begin styles := docx_components_module_.GetStylesAdapter(); style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin based_on := style.BasedOn.Val; {self.}SetPPrByStyleId(ppr, based_on); ppr.Copy(style.PPr); ppr.RPr.Copy(style.RPr); end end; function ParagraphRange.SetRRPr(var r: R; ppr_unit_decorator: PPrUnitDecorator); begin new_rpr := new RPr(); styles := docx_components_module_.GetStyles(); new_rpr.Copy(styles.DocDefaults.RPrDefault.RPr); {self.}SetRPrByTblStyleId(new_rpr, table_style_id_); {self.}SetRPrByStyleId(new_rpr, ppr_unit_decorator.PStyle.Val); {self.}SetRPrByStyleId(new_rpr, r.RPr.RStyle.Val); new_rpr.Copy(r.RPr); r.RPr.Copy(new_rpr); end; function ParagraphRange.SetRPrByTblStyleId(var rpr: RPr; style_id: string); begin styles := docx_components_module_.GetStylesAdapter(); style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin based_on := style.BasedOn.Val; {self.}SetRPrByTblStyleId(rpr, based_on); rpr.Copy(style.RPr); end if table_style_type_ then begin tbl_style_pr := docx_components_module_.GetTblStylePrByType(table_style_id_, table_style_type_); if tbl_style_pr then rpr.Copy(tbl_style_pr.RPr); end end; function ParagraphRange.SetRPrByStyleId(var rpr: RPr; style_id: string); begin styles := docx_components_module_.GetStylesAdapter(); style := styles.GetStyleByStyleId(style_id); if ifObj(style) then begin based_on := style.BasedOn.Val; {self.}SetRPrByStyleId(rpr, based_on); rpr.Copy(style.RPr); end end; function ParagraphRange.SetLvlText(); begin numbering_module := docx_components_module_.GetNumberingModule(); if not ifObj(numbering_module) then return; [lvl_text, lvl] := numbering_module.GetNumberLvl(paragraph_.PPr); if lvl_text = "" and ifnil(lvl) then return; {self.}SetRRPr(lvl, ppr_unit_decorator_); rpr := new RPrUnitDecorator(lvl.RPr); // {self.}SplitTextToTextRange(bullet_range_array_, lvl_text, rpr); {self.}SplitTextToTextRange(body_range_array_, lvl_text, rpr); end; function ParagraphRange.ResetCoordinates(); begin // 根据段落的间距确定新的坐标 ppr := ppr_unit_decorator_; sz := ppr.RPr.SzCs.Val ? ppr.RPr.SzCs.Val : ppr.RPr.Sz.Val ? ppr.RPr.Sz.Val : docx_to_pdf_.Font.GetDefaultSz(); {self.}StartX += ppr.Ind.LeftChars ? ppr.Ind.LeftChars * sz : ppr.Ind.Left; {self.}Width -= ppr.Ind.LeftChars ? ppr.Ind.LeftChars * sz : ppr.Ind.Left; {self.}Width -= ppr.Ind.RightChars ? ppr.Ind.RightChars * sz : ppr.Ind.Right; end; function ParagraphRange.GetLastPage(): Page; begin return page_; end; function ParagraphRange.AdjustRangeOffset(pg: Page; x_offset: real; y_offset: real); begin for _,line_range in line_range_array_ do line_range.AdjustRangeOffset(pg, x_offset, y_offset); end; function ParagraphRange.GetParagraphLineRangeArr(): array of ParagraphLineRange; begin return line_range_array_; end; function ParagraphRange.Empty(): boolean; begin return empty_; end; function ParagraphRange.Offset(x: real; y: real); begin for _,line_range in line_range_array_ do line_range.Offset(x, y); end; function ParagraphRange.OMathPara(element: OMathPara); begin math_range := new MathRange(docx_to_pdf_, page_, element); math_range.StartX := {self.}StartX; math_range.StartY := {self.}StartY - 15.6; math_range.Calc(); // math_range.Do(); body_range_array_[length(body_range_array_)] := math_range; end; end.