PdfConverter/internal/DTPAdvancedRanges.tsf

3044 lines
96 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

unit DTPAdvancedRanges;
interface
uses DTPPrimitiveRanges, DTPUtils, DocxML, TSPdfEnumerations;
type AdvancedRange = class(BasicRange)
public
function Create();
function Do();virtual;
function Calc(): boolean;virtual;
function Offset(x: real; y: real; page: Page);virtual;
public
LowerBound: real;
StartPage: Page;
StartX: real;
StartY: real;
end;
type TocRange = class(AdvancedRange)
public
function Create();
function CalculateRect();
function LinkAnnot(dst: PdfDestination);
function AddPageNumber(pg: Page);
public
TextRange: TextRange;
BaseLine: real; // 目录...基线
[weakref]StartRange: AdvancedRange;
[weakref]EndRange: AdvancedRange;
private
rect_: array of real;
end;
type HdrRange = class(AdvancedRange)
public
function Create(docx_to_pdf: TSDocxToPdf; hdr: Hdr);
function Do();override;
function Calc(): boolean;override;
function Offset(x: real; y: real; page: Page);override;
function ProcessRealtimeArray();
private
function Traverse(obj: OpenXmlElement);
private
[weakref]docx_to_pdf_: TSDocxToPdf;
hdr_: Hdr;
range_array_: array of Range;
end;
type FtrRange = class(AdvancedRange)
public
function Create(docx_to_pdf: TSDocxToPdf; ftr: Ftr);
function Do();override;
function Calc(): boolean;override;
function Offset(x: real; y: real; page: Page);override;
function ProcessRealtimeArray();
private
function Traverse(obj: OpenXmlElement);
private
[weakref]docx_to_pdf_: TSDocxToPdf;
ftr_: Ftr;
range_array_: array of Range;
end;
type PLineRange = class(AdvancedRange)
public
function Create();
function Do();override;
function Offset(x: real; y: real; page: Page);override;
function CanFitInLine(range: BasicRange): boolean;
function AddRange(range: BasicRange);
function Align(val: string);
function AlignRightBound(right_bound: real);
function RangeArr(): array of BasicRange;
public
TextMaxSize: real; // 行的文字最大size
LineSpace: real; // 行间距
Index: integer;
private
range_array_: array of BasicRange;
end;
type PRange = class(AdvancedRange)
public
function Create(docx_to_pdf: TSDocxToPdf; p: P);
function Init();
function Do();override;
function Calc(): boolean;override;
function Offset(x: real; y: real; page: Page);override;
function DeterminePosition();
function ProcessRealtimeArray();
function IsFirstLineOnNextPage(): boolean;
function PLineRanges(): array of PLineRange;
property P read p_;
private
function RangesToLines();
function BasicRangesToPLineRange();
function UpdateTextRangeWidth();
function NewPLineRange(): PLineRange;
function AddPLineRange(pline_range: PLineRange);
function CheckAndAddPage(y: real; offset: real): boolean;
function AlignRightBound();
function HyperlinkToToc();
function DoDrawingAnchor();
function DoAlternateContentAnchor();
function DoToc();
function SetPPPr(var p: P);
function SetPPrByStyleId(var ppr: PPr; style_id: string);
function SetRRPr(var r: R; ppr_: PPr);
function SetRPrByStyleId(var rpr: RPr; style_id: string);
function SetRPrByTblStyleId(var rpr: RPr; style_id: string);
function SetLvlText();
function GetXYCordinates(): array of real;
function GetImageFileType(data: binary): string;
function GetImageData(id: string): PdfImage;
function GetParagraphLineSpace(size: real; line: integer; line_rule: string): real;
function SplitTextToTextRange(range_arr: array of BasicRange; text: string; rpr: RPr; anchor: string);
function RBr(r: R);
function RFootnoteReference(r: R);
function RT(r: R; anchor: string);
function RDrawing(r: R);
function RFldChar(r: R; stack: Stack);
function RAlternateContent(r: R);
function RObject(r: R);
function FldSimple(fld_simple: fldSimple);
function Hyperlink(hyperlink: Hyperlink);
function OMathPara(o_math_para: OMathPara);
function OMath(o_math: OMath);
private
[weakref]docx_to_pdf_: TSDocxToPdf;
p_: P;
ppr_: PPr;
body_range_array_: array of BasicRange; // 正文range
bullet_range_array_: array of BasicRange; // 项目符号的range
line_range_array_: array of PLineRange; // 行range
drawing_anchor_array_: array of Anchor; // 浮动对象节点比如浮动型图片r.Drawing.Anchor
alternate_content_array_: array of AlternateContent; // 文本框
right_bound_: real; // 右对齐边界
br_type_: string;
bookmark_hash_: hash;
hyperlink_hash_: hash;
footnote_reference_hash_: hash; // 脚注
// 存放一些需要实时计算的值,比如页码
realtime_page_array_: hash;
realtime_numpages_array_: hash;
end;
type TcRange = class(AdvancedRange)
public
function Create(docx_to_pdf: TSDocxToPdf; tc: Tc; trp: TrProperty);
function Do();override;
function Calc(): boolean;override;
function Offset(x: real; y: real; page: Page);override;
function DoBordersRangeFill();
function GetTblStyleId(): string;
function GetPrType(): string;
function ContentNextPage(): boolean;
function AlignHeight(height: real);
function SetVAlign();
function SetTop();
property Tc read tc_;
public
Row: integer;
Col: integer;
SpacingBottom: real;
private
function GetLowerBound(pg: Page): real;
function SetBorderRange(range: BordersRange);
private
[weakref]docx_to_pdf_: TSDocxToPdf;
tc_: Tc;
trp_: TrProperty;
tc_pr_: TcPr;
content_next_page_: boolean;
range_array_: array of BasicRange;
region_array_: array of Region;
top_: boolean;
end;
type TblRange = class(AdvancedRange)
public
function Create(docx_to_pdf: TSDocxToPdf; tbl: Tbl);
function Do();override;
function Calc(): boolean;override;
function Offset(x: real; y: real; page: Page);override;
property TblPr read tbl_pr_;
property Rows read rows_;
property Cols read cols_;
private
function CreateTableMatrix(grid_cols: array of GridCol; trs: array of Tr);
function ResetCoordinates(tbl_pr: TblPr; 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; type: string);
function SetTcPrByStyleId(var tc_pr: TcPr; style_id: string; type: string);
private
[weakref]docx_to_pdf_: TSDocxToPdf;
tbl_: Tbl;
tbl_pr_: TblPr;
grid_cols_: array of GridCol;
rows_: integer;
cols_: integer;
tc_range_matrix_: array of TcRange;
tr_pr_array_: array of TrProperty;
end;
type OMathParaRange = class(AdvancedRange)
public
function Create(docx_to_pdf: TSDocxToPdf; o_math_para: OMathPara);
function Do();override;
function Calc();override;
function Offset(x: real; y: real; page: Page);override;
function AdjustOffset(x: real; y: real);override;
public
BaseHeight: real; // 基准高度
private
[weakref]docx_to_pdf_: TSDocxToPdf;
o_math_para_: OMathPara;
o_math_range_: OMathRange;
end;
type OMathRange = class(AdvancedRange)
public
function Create(docx_to_pdf: TSDocxToPdf; element: OpenXmlElement);
function Do();override;
function Calc();override;
function Offset(x: real; y: real; page: Page);override;
function AdjustOffset(x: real; y: real);override;
function SetMathSize();
public
BaseHeight: real; // 基准高度
BaseSz: real; // 基准字体大小
SingleLine: boolean; // 是否单行公式
private
[weakref]docx_to_pdf_: TSDocxToPdf;
element_: OMath;
range_array_: array of BasicRange;
end;
type OMathRRange = class(AdvancedRange)
public
function Create(docx_to_pdf: TSDocxToPdf; r: R);
function Do();override;
function Calc();override;
function Offset(x: real; y: real; page: Page);override;
function AdjustOffset(x: real; y: real);overload;
public
BaseHeight: real; // 基准高度
BaseSz: real; // 基准字体大小
private
[weakref]docx_to_pdf_: TSDocxToPdf;
r_: R;
range_array_: array of BasicRange;
end;
type OMathFRange = class(AdvancedRange)
public
function Create(docx_to_pdf: TSDocxToPdf; f: F);
function Do();override;
function Calc();override;
function Offset(x: real; y: real; page: Page);override;
function AdjustOffset(x: real; y: real);overload;
public
BaseHeight: real; // 基准高度
BaseSz: real; // 基准字体大小
private
[weakref]docx_to_pdf_: TSDocxToPdf;
f_: F;
range_array_: array of BasicRange;
end;
type OMathNaryRange = class(AdvancedRange)
public
function Create(docx_to_pdf: TSDocxToPdf; nary: Nary);
function Do();override;
function Calc();override;
function Offset(x: real; y: real; page: Page);override;
function AdjustOffset(x: real; y: real);overload;
public
BaseHeight: real; // 基准高度
BaseSz: real; // 基准字体大小
private
[weakref]docx_to_pdf_: TSDocxToPdf;
nary_: Nary;
range_array_: array of BasicRange;
end;
type OMathRadRange = class(AdvancedRange)
public
function Create(docx_to_pdf: TSDocxToPdf; rad: Rad);
function Do();override;
function Calc();override;
function Offset(x: real; y: real; page: Page);override;
function AdjustOffset(x: real; y: real);overload;
public
BaseHeight: real; // 基准高度
BaseSz: real; // 基准字体大小
private
[weakref]docx_to_pdf_: TSDocxToPdf;
rad_: rad;
range_array_: array of BasicRange;
end;
type OMathSSupRange = class(AdvancedRange)
public
function Create(docx_to_pdf: TSDocxToPdf; s_sup: SSup);
function Do();override;
function Calc();override;
function Offset(x: real; y: real; page: Page);override;
function AdjustOffset(x: real; y: real);overload;
public
BaseHeight: real; // 基准高度
BaseSz: real; // 基准字体大小
private
[weakref]docx_to_pdf_: TSDocxToPdf;
s_sup_: SSup;
range_array_: array of BasicRange;
end;
type OMathSSubRange = class(AdvancedRange)
public
function Create(docx_to_pdf: TSDocxToPdf; s_sub: SSub);
function Do();override;
function Calc();override;
function Offset(x: real; y: real; page: Page);override;
function AdjustOffset(x: real; y: real);overload;
public
BaseHeight: real; // 基准高度
BaseSz: real; // 基准字体大小
private
[weakref]docx_to_pdf_: TSDocxToPdf;
s_sub_: SSub;
range_array_: array of BasicRange;
end;
type OMathDRange = class(AdvancedRange)
public
function Create(docx_to_pdf: TSDocxToPdf; d: D);
function Do();override;
function Calc();override;
function Offset(x: real; y: real; page: Page);override;
function AdjustOffset(x: real; y: real);overload;
public
BaseHeight: real; // 基准高度
BaseSz: real; // 基准字体大小
private
[weakref]docx_to_pdf_: TSDocxToPdf;
d_: D;
range_array_: array of BasicRange;
end;
type OMathFuncRange = class(AdvancedRange)
public
function Create(docx_to_pdf: TSDocxToPdf; func: Func);
function Do();override;
function Calc();override;
function Offset(x: real; y: real; page: Page);override;
function AdjustOffset(x: real; y: real);overload;
public
BaseHeight: real; // 基准高度
BaseSz: real; // 基准字体大小
private
[weakref]docx_to_pdf_: TSDocxToPdf;
func_: Func;
range_array_: array of BasicRange;
end;
implementation
function AdvancedRange.Create();
begin
class(BasicRange).Create();
{self.}LowerBound := 0.0;
{self.}StartPage := nil;
{self.}StartX := 0.0;
{self.}StartY := 0.0;
range_array_ := array();
end;
function AdvancedRange.Offset(x: real; y: real; page: Page);
begin
{self.}StartX := {self.}XOffset + x;
{self.}StartY := {self.}YOffset + y;
{self.}StartPage := page;
{self.}EndX := {self.}StartX;
{self.}EndY := {self.}StartY;
{self.}EndPage := {self.}StartPage;
end;
function TocRange.Create();
begin
class(AdvancedRange).Create();
{self.}TextRange := nil;
{self.}BaseLine := 0;
end;
function TocRange.LinkAnnot(dst: PdfDestination);
begin
annot := {self.}EndPage.PdfPage.CreateLinkAnnot(rect_, dst);
annot.LinkAnnotSetHighlightMode(TSPdfEnumerations.ANNOT_NO_HIGHTLIGHT);
annot.LinkAnnotSetBorderStyle(0, 0, 0);
end;
function TocRange.AddPageNumber(pg: Page);
begin
number_str := tostring(pg.Number);
{self.}EndPage.PdfPage.SetFontAndSize({self.}TextRange.Font, {self.}TextRange.RPr.Sz.Val);
number_sz := {self.}EndPage.PdfPage.TextWidth(number_str);
x := rect_[2] - number_sz;
y := {self.}BaseLine;
{self.}TextRange.EndPage := {self.}EndPage;
{self.}TextRange.Text := number_str;
{self.}TextRange.EndX := x;
{self.}TextRange.EndY := y;
{self.}TextRange.Do();
// 目录......
sx := {self.}EndX;
{self.}EndPage.PdfPage.SetRGBStroke(0, 0, 0);
{self.}EndPage.PdfPage.SetDash(array(0.5, 2), 2, 0);
{self.}EndPage.PdfPage.SetLineWidth(0.5);
{self.}EndPage.PdfPage.SetLineCap(TSPdfEnumerations.ROUND_END);
{self.}EndPage.PdfPage.MoveTo(sx, y);
{self.}EndPage.PdfPage.LineTo(x-0.5, y);
{self.}EndPage.PdfPage.Stroke();
end;
function TocRange.CalculateRect();
begin
pline_range := {self.}Parent;
{self.}EndPage := pline_range.EndPage;
if {self.}StartRange then
begin
rect_ := array({self.}StartRange.EndX, pline_range.EndY, pline_range.StartX + pline_range.Width, pline_range.StartY);
end
else begin
rect_ := array(pline_range.StartX, pline_range.EndY, pline_range.StartX + pline_range.Width, pline_range.StartY);
end
offset := pline_range.LineSpace >= pline_range.DynamicHeight ? (pline_range.LineSpace - pline_range.TextMaxSize) / 2 + pline_range.TextMaxSize - pline_range.TextMaxSize / 5 : pline_range.DynamicHeight;
y := pline_range.StartY - offset;
{self.}BaseLine := y;
{self.}EndX := ifObj({self.}EndRange) ? {self.}EndRange.EndX + {self.}EndRange.Width + 1 : {self.}Parent.StartX;
end;
function HdrRange.Create(docx_to_pdf: TSDocxToPdf; hdr: Hdr);
begin
class(AdvancedRange).Create();
docx_to_pdf_ := docx_to_pdf;
hdr_ := hdr;
range_array_ := array();
end;
function HdrRange.Do();override;
begin
for _,range in range_array_ do
range.Do();
end;
function HdrRange.Calc(): boolean;override;
begin
{self.}DynamicHeight := 0;
return {self.}Traverse(hdr_);
end;
function HdrRange.Offset(x: real; y: real; page: Page);virtual;
begin
class(AdvancedRange).Offset(x, y, page);
for _,range in range_array_ do
begin
range.LowerBound := {self.}LowerBound;
range.Offset({self.}EndX, {self,}EndY, {self.}EndPage);
{self.}EndY := range.EndY;
end
end;
function HdrRange.Traverse(obj: OpenXmlElement);
begin
flag := true;
elements := obj.Elements();
for _,element in elements do
begin
if element.LocalName = "p" then
begin
range := new PRange(docx_to_pdf_, element);
range.Width := {self.}Width;
range.Parent := self;
fg := range.Calc();
if not fg then flag := fg;
range_array_[length(range_array_)] := range;
{self.}DynamicHeight += range.DynamicHeight;
end
else if element.LocalName = "sdt" then
begin
{self.}Traverse(element.SdtContent);
end
end
return flag;
end;
function HdrRange.ProcessRealtimeArray();
begin
for _,range in range_array_ do
range.ProcessRealtimeArray();
end;
function FtrRange.Create(docx_to_pdf: TSDocxToPdf; ftr: Ftr);
begin
class(AdvancedRange).Create();
docx_to_pdf_ := docx_to_pdf;
ftr_ := ftr;
range_array_ := array();
end;
function FtrRange.Do();override;
begin
for _,range in range_array_ do
range.Do();
end;
function FtrRange.Calc();
begin
{self.}DynamicHeight := 0;
return {self.}Traverse(ftr_);
end;
function FtrRange.Offset(x: real; y: real; page: Page);virtual;
begin
class(AdvancedRange).Offset(x, y, page);
for _,range in range_array_ do
begin
range.LowerBound := {self.}LowerBound;
range.Offset({self.}StartX, {self.}EndY, {self.}EndPage);
{self.}EndY := range.EndY;
end
end;
function FtrRange.Traverse(obj: OpenXmlElement);
begin
flag := true;
elements := obj.Elements();
for _,element in elements do
begin
if element.LocalName = "p" then
begin
range := new PRange(docx_to_pdf_, element);
range.Width := {self.}Width;
range.Parent := self;
fg := range.Calc();
if not fg then flag := fg;
range_array_[length(range_array_)] := range;
{self.}DynamicHeight += range.DynamicHeight;
end
else if element.LocalName = "sdt" then
begin
flag := {self.}Traverse(element.SdtContent);
end
end
return flag;
end;
function FtrRange.ProcessRealtimeArray();
begin
for _,range in range_array_ do
begin
range.ProcessRealtimeArray();
end
end;
function PLineRange.Create();
begin
class(AdvancedRange).Create();
{self.}TextMaxSize := 0;
{self.}LineSpace := 0;
range_array_ := array();
end
function PLineRange.Do();override;
begin
for _,range in range_array_ do
range.Do();
end;
function PLineRange.Offset(x: real; y: real; page: Page);override;
begin
{self.}StartX := x;
{self.}StartY := y;
{self.}StartPage := page;
{self.}EndX := x + {self.}XOffset;
{self.}EndY := y - {self.}DynamicHeight; // 没用上YOffset
{self.}EndPage := page;
offset := {self.}LineSpace >= {self.}DynamicHeight ? ({self.}LineSpace - {self.}TextMaxSize) / 2 + {self.}TextMaxSize - {self.}TextMaxSize / 5 : {self.}DynamicHeight;
y_offset := {self.}StartY - offset;
for _,range in range_array_ do
begin
if range is class(OMathRange) then // 公式不是y值需要处理公式
range.Offset(x, y, page);
// range.Offset(0, 841.9, page);
else
range.Offset(x, y_offset, page);
end
end;
function PLineRange.CanFitInLine(range: BasicRange): boolean;
begin
if range.Width > {self.}Width then return false; // 单一宽度比行宽还宽
if {self.}XOffset + range.Width < {self.}Width + 1e-6 then return false; // 未超过行宽
if range is class(TextRange) and
range.Type = 4 and
not ({self.}Parent.Parent is class(TcRange)) then return false; // 中文标点不换行
if range is class(OMathParaRange) then return false; // 公式不换行
return true;
end;
function PLineRange.AddRange(range: BasicRange);
begin
range_array_[length(range_array_)] := range;
end;
function PLineRange.Align(val: string);
begin
offset := 0;
last := range_array_[length(range_array_)-1];
case val of
"center":
offset := ({self.}Width + {self.}StartX - {self.}EndX) / 2;
"right":
offset := {self.}Width + {self.}StartX - {self.}EndX;
end;
if offset <= 0 then return;
for _,range in range_array_ do
range.EndX += offset;
end;
function PLineRange.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 PLineRange.RangeArr(): array of BasicRange;
begin
return range_array_;
end;
function PRange.Create(docx_to_pdf: TSDocxToPdf; p: P);
begin
class(AdvancedRange).Create();
docx_to_pdf_ := docx_to_pdf;
p_ := p;
end;
function PRange.Init();
begin
br_type_ := "";
body_range_array_ := array();
bullet_range_array_ := array();
line_range_array_ := array();
drawing_anchor_array_ := array();
alternate_content_array_ := array();
bookmark_hash_ := array();
hyperlink_hash_ := array();
footnote_reference_hash_ := array();
realtime_page_array_ := array();
realtime_numpages_array_ := array();
// 根据段落的间距确定新的坐标
ppr := ppr_;
sz := ppr.RPr.SzCs.Val ? : ppr.RPr.Sz.Val;
{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 PRange.Do();override;
begin
for _,line_range in line_range_array_ do
line_range.Do();
// 段落边框
if length(line_range_array_) > 0 and ppr_.PBdr.Bottom.Val = "single" then
begin
{self.}EndPage.PdfPage.SetLineWidth(0.5);
{self.}EndPage.PdfPage.SetGrayStroke(0.25);
{self.}EndPage.PdfPage.MoveTo({self.}StartX, {self.}EndY);
{self.}EndPage.PdfPage.LineTo({self.}StartX + {self.}Width, {self.}EndY);
{self.}EndPage.PdfPage.Stroke();
end
// 处理bookmark
for anchor,arr in bookmark_hash_ do
if arr[0] then docx_to_pdf_.Toc.LinkToToc(anchor, arr[0]);
// 检查是否有hyperlink要链接
for anchor,_ in hyperlink_hash_ do
docx_to_pdf_.Toc.LinkToToc(anchor);
end;
function PRange.Calc(): boolean;override;
begin
// ppr.rpr是无效的应该以ppr.pStyle为准
{self.}SetPPPr(p_);
if not p_.PPr.RPr.Sz.Val then p_.PPr.RPr.Sz.Val := docx_to_pdf_.Font.GetDefaultSz();
ppr_ := p_.PPr;
{self.}Init();
{self.}SetLvlText();
bookmark_name := "";
elements := p_.Elements();
fld_stack := new DTPUtils.Stack();
for _, element in elements do
begin
if element.LocalName = "pPr" then continue;
else if element.LocalName = "bookmarkStart" then
begin
bookmark_name := element.Name;
bookmark_hash_[bookmark_name] := array();
end
else if element.LocalName = "bookmarkEnd" then
begin
bookmark_name := "";
end
else if element.LocalName = "r" then
begin
{self.}SetRRPr(element, ppr_);
if element.FldChar.FldCharType = "begin" then
begin
fld_struct := new DTPUtils.FldStruct();
fld_stack.Push(fld_struct);
continue;
end
if not fld_stack.Empty() then
begin
{self.}RFldChar(element, fld_stack);
continue;
end
if element.T then {self.}RT(element, bookmark_name);
else if element.Br then {self.}RBr(element);
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.Anchor then {self.}Hyperlink(element);
end
else if element.LocalName = "fldSimple" then
begin
{self.}FldSimple(element);
end
else if element.LocalName = "hyperlink" then
begin
{self.}Hyperlink(element);
end
else if element.LocalName = "oMathPara" then
begin
// 公式单独成行
{self.}OMathPara(element);
end
else if element.LocalName = "oMath" then
begin
// 公式嵌入段落
{self.}OMath(element);
end
end
{self.}RangesToLines();
// 需要实时计算总页码的情况是需要最后处理的
return length(realtime_numpages_array_) ? false : true;
end;
function PRange.Offset(x: real; y: real; page: Page);override;
begin
// println("PRange::x = {}, y = {}, page = {}", x, y, page);
class(AdvancedRange).Offset(x, y, page);
right_bound_ := {self.}StartX + {self.}Width;
// 检查是否需要实时计算页码
if length(realtime_page_array_) > 0 then
begin
pg := {self.}StartPage;
for _,range in realtime_page_array_ do
begin
pg.PdfPage.SetFontAndSize(range.Font, range.RPr.Sz.Val);
range.Text := tostring(pg.Number);
range.Width := pg.PdfPage.TextWidth(range.Text);
range.Type := 1;
end
realtime_page_array_ := array();
{self.}RangesToLines();
end
{self.}DeterminePosition();
end;
function PRange.RBr(r: R);
begin
br_type_ := r.Br.Type;
end;
function PRange.RFootnoteReference(r: R);
begin
return;
docx_to_pdf_.Note.AddFootnoteId(r.FootnoteReference.Id);
if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz();
font_name := rpr.RFonts.Ascii ?: rpr.RFonts.EastAsia;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B.IsApplied, rpr.I.IsApplied);
text := new TextRange();
text.RPr := rpr;
text.Font := font_obj;
text.Text := docx_to_pdf_.Note.GetFootnoteOrderNumber();
text.Width := docx_to_pdf_.PageManager[0].PdfPage.TextWidth(text.Text);
body_range_array_[length(body_range_array_)] := text;
footnote_reference_hash_[text] := id;
end;
function PRange.RDrawing(r: R);
begin
if r.Drawing.Anchor then
begin
anchor := r.Drawing.Anchor;
drawing_anchor_array_[length(drawing_anchor_array_)] := anchor;
end
else 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 := r.Drawing._Inline.Graphic.GraphicData.Pic.SpPr.Xfrm;
image_range := new ImageRange();
image_range.Image := image;
image_range.Type := image_type;
image_range.Width := xfrm.Ext.CX;
image_range.DynamicHeight := xfrm.Ext.CY;
image_range.RPr := r.RPr;
body_range_array_[length(body_range_array_)] := image_range;
end
end;
function PRange.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.Width := w;
image_range.DynamicHeight := h;
image_range.RPr := r.RPr;
body_range_array_[length(body_range_array_)] := image_range;
end;
function PRange.RFldChar(r: R; stack: Stack);
begin
fld_struct := stack.Pop();
if r.FldChar.FldCharType = "separate" then
begin
fld_struct.Status := 1;
stack.Push(fld_struct);
return;
end
// else if r.FldChar.FldCharType = "end" then
// fld_struct.Status = 2;
if fld_struct.Status = 2 then return;
if r.InstrText.Text then
begin
fields := str2array(r.InstrText.Text, " ");
for _,field in fields do
begin
fld := trim(field);
if fld = "NUMPAGES" then
fld_struct.Type.NumPages := true;
else if fld = "PAGE" then
fld_struct.Type.Page := true;
else if fld = "QUOTE" then
fld_struct.Type.Quote := true;
else if fld = "PAGEREF" then
fld_struct.Type.PageRef := true;
else if fld = "Arabic" then
fld_struct.Arabic := true;
else if fld = "MERGEFORMAT" then
fld_struct.MergeFormat := true;
end
end
if fld_struct.Status = 1 then
begin
rpr := r.RPr;
if fld_struct.Type.Page then
begin
if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz();
font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B.IsApplied, rpr.I.IsApplied);
text := new TextRange();
text.RPr := rpr;
// text.Type := 1;
text.Font := font_obj;
text.DynamicHeight := rpr.Sz.Val;
text.Width := 1.5 * RPr.Sz.Val; // 预留三个数字的宽度
realtime_page_array_[length(realtime_page_array_)] := text;
body_range_array_[length(body_range_array_)] := text;
end
else if fld_struct.Type.NumPages then
begin
if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz();
font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B.IsApplied, rpr.I.IsApplied);
text := new TextRange();
text.RPr := rpr;
// text.Type := 1;
text.Font := font_obj;
text.DynamicHeight := rpr.Sz.Val;
text.Width := 1.5 * RPr.Sz.Val; // 预留三个数字的宽度
realtime_numpages_array_[length(realtime_numpages_array_)] := text;
body_range_array_[length(body_range_array_)] := text;
end
else if fld_struct.Type.Quote then
begin
if r.Drawing then {self.}RDrawing(r);
end
fld_struct.Status := 2;
end
if fld_struct.Status <> 2 then stack.Push(fld_struct);
end;
function PRange.RAlternateContent(r: R);
begin
anchor := r.AlternateContent.Choice.Drawing.Anchor;
alternate_content_array_[length(alternate_content_array_)] := anchor;
end;
function PRange.FldSimple(fld_simple: fldSimple);
begin
if fld_simple.Instr then
begin
fields := str2array(fld_simple.Instr, " ");
fld_struct := new DTPUtils.FldStruct();
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_);
if fld_struct.Type.NumPages then
begin
if fld_struct.Arabic then
begin
rpr := r.RPr;
if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz();
font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B.IsApplied, rpr.I.IsApplied);
text := new TextRange();
text.RPr := rpr;
// text.Type := 1;
text.Font := font_obj;
text.DynamicHeight := rpr.Sz.Val;
text.Width := 1.5 * RPr.Sz.Val; // 预留三个数字的宽度
realtime_numpages_array_[length(realtime_numpages_array_)] := text;
body_range_array_[length(body_range_array_)] := text;
end
end
end;
function PRange.Hyperlink(hyperlink: Hyperlink);
begin
i := length(body_range_array_);
rs := hyperlink.Rs();
fld_stack := new DTPUtils.Stack();
for _,r in rs do
begin
if r.FldChar.FldCharType = "begin" then
begin
fld_struct := new DTPUtils.FldStruct();
fld_stack.Push(fld_struct);
end
else if r.FldChar.FldCharType = "end" then
begin
fld_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);
rpr := r.RPr;
if not rpr.Sz.Val then rpr.Sz.Val := rpr.SzCs.Val ? rpr.SzCs.Val : docx_to_pdf_.Font.GetDefaultSz();
font_name := rpr.RFonts.EastAsia ? rpr.RFonts.EastAsia : rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B.IsApplied, rpr.I.IsApplied);
text := new TextRange();
text.RPr := rpr;
text.Font := font_obj;
text.DynamicHeight := rpr.Sz.Val;
text.Width := 1.5 * RPr.Sz.Val; // 预留三个数字的宽度
end
if not fld_stack.Empty() then continue;
if r.T then
begin
{self.}SetRRPr(r, ppr_);
r.RPr.Color.Val := nil;
{self.}RT(r);
end
end
arr := array();
while i < length(body_range_array_) do
begin
arr[length(arr)] := body_range_array_[i];
i++;
end
hyperlink_hash_[hyperlink.Anchor] := array(text, arr);
end;
function PRange.OMathPara(o_math_para: OMathPara);
begin
math_para_range := new OMathParaRange(docx_to_pdf_, o_math_para);
math_para_range.Width := 0;
math_para_range.Parent := self;
math_para_range.Calc();
body_range_array_[length(body_range_array_)] := math_para_range;
end;
function PRange.OMath(o_math: OMath);
begin
math_range := new OMathRange(docx_to_pdf_, o_math);
math_range.Width := 0;
math_range.Parent := self;
math_range.XOffset := 0;
math_range.YOffset := 0;
math_range.SetMathSize();
math_range.Calc();
math_range.AdjustOffset(0, -math_range.DynamicHeight);
body_range_array_[length(body_range_array_)] := math_range;
end;
function PRange.HyperlinkToToc();
begin
for anchor, arr in hyperlink_hash_ do
begin
text := arr[0];
r_arr := arr[1];
range0 := r_arr[0];
range1 := r_arr[length(r_arr)-1];
if range0.Parent.Index = range1.Parent.Index then // 同一行
begin
if range1.Parent.EndX + text.Width < {self.}Width then // 页码不需要换行
begin
toc := new TocRange();
toc.Parent := range0.Parent;
toc.TextRange := text;
toc.StartRange := range0;
toc.EndRange := range1;
docx_to_pdf_.Toc.AddToc(anchor, toc);
end
else begin // 需要新增一行
pline_range := new PLineRange();
pline_range.Parent := self;
pline_range.Width := {self.}Width;
pline_range.EndX := 0;
pline_range.DynamicHeight := range1.Parent.DynamicHeight;
pline_range.LineSpace := range1.Parent.LineRule;
index := range1.Parent.Index + 1;
for i:=length(line_range_array_) downto index do
begin
line_range := line_range_array_[i];
line_range.Index++;
line_range_array_[i+1] := line_range;
end
line_range_array_[index] := pline_range;
toc := new TocRange();
toc.Parent := pline_range;
toc.TextRange := text;
docx_to_pdf_.Toc.AddToc(anchor, toc);
end
end
else begin
for i:=range0.Parent.Index to range1.Parent.Index do
begin
if i = range1.Parent.Index then
begin
if range1.Parent.EndX + text.Width < {self.}Width then // 页码不需要换行
begin
toc := new TocRange();
toc.Parent := range1.Parent;
toc.TextRange := text;
toc.EndRange := range1;
docx_to_pdf_.Toc.AddToc(anchor, toc);
end
else begin // 需要新增一行
pline_range := new PLineRange();
pline_range.Parent := self;
pline_range.Width := {self.}Width;
pline_range.EndX := 0;
pline_range.DynamicHeight := range1.Parent.DynamicHeight;
pline_range.LineSpace := range1.Parent.LineRule;
index := range1.Parent.Index + 1;
for i:=length(line_range_array_) downto index do
begin
line_range := line_range_array_[i];
line_range.Index++;
line_range_array_[i+1] := line_range;
end
line_range_array_[index] := pline_range;
toc := new TocRange();
toc.Parent := pline_range;
toc.TextRange := text;
docx_to_pdf_.Toc.AddToc(anchor, toc);
end
end
else begin
toc := new TocRange();
toc.Parent := line_range_array_[i];
toc.TextRange := text;
docx_to_pdf_.Toc.AddToc(anchor, toc);
end
end
end
end
end;
function PRange.PLineRanges(): array of PLineRange;
begin
return line_range_array_;
end;
function PRange.RangesToLines();
begin
{self.}UpdateTextRangeWidth();
{self.}BasicRangesToPLineRange();
{self.}HyperlinkToToc();
end;
function PRange.BasicRangesToPLineRange();
begin
line_range_array_ := array();
{self.}DynamicHeight := 0;
{self.}DynamicHeight += ppr_.Spacing.Before;
// 段落的x偏移是缩进
{self.}XOffset := ppr_.Ind.LeftChars ? ppr_.Ind.LeftChars * ppr_.RPr.Sz.Val : ppr_.Ind.Left;
{self.}YOffset := 0;
pline_range := {self.}NewPLineRange();
pline_range.XOffset := ppr_.Ind.FirstLine; // 首行有间距.用offsetx作为位置计算
i := 0;
anchor := nil;
while i < length(body_range_array_) do
begin
range := body_range_array_[i];
if_newline := pline_range.CanFitInLine(range);
if if_newline then
begin
{self.}AddPLineRange(pline_range);
{self.}DynamicHeight += pline_range.DynamicHeight;
pline_range := {self.}NewPLineRange();
end
if range is class(TextRange) and range.RPr.Sz.Val > pline_range.TextMaxSize then
pline_range.TextMaxSize := range.RPr.Sz.Val;
if range.DynamicHeight > pline_range.DynamicHeight then pline_range.DynamicHeight := range.DynamicHeight;
// range.AdjustOffset(pline_range.XOffset, 0);
range.XOffset := pline_range.XOffset;
range.Parent := pline_range;
pline_range.AddRange(range);
pline_range.XOffset += range.Width;
i++;
if i = length(body_range_array_) then
begin
{self.}AddPLineRange(pline_range);
{self.}DynamicHeight += pline_range.DynamicHeight;
end
end
if length(line_range_array_) = 0 then
begin
line_space := {self.}GetParagraphLineSpace(ppr_.RPr.Sz.Val, ppr_.Spacing.Line, ppr_.Spacing.LineRule);
{self.}DynamicHeight += line_space;
end
{self.}DynamicHeight += ppr_.Spacing.After;
// println("line_range_array_ = {}", line_range_array_);
end;
function PRange.NewPLineRange(): PLineRange;
begin
pline_range := new PLineRange();
pline_range.Parent := self;
pline_range.Width := {self.}Width;
return pline_range;
end;
function PRange.AddPLineRange(pline_range: PLineRange);
begin
pline_range.LineSpace := {self.}GetParagraphLineSpace(pline_range.TextMaxSize, ppr_.Spacing.Line, ppr_.Spacing.LineRule);
pline_range.DynamicHeight := max(pline_range.LineSpace, pline_range.DynamicHeight);
pline_range.Index := length(line_range_array_);
line_range_array_[length(line_range_array_)] := pline_range;
end;
function PRange.UpdateTextRangeWidth();
begin
if length(realtime_page_array_) > 0 or length(realtime_numpages_array_) > 0 then return;
i := 0;
head_range := nil;
tail_range := nil;
while i < length(body_range_array_)-1 do
begin
if not (head_range is class(TextRange)) then
begin
i++;
head_range := body_range_array_[i];
end
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 (tail_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 PRange.DeterminePosition();
begin
// 检查是否有分页,分一栏
if br_type_ = "page" then
{self.}EndY := {self.}LowerBound;
else if br_type_ = "column" and (ifnil(docx_to_pdf_.CurrentSect.SectPr.Cols.Num) or docx_to_pdf_.CurrentSect.SectPr.Cols.Num <= 1) then
{self.}EndY := {self.}LowerBound;
// 段前距只有不换页情况才计算
if not {self.}CheckAndAddPage({self.}EndY, ppr_.Spacing.Before) then
{self.}EndY -= ppr_.Spacing.Before;
// 检查是否有段前分页
if ppr_.PageBreakBefore then
{self.}CheckAndAddPage({self.}LowerBound, 1);
for _,line_range in line_range_array_ do
begin
y := {self.}EndY;
if {self.}CheckAndAddPage(y, line_range.DynamicHeight) then // 行不够时候调整上一页LowerBound
docx_to_pdf_.PageManager[{self.}EndPage.Index - 1].LowerBound := y;
line_range.Offset({self.}EndX, {self.}EndY, {self.}EndPage);
line_range.Align(ppr_.Jc.Val);
{self.}EndY := line_range.EndY;
end
if not {self.}Parent is class(TcRange) then
{self.}AlignRightBound();
if length(line_range_array_) = 0 then // 空段落
begin
line_space := {self.}GetParagraphLineSpace(ppr_.RPr.Sz.Val, ppr_.Spacing.Line, ppr_.Spacing.LineRule);
{self.}EndY -= line_space;
end
{self.}DoDrawingAnchor();
{self.}DoAlternateContentAnchor();
{self.}DoToc();
{self.}EndY -= ppr_.Spacing.After;
end;
function PRange.DoToc();
begin
for anchor,_ in hyperlink_hash_ do
docx_to_pdf_.Toc.CalculateRect(anchor);
end;
function PRange.DoDrawingAnchor();
begin
for _,anchor in drawing_anchor_array_ do
begin
id := anchor.Graphic.GraphicData.Pic.BlipFill.Blip.Embed;
[image_type, image] := {self.}GetImageData(id);
if not image then return;
xfrm := anchor.Graphic.GraphicData.Pic.SpPr.Xfrm;
position_h := anchor.PositionH;
position_v := anchor.PositionV;
[x, y] := {self.}GetXYCordinates();
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.EndPage := {self.}EndPage;
image_range.Do();
end
end;
function PRange.DoAlternateContentAnchor();
begin
for _,anchor in alternate_content_array_ do
begin
wsp := anchor.Graphic.GraphicData.Wsp;
[x, y] := {self.}GetXYCordinates();
xfrm := wsp.SpPr.Xfrm;
position_h := anchor.PositionH;
position_v := 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 := 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 PRange(docx_to_pdf_, p);
range.Width := w;
range.Parent := self;
range.LowerBound := 0;
fg := range.Calc();
if not fg then flag := fg;
range.Offset(x, y, {self.}EndPage);
range.Do();
y := range.EndY;
end
end
end;
function PRange.ProcessRealtimeArray();
begin
for _,range in realtime_numpages_array_ do
begin
range.Text := tostring(docx_to_pdf_.PageManager[docx_to_pdf_.PageManager.Count-1].Number);
first_page := docx_to_pdf_.PageManager[0];
range.Width := first_page.PdfPage.TextWidth(range.Text);
range.Type := 1;
end
realtime_numpages_array_ := array();
{self.}RangesToLines();
{self.}DeterminePosition();
end;
function PRange.IsFirstLineOnNextPage(): boolean;
begin
lrange := line_range_array_[0];
return ifnil(lrange) ? false : lrange.EndPage <> {self.}StartPage;
end;
function PRange.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 PRange.CheckAndAddPage(y: real; offset: real): boolean;
begin
lb := {self.}LowerBound;
if lb > 0 then
lb := lb > {self.}EndPage.LowerBound ? lb : {self.}EndPage.LowerBound;
if y - offset < lb then
begin
{self.}EndPage := docx_to_pdf_.PageManager[{self.}EndPage.Index + 1];
if ifnil({self.}EndPage) then {self.}EndPage := docx_to_pdf_.AddPage();
{self.}EndY := {self.}EndPage.OriginalTextCoordinates()[1];
return true;
end
return false;
end;
function PRange.RT(r: R; anchor: string);
begin
text := r.T.Text;
if text then {self.}SplitTextToTextRange(body_range_array_, text, r.rpr, anchor);
end;
function PRange.SplitTextToTextRange(range_arr: array of BasicRange; text: string; rpr: RPr; anchor: 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;
else if char = 0x44 or char = 0x46 then
text_range.Type := 5;
word := a_word;
font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B.IsApplied, rpr.I.IsApplied);
// font_name := rpr.RFonts.Ascii ?: rpr.RFonts.EastAsia;
// font_obj := docx_to_pdf_.Font.GetAsciiFont(font_name, rpr.B.IsApplied, rpr.I.IsApplied);
end
else if DTPUtils.IsChineseChar(a_word) then
begin
text_range.Type := 3;
word := utf8ToAnsi(a_word);
font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B.IsApplied, rpr.I.IsApplied);
end
else if DTPUtils.IsChinesePunctuation(a_word) then
begin
text_range.Type := 4;
word := utf8ToAnsi(a_word);
font_name := rpr.RFonts.EastAsia ?: rpr.RFonts.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B.IsApplied, rpr.I.IsApplied);
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.Ascii;
font_obj := docx_to_pdf_.Font.GetCNSFont(font_name, rpr.B.IsApplied, rpr.I.IsApplied);
end
end
first_page := docx_to_pdf_.PageManager[0];
pdf_page := first_page.PdfPage;
pdf_page.SetFontAndSize(font_obj, rpr.Sz.Val);
text_range.RPr := rpr;
text_range.Text := word;
text_range.Font := font_obj;
text_range.Width := pdf_page.TextWidth(word);
text_range.DynamicHeight := rpr.Sz.Val;
pos += num;
range_arr[length(range_arr)] := text_range;
if ifarray(bookmark_hash_[anchor]) then bookmark_hash_[anchor] union= array(text_range);
end
end;
function PRange.SetPPPr(var p: P);
begin
if not p.PPr then
begin
styles := docx_to_pdf_.DocxComponents.GetStyles();
p.PPr := styles.DocDefaults.PPrDefault.PPr;
end
else begin
if p.PPr.PStyle.Val then
{self.}SetPPrByStyleId(p.PPr, p.PPr.PStyle.Val);
else if {self.}Parent is class(TcRange) then
{self.}SetPPrByStyleId(p.PPr, {self.}Parent.GetTblStyleId());
end
end;
function PRange.SetPPrByStyleId(var ppr: PPr; style_id: string);
begin
styles := docx_to_pdf_.DocxComponents.GetStylesAdapter();
style := styles.GetStyleByStyleId(style_id);
if ifObj(style) then
begin
ppr.SetFallback(style.PPr);
based_on := style.BasedOn.Val;
{self.}SetPPrByStyleId(ifnil(style.PPr) ? ppr : style.PPr, based_on);
end
end;
function PRange.SetRRPr(var r: R; ppr_: PPr);
begin
if ifnil(r.RPr) then
begin
styles := docx_to_pdf_.DocxComponents.GetStyles();
r.RPr := styles.DocDefaults.RPrDefault.RPr;
end
else begin
if r.RPr.RStyle.Val then
{self.}SetRPrByStyleId(r.RPr, r.RPr.RStyle.Val);
else if ppr_.PStyle.Val then
{self.}SetRPrByStyleId(r.RPr, ppr_.PStyle.Val);
else if {self.}Parent is class(TcRange) then
{self.}SetRPrByTblStyleId(r.RPr, {self.}Parent.GetTblStyleId());
end
end;
function PRange.SetRPrByTblStyleId(var rpr: RPr; style_id: string);
begin
styles := docx_to_pdf_.DocxComponents.GetStylesAdapter();
style := styles.GetStyleByStyleId(style_id);
if ifObj(style) then
begin
pr_type := {self.}Parent.GetPrType();
tbl_style_pr := docx_to_pdf_.DocxComponents.GetTblStylePrByType(style_id, pr_type);
rpr.SetFallback(tbl_style_pr.RPr);
{self.}SetRPrByTblStyleId(ifnil(tbl_style_pr.RPr) ? rpr : tbl_style_pr.RPr, style.BasedOn.Val);
end
end;
function PRange.SetRPrByStyleId(var rpr: RPr; style_id: string);
begin
styles := docx_to_pdf_.DocxComponents.GetStylesAdapter();
style := styles.GetStyleByStyleId(style_id);
if ifObj(style) then
begin
rpr.SetFallback(style.RPr);
based_on := style.BasedOn.Val;
{self.}SetRPrByStyleId(ifnil(style.RPr) ? rpr : style.RPr, based_on);
end
end;
function PRange.SetLvlText();
begin
numbering_module := docx_to_pdf_.DocxComponents.GetNumberingModule();
if not ifObj(numbering_module) then return;
[lvl_text, lvl] := numbering_module.GetNumberLvl(p_.PPr);
if lvl_text = "" and ifnil(lvl) then return;
{self.}SetRRPr(lvl, ppr_);
// {self.}SplitTextToTextRange(bullet_range_array_, lvl_text, rpr);
{self.}SplitTextToTextRange(body_range_array_, lvl_text, lvl.RPr);
end;
function PRange.GetXYCordinates(): array of real;
begin
xml_file := docx_to_pdf_.GetCurrentXmlFile();
if xml_file = "document.xml" then
begin
[x, y] := {self.}EndPage.OriginalTextCoordinates();
end
else begin
x := {self.}EndPage.SectPr.PgMar.Left;
if ansiContainsStr(xml_file, "footer") then
y := {self.}EndPage.SectPr.PgMar.Bottom;
else if ansiContainsStr(xml_file, "header") then
y := {self.}EndPage.SectPr.PgSz.H - {self.}EndPage.SectPr.PgMar.Header;
end
return array(x, y);
end;
function PRange.GetImageData(id: string): PdfImage;
begin
xml_file := docx_to_pdf_.GetCurrentXmlFile();
if {self.}Parent is class(HdrRange) then
rels_adapter := docx_to_pdf_.DocxComponents.GetHdrRelsAdapter(xml_file);
else if {self.}Parent is class(FtrRange) then
rels_adapter := docx_to_pdf_.DocxComponents.GetFtrRelsAdapter(xml_file);
else
rels_adapter := docx_to_pdf_.DocxComponents.GetDocumentRelsAdapter();
rel := rels_adapter.GetRelationshipById(id);
image_path := "word/" + rel.Target;
image := docx_to_pdf_.DocxComponents.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 PRange.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 PRange.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 / docx_to_pdf_.CurrentSect.BaseSize);
if (not ifnil(ppr_.SnapToGrid) and not ppr_.SnapToGrid) or
((ifnil(ppr_.SnapToGrid) or ppr_.SnapToGrid) and lines > multi) then
multi *= lines;
return docx_to_pdf_.CurrentSect.SectPr.DocGrid.LinePitch * multi;
end
end;
function TcRange.Create(docx_to_pdf: TSDocxToPdf; tc: Tc; trp: TrProperty);
begin
class(AdvancedRange).Create();
docx_to_pdf_ := docx_to_pdf;
tc_ := tc;
trp_ := trp;
tc_pr_ := tc_.TcPr;
content_next_page_ := false;
top_ := false;
end;
function TcRange.Do();
begin
for _,region in region_array_ do
begin
region.BordersRange.Do();
for __,range in region.RangeArr do
range.Do();
end
end;
function TcRange.DoBordersRangeFill();
begin
for _,region in region_array_ do
begin
region.BordersRange.DoFill();
end
end;
function TcRange.Calc(): boolean;override;
begin
range_array_ := array();
{self.}DynamicHeight := 0;
cell_w := {self.}Width - {self.}Parent.TblPr.TblCellMar.Right.W - {self.}Parent.TblPr.TblCellMar.Left.W;
elements := tc_.Elements();
for _,element in elements do
begin
if element.LocalName = "p" then
begin
range := new PRange(docx_to_pdf_, element);
range.Width := cell_w;
range.Parent := self;
range.Calc();
range_array_[length(range_array_)] := range;
{self.}DynamicHeight += range.DynamicHeight;
end
end
{self.}DynamicHeight += {self.}Parent.TblPr.TblCellMar.Bottom.W + {self.}Parent.TblPr.TblCellMar.Top.W;
// 同步行高
if not tc_.TcPr.VMerge.IsApplied and {self.}DynamicHeight > trp_.Height then
trp_.Height := {self.}DynamicHeight;
return true;
end;
function TcRange.Offset(x: real; y: real; page: Page);override;
begin
// println("TcRange::x = {}, y = {}, page = {}", x, y, page);
class(AdvancedRange).Offset(x, y, page);
content_next_page_ := false;
cell_x := {self.}EndX + {self.}Parent.TblPr.TblCellMar.Left.W;
cell_y := {self.}EndY - {self.}Parent.TblPr.TblCellMar.Top.W;
cell_h := {self.}FixedHeight;
for _,range in range_array_ do
begin
range.LowerBound := {self.}LowerBound;
range.Offset(cell_x, cell_y, {self.}EndPage);
if _ = 0 and range.IsFirstLineOnNextPage() then
begin
content_next_page_ := true;
break;
end
cell_y := range.EndY;
{self.}EndPage := range.EndPage;
end
{self.}EndY := cell_y - {self.}Parent.TblPr.TblCellMar.Bottom.W;
end;
function TcRange.SetTop();
begin
top_ := true;
end;
function TcRange.ContentNextPage(): boolean;
begin
return content_next_page_;
end;
function TcRange.AlignHeight(height: real);
begin
region_array_ := array();
region := new DTPUtils.Region();
region.BordersRange.Width := {self.}Width;
region.BordersRange.FixedHeight := {self.}FixedHeight;
region.BordersRange.TcPr := tc_pr_;
{self.}SetBorderRange(region.BordersRange);
region_array_[length(region_array_)] := region;
pg := {self.}StartPage;
y := {self.}StartY;
page_remaining_height := y - {self.}GetLowerBound(pg);
surplus := height - page_remaining_height;
if surplus < 1e-6 then // 一页就够
begin
region.BordersRange.EndX := {self.}StartX;
region.BordersRange.EndY := {self.}StartY;
region.BordersRange.EndPage := pg;
region.BordersRange.DynamicHeight := height;
region.RangeArr union= range_array_;
{self.}EndY := {self.}StartY - height;
end
else begin
page_hash := array();
region.BordersRange.EndX := {self.}StartX;
region.BordersRange.EndY := {self.}StartY;
region.BordersRange.EndPage := pg;
region.BordersRange.DynamicHeight := page_remaining_height;
page_hash[pg.Index] := region;
// surplus -= page_remaining_height;
pg := docx_to_pdf_.PageManager[{self.}pg.Index + 1];
if ifnil(pg) then // 受间距影响,实际上文字没有进入下一页
begin
region.RangeArr union= range_array_;
{self.}EndY := {self.}StartY - page_remaining_height;
return;
end
y := pg.OriginalTextCoordinates()[1];
page_remaining_height := y - {self.}GetLowerBound(pg);
while surplus > page_remaining_height do
begin
region := new DTPUtils.Region();
region.BordersRange.Width := {self.}Width;
region.BordersRange.EndX := {self.}StartX;
region.BordersRange.EndY := y;
region.BordersRange.EndPage := pg;
region.BordersRange.DynamicHeight := page_remaining_height;
region.BordersRange.TcPr := tc_pr_;
region.BordersRange.Top := true;
region.BordersRange.Bottom := true;
{self.}SetBorderRange(region.BordersRange);
region_array_[length(region_array_)] := region;
page_hash[pg.Index] := region;
surplus -= page_remaining_height;
pg := docx_to_pdf_.PageManager[{self.}pg.Index + 1];
y := pg.OriginalTextCoordinates()[1];
page_remaining_height := y - {self.}GetLowerBound(pg);
end
if surplus > 1e-6 then
begin
region := new DTPUtils.Region();
region.BordersRange.Width := {self.}Width;
region.BordersRange.EndX := {self.}StartX;
region.BordersRange.EndY := y;
region.BordersRange.EndPage := pg;
region.BordersRange.DynamicHeight := surplus;
region.BordersRange.TcPr := tc_pr_;
region.BordersRange.Top := true;
page_hash[pg.Index] := region;
{self.}SetBorderRange(region.BordersRange);
region_array_[length(region_array_)] := region;
{self.}EndY := y - surplus;
end
// 对应page分散到对应region
ranges := array();
for _,range in range_array_ do
ranges union= range.PLineRanges();
for _,range in ranges do
begin
region := page_hash[range.EndPage.Index];
region.RangeArr[length(region.RangeArr)] := range;
end
end
end;
function TcRange.GetLowerBound(pg: Page): real;
begin
return {self.}LowerBound = 0 ? pg.LowerBound : max({self.}LowerBound, pg.LowerBound);
end;
function TcRange.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) - {self.}Parent.TblPr.TblCellMar.Bottom.W;
case val of
"center":
begin
offset /= 2;
for _,range in arr do
range.Offset(range.StartX, range.StartY - offset, range.StartPage);
end
end;
end;
function TcRange.SetBorderRange(range: BordersRange);
begin
tbl_pr := {self.}Parent.TblPr;
if ifObj(tbl_pr.TblBorders) then
begin
if {self.}Row = 0 then
begin
if tbl_pr.TblBorders.Top then
begin
if not tc_pr_.TcBorders.Top then
tc_pr_.TcBorders.Top.SetFallback(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_.TcBorders.Bottom then
tc_pr_.TcBorders.Bottom.SetFallback(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_.TcBorders.Right then
tc_pr_.TcBorders.Right.SetFallback(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_.TcBorders.Bottom then
tc_pr_.TcBorders.Bottom.SetFallback(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_.TcBorders.Bottom then
tc_pr_.TcBorders.Bottom.SetFallback(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_.TcBorders.Right then
tc_pr_.TcBorders.Right.SetFallback(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_.TcBorders.Bottom then
tc_pr_.TcBorders.Bottom.SetFallback(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_.TcBorders.Bottom then
tc_pr_.TcBorders.Bottom.SetFallback(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_.TcBorders.Right then
tc_pr_.TcBorders.Right.SetFallback(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_.TcBorders.Left then
tc_pr_.TcBorders.Left.SetFallback(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_.TcBorders.Right then
tc_pr_.TcBorders.Right.SetFallback(tbl_pr.TblBorders.Right);
range.Right := true;
end
end
end
else begin
range.Left := false;
range.Top := false;
range.Right := false;
range.Bottom := false;
end
if top_ and ifObj(tbl_pr.TblBorders) then range.Top := true;
end;
function TcRange.GetTblStyleId(): string;
begin
return {self.}Parent.TblPr.TblStyle.Val;
end;
function TcRange.GetPrType(): string;
begin
if {self.}Row = 0 then return "firstRow";
else if ({self.}Row + 1) % 2 = 0 then return "band1Horz";
else return "band2Horz";
end;
function TblRange.Create(docx_to_pdf: TSDocxToPdf; tbl: Tbl);
begin
class(AdvancedRange).Create();
docx_to_pdf_ := docx_to_pdf;
tbl_ := tbl;
end;
function TblRange.Do();
begin
for _,r in tc_range_matrix_ do
for __,range in r do
if ifObj(range) then
range.DoBordersRangeFill();
for _,r in tc_range_matrix_ do
for __,range in r do
if ifObj(range) then
range.Do();
end;
function TblRange.Calc();
begin
{self.}SetTblTblPr(tbl_);
tbl_pr_:= tbl_.TblPr;
tbl_grid_:= tbl_.TblGrid;
grid_cols_ := tbl_grid_.GridCols();
// 如果是根据内容自适应应该计算并调整grid_cols的值
trs := tbl_.Trs();
rows_ := length(trs);
cols_ := length(grid_cols_);
tr_pr_array_ := array();
tc_range_matrix_ := nils(rows_, cols_);
// 先构建一个矩阵
{self.}CreateTableMatrix(grid_cols_, trs);
end;
function TblRange.CreateTableMatrix(grid_cols: array of GridCol; trs: array of Tr);
begin
for i,tr in trs do
begin
{self.}SetTrTrPr(tr);
tr_pr := tr.TrPr;
tc_x := 0;
trp := new DTPUtils.TrProperty();
trp.TrPr := tr_pr;
tr_pr_array_[i] := trp;
tcs := tr.Tcs();
pos := 0;
for j,tc in tcs do
begin
if i = 0 then {self.}SetTcTcPr(tc, "firstRow");
else if i = length(trs)-1 then {self.}SetTcTcPr(tc, "lastRow");
else if (i + 1) % 2 = 0 then {self.}SetTcTcPr(tc, "band1Horz");
else {self.}SetTcTcPr(tc, "band2Horz");
grid_span := tc.TcPr.GridSpan;
if tc.TcPr.VMerge.IsApplied and tc.TcPr.VMerge.Val <> "restart" then
begin
tc_x += grid_cols[pos++].W;
for k:=grid_span.Val-1 downto 1 do
begin
tc_range_matrix_[i][pos] := 0;
tc_x += grid_cols[pos++].W;
end
continue;
end
tc_range := new TcRange(docx_to_pdf_, tc, trp);
tc_range.Width := grid_cols[pos].W;
tc_range.FixedHeight := tr_pr.TrHeight.Val;
tc_range.Parent := self;
tc_range.XOffset := tc_x;
tc_range.Row := i;
tc_range.Col := pos;
tc_range_matrix_[i][pos] := tc_range;
pos++;
// 水平合并的单元格,占位需要和垂直的区分
for k:=grid_span.Val-1 downto 1 do
begin
tc_range_matrix_[i][pos] := 0; // 水平合并占位0
tc_range.Width += grid_cols[pos++].W;
end
tc_x += tc_range.Width;
end
end
// for i,arr in tc_range_matrix_ do
// println("i = {}, arr = {}", i, arr);
// println("\n");
return true;
end;
function TblRange.Offset(x: real; y: real; page: Page);override;
begin
// println("TblRange::x = {}, y = {}, page = {}", x, y, page);
{self.}StartX := x + {self.}XOffset;
{self.}StartY := y + {self.}YOffset; // table的offset实际都为0
{self.}StartPage := page;
{self.}ResetCoordinates(tbl_pr_, grid_cols_);
{self.}EndX := {self.}StartX;
{self.}EndY := {self.}StartY;
{self.}EndPage := {self.}StartPage;
i := 0;
merge_arr := array();
vmerge_height := array();
vmerge_info := array();
while i < rows_ do
begin
j := 0;
tc_y := {self.}EndY;
top := recompute_flag;
recompute_flag := false;
while j < cols_ do
begin
// if i = 13 then
// println(">>>>>>>>>>>>>>>");
range := tc_range_matrix_[i][j];
if not ifObj(range) then
begin
j++;
continue;
end
if top then range.SetTop();
range.Calc();
range.LowerBound := {self.}LowerBound;
range.Offset({self.}EndX, {self.}tc_y, {self.}EndPage);
// println("i = {}, j = {}, height = {}, sy = {}, LowerBound = {}", i, j, range.DynamicHeight, range.StartY, range.LowerBound);
if range.ContentNextPage() then // 单元格新页开始,调整上一页的下边界,并重新计算
begin
top := true;
recompute_flag := true;
{self.}EndPage.LowerBound := tc_y;
{self.}EndPage := docx_to_pdf_.PageManager[{self.}EndPage.Index + 1];
[x, y] := {self.}EndPage.OriginalTextCoordinates();
{self.}EndY := y;
break;
end
if range.Tc.TcPr.VMerge.IsApplied then
begin
b_merge_index := i;
e_merge_index := i + 1;
while ifnil(tc_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;
if ifnil(vmerge_height[e_merge_index]) or range.DynamicHeight > vmerge_height[e_merge_index] then
vmerge_height[e_merge_index] := range.DynamicHeight;
vmerge_info[e_merge_index] := b_merge_index;
end
j++;
end
if recompute_flag then continue;
top := false;
i_height := 0;
for k,v in merge_arr[i] do
begin
i_height := tr_pr_array_[i].Height;
r := tc_range_matrix_[v][k];
total_height := 0;
for index:=v to i-1 do
total_height += tr_pr_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);
r.SetVAlign();
end
if i_height then tr_pr_array_[i].Height := i_height;
for _,range in tc_range_matrix_[i] do
begin
if not ifObj(range) or range.Tc.TcPr.VMerge.IsApplied then continue;
range.AlignHeight(tr_pr_array_[i].Height);
range.SetVAlign();
{self.}EndY := range.EndY;
if {self.}EndPage.Index < range.EndPage.Index then
{self.}EndPage := range.EndPage;
end
i++;
end
end;
function TblRange.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 TblRange.SetTblTblPr(var tbl: Tbl);
begin
if ifnil(tbl.TblPr) then
tbl.TblPr := new TblPr();
{self.}SetTblPrByStyleId(tbl.TblPr, tbl.TblPr.TblStyle.Val);
end;
function TblRange.SetTblPrByStyleId(var tbl_pr: TblPr; style_id: string);
begin
styles := docx_to_pdf_.DocxComponents.GetStylesAdapter();
style := styles.GetStyleByStyleId(style_id);
if ifObj(style) then
begin
tbl_pr.SetFallback(style.TblPr);
based_on := style.BasedOn.Val;
{self.}SetTblPrByStyleId(ifnil(style.TblPr) ? tbl_pr : style.TblPr, based_on);
end
end;
function TblRange.SetTrTrPr(var tr: Tr);
begin
if ifnil(tr.TrPr) then
tr.TrPr := new TrPr();
{self.}SetTrPrByStyleId(tr.TrPr, tbl_pr_.TblStyle.Val);
end;
function TblRange.SetTrPrByStyleId(var tr_pr: TrPr; style_id: string);
begin
styles := docx_to_pdf_.DocxComponents.GetStylesAdapter();
style := styles.GetStyleByStyleId(style_id);
if ifObj(style) then
begin
tr_pr.SetFallback(style.TrPr);
based_on := style.BasedOn.Val;
{self.}SetTrPrByStyleId(ifnil(style.TrPr) ? tr_pr : style.TrPr, based_on);
end
end;
function TblRange.SetTcTcPr(var tc: Tc; type: string);
begin
if ifnil(tc.TcPr) then
tc.TcPr := new TcPr();
{self.}SetTcPrByStyleId(tc.TcPr, tbl_pr_.TblStyle.Val, type);
end;
function TblRange.SetTcPrByStyleId(var tc_pr: TcPr; style_id: string; type: string);
begin
if type then
begin
style := docx_to_pdf_.DocxComponents.GetTblStylePrByType(style_id, type);
if ifObj(style) then
tc_pr.SetFallback(style.TcPr);
end
else begin
styles := docx_to_pdf_.DocxComponents.GetStylesAdapter();
style := styles.GetStyleByStyleId(style_id);
if ifObj(style) then
begin
tc_pr.SetFallback(style.TcPr);
based_on := style.BasedOn.Val;
{self.}SetTcPrByStyleId(ifnil(style.TcPr) ? tc_pr : style.TcPr, based_on);
end
end
end;
function OMathParaRange.Create(docx_to_pdf: TSDocxToPdf; o_math_para: OMathPara);
begin
class(AdvancedRange).Create();
docx_to_pdf_ := docx_to_pdf;
o_math_para_ := o_math_para;
end;
function OMathParaRange.Do();override;
begin
o_math_range_.Do();
end;
function OMathParaRange.Offset(x: real; y: real; page: Page);override;
begin
class(AdvancedRange).Offset(x, y, page);
o_math_range_.Offset({self.}EndX, {self.}EndY, {self.}EndPage);
end;
function OMathParaRange.Calc();override;
begin
o_math_range_ := new OMathRange(docx_to_pdf_, o_math_para_.OMath);
o_math_range_.Width := {self.}Width;
o_math_range_.Parent := self;
o_math_range_.XOffset := 0;
o_math_range_.YOffset := 0;
o_math_range_.SingleLine := true;
o_math_range_.SetMathSize();
o_math_range_.Calc();
o_math_range_.AdjustOffset(0, -o_math_range_.DynamicHeight);
{self.}Width := o_math_range_.Width;
{self.}DynamicHeight := o_math_range_.DynamicHeight;
end;
function OMathParaRange.AdjustOffset(x: real; y: real);override;
begin
class(BasicRange).AdjustOffset(x, y);
o_math_range_.AdjustOffset(x, y);
end;
function OMathRange.Create(docx_to_pdf: TSDocxToPdf; element: OpenXmlElement);
begin
class(AdvancedRange).Create();
docx_to_pdf_ := docx_to_pdf;
element_ := element;
{self.}BaseHeight := 0;
{self.}BaseSz := 0;
{self.}SingleLine := false;
end;
function OMathRange.Do();override;
begin
for _,range in range_array_ do
range.Do();
end;
function OMathRange.Offset(x: real; y: real; page: Page);override;
begin
class(AdvancedRange).Offset(x, y, page);
for _,range in range_array_ do
range.Offset(x, y, page);
end;
function OMathRange.AdjustOffset(x: real; y: real);overload;
begin
class(BasicRange).AdjustOffset(x, y);
for _,range in range_array_ do
range.AdjustOffset(x, y);
end;
function OMathRange.Calc();override;
begin
range_array_ := array();
x := {self.}XOffset;
y := {self.}YOffset;
elements := element_.Elements();
up_h := 0;
for _,element in elements do
begin
range := nil;
if element.LocalName = "r" then
begin
range := new OMathRRange(docx_to_pdf_, element);
range.BaseSz := {self.}BaseSz;
end
else if element.LocalName = "f" then
begin
range := new OMathFRange(docx_to_pdf_, element);
range.BaseSz := {self.}SingleLine ? {self.}BaseSz : 0.7 * {self.}BaseSz;
end
else if element.LocalName = "rad" then
begin
range := new OMathRadRange(docx_to_pdf_, element);
range.BaseSz := {self.}BaseSz;
end
else if element.LocalName = "nary" then
begin
range := new OMathNaryRange(docx_to_pdf_, element);
range.BaseSz := {self.}BaseSz;
end
else if element.LocalName = "sSup" then
begin
range := new OMathSSupRange(docx_to_pdf_, element);
range.BaseSz := {self.}BaseSz;
end
else if element.LocalName = "sSub" then
begin
range := new OMathSSubRange(docx_to_pdf_, element);
range.BaseSz := {self.}BaseSz;
end
else if element.LocalName = "d" then
begin
range := new OMathDRange(docx_to_pdf_, element);
range.BaseSz := {self.}BaseSz;
end
else if element.LocalName = "func" then
begin
range := new OMathFuncRange(docx_to_pdf_, element);
range.BaseSz := {self.}BaseSz;
end
if not ifObj(range) then
begin
echo format("Math do not support <%s>\n", element.ElementName);
continue;
end
range.Parent := self;
range.XOffset := x;
range.YOffset := y;
range.Calc();
x += range.Width; // 下一个元素偏移位置
{self.}Width += range.Width;
if range.BaseHeight > {self.}BaseHeight then
{self.}BaseHeight := range.BaseHeight;
if range.DynamicHeight - range.BaseHeight > up_h then
up_h := range.DynamicHeight - range.BaseHeight;
// if range.DynamicHeight > {self.}DynamicHeight then
// {self.}DynamicHeight := range.DynamicHeight;
range_array_[length(range_array_)] := range;
end
{self.}DynamicHeight := {self.}BaseHeight + up_h;
for _,range in range_array_ do
range.AdjustOffset(0, {self.}BaseHeight - range.BaseHeight);
end;
function OMathRange.SetMathSize();
begin
elements := element_.Elements();
element := elements[0];
rpr := nil;
if element.LocalName = "r" then
rpr := element.RPr("w");
else if element.LocalName = "f" then
rpr := element.FPr.CtrlPr.RPr("w");
else if element.LocalName = "nary" then
rpr := element.NaryPr.CtrlPr.RPr("w");
else if element.LocalName = "rad" then
rpr := element.RadPr.CtrlPr.RPr("w");
else if element.LocalName = "sSup" then
rpr := element.SSupPr.CtrlPr.RPr("w");
styles := docx_to_pdf_.DocxComponents.GetStyles();
default_rpr := styles.DocDefaults.RPrDefault.RPr;
default_rpr.SetFallback(rpr);
{self.}BaseSz := strtofloat(default_rpr.Sz.Val) / 2;
end;
function OMathFRange.Create(docx_to_pdf: TSDocxToPdf; f: F);
begin
class(AdvancedRange).Create();
docx_to_pdf_ := docx_to_pdf;
f_ := f;
range_array_ := array();
end;
function OMathFRange.Do();override;
begin
for _,range in range_array_ do
range.Do();
end;
function OMathFRange.Offset(x: real; y: real; page: Page);override;
begin
class(AdvancedRange).Offset(x, y, page);
for _,range in range_array_ do
range.Offset(x, y, page);
end;
function OMathFRange.Calc();override;
begin
x := {self.}XOffset;
y := {self.}YOffset;
// 分子分母单独计算高度,最后再合并
// 分母
den_range := new OMathRange(docx_to_pdf_, f_.Den);
den_range.BaseSz := {self.}BaseSz;
den_range.XOffset := x;
den_range.YOffset := y;
den_range.Calc(); // 需要得到高宽
// 分子
num_range := new OMathRange(docx_to_pdf_, f_.Num);
num_range.BaseSz := {self.}BaseSz;
num_range.XOffset := x;
num_range.YOffset := y;
num_range.Calc(); // 需要得到高宽
max_len := max(den_range.Width, num_range.Width);
xo := (max_len - num_range.Width) / 2;
num_range.AdjustOffset(xo, den_range.DynamicHeight + 0.3 * {self.}BaseSz);
xo := (max_len - den_range.Width) / 2;
den_Range.AdjustOffset(xo, 0);
// 线
line_range := new LineRange();
line_range.XOffset := {self.}XOffset;
line_range.YOffset := y + den_range.DynamicHeight;
line_range.Width := max_len;
line_range.LineWidth := 0.04 * {self.}BaseSz;
{self.}DynamicHeight := num_range.DynamicHeight + den_range.DynamicHeight + 0.3 * {self.}BaseSz;
{self.}Width := line_range.Width;
range_array_ union= array(den_range, num_range, line_range);
// 分式的基准在line处
{self.}BaseHeight := den_range.DynamicHeight;
end;
function OMathFRange.AdjustOffset(x: real; y: real);override;
begin
class(BasicRange).AdjustOffset(x, y);
for _,range in range_array_ do
range.AdjustOffset(x, y);
end;
function OMathRRange.Create(docx_to_pdf: TSDocxToPdf; r: R);
begin
class(AdvancedRange).Create();
docx_to_pdf_ := docx_to_pdf;
r_ := r;
range_array_ := array();
end;
function OMathRRange.Do();override;
begin
for _,range in range_array_ do
range.Do();
end;
function OMathRRange.Offset(x: real; y: real; page: Page);
begin
class(AdvancedRange).Offset(x, y, page);
{self.}DynamicHeight := {self.}BaseSz;
for _,range in range_array_ do
range.Offset(x, y, page);
{self.}EndY := {self.}StartY - {self.}DynamicHeight;
end;
function OMathRRange.AdjustOffset(x: real; y: real);override;
begin
class(BasicRange).AdjustOffset(x, y);
for _,range in range_array_ do
range.AdjustOffset(x, y);
end;
function OMathRRange.Calc();
begin
{self.}DynamicHeight := {self.}BaseSz;
if not r_.T then return;
x := {self.}XOffset;
y := {self.}YOffset;
text := r_.T.Text;
pos := 1;
case r_.RPr.Sty.Val of
"p":
begin
b := false;
i := false;
end
"b":
begin
b := true;
i := false;
end
"i":
begin
b := false;
i := true;
end
"bi":
begin
b := true;
i := true;
end
else begin
b := false;
i := true;
end
end;
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;
else if char = 0x44 or char = 0x46 then
text_range.Type := 5;
word := a_word;
font_obj := docx_to_pdf_.Font.GetCNSFont("Times-Roman", b, i);
end
else if DTPUtils.IsChineseChar(a_word) then
begin
text_range.Type := 3;
word := utf8ToAnsi(a_word);
font_obj := docx_to_pdf_.Font.GetCNSFont("SimSun", b, i);
end
else if DTPUtils.IsChinesePunctuation(a_word) then
begin
text_range.Type := 4;
word := utf8ToAnsi(a_word);
font_obj := docx_to_pdf_.Font.GetCNSFont("SimSun", b, i);
end
else begin
word := class(SymbolMapper).SymbolChr(a_word);
if ifnil(word) then
begin
echo format("error symbol {{%s}}.\n", a_word);
word := chr(0x20);
end
font_obj := docx_to_pdf_.Font.GetSymbolFont();
end
rpr := new RPr();
rpr.Sz.Val := {self.}BaseSz;
first_page := docx_to_pdf_.PageManager[0];
pdf_page := first_page.PdfPage;
pdf_page.SetFontAndSize(font_obj, {self.}BaseSz);
text_range.RPr := rpr;
text_range.Text := word;
text_range.Font := font_obj;
text_range.Width := pdf_page.TextWidth(word);
text_range.Parent := self;
text_range.DynamicHeight := rpr.Sz.Val;
text_range.XOffset := x;
text_range.YOffset := y;
x += text_range.Width;
pos += num;
range_array_[length(range_array_)] := text_range;
{self.}Width += text_range.Width;
end
{self.}BaseHeight := {self.}BaseSz / 4;
end;
function OMathNaryRange.Create(docx_to_pdf: TSDocxToPdf; nary: Nary);
begin
class(AdvancedRange).Create();
docx_to_pdf_ := docx_to_pdf;
nary_ := nary;
range_array_ := array();
end;
function OMathNaryRange.Do();override;
begin
for _,range in range_array_ do
range.Do();
end;
function OMathNaryRange.Offset(x: real; y: real; page: Page);override;
begin
class(AdvancedRange).Offset(x, y, page);
for _,range in range_array_ do
range.Offset(x, y, page);
end;
function OMathNaryRange.AdjustOffset(x: real; y: real);overload;
begin
for _,range in range_array_ do
range.AdjustOffset(x, y);
end;
function OMathNaryRange.Calc();override;
begin
x := {self.}XOffset;
y := {self.}YOffset;
val := nary_.NaryPr.Chr.Val ?: "Į";
symbol := class(SymbolMapper).SymbolChr(val);
if ifnil(symbol) then
begin
echo format("error = %s", val);
return;
end
symbol_font := docx_to_pdf_.Font.GetSymbolFont();
first_page := docx_to_pdf_.PageManager[0];
pdf_page := first_page.PdfPage;
size := {self.}BaseSz;
pdf_page.SetFontAndSize(symbol_font, size);
symbol_range := new TextRange();
symbol_range.Text := symbol;
symbol_range.XOffset := x;
symbol_range.YOffset := y;
symbol_range.Width := pdf_page.TextWidth(symbol);
symbol_range.Font := symbol_font;
symbol_range.RPr := new DocxML.RPr();
symbol_range.RPr.Sz.Val := size;
symbol_range.DynamicHeight := size;
sub_range := new OMathRange(docx_to_pdf_, nary_.Sub);
sub_range.BaseSz := {self.}BaseSz / 2;
sub_range.XOffset := x;
sub_range.YOffset := y;
sub_range.Calc();
sup_range := new OMathRange(docx_to_pdf_, nary_.Sup);
sup_range.BaseSz := {self.}BaseSz / 2;
sup_range.XOffset := x;
sup_range.YOffset := y;
sup_range.Calc(); // 需要得到高宽
if nary_.NaryPr.LimLoc.Val = "subSup" then
begin
max_width := max(sub_range.Width, sup_range.Width) + symbol_range.Width;
sub_range.AdjustOffset(symbol_range.Width, -sub_range.DynamicHeight/2);
sup_range.AdjustOffset(symbol_range.Width, symbol_range.DynamicHeight - sup_range.DynamicHeight/2);
{self.}Width := max_width;
{self.}DynamicHeight := symbol_range.DynamicHeight + sub_range.DynamicHeight/2 + sup_range.DynamicHeight + {self.}BaseSz * 0.1;
end
// else if nary_.Nary.LimLoc.Val = "undOvr" then
else begin // undOvr
max_width := maxValue(array(sub_range.Width, sup_range.Width, symbol_range.Width));
sub_range.AdjustOffset((max_width - sub_range.Width)/2, 0);
symbol_range.AdjustOffset((max_width - symbol_range.Width)/2, sub_range.DynamicHeight);
sup_range.AdjustOffset((max_width - sup_range.Width)/2, symbol_range.DynamicHeight + sub_range.DynamicHeight);
{self.}Width := max_width;
{self.}DynamicHeight := sup_range.DynamicHeight + symbol_range.DynamicHeight + sub_range.DynamicHeight;
end
e_range := new OMathRange(docx_to_pdf_, nary_.E);
e_range.BaseSz := {self.}BaseSz;
e_range.XOffset := x + max_width;
e_range.YOffset := y + sub_range.DynamicHeight;
e_range.Calc();
range_array_ union= array(symbol_range, sub_range, sup_range, e_range);
{self.}Width += e_range.Width;
{self.}DynamicHeight := max({self.}DynamicHeight, e_range.DynamicHeight);
{self.}BaseHeight := symbol_range.DynamicHeight / 4 + sub_range.DynamicHeight;
end;
function OMathRadRange.Create(docx_to_pdf: TSDocxToPdf; rad: Rad);
begin
class(AdvancedRange).Create();
docx_to_pdf_ := docx_to_pdf;
rad_ := rad;
range_array_ := array();
end;
function OMathRadRange.Do();override;
begin
for _,range in range_array_ do
range.Do();
end;
function OMathRadRange.Offset(x: real; y: real; page: Page);override;
begin
class(AdvancedRange).Offset(x, y, page);
for _,range in range_array_ do
range.Offset(x, y, page);
end;
function OMathRadRange.AdjustOffset(x: real; y: real);overload;
begin
for _,range in range_array_ do
range.AdjustOffset(x, y);
end;
function OMathRadRange.Calc();override;
begin
x := {self.}XOffset;
y := {self.}YOffset;
deg_range := new OMathRange(docx_to_pdf_, rad_.Deg);
deg_range.BaseSz := {self.}BaseSz / 2;
deg_range.XOffset := x;
deg_range.YOffset := y;
deg_range.Calc();
e_range := new OMathRange(docx_to_pdf_, rad_.E);
e_range.BaseSz := {self.}BaseSz;
e_range.XOffset := x;
e_range.YOffset := y;
e_range.Calc(); // 需要得到高宽
symbol := chr(0xD6);
symbol_font := docx_to_pdf_.Font.GetSymbolFont();
first_page := docx_to_pdf_.PageManager[0];
pdf_page := first_page.PdfPage;
size := e_range.DynamicHeight;
pdf_page.SetFontAndSize(symbol_font, size);
symbol_range := new TextRange();
symbol_range.Text := symbol;
symbol_range.XOffset := x;
symbol_range.YOffset := y;
symbol_range.Width := pdf_page.TextWidth(symbol);
symbol_range.Font := symbol_font;
symbol_range.RPr := new DocxML.RPr();
symbol_range.RPr.Sz.Val := size;
symbol_range.DynamicHeight := size;
deg_range.AdjustOffset(0, -e_range.DynamicHeight / 2);
symbol_range.AdjustOffset(deg_range.Width, 0);
e_range.AdjustOffset(size*0.3 + deg_range.Width, 0);
line_range := new LineRange();
line_range.XOffset := symbol_range.XOffset + symbol_range.Width * 0.9;
line_range.YOffset := symbol_range.DynamicHeight * 0.9;
line_range.Width := e_range.Width;
line_range.LineWidth := 0.04 * size;
range_array_ union= array(symbol_range, deg_range, e_range, line_range);
{self.}Width := deg_range.Width + symbol_range.Width + e_range.Width + 0.3*size;
{self.}DynamicHeight := symbol_range.DynamicHeight;
{self.}BaseHeight := symbol_range.DynamicHeight / 2;
end;
function OMathSSupRange.Create(docx_to_pdf: TSDocxToPdf; s_sup: SSup);
begin
class(AdvancedRange).Create();
docx_to_pdf_ := docx_to_pdf;
s_sup_ := s_sup;
range_array_ := array();
end;
function OMathSSupRange.Do();override;
begin
for _,range in range_array_ do
range.Do();
end;
function OMathSSupRange.Offset(x: real; y: real; page: Page);override;
begin
class(AdvancedRange).Offset(x, y, page);
for _,range in range_array_ do
range.Offset(x, y, page);
end;
function OMathSSupRange.AdjustOffset(x: real; y: real);overload;
begin
for _,range in range_array_ do
range.AdjustOffset(x, y);
end;
function OMathSSupRange.Calc();override;
begin
x := {self.}XOffset;
y := {self.}YOffset;
e_range := new OMathRange(docx_to_pdf_, s_sup_.E);
e_range.BaseSz := {self.}BaseSz;
e_range.XOffset := x;
e_range.YOffset := y;
e_range.Calc(); // 需要得到高宽
sup_range := new OMathRange(docx_to_pdf_, s_sup_.Sup);
sup_range.BaseSz := {self.}BaseSz * 0.4;
sup_range.XOffset := x;
sup_range.YOffset := y;
sup_range.Calc();
sup_range.AdjustOffset(e_range.Width, e_range.DynamicHeight / 2);
range_array_ union= array(e_range, sup_range);
{self.}Width := e_range.Width + sup_range.Width;
h := sup_range.DynamicHeight + e_range.DynamicHeight / 2;
{self.}DynamicHeight := max(h, e_range.DynamicHeight);
{self.}BaseHeight := e_range.BaseHeight;
end;
function OMathSSubRange.Create(docx_to_pdf: TSDocxToPdf; s_sub: SSub);
begin
class(AdvancedRange).Create();
docx_to_pdf_ := docx_to_pdf;
s_sub_ := s_sub;
range_array_ := array();
end;
function OMathSSubRange.Do();override;
begin
for _,range in range_array_ do
range.Do();
end;
function OMathSSubRange.Offset(x: real; y: real; page: Page);override;
begin
class(AdvancedRange).Offset(x, y, page);
for _,range in range_array_ do
range.Offset(x, y, page);
end;
function OMathSSubRange.AdjustOffset(x: real; y: real);overload;
begin
for _,range in range_array_ do
range.AdjustOffset(x, y);
end;
function OMathSSubRange.Calc();override;
begin
x := {self.}XOffset;
y := {self.}YOffset;
e_range := new OMathRange(docx_to_pdf_, s_sub_.E);
e_range.BaseSz := {self.}BaseSz;
e_range.XOffset := x;
e_range.YOffset := y;
e_range.Calc(); // 需要得到高宽
sub_range := new OMathRange(docx_to_pdf_, s_sub_.Sub);
sub_range.BaseSz := {self.}BaseSz * 0.4;
sub_range.XOffset := x;
sub_range.YOffset := y;
sub_range.Calc();
sub_range.AdjustOffset(e_range.Width, -(sub_range.DynamicHeight - {self.}BaseSz * 0.4));
range_array_ union= array(e_range, sub_range);
{self.}Width += e_range.Width + sub_range.Width;
h := e_range.DynamicHeight + sub_range.DynamicHeight - {self.}BaseSz * 0.4;
{self.}DynamicHeight := max(h, e_range.DynamicHeight);
{self.}BaseHeight := e_range.BaseHeight;
end;
function OMathDRange.Create(docx_to_pdf: TSDocxToPdf; d: D);
begin
class(AdvancedRange).Create();
docx_to_pdf_ := docx_to_pdf;
d_ := d;
range_array_ := array();
end;
function OMathDRange.Do();override;
begin
for _,range in range_array_ do
range.Do();
end;
function OMathDRange.Offset(x: real; y: real; page: Page);override;
begin
class(AdvancedRange).Offset(x, y, page);
for _,range in range_array_ do
range.Offset(x, y, page);
end;
function OMathDRange.AdjustOffset(x: real; y: real);overload;
begin
for _,range in range_array_ do
range.AdjustOffset(x, y);
end;
function OMathDRange.Calc();override;
begin
x := {self.}XOffset;
y := {self.}YOffset;
e_range := new OMathRange(docx_to_pdf_, d_.E);
e_range.BaseSz := {self.}BaseSz;
e_range.XOffset := x;
e_range.YOffset := y;
e_range.Calc();
beg_chr := class(SymbolMapper).SymbolChr(d_.DPr.BegChr.Val) ?: chr(0x28); // (
end_chr := class(SymbolMapper).SymbolChr(d_.DPr.EndChr.Val) ?: chr(0x29); // )
max_h := e_range.DynamicHeight;
font_obj := docx_to_pdf_.Font.GetSymbolFont();
first_page := docx_to_pdf_.PageManager[0];
pdf_page := first_page.PdfPage;
pdf_page.SetFontAndSize(font_obj, max_h);
beg_range := new TextRange();
beg_range.Text := beg_chr;
beg_range.RPr := new RPr();
beg_range.RPr.Sz.Val := max_h;
beg_range.Font := font_obj;
beg_range.Width := pdf_page.TextWidth(beg_chr);
beg_range.Parent := self;
beg_range.DynamicHeight := max_h;
beg_range.XOffset := x;
beg_range.YOffset := y;
end_range := new TextRange();
end_range.Text := end_chr;
end_range.RPr := new RPr();
end_range.RPr.Sz.Val := max_h;
end_range.Font := font_obj;
end_range.Width := pdf_page.TextWidth(end_chr);
end_range.Parent := self;
end_range.DynamicHeight := max_h;
end_range.XOffset := x;
end_range.YOffset := y;
e_range.AdjustOffset(beg_range.Width, 0);
end_range.AdjustOffset(e_range.Width + beg_range.Width, 0);
range_array_ union= array(beg_range, e_range, end_range);
{self.}Width := beg_range.Width + e_range.Width + end_range.Width;
{self.}DynamicHeight := max_h;
{self.}BaseHeight := {self.}DynamicHeight / 2;
end;
function OMathFuncRange.Create(docx_to_pdf: TSDocxToPdf; func: Func);
begin
class(AdvancedRange).Create();
docx_to_pdf_ := docx_to_pdf;
func_ := func;
range_array_ := array();
end;
function OMathFuncRange.Do();override;
begin
for _,range in range_array_ do
range.Do();
end;
function OMathFuncRange.Offset(x: real; y: real; page: Page);override;
begin
class(AdvancedRange).Offset(x, y, page);
for _,range in range_array_ do
range.Offset(x, y, page);
end;
function OMathFuncRange.AdjustOffset(x: real; y: real);overload;
begin
for _,range in range_array_ do
range.AdjustOffset(x, y);
end;
function OMathFuncRange.Calc();override;
begin
x := {self.}XOffset;
y := {self.}YOffset;
f_name_range := new OMathRange(docx_to_pdf_, func_.FName);
f_name_range.BaseSz := {self.}BaseSz;
f_name_range.XOffset := x;
f_name_range.YOffset := y;
f_name_range.Calc(); // 需要得到高宽
e_range := new OMathRange(docx_to_pdf_, func_.E);
e_range.BaseSz := {self.}BaseSz;
e_range.XOffset := x;
e_range.YOffset := y;
e_range.Calc();
max_h := max(f_name_range.DynamicHeight, e_range.DynamicHeight);
e_range.AdjustOffset(f_name_range.Width, (max_h - e_range.DynamicHeight) / 2);
f_name_range.AdjustOffset(0, (max_h - f_name_range.DynamicHeight) / 2);
range_array_ union= array(f_name_range, e_range);
{self.}Width += f_name_range.Width + e_range.Width;
{self.}DynamicHeight := max(f_name_range.DynamicHeight, e_range.DynamicHeight);
{self.}BaseHeight := f_name_range.BaseHeight;
end;
end.