lazarus/components/turbopower_ipro/iphtmltablelayout.pas

975 lines
31 KiB
ObjectPascal

// Global defines
{$I IPDEFINE.INC}
unit ipHtmlTableLayout;
interface
uses
types, Classes, LCLType, LCLIntf,
IpHtmlTypes, IpHtmlProp, IpHtmlUtils, IpHtmlClasses, IpHtml, IpHtmlNodes;
type
{ TIpNodeTableLayouter }
TIpNodeTableLayouter = class(TIpHtmlBaseTableLayouter)
private
FTableOwner : TIpHtmlNodeTABLE;
CellOverhead : Integer; // sum of col widths + CellOverhead = TableWidth
RUH, RUV : Integer; // ruler width hor/vert
BL, BR, BT, BB : Integer; // border width, left, right, top, bottom
FColCount : Integer;
ColTextWidthMin, ColTextWidthMax : TIntArr; // min and max column widths
ColTextWidth : TIntArr; //actual column widths
ColStart : TIntArr; // start of each column relative to table's left
public
constructor Create(AOwner: TIpHtmlNodeCore); override;
destructor Destroy; override;
procedure CalcMinMaxColTableWidth(RenderProps: TIpHtmlProps;
var aMin, aMax: Integer); override;
procedure CalcSize(ParentWidth: Integer; RenderProps: TIpHtmlProps); override;
function GetColCount: Integer; override;
public
property ColCount : Integer read GetColCount; // Same as FTableOwner.ColCount.
end;
implementation
{ TIpNodeTableLayouter }
constructor TIpNodeTableLayouter.Create(AOwner: TIpHtmlNodeCore);
begin
inherited Create(AOwner);
FTableOwner := TIpHtmlNodeTABLE(FOwner);
FColCount := -1;
ColTextWidthMin := TIntArr.Create;
ColTextWidthMax := TIntArr.Create;
ColTextWidth := TIntArr.Create;
ColStart := TIntArr.Create;
end;
destructor TIpNodeTableLayouter.Destroy;
begin
ColTextWidth.Free;
ColStart.Free;
ColTextWidthMin.Free;
ColTextWidthMax.Free;
inherited Destroy;
end;
procedure TIpNodeTableLayouter.CalcMinMaxColTableWidth(RenderProps: TIpHtmlProps;
var aMin, aMax: Integer);
var
z, Min0, Max0: Integer;
i, j, CurCol, k : Integer;
TWMin, TWMax : Integer;
PendSpanWidthMin,
PendSpanWidthMax,
PendSpanStart,
PendSpanSpan : TIntArr;
PendCol : Integer;
CoreNode: TIpHtmlNodeCore;
TrNode: TIpHtmlNodeTR;
CellNode: TIpHtmlNodeTableHeaderOrCell;
procedure DistributeColSpace(ColSpan: Integer);
var
i, Rest, MinNow : Integer;
begin
if ColSpan > 1 then begin
PendSpanWidthMin[PendCol] := Min0;
PendSpanWidthMax[PendCol] := Max0;
PendSpanStart[PendCol] := CurCol;
PendSpanSpan[PendCol] := ColSpan;
Inc(PendCol);
Exit;
end;
MinNow := 0;
for i := CurCol to CurCol + ColSpan - 1 do
Inc(MinNow, ColTextWidthMin[i]);
if MinNow = 0 then begin
for i := CurCol to CurCol + ColSpan - 1 do
ColTextWidthMin[i] := Min0 div ColSpan;
end else begin
Rest := Min0 - MinNow;
if Rest > 0 then begin
for i := CurCol to CurCol + ColSpan - 1 do
ColTextWidthMin[i] := ColTextWidthMin[i] +
round(Rest * ColTextWidthMin[i] / MinNow);
MinNow := 0;
for i := CurCol to CurCol + ColSpan - 1 do
Inc(MinNow, ColTextWidthMin[i]);
Rest := Min0 - MinNow;
if Rest > 0 then begin
for i := CurCol to CurCol + ColSpan - 1 do begin
ColTextWidthMin[i] := ColTextWidthMin[i] + 1;
Dec(Rest);
if rest = 0 then
break;
end;
end;
end;
end;
MinNow := 0;
for i := CurCol to CurCol + ColSpan - 1 do
Inc(MinNow, ColTextWidthMax[i]);
if MinNow = 0 then begin
for i := CurCol to CurCol + ColSpan - 1 do
ColTextWidthMax[i] := Max0 div ColSpan;
end else begin
Rest := Max0 - MinNow;
if Rest > 0 then begin
for i := CurCol to CurCol + ColSpan - 1 do
ColTextWidthMax[i] := ColTextWidthMax[i] +
round(Rest * ColTextWidthMax[i] / MinNow);
MinNow := 0;
for i := CurCol to CurCol + ColSpan - 1 do
Inc(MinNow, ColTextWidthMax[i]);
Rest := Max0 - MinNow;
if Rest > 0 then begin
for i := CurCol to CurCol + ColSpan - 1 do begin
ColTextWidthMax[i] := ColTextWidthMax[i] + 1;
Dec(Rest);
if rest = 0 then
break;
end;
end;
end;
end;
for i := 0 to Pred(ColCount) do begin
ColTextWidthMin[i] := MinI2(ColTextWidthMin[i], ColTextWidthMax[i]);
ColTextWidthMax[i] := MaxI2(ColTextWidthMin[i], ColTextWidthMax[i]);
end;
end;
procedure DistributeSpannedColSpace;
var
z, i, Rest, MinNow, Min0, Max0, CurCol, ColSpan : Integer;
begin
for z := 0 to Pred(PendCol) do begin
Min0 := PendSpanWidthMin[z];
Max0 := PendSpanWidthMax[z];
CurCol := PendSpanStart[z];
ColSpan := PendSpanSpan[z];
MinNow := 0;
for i := CurCol to CurCol + ColSpan - 1 do
Inc(MinNow, ColTextWidthMin[i]);
if MinNow = 0 then begin
Rest := 0;
for i := CurCol to CurCol + ColSpan - 1 do begin
ColTextWidthMin[i] := Min0 div ColSpan;
Inc(Rest, ColTextWidthMin[i]);
end;
ColTextWidthMin[0] := ColTextWidthMin[0] + (Min0 - Rest);
end else begin
Rest := Min0 - MinNow;
if Rest > 0 then begin
for i := CurCol to CurCol + ColSpan - 1 do
ColTextWidthMin[i] := ColTextWidthMin[i] +
round(Rest * ColTextWidthMin[i] / MinNow);
MinNow := 0;
for i := CurCol to CurCol + ColSpan - 1 do
Inc(MinNow, ColTextWidthMin[i]);
Rest := Min0 - MinNow;
if Rest > 0 then begin
for i := CurCol to CurCol + ColSpan - 1 do begin
ColTextWidthMin[i] := ColTextWidthMin[i] + 1;
Dec(Rest);
if rest = 0 then
break;
end;
end;
end;
end;
MinNow := 0;
for i := CurCol to CurCol + ColSpan - 1 do
Inc(MinNow, ColTextWidthMax[i]);
if MinNow = 0 then begin
Rest := 0;
for i := CurCol to CurCol + ColSpan - 1 do begin
ColTextWidthMax[i] := Max0 div ColSpan;
Inc(Rest, ColTextWidthMax[i]);
end;
ColTextWidthMax[0] := ColTextWidthMax[0] + (Max0 - Rest);
end else begin
Rest := Max0 - MinNow;
if Rest > 0 then begin
for i := CurCol to CurCol + ColSpan - 1 do
ColTextWidthMax[i] := ColTextWidthMax[i] +
round(Rest * ColTextWidthMax[i] / MinNow);
MinNow := 0;
for i := CurCol to CurCol + ColSpan - 1 do
Inc(MinNow, ColTextWidthMax[i]);
Rest := Max0 - MinNow;
if Rest > 0 then begin
for i := CurCol to CurCol + ColSpan - 1 do begin
ColTextWidthMax[i] := ColTextWidthMax[i] + 1;
Dec(Rest);
if rest = 0 then
break;
end;
end;
end;
end;
for i := 0 to Pred(ColCount) do begin
ColTextWidthMax[i] := MaxI2(ColTextWidthMin[i], ColTextWidthMax[i]);
end;
end;
end;
begin
if FMin <> -1 then begin
aMin := FMin;
aMax := FMax;
Exit;
end;
FMin := 0;
FMax := 0;
if ColCount = 0 then
Exit;
PendSpanWidthMin := nil;
PendSpanWidthMax := nil;
PendSpanStart := nil;
PendSpanSpan := nil;
try
PendSpanWidthMin := TIntArr.Create;
PendSpanWidthMax := TIntArr.Create;
PendSpanStart := TIntArr.Create;
PendSpanSpan := TIntArr.Create;
{calc col and table widths}
for i := 0 to Pred(ColCount) do begin
FRowSp[i] := 0;
ColTextWidthMin[i] := 0;
ColTextWidthMax[i] := 0;
end;
PendCol := 0;
for z := 0 to Pred(FTableOwner.ChildCount) do
if FTableOwner.ChildNode[z] is TIpHtmlNodeTHeadFootBody then
begin
CoreNode := TIpHtmlNodeCore(FTableOwner.ChildNode[z]);
for i := 0 to Pred(CoreNode.ChildCount) do begin
if CoreNode.ChildNode[i] is TIpHtmlNodeTR then
begin
TrNode := TIpHtmlNodeTR(CoreNode.ChildNode[i]);
CurCol := 0;
while FRowSp[CurCol] <> 0 do begin
FRowSp[CurCol] := FRowSp[CurCol] - 1;
Inc(CurCol);
end;
for j := 0 to Pred(TrNode.ChildCount) do
if TrNode.ChildNode[j] is TIpHtmlNodeTableHeaderOrCell then
begin
CellNode := TIpHtmlNodeTableHeaderOrCell(TrNode.ChildNode[j]);
while FRowSp[CurCol] <> 0 do begin
FRowSp[CurCol] := FRowSp[CurCol] - 1;
Inc(CurCol);
end;
CellNode.CalcMinMaxPropWidth(RenderProps, Min0, Max0);
case CellNode.Width.LengthType of
hlAbsolute :
begin
if CellNode.Width.LengthValue <= CellNode.ExpParentWidth then
Min0 := MaxI2(Min0, CellNode.Width.LengthValue - 2*FCellPadding
- FCellSpacing - RUH);
Max0 := Min0;
end;
end;
CellNode.CalcWidthMin := Min0;
CellNode.CalcWidthMax := Max0;
DistributeColSpace(CellNode.ColSpan);
for k := 0 to Pred(CellNode.ColSpan) do begin
while FRowSp[CurCol] <> 0 do begin
FRowSp[CurCol] := FRowSp[CurCol] - 1;
Inc(CurCol);
end;
FRowSp[CurCol] := CellNode.RowSpan - 1;
Inc(CurCol);
end;
end;
for j := CurCol to Pred(ColCount) do
if FRowSp[j] > 0 then
FRowSp[j] := FRowSp[j] - 1;
end;
end;
end;
DistributeSpannedColSpace;
finally
PendSpanWidthMin.Free;
PendSpanWidthMax.Free;
PendSpanStart.Free;
PendSpanSpan.Free;
end;
TWMin := 0;
TWMax := 0;
CellOverhead := BL + FCellSpacing + BR;
for i := 0 to Pred(ColCount) do begin
Inc(TWMin, ColTextWidthMin[i]);
Inc(TWMax, ColTextWidthMax[i]);
Inc(CellOverhead, RUH + 2*FCellPadding + FCellSpacing + RUH);
FRowSp[i] := 0;
end;
FMin := MaxI2(FMin, TWMin + CellOverhead);
FMax := MaxI2(FMax, TWMax + CellOverhead);
aMin := FMin;
aMax := FMax;
end;
procedure TIpNodeTableLayouter.CalcSize(ParentWidth: Integer; RenderProps: TIpHtmlProps);
var
z, GrossCellSpace, NetCellSpace, CellExtra,
NetCellSpaceExtraExtra,
RelCellExtra,
i, j, CurCol, k,
CellSpace,
MinW, MaxW : Integer;
R : TRect;
TargetRect : TRect;
RowFixup : TRectRectArr;
RowFixupCount : Integer;
function GetSpanBottom(Row, Col: Integer): Integer;
var
R: PRect;
begin
R := RowFixup.Value[Row].Value[Col];
if R <> nil then
Result := R.Bottom
else
Result := 0;
end;
procedure SetSpanBottom(Row, Col, Value: Integer);
var
R: PRect;
begin
R := RowFixup.Value[Row].Value[Col];
if R <> nil then
R^.Bottom := Value;
end;
procedure SetSpanRect(Row,Col : Integer; const Rect: PRect);
begin
RowFixup[Row].Value[Col] := Rect;
end;
procedure DeleteFirstSpanRow;
begin
RowFixup.Delete(0);
end;
procedure AdjustCol(ColSpan, DesiredWidth: Integer);
var
i, Rest, WNow, Avail : Integer;
begin
WNow := 0;
for i := CurCol to CurCol + ColSpan - 1 do
Inc(WNow, ColTextWidth[i]);
Avail := MinI2(DesiredWidth, CellSpace);
if WNow = 0 then begin
for i := CurCol to CurCol + ColSpan - 1 do
ColTextWidth[i] := Avail div ColSpan;
end else begin
Rest := MinI2(CellSpace, DesiredWidth - WNow);
if Rest > 0 then begin
for i := CurCol to CurCol + ColSpan - 1 do
ColTextWidth[i] := ColTextWidth[i] + round(Rest * ColTextWidth[i] / WNow);
end;
end;
end;
procedure DoBlock(BlockType : TIpHtmlNodeTABLEHEADFOOTBODYClass);
var
z, i, j, k, zz : Integer;
RowSp2 : TIntArr;
AL0, AL : TIpHtmlAlign;
CellRect1 : TRect;
HA, HB, Y0: Integer;
maxY, maxYY: Integer;
VA0, VA : TIpHtmlVAlign3;
CoreNode: TIpHtmlNodeCore;
TrNode: TIpHtmlNodeTR;
CellNode: TIpHtmlNodeTableHeaderOrCell;
isRTL: Boolean;
rtlNode: TIpHtmlNodeCORE;
begin
RowSp2 := TIntArr.Create;
try
for z := 0 to Pred(FTableOwner.ChildCount) do
if (TIpHtmlNode(FTableOwner.ChildNode[z]) is BlockType) then
begin
CoreNode := TIpHtmlNodeCore(FTableOwner.ChildNode[z]);
for i := 0 to Pred(CoreNode.ChildCount) do begin
if CoreNode.ChildNode[i] is TIpHtmlNodeTR then
begin
TrNode := TIpHtmlNodeTR(CoreNode.ChildNode[i]);
for j := 0 to Pred(ColCount) do
RowSp2[j] := FRowSp[j];
CurCol := 0;
while FRowSp[CurCol] <> 0 do begin
FRowSp[CurCol] := FRowSp[CurCol] - 1;
Inc(CurCol);
end;
VA0 := TrNode.Props.VAlignment;
case TrNode.VAlign of
hvaTop :
VA0 := hva3Top;
hvaMiddle :
VA0 := hva3Middle;
hvaBottom :
VA0 := hva3Bottom;
end;
case TrNode.Align of
haDefault :
AL0 := haLeft;
else
AL0 := TrNode.Align;
end;
{determine height of cells and lay out with top alignment}
for j := 0 to Pred(TrNode.ChildCount) do
if TIpHtmlNode(TrNode.ChildNode[j]) is TIpHtmlNodeTableHeaderOrCell then
begin
CellNode := TIpHtmlNodeTableHeaderOrCell(TrNode.ChildNode[j]);
while FRowSp[CurCol] <> 0 do begin
FRowSp[CurCol] := FRowSp[CurCol] - 1;
Inc(CurCol);
end;
AL := AL0;
CellNode.Props.Assign(FOwner.Props); // assign table props
CellRect1 := TargetRect;
Inc(CellRect1.Left, ColStart[CurCol]);
Inc(CellRect1.Top, FCellSpacing + RUV);
CellRect1.Right := CellRect1.Left + 2*FCellPadding + ColTextWidth[CurCol];
for k := 1 to CellNode.ColSpan - 1 do
Inc(CellRect1.Right, ColTextWidth[CurCol + k] + 2*FCellPadding +
2*RUH + FCellSpacing);
// PadRect area of cell excluding rules
// CellRect area of text contained in cell
CellNode.PadRect := CellRect1;
Inc(CellRect1.Top, FCellPadding);
inflateRect(CellRect1, -FCellPadding, 0);
VA := CellNode.VAlign;
if VA = hva3Default then
VA := VA0;
case CellNode.Align of
haDefault : ;
else
AL := CellNode.Align;
end;
CellNode.Props.VAlignment := VA;
CellNode.Props.Alignment := AL;
CellNode.Layout(CellNode.Props, CellRect1);
if (CellNode.Height.PixelsType <> hpUndefined) {Height <> -1} then
if CellNode.PageRect.Bottom - CellNode.PageRect.Top < CellNode.Height.Value then
CellNode.Layouter.FPageRect.Bottom := CellRect1.Top + CellNode.Height.Value;
if (CellNode.Height.PixelsType = hpUndefined) {Height = -1}
and IsRectEmpty(CellNode.PageRect) then
CellNode.FPadRect.Bottom := CellRect1.Top + FCellPadding
else begin
CellNode.FPadRect.Bottom := CellNode.PageRect.Bottom + FCellPadding;
end;
SetSpanRect(CellNode.RowSpan - 1, CurCol, @CellNode.PadRect);
for k := 0 to Pred(CellNode.ColSpan) do begin
FRowSp[CurCol] := CellNode.RowSpan - 1;
Inc(CurCol);
end;
end;
{Adjust any trailing spanning columns}
for j := CurCol to Pred(ColCount) do
if FRowSp[j] > 0 then
FRowSp[j] := FRowSp[j] - 1;
maxYY := 0;
maxY := 0;
for zz := 0 to Pred(ColCount) do
maxY := MaxI2(GetSpanBottom(0, zz), maxY);
for zz := 0 to Pred(ColCount) do
SetSpanBottom(0, zz, maxY);
if maxY > maxYY then
maxYY := maxY;
for j := 0 to Pred(ColCount) do
FRowSp[j] := RowSp2[j];
CurCol := 0;
while FRowSp[CurCol] <> 0 do begin
FRowSp[CurCol] := FRowSp[CurCol] - 1;
Inc(CurCol);
end;
{relocate cells which are not top aligned}
for j := 0 to Pred(TrNode.ChildCount) do
if TrNode.ChildNode[j] is TIpHtmlNodeTableHeaderOrCell then
begin
CellNode := TIpHtmlNodeTableHeaderOrCell(TrNode.ChildNode[j]);
while FRowSp[CurCol] <> 0 do begin
FRowSp[CurCol] := FRowSp[CurCol] - 1;
Inc(CurCol);
end;
AL := AL0;
HA := maxYY - (TargetRect.Top + FCellSpacing + RUV);
HB := CellNode.PageRect.Bottom - CellNode.PageRect.Top;
VA := CellNode.VAlign;
if VA = hva3Default then
VA := VA0;
case VA of
hva3Middle :
Y0 := (HA - HB) div 2;
hva3Bottom :
Y0 := (HA - HB);
else
Y0 := 0;
end;
if Y0 > 0 then begin
CellRect1 := TargetRect;
Inc(CellRect1.Left, ColStart[CurCol]);
Inc(CellRect1.Top, FCellSpacing + RUV + Y0);
CellRect1.Right := CellRect1.Left + 2*FCellPadding + ColTextWidth[CurCol];
for k := 1 to CellNode.ColSpan - 1 do
Inc(CellRect1.Right, ColTextWidth[CurCol + k] + 2*FCellPadding +
2*RUH + FCellSpacing);
Inc(CellRect1.Top, FCellPadding);
inflateRect(CellRect1, -FCellPadding, 0);
case CellNode.Align of
haDefault : ;
else
AL := CellNode.Align;
end;
CellNode.Props.VAlignment := VA;
CellNode.Props.Alignment := AL;
CellNode.Layout(CellNode.Props, CellRect1);
if CellNode.Height.PixelsType <> hpUndefined then
if CellNode.PageRect.Bottom - CellNode.PageRect.Top < CellNode.Height.Value then
CellNode.Layouter.FPageRect.Bottom := CellRect1.Top + CellNode.Height.Value;
if (CellNode.Height.PixelsType = hpUndefined)
and IsRectEmpty(CellNode.PageRect) then
CellNode.FPadRect.Bottom := CellRect1.Top + FCellPadding
else begin
CellNode.FPadRect.Bottom := CellNode.PageRect.Bottom + FCellPadding;
end;
SetSpanRect(CellNode.RowSpan - 1, CurCol, @CellNode.PadRect);
end;
for k := 0 to Pred(CellNode.ColSpan) do begin
FRowSp[CurCol] := CellNode.RowSpan - 1;
Inc(CurCol);
end;
{ mirroring for RTL reading }
isRTL := (FOwner.Dir = hdRTL);
if (CellNode is TIpHTMLNodeCORE) then
begin
rtlNode := TIpHtmlNodeCORE(CellNode);
if isRTL and (rtlNode.Dir = hdLTR) then
isRTL := false
else
if not isRTL and (rtlNode.Dir = hdRTL) then
isRTL := true;
end;
if isRTL then
begin
CellNode.Dir := hdRTL;
CellRect1 := CellNode.PadRect;
CellRect1.SetLocation(FTableWidth - CellRect1.Right, CellRect1.Top);
CellNode.PadRect := CellRect1;
CellNode.Layouter.Layout(RenderProps, CellRect1);
end;
end;
maxYY := 0;
maxY := 0;
for zz := 0 to Pred(ColCount) do
maxY := MaxI2(GetSpanBottom(0, zz), maxY);
for zz := 0 to Pred(ColCount) do
SetSpanBottom(0, zz, maxY);
if maxY > maxYY then
maxYY := maxY;
{Adjust any trailing spanning columns}
for j := CurCol to Pred(ColCount) do
if FRowSp[j] > 0 then
FRowSp[j] := FRowSp[j] - 1;
TargetRect.Top := MaxI2(maxYY, TargetRect.Top) + RUV;
DeleteFirstSpanRow;
end;
end;
end;
while RowFixupCount > 0 do begin
maxYY := 0;
maxY := 0;
for zz := 0 to Pred(ColCount) do
maxY := MaxI2(GetSpanBottom(0, zz), maxY);
for zz := 0 to Pred(ColCount) do
SetSpanBottom(0, zz, maxY);
if maxY > maxYY then
maxYY := maxY;
TargetRect.Top := MaxI2(maxYY, TargetRect.Top);
DeleteFirstSpanRow;
end;
finally
RowSp2.Free;
end;
end;
var
P : Integer;
CoreNode: TIpHtmlNodeCore;
TrNode: TIpHtmlNodeTR;
CellNode: TIpHtmlNodeTableHeaderOrCell;
begin
FTableWidth := 0;
if ColCount = 0 then
Exit;
Props.Assign(RenderProps);
CalcMinMaxColTableWidth(Props, MinW, MaxW);
case FTableOwner.Width.LengthType of
hlUndefined :
begin
P := 0;
for z := 0 to Pred(FTableOwner.ChildCount) do
if FTableOwner.ChildNode[z] is TIpHtmlNodeTHeadFootBody then
begin
CoreNode := TIpHtmlNodeCore(FTableOwner.ChildNode[z]);
for i := 0 to Pred(CoreNode.ChildCount) do begin
if CoreNode.ChildNode[i] is TIpHtmlNodeTR then
begin
TrNode := TIpHtmlNodeTR(CoreNode.ChildNode[i]);
for j := 0 to Pred(TrNode.ChildCount) do
if TrNode.ChildNode[j] is TIpHtmlNodeTableHeaderOrCell then
begin
CellNode := TIpHtmlNodeTableHeaderOrCell(TrNode.ChildNode[j]);
case CellNode.Width.LengthType of
hlPercent :
Inc(P, CellNode.Width.LengthValue);
end;
end;
end;
end;
end;
if P <> 0 then
FTableWidth := MaxI2(MinW, round((P * ParentWidth) / 100))
else
FTableWidth := MaxI2(MinW, MinI2(MaxW, ParentWidth));
end;
hlAbsolute :
FTableWidth := MaxI2(FTableOwner.Width.LengthValue, MinW);
hlPercent :
FTableWidth := MaxI2(MinW, round((FTableOwner.Width.LengthValue * ParentWidth) / 100));
end;
for i := 0 to Pred(ColCount) do
ColTextWidth[i] := ColTextWidthMin[i];
for z := 0 to Pred(ColCount) do
FRowSp[z] := 0;
for z := 0 to Pred(FTableOwner.ChildCount) do
if FTableOwner.ChildNode[z] is TIpHtmlNodeTHeadFootBody then
begin
CoreNode := TIpHtmlNodeCore(FTableOwner.ChildNode[z]);
for i := 0 to Pred(CoreNode.ChildCount) do begin
if CoreNode.ChildNode[i] is TIpHtmlNodeTR then
begin
TrNode := TIpHtmlNodeTR(CoreNode.ChildNode[i]);
CellSpace := FTableWidth - CellOverhead;
for j := 0 to Pred(ColCount) do
Dec(CellSpace, ColTextWidth[j]);
if CellSpace > 0 then begin
{distribute extra space}
CurCol := 0;
while FRowSp[CurCol] <> 0 do begin
FRowSp[CurCol] := FRowSp[CurCol] - 1;
Inc(CurCol);
end;
for j := 0 to Pred(TrNode.ChildCount) do
if TrNode.ChildNode[j] is TIpHtmlNodeTableHeaderOrCell then
begin
CellNode := TIpHtmlNodeTableHeaderOrCell(TrNode.ChildNode[j]);
case CellNode.Width.LengthType of
hlAbsolute :
AdjustCol(CellNode.ColSpan, CellNode.Width.LengthValue - 2*FCellPadding
- FCellSpacing - RUH);
hlPercent :
AdjustCol(CellNode.Colspan,
round((FTableWidth - CellOverhead) *
CellNode.Width.LengthValue / 100));
end;
CellSpace := FTableWidth - CellOverhead;
for k := 0 to Pred(ColCount) do
Dec(CellSpace, ColTextWidth[k]);
for k := 0 to Pred(CellNode.ColSpan) do begin
while FRowSp[CurCol] <> 0 do begin
FRowSp[CurCol] := FRowSp[CurCol] - 1;
Inc(CurCol);
end;
FRowSp[CurCol] := CellNode.RowSpan - 1;
Inc(CurCol);
end;
end;
for j := CurCol to Pred(ColCount) do
if FRowSp[j] > 0 then
FRowSp[j] := FRowSp[j] - 1;
end;
end;
end;
end;
GrossCellSpace := MaxI2(FTableWidth - CellOverhead, 0);
NetCellSpace := 0;
for i := 0 to Pred(ColCount) do
Inc(NetCellSpace, ColTextWidth[i]);
if NetCellSpace > 0 then begin
CellExtra := GrossCellSpace - NetCellSpace;
if CellExtra > 0 then
for i := 0 to Pred(ColCount) do begin
RelCellExtra := round(CellExtra / NetCellSpace * ColTextWidth[i] );
if ColTextWidth[i] + RelCellExtra > ColTextWidthMax[i] then
ColTextWidth[i] := MaxI2(ColTextWidth[i], ColTextWidthMax[i])
else
ColTextWidth[i] := ColTextWidth[i] + RelCellExtra;
end;
end;
NetCellSpace := 0;
for i := 0 to Pred(ColCount) do
Inc(NetCellSpace, ColTextWidth[i]);
CellExtra := GrossCellSpace - NetCellSpace;
if CellExtra > 0 then begin
RelCellExtra := CellExtra div ColCount;
NetCellSpaceExtraExtra := CellExtra mod ColCount;
for i := 0 to Pred(ColCount) do begin
if (ColTextWidth[i] < ColTextWidthMax[i]) then begin
ColTextWidth[i] := ColTextWidth[i] + RelCellExtra;
if NetCellSpaceExtraExtra > 0 then begin
ColTextWidth[i] := ColTextWidth[i] + 1;
Dec(NetCellSpaceExtraExtra);
end;
end;
end;
end;
NetCellSpace := 0;
for i := 0 to Pred(ColCount) do
Inc(NetCellSpace, ColTextWidth[i]);
CellExtra := GrossCellSpace - NetCellSpace;
if CellExtra > 0 then begin
for i := 0 to Pred(ColCount) do begin
RelCellExtra := MinI2(ColTextWidthMax[i] - ColTextWidth[i], CellExtra);
if RelCellExtra > 0 then begin
ColTextWidth[i] := ColTextWidth[i] + RelCellExtra;
Dec(CellExtra, RelCellExtra);
end;
end;
end;
NetCellSpace := 0;
for i := 0 to Pred(ColCount) do
Inc(NetCellSpace, ColTextWidth[i]);
CellExtra := GrossCellSpace - NetCellSpace;
if CellExtra > 0 then begin
RelCellExtra := CellExtra div ColCount;
NetCellSpaceExtraExtra := CellExtra mod ColCount;
for i := 0 to Pred(ColCount) do begin
ColTextWidth[i] := ColTextWidth[i] + RelCellExtra;
if NetCellSpaceExtraExtra > 0 then begin
ColTextWidth[i] := ColTextWidth[i] + 1;
Dec(NetCellSpaceExtraExtra);
end;
end;
end;
for i := 0 to Pred(ColCount) do
FRowSp[i] := 0;
TargetRect := Rect(0, 0, ParentWidth, MaxInt);
with FTableOwner do
begin
BorderRect2 := TargetRect;
BorderRect := TargetRect;
for z := 0 to Pred(ChildCount) do
if ChildNode[z] is TIpHtmlNodeCAPTION then begin
FCaption := TIpHtmlNodeCAPTION(ChildNode[z]);
if FCaption.Align <> hva2Bottom then begin
FCaption.Layout(Props, BorderRect2);
Inc(BorderRect.Top, FCaption.PageRect.Bottom - FCaption.PageRect.Top);
end;
end;
TargetRect := BorderRect;
R := BorderRect;
end;
ColStart[0] := BL + FCellSpacing + RUH;
FRowSp[0] := 0;
for i := 1 to Pred(ColCount) do begin
ColStart[i] := ColStart[i-1] + 2*FCellPadding + ColTextWidth[i-1]
+ FCellSpacing + 2*RUH;
FRowSp[i] := 0;
end;
{calc size of table body}
Inc(TargetRect.Top, BT);
{calc rows}
RowFixup := TRectRectArr.Create;
try
RowFixupCount := 0;
DoBlock(TIpHtmlNodeTHEAD);
DoBlock(TIpHtmlNodeTBODY);
DoBlock(TIpHtmlNodeTFOOT);
finally
RowFixup.Free;
end;
Inc(TargetRect.Top, FCellSpacing + RUV + BB);
R.Right := R.Left + FTableWidth;
R.Bottom := TargetRect.Top;
if (R.Bottom > R.Top) and (R.Right = R.Left) then
R.Right := R.Left + 1;
with FTableOwner do
begin
BorderRect.BottomRight := R.BottomRight;
BorderRect2.BottomRight := R.BottomRight;
if assigned(FCaption) and (FCaption.Align = hva2Bottom) then begin
R.Top := BorderRect.Bottom;
R.Bottom := MaxInt;
FCaption.Layout(Props, R);
BorderRect2.Bottom := FCaption.PageRect.Bottom;
end;
end;
end;
function TIpNodeTableLayouter.GetColCount: Integer;
var
z, i, j, c : Integer;
Brd : Integer; // Border
CoreNode: TIpHtmlNodeCore;
TrNode: TIpHtmlNodeTR;
CellNode: TIpHtmlNodeTableHeaderOrCell;
begin
if FColCount = -1 then
begin
FColCount := 0;
for z := 0 to Pred(FTableOwner.ChildCount) do
if FTableOwner.ChildNode[z] is TIpHtmlNodeTHeadFootBody then
begin
CoreNode := TIpHtmlNodeCore(FTableOwner.ChildNode[z]);
for i := 0 to Pred(CoreNode.ChildCount) do begin
c := 0;
if CoreNode.ChildNode[i] is TIpHtmlNodeTR then
begin
TrNode := TIpHtmlNodeTR(CoreNode.ChildNode[i]);
for j := 0 to Pred(TrNode.ChildCount) do
if TrNode.ChildNode[j] is TIpHtmlNodeTableHeaderOrCell then
begin
CellNode := TIpHtmlNodeTableHeaderOrCell(TrNode.ChildNode[j]);
Inc(c, CellNode.Colspan);
end;
end;
if c > FColCount then
FColCount := c;
end;
end;
RUH := 0;
RUV := 0;
case FTableOwner.Rules of
hrNone :;
hrGroups : begin
RUH := 1;
RUV := 1;
end;
hrRows :
RUV := 1;
hrCols :
RUH := 1;
hrAll : begin
RUH := 1;
RUV := 1;
end;
end;
BL := 0; BR := 0;
BT := 0; BB := 0;
Brd := FTableOwner.Border;
case FTableOwner.Frame of
hfVoid,
hfAbove :
BT := Brd;
hfBelow :
BB := Brd;
hfHSides : begin
BT := Brd;
BB := Brd;
end;
hfLhs :
BL := Brd;
hfRhs :
BR := Brd;
hfvSides : begin
BL := Brd;
BR := Brd;
end;
hfBox,
hfBorder : begin
BT := Brd;
BB := Brd;
BL := Brd;
BR := Brd;
end;
end;
end;
Result := FColCount;
end;
initialization
TableLayouterClass := TIpNodeTableLayouter;
end.