mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-28 09:03:50 +02:00
975 lines
31 KiB
ObjectPascal
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.
|
|
|