|
@@ -6,6 +6,35 @@
|
|
|
for details about the license.
|
|
|
*****************************************************************************
|
|
|
|
|
|
+Todo:
|
|
|
+- ComputeCSS: base attributes, like display, font
|
|
|
+- layout:
|
|
|
+ - create layouter
|
|
|
+ - resolve layout length properties: if not c value
|
|
|
+ - set used values (width, height, border
|
|
|
+
|
|
|
+- can margin/border/padding be computed before layout and stored?
|
|
|
+ - ? percentage margin+padding
|
|
|
+ - ? calc(min-content/10)
|
|
|
+- utility functions:
|
|
|
+ - ContentToPaddingWidth, PaddingToContentWidth
|
|
|
+ - ContentToBorderWidth, BorderToContentWidth
|
|
|
+ - ContentToMarginWidth, BorderToMarginWidth
|
|
|
+- min-content GetMinContentWidth/Height
|
|
|
+ - needs
|
|
|
+ - replaced elements
|
|
|
+ - flow layout
|
|
|
+ - flex layout
|
|
|
+- max-content width/height
|
|
|
+ - replaced elements
|
|
|
+ - flow layout
|
|
|
+ - flex layout
|
|
|
+- fit-content(max) width/height
|
|
|
+ - replaced elements
|
|
|
+ - flow layout
|
|
|
+ - flex layout
|
|
|
+- content(max) width/height
|
|
|
+
|
|
|
}
|
|
|
unit Fresnel.Layouter;
|
|
|
|
|
@@ -106,7 +135,7 @@ type
|
|
|
MaxHeight: TFresnelLength;
|
|
|
|
|
|
// computed layout
|
|
|
- BorderBox: TFresnelRect; // left, top, right, bottom
|
|
|
+ MarginBox: TFresnelRect; // left, top, right, bottom
|
|
|
ContentBoxWidth: TFresnelLength;
|
|
|
ContentBoxHeight: TFresnelLength;
|
|
|
end;
|
|
@@ -190,10 +219,12 @@ type
|
|
|
|
|
|
TFlexItem = class(TLineItem)
|
|
|
public
|
|
|
- Basis: TFresnelLength;
|
|
|
+ Basis: TFresnelLength; // including border+padding
|
|
|
Grow: TFresnelLength;
|
|
|
Shrink: TFresnelLength;
|
|
|
- CurMainContentSize: TFresnelLength;
|
|
|
+ MainContentSize: TFresnelLength;
|
|
|
+ CrossMarginBoxSize: TFresnelLength; // including margin
|
|
|
+ AlignSelf, AlignSelfSub: TCSSNumericalID;
|
|
|
end;
|
|
|
|
|
|
protected
|
|
@@ -201,10 +232,14 @@ type
|
|
|
FlexWrap: TCSSNumericalID;
|
|
|
JustifyContent, JustifyContentSub: TCSSNumericalID;
|
|
|
AlignItems, AlignItemsSub: TCSSNumericalID;
|
|
|
+ MainIsRow: boolean; // flex-direction is row or row-reverse
|
|
|
+ MainIsReverse: boolean; // flex-direction is row-reverse or column-reverse
|
|
|
procedure EndLine(Commit: boolean); virtual;
|
|
|
procedure StartLine; virtual;
|
|
|
- procedure FlexLineMainDirection(MaxMainSize, MainGap: TFresnelLength); virtual;
|
|
|
- procedure FlexLineCrossDirection; virtual;
|
|
|
+ procedure FlexLineMainDirection(MaxMainSize, MainGap: TFresnelLength;
|
|
|
+ Commit: boolean; var NewContentWidth, NewContentHeight: TFresnelLength); virtual;
|
|
|
+ procedure FlexLineCrossDirection(Commit: boolean;
|
|
|
+ var NewContentWidth, NewContentHeight: TFresnelLength); virtual;
|
|
|
procedure PlaceLineItems; override;
|
|
|
procedure ComputeChildAttributes(Item: TLineItem; El: TFresnelElement); override;
|
|
|
public
|
|
@@ -352,9 +387,9 @@ begin
|
|
|
//ChildNode:=BFCNode.Node;
|
|
|
//ChildEl:=ChildNode.Element;
|
|
|
|
|
|
- BFCNode.BorderBox.Top:=FLineBorderBoxTop-BFCNode.MarginTop;
|
|
|
+ BFCNode.MarginBox.Top:=FLineBorderBoxTop-BFCNode.MarginTop;
|
|
|
//writeln('TFLBlockFormattingContext.PlaceLineNodes ',i,' ',ChildEl.GetPath,' ',FloatToCSSStr(BFCNode.Left),' ',FloatToCSSStr(ChildTop),' BFCNode.Height=',FloatToCSSStr(BFCNode.ContentBoxHeight));
|
|
|
- BFCNode.BorderBox.Bottom:=FLineBorderBoxTop
|
|
|
+ BFCNode.MarginBox.Bottom:=FLineBorderBoxTop
|
|
|
+BFCNode.BorderTop+BFCNode.PaddingTop
|
|
|
+BFCNode.ContentBoxHeight
|
|
|
+BFCNode.PaddingBottom+BFCNode.BorderBottom+BFCNode.MarginBottom;
|
|
@@ -453,8 +488,8 @@ var
|
|
|
N.MarginRight:=ChildMarginRight;
|
|
|
N.MarginTop:=ChildMarginTop;
|
|
|
N.MarginBottom:=ChildMarginBottom;
|
|
|
- N.BorderBox.Left:=ChildLeft;
|
|
|
- N.BorderBox.Right:=ChildRight;
|
|
|
+ N.MarginBox.Left:=ChildLeft-ChildMarginLeft;
|
|
|
+ N.MarginBox.Right:=ChildRight+ChildMarginRight;
|
|
|
N.ContentBoxWidth:=ChildWidth;
|
|
|
N.ContentBoxHeight:=ChildHeight;
|
|
|
end;
|
|
@@ -717,112 +752,304 @@ begin
|
|
|
end;
|
|
|
|
|
|
procedure TFLFlexLayouter.FlexLineMainDirection(MaxMainSize,
|
|
|
- MainGap: TFresnelLength);
|
|
|
+ MainGap: TFresnelLength; Commit: boolean; var NewContentWidth,
|
|
|
+ NewContentHeight: TFresnelLength);
|
|
|
const
|
|
|
- MinAdjust = 0.005;
|
|
|
+ MinAdjust = 0.0001;
|
|
|
+var
|
|
|
+ CurMainSize, aSpace: TFresnelLength;
|
|
|
+
|
|
|
+ procedure CalcMainSize;
|
|
|
+ var
|
|
|
+ i: Integer;
|
|
|
+ Item: TFlexItem;
|
|
|
+ begin
|
|
|
+ CurMainSize:=0;
|
|
|
+ for i:=0 to FLineItems.Count-1 do
|
|
|
+ begin
|
|
|
+ Item:=TFlexItem(FLineItems[i]);
|
|
|
+ CurMainSize:=CurMainSize+Item.MarginLeft+Item.BorderLeft+Item.PaddingLeft
|
|
|
+ +Item.MainContentSize+Item.PaddingRight+Item.BorderRight+Item.MarginRight;
|
|
|
+ if i>0 then
|
|
|
+ CurMainSize:=CurMainSize+MainGap;
|
|
|
+ end;
|
|
|
+ aSpace:=MaxMainSize-CurMainSize;
|
|
|
+ end;
|
|
|
+
|
|
|
+ function CalcSpaceItem(Count: integer; StartSpaceMul: TFresnelLength;
|
|
|
+ out aPos: TFresnelLength): TFresnelLength;
|
|
|
+ begin
|
|
|
+ Result:=Max(0,aSpace)/Count;
|
|
|
+ aPos:=Result*StartSpaceMul;
|
|
|
+ if FlexDirection in [CSSRegistry.kwRowReverse,CSSRegistry.kwColumnReverse] then
|
|
|
+ begin
|
|
|
+ aPos:=MaxMainSize-aPos;
|
|
|
+ Result:=-Result;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
var
|
|
|
- CurMainSize, Dist, SumGrow, SumShrink, NewMainSize: TFresnelLength;
|
|
|
+ SumGrow, SumShrink, p, aSpaceItem: TFresnelLength;
|
|
|
i: Integer;
|
|
|
Item: TFlexItem;
|
|
|
begin
|
|
|
for i:=0 to FLineItems.Count-1 do
|
|
|
begin
|
|
|
Item:=TFlexItem(FLineItems[i]);
|
|
|
- Item.CurMainContentSize:=Item.Basis;
|
|
|
+ Item.MainContentSize:=Item.Basis;
|
|
|
end;
|
|
|
- if not IsNan(MaxMainSize) then
|
|
|
- begin
|
|
|
- repeat
|
|
|
- // compute difference between current size and max size
|
|
|
- CurMainSize:=0;
|
|
|
+ repeat
|
|
|
+ // compute difference between current size and max size
|
|
|
+ CalcMainSize;
|
|
|
+ if aSpace>MinAdjust then
|
|
|
+ begin
|
|
|
+ // try to grow
|
|
|
+ // collect grow factors of all items able to grow
|
|
|
+ SumGrow:=0;
|
|
|
for i:=0 to FLineItems.Count-1 do
|
|
|
begin
|
|
|
Item:=TFlexItem(FLineItems[i]);
|
|
|
- CurMainSize:=CurMainSize+Item.MarginLeft+Item.BorderLeft+Item.PaddingLeft
|
|
|
- +Item.CurMainContentSize+Item.PaddingRight+Item.BorderRight+Item.MarginRight;
|
|
|
- if i>0 then
|
|
|
- CurMainSize:=CurMainSize+MainGap;
|
|
|
+ if Item.Grow<MinAdjust then continue;
|
|
|
+ if (not IsNan(Item.MaxWidth))
|
|
|
+ and (Item.MainContentSize>Item.MaxWidth-MinAdjust) then continue;
|
|
|
+ SumGrow:=SumGrow+Item.Grow;
|
|
|
end;
|
|
|
- Dist:=MaxMainSize-CurMainSize;
|
|
|
- if Dist>MinAdjust then
|
|
|
+ if SumGrow=0 then
|
|
|
+ break; // can not grow
|
|
|
+ // grow
|
|
|
+ for i:=0 to FLineItems.Count-1 do
|
|
|
begin
|
|
|
- // try to grow
|
|
|
- // collect grow factors of all items able to grow
|
|
|
- SumGrow:=0;
|
|
|
- for i:=0 to FLineItems.Count-1 do
|
|
|
- begin
|
|
|
- Item:=TFlexItem(FLineItems[i]);
|
|
|
- if Item.Grow<MinAdjust then continue;
|
|
|
- SumGrow:=SumGrow+Item.Grow;
|
|
|
- end;
|
|
|
- if SumGrow=0 then
|
|
|
- break; // can not grow
|
|
|
- // grow
|
|
|
- for i:=0 to FLineItems.Count-1 do
|
|
|
- begin
|
|
|
- Item:=TFlexItem(FLineItems[i]);
|
|
|
- if Item.Grow<MinAdjust then continue;
|
|
|
- Item.CurMainContentSize:=Item.CurMainContentSize+(Item.Grow/SumGrow)*Dist;
|
|
|
- end;
|
|
|
- end else if Dist<-MinAdjust then begin
|
|
|
- // try to shrink
|
|
|
- // collect shrink factors of all items able to shrink
|
|
|
- SumShrink:=0;
|
|
|
- for i:=0 to FLineItems.Count-1 do
|
|
|
- begin
|
|
|
- Item:=TFlexItem(FLineItems[i]);
|
|
|
- if Item.Shrink<MinAdjust then continue;
|
|
|
- if Item.CurMainContentSize<MinAdjust then continue;
|
|
|
- SumShrink:=SumShrink+Item.Shrink;
|
|
|
- end;
|
|
|
- if SumShrink=0 then
|
|
|
- break; // can not shrink
|
|
|
- // shrink
|
|
|
- for i:=0 to FLineItems.Count-1 do
|
|
|
- begin
|
|
|
- Item:=TFlexItem(FLineItems[i]);
|
|
|
- if Item.Shrink<MinAdjust then continue;
|
|
|
- if Item.CurMainContentSize<MinAdjust then continue;
|
|
|
- Item.CurMainContentSize:=Max(0,Item.CurMainContentSize+(Item.Shrink/SumShrink)*Dist);
|
|
|
- end;
|
|
|
- end else
|
|
|
- break;
|
|
|
- until false;
|
|
|
+ Item:=TFlexItem(FLineItems[i]);
|
|
|
+ if Item.Grow<MinAdjust then continue;
|
|
|
+ if (not IsNan(Item.MaxWidth))
|
|
|
+ and (Item.MainContentSize>Item.MaxWidth-MinAdjust) then continue;
|
|
|
+ Item.MainContentSize:=Item.MainContentSize+(Item.Grow/SumGrow)*aSpace;
|
|
|
+ if (not IsNan(Item.MaxWidth))
|
|
|
+ and (Item.MainContentSize>Item.MaxWidth) then
|
|
|
+ Item.MainContentSize:=Item.MaxWidth;
|
|
|
+ end;
|
|
|
+ end else if aSpace<-MinAdjust then begin
|
|
|
+ // try to shrink
|
|
|
+ // collect shrink factors of all items able to shrink
|
|
|
+ SumShrink:=0;
|
|
|
+ for i:=0 to FLineItems.Count-1 do
|
|
|
+ begin
|
|
|
+ Item:=TFlexItem(FLineItems[i]);
|
|
|
+ if Item.Shrink<MinAdjust then continue;
|
|
|
+ if Item.MainContentSize<MinAdjust then continue;
|
|
|
+ if (not IsNan(Item.MinWidth))
|
|
|
+ and (Item.MainContentSize<Item.MinWidth+MinAdjust) then continue;
|
|
|
+ SumShrink:=SumShrink+Item.Shrink;
|
|
|
+ end;
|
|
|
+ if SumShrink=0 then
|
|
|
+ break; // can not shrink
|
|
|
+ // shrink
|
|
|
+ for i:=0 to FLineItems.Count-1 do
|
|
|
+ begin
|
|
|
+ Item:=TFlexItem(FLineItems[i]);
|
|
|
+ if Item.Shrink<MinAdjust then continue;
|
|
|
+ if Item.MainContentSize<MinAdjust then continue;
|
|
|
+ if (not IsNan(Item.MinWidth))
|
|
|
+ and (Item.MainContentSize<Item.MinWidth+MinAdjust) then continue;
|
|
|
+ Item.MainContentSize:=Max(0,Item.MainContentSize+(Item.Shrink/SumShrink)*aSpace);
|
|
|
+ if (not IsNan(Item.MinWidth))
|
|
|
+ and (Item.MainContentSize<Item.MinWidth) then
|
|
|
+ Item.MainContentSize:=Item.MinWidth;
|
|
|
+ end;
|
|
|
+ end else
|
|
|
+ break;
|
|
|
+ until false;
|
|
|
+
|
|
|
+ // justify-content:
|
|
|
+ // todo safe: ?
|
|
|
+ // unsafe: ?
|
|
|
+
|
|
|
+ CalcMainSize;
|
|
|
+ p:=0;
|
|
|
+ aSpaceItem:=0;
|
|
|
+ case JustifyContent of
|
|
|
+ CSSRegistry.kwLeft: ;
|
|
|
+ // left: in row/row-reverse move line left, in column: top
|
|
|
+ CSSRegistry.kwRight:
|
|
|
+ // right: in row/row-reverse move line right, in column: top
|
|
|
+ if MainIsRow then
|
|
|
+ p:=MaxMainSize;
|
|
|
+ CSSRegistry.kwStart: ;
|
|
|
+ // start: move line left or top
|
|
|
+ CSSRegistry.kwEnd:
|
|
|
+ // end: move line right or bottom
|
|
|
+ p:=MaxMainSize;
|
|
|
+ CSSRegistry.kwFlexStart,
|
|
|
+ CSSRegistry.kwStretch: ;
|
|
|
+ // flex-start: main start
|
|
|
+ CSSRegistry.kwFlexEnd:
|
|
|
+ // flex-end: main end
|
|
|
+ p:=MaxMainSize;
|
|
|
+ CSSRegistry.kwCenter:
|
|
|
+ // center: main center
|
|
|
+ begin
|
|
|
+ p:=(MaxMainSize-CurMainSize)/2;
|
|
|
+ if MainIsReverse then
|
|
|
+ p:=MaxMainSize-p;
|
|
|
+ end;
|
|
|
+ CSSRegistry.kwSpaceAround:
|
|
|
+ // space-around: distribute space between each pair and half at start and end
|
|
|
+ CalcSpaceItem(FLineItems.Count,0.5,p);
|
|
|
+ CSSRegistry.kwSpaceBetween:
|
|
|
+ // space-between: distribute space between each pair
|
|
|
+ CalcSpaceItem(Max(1,FLineItems.Count-1),0,p);
|
|
|
+ CSSRegistry.kwSpaceEvenly:
|
|
|
+ // space-evenly: distribute space between each pair and full at start and end
|
|
|
+ CalcSpaceItem(FLineItems.Count+1,1,p);
|
|
|
end;
|
|
|
|
|
|
- // todo: justify-content / align-content
|
|
|
for i:=0 to FLineItems.Count-1 do
|
|
|
begin
|
|
|
Item:=TFlexItem(FLineItems[i]);
|
|
|
- NewMainSize:=Item.CurMainContentSize;
|
|
|
- if FlexDirection in [CSSRegistry.kwRow,CSSRegistry.kwRowReverse] then
|
|
|
- begin
|
|
|
- if not IsNan(Item.MaxWidth) then
|
|
|
- NewMainSize:=Min(NewMainSize,Item.MarginLeft+Item.BorderLeft+Item.PaddingLeft
|
|
|
- +Item.MaxWidth
|
|
|
- +Item.PaddingRight+Item.BorderRight+Item.MarginRight);
|
|
|
- if not IsNan(Item.MinWidth) then
|
|
|
- NewMainSize:=Max(NewMainSize,Item.MarginLeft+Item.BorderLeft+Item.PaddingLeft
|
|
|
- +Item.MinWidth
|
|
|
- +Item.PaddingRight+Item.BorderRight+Item.MarginRight);
|
|
|
- end else begin
|
|
|
- if not IsNan(Item.MaxHeight) then
|
|
|
- NewMainSize:=Min(NewMainSize,Item.MarginTop+Item.BorderTop+Item.PaddingTop
|
|
|
- +Item.MaxHeight
|
|
|
- +Item.PaddingBottom+Item.BorderBottom+Item.MarginBottom);
|
|
|
- if not IsNan(Item.MinHeight) then
|
|
|
- NewMainSize:=Max(NewMainSize,Item.MarginTop+Item.BorderTop+Item.PaddingTop
|
|
|
- +Item.MinHeight
|
|
|
- +Item.PaddingBottom+Item.BorderBottom+Item.MarginBottom);
|
|
|
+ case FlexDirection of
|
|
|
+ CSSRegistry.kwRow:
|
|
|
+ begin
|
|
|
+ Item.MarginBox.Left:=p;
|
|
|
+ p:=p+Item.MainContentSize;
|
|
|
+ Item.MarginBox.Right:=p;
|
|
|
+ end;
|
|
|
+ CSSRegistry.kwRowReverse:
|
|
|
+ begin
|
|
|
+ Item.MarginBox.Right:=p;
|
|
|
+ p:=p-Item.MainContentSize;
|
|
|
+ Item.MarginBox.Left:=p;
|
|
|
+ end;
|
|
|
+ CSSRegistry.kwColumn:
|
|
|
+ begin
|
|
|
+ Item.MarginBox.Top:=p;
|
|
|
+ p:=p+Item.MainContentSize;
|
|
|
+ Item.MarginBox.Bottom:=p;
|
|
|
+ end;
|
|
|
+ CSSRegistry.kwColumnReverse:
|
|
|
+ begin
|
|
|
+ Item.MarginBox.Bottom:=p;
|
|
|
+ p:=p-Item.MainContentSize;
|
|
|
+ Item.MarginBox.Top:=p;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
+ case JustifyContent of
|
|
|
+ CSSRegistry.kwSpaceAround:
|
|
|
+ // space-around: distribute space between each pair and half at start and end
|
|
|
+ if i<FLineItems.Count-1 then
|
|
|
+ p:=p+aSpaceItem
|
|
|
+ else
|
|
|
+ p:=p+aSpaceItem/2;
|
|
|
+ CSSRegistry.kwSpaceBetween:
|
|
|
+ // space-between: distribute space between each pair
|
|
|
+ if i<FLineItems.Count-1 then
|
|
|
+ p:=p+aSpaceItem;
|
|
|
+ CSSRegistry.kwSpaceEvenly:
|
|
|
+ // space-evenly: distribute space between each pair and full at start and end
|
|
|
+ p:=p+aSpaceItem;
|
|
|
end;
|
|
|
end;
|
|
|
+
|
|
|
+ if MainIsRow then
|
|
|
+ NewContentWidth:=p
|
|
|
+ else
|
|
|
+ NewContentHeight:=p;
|
|
|
end;
|
|
|
|
|
|
-procedure TFLFlexLayouter.FlexLineCrossDirection;
|
|
|
+procedure TFLFlexLayouter.FlexLineCrossDirection(Commit: boolean;
|
|
|
+ var NewContentWidth, NewContentHeight: TFresnelLength);
|
|
|
+var
|
|
|
+ i: Integer;
|
|
|
+ Item: TFlexItem;
|
|
|
+ Size, MaxSize, StartPos, EndPos: TFresnelLength;
|
|
|
begin
|
|
|
// all items on line now have their size and position in main direction
|
|
|
// -> now compute their cross direction size and position
|
|
|
- // todo
|
|
|
+
|
|
|
+ // find biggest
|
|
|
+ MaxSize:=0;
|
|
|
+ for i:=0 to FLineItems.Count-1 do
|
|
|
+ begin
|
|
|
+ Item:=TFlexItem(FLineItems[i]);
|
|
|
+ //El:=Item.Node.Element;
|
|
|
+ if MainIsRow then
|
|
|
+ begin
|
|
|
+ Size:=Item.Height;
|
|
|
+ if IsNan(Size) then
|
|
|
+ Size:=100; // get content size using the item's main size
|
|
|
+ Size:=Size+Item.MarginTop+Item.BorderTop+Item.PaddingTop
|
|
|
+ +Item.PaddingBottom+Item.BorderBottom+Item.MarginBottom;
|
|
|
+ end else begin
|
|
|
+ Size:=Item.Width;
|
|
|
+ if IsNan(Size) then
|
|
|
+ Size:=100; // get content size using the item's main size
|
|
|
+ Size:=Size+Item.MarginLeft+Item.BorderLeft+Item.PaddingLeft
|
|
|
+ +Item.PaddingRight+Item.BorderRight+Item.MarginRight;
|
|
|
+ end;
|
|
|
+ Item.CrossMarginBoxSize:=Size;
|
|
|
+
|
|
|
+ MaxSize:=Max(MaxSize,Size);
|
|
|
+ end;
|
|
|
+
|
|
|
+ // align items
|
|
|
+ for i:=0 to FLineItems.Count-1 do
|
|
|
+ begin
|
|
|
+ Item:=TFlexItem(FLineItems[i]);
|
|
|
+ //El:=Item.Node.Element;
|
|
|
+ StartPos:=0;
|
|
|
+ EndPos:=Item.CrossMarginBoxSize;
|
|
|
+ case Item.AlignSelf of
|
|
|
+ CSSRegistry.kwLeft,
|
|
|
+ CSSRegistry.kwStart,
|
|
|
+ CSSRegistry.kwFlexStart:
|
|
|
+ ;
|
|
|
+ CSSRegistry.kwRight,
|
|
|
+ CSSRegistry.kwEnd,
|
|
|
+ CSSRegistry.kwFlexEnd:
|
|
|
+ begin
|
|
|
+ StartPos:=MaxSize-Item.CrossMarginBoxSize;
|
|
|
+ EndPos:=MaxSize;
|
|
|
+ end;
|
|
|
+ CSSRegistry.kwCenter:
|
|
|
+ begin
|
|
|
+ StartPos:=(MaxSize-Item.CrossMarginBoxSize)/2;
|
|
|
+ EndPos:=StartPos+Item.CrossMarginBoxSize;
|
|
|
+ end;
|
|
|
+ // todo: baseline, first baseline, last baseline
|
|
|
+ else
|
|
|
+ //CSSRegistry.kwNormal,
|
|
|
+ //CSSRegistry.kwStretch:
|
|
|
+ begin
|
|
|
+ EndPos:=MaxSize;
|
|
|
+ if MainIsRow then
|
|
|
+ begin
|
|
|
+ if IsNan(Item.MaxHeight) and (EndPos<Item.MaxHeight) then
|
|
|
+ EndPos:=Item.MaxHeight;
|
|
|
+ if IsNan(Item.MinHeight) and (EndPos>Item.MinHeight) then
|
|
|
+ EndPos:=Item.MinHeight;
|
|
|
+ end else begin
|
|
|
+ if IsNan(Item.MaxWidth) and (EndPos<Item.MaxWidth) then
|
|
|
+ EndPos:=Item.MaxWidth;
|
|
|
+ if IsNan(Item.MinWidth) and (EndPos>Item.MinWidth) then
|
|
|
+ EndPos:=Item.MinWidth;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
+ if MainIsRow then
|
|
|
+ begin
|
|
|
+ Item.MarginBox.Top:=StartPos;
|
|
|
+ Item.MarginBox.Bottom:=EndPos;
|
|
|
+ end else begin
|
|
|
+ Item.MarginBox.Left:=StartPos;
|
|
|
+ Item.MarginBox.Right:=EndPos;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
+ if MainIsRow then
|
|
|
+ NewContentHeight:=MaxSize
|
|
|
+ else
|
|
|
+ NewContentWidth:=MaxSize;
|
|
|
end;
|
|
|
|
|
|
procedure TFLFlexLayouter.PlaceLineItems;
|
|
@@ -842,11 +1069,14 @@ begin
|
|
|
FlexItem.Basis:=El.GetComputedLength(fcaFlexBasis,true);
|
|
|
FlexItem.Grow:=El.GetComputedLength(fcaFlexGrow,true);
|
|
|
FlexItem.Shrink:=El.GetComputedLength(fcaFlexShrink,true);
|
|
|
+ FlexItem.AlignSelf:=El.GetComputedAlignSelf(FlexItem.AlignSelfSub);
|
|
|
+ if FlexItem.AlignSelf=CSSRegistry.kwAuto then
|
|
|
+ FlexItem.AlignSelf:=AlignItems;
|
|
|
|
|
|
if IsNan(FlexItem.Basis) then
|
|
|
begin
|
|
|
- if FlexDirection in [CSSRegistry.kwRow,CSSRegistry.kwRowReverse]
|
|
|
- then begin
|
|
|
+ if MainIsRow then
|
|
|
+ begin
|
|
|
FlexItem.Basis:=FlexItem.Width;
|
|
|
if IsNan(FlexItem.Basis) then
|
|
|
FlexItem.Basis:=El.GetMaxWidthContentBox;
|
|
@@ -910,49 +1140,13 @@ begin
|
|
|
inherited Init;
|
|
|
El:=Node.Element;
|
|
|
FlexDirection:=El.GetComputedKeyword(fcaFlexDirection,CSSRegistry.Chk_FlexDirection_KeywordIDs);
|
|
|
+ MainIsRow:=FlexDirection in [CSSRegistry.kwRow,CSSRegistry.kwRowReverse];
|
|
|
+ MainIsReverse:=FlexDirection in [CSSRegistry.kwRowReverse,CSSRegistry.kwColumnReverse];
|
|
|
FlexWrap:=El.GetComputedKeyword(fcaFlexWrap,CSSRegistry.Chk_FlexWrap_KeywordIDs);
|
|
|
JustifyContent:=El.GetComputedJustifyContent(JustifyContentSub);
|
|
|
- AlignItems:=El.GetComputedJustifyContent(AlignItemsSub);
|
|
|
+ AlignItems:=El.GetComputedAlignItems(AlignItemsSub);
|
|
|
//if El.ComputedDirection; // todo direction
|
|
|
|
|
|
- case FlexDirection of
|
|
|
- CSSRegistry.kwRow:
|
|
|
- case JustifyContent of
|
|
|
- CSSRegistry.kwLeft,
|
|
|
- CSSRegistry.kwStart: JustifyContent:=CSSRegistry.kwFlexStart;
|
|
|
- CSSRegistry.kwRight,
|
|
|
- CSSRegistry.kwEnd: JustifyContent:=CSSRegistry.kwFlexEnd;
|
|
|
- end;
|
|
|
- CSSRegistry.kwRowReverse:
|
|
|
- case JustifyContent of
|
|
|
- CSSRegistry.kwRight,
|
|
|
- CSSRegistry.kwEnd: JustifyContent:=CSSRegistry.kwFlexStart;
|
|
|
- CSSRegistry.kwLeft,
|
|
|
- CSSRegistry.kwStart: JustifyContent:=CSSRegistry.kwFlexEnd;
|
|
|
- end;
|
|
|
- CSSRegistry.kwColumn:
|
|
|
- case JustifyContent of
|
|
|
- CSSRegistry.kwLeft,
|
|
|
- CSSRegistry.kwRight,
|
|
|
- CSSRegistry.kwStart: JustifyContent:=CSSRegistry.kwFlexStart;
|
|
|
- CSSRegistry.kwEnd: JustifyContent:=CSSRegistry.kwFlexEnd;
|
|
|
- end;
|
|
|
- CSSRegistry.kwColumnReverse:
|
|
|
- case JustifyContent of
|
|
|
- CSSRegistry.kwLeft,
|
|
|
- CSSRegistry.kwRight,
|
|
|
- CSSRegistry.kwEnd: JustifyContent:=CSSRegistry.kwFlexStart;
|
|
|
- CSSRegistry.kwStart: JustifyContent:=CSSRegistry.kwFlexEnd;
|
|
|
- end;
|
|
|
- end;
|
|
|
- case JustifyContent of
|
|
|
- CSSRegistry.kwLeft:;
|
|
|
- //kwNormal,kwStretch,
|
|
|
- // kwStart,kwEnd,kwFlexStart,kwFlexEnd,kwCenter,kwLeft,kwRight,
|
|
|
- // kwSpaceBetween,kwSpaceAround,kwSpaceEvenly,
|
|
|
- // kwSafe,kwUnsafe
|
|
|
- end;
|
|
|
-
|
|
|
FGap[false]:=NaN;
|
|
|
FGap[true]:=NaN;
|
|
|
end;
|
|
@@ -995,51 +1189,32 @@ procedure TFLFlexLayouter.ComputeLayout(MaxContentWidth, MaxContentHeight: TFres
|
|
|
var
|
|
|
NodeIndex: Integer;
|
|
|
ChildNode: TSimpleFresnelLayoutNode;
|
|
|
- ChildEl, El, Container: TFresnelElement;
|
|
|
- FlexNode: TFlexItem;
|
|
|
+ ChildEl: TFresnelElement;
|
|
|
+ Item: TFlexItem;
|
|
|
MaxMainSize: TFresnelLength; // max content size in main direction
|
|
|
- CurMainSize: TFresnelLength; // current line size in main direction without ending margin
|
|
|
- CurMainMargin: TFresnelLength; // current ending margin in main direction
|
|
|
- MainGap: TFresnelLength; // gap in main direction
|
|
|
- Fits: Boolean;
|
|
|
+ CurMainSize: TFresnelLength; // current line size in main direction
|
|
|
+ NewMainSize, MainGap: TFresnelLength; // gap in main direction
|
|
|
begin
|
|
|
- El:=Node.Element;
|
|
|
NewContentWidth:=0;
|
|
|
NewContentHeight:=0;
|
|
|
|
|
|
- if FlexDirection in [CSSRegistry.kwRow,CSSRegistry.kwRowReverse] then
|
|
|
+ if MainIsRow then
|
|
|
begin
|
|
|
- if IsNan(MaxContentWidth) then
|
|
|
- MaxMainSize:=ContentWidth
|
|
|
- else
|
|
|
- MaxMainSize:=MaxContentWidth;
|
|
|
+ MaxMainSize:=MaxContentWidth;
|
|
|
MainGap:=GetComputedGap(true);
|
|
|
end else begin
|
|
|
- if IsNan(MaxContentHeight) then
|
|
|
- MaxMainSize:=ContentHeight
|
|
|
- else
|
|
|
- MaxMainSize:=MaxContentHeight;
|
|
|
+ MaxMainSize:=MaxContentHeight;
|
|
|
MainGap:=GetComputedGap(false);
|
|
|
end;
|
|
|
if IsNan(MaxMainSize) then
|
|
|
- begin
|
|
|
- Container:=El.GetBlockContainer;
|
|
|
- if Container<>nil then
|
|
|
- begin
|
|
|
- if FlexDirection in [CSSRegistry.kwRow,CSSRegistry.kwRowReverse] then
|
|
|
- MaxMainSize:=Container.GetComputedLength(fcaWidth,true) // todo Container.BoxSizing
|
|
|
- else
|
|
|
- MaxMainSize:=Container.GetComputedLength(fcaHeight,true); // todo Container.BoxSizing
|
|
|
- end;
|
|
|
- end;
|
|
|
+ raise EFresnelLayout.Create('20240908163359');
|
|
|
|
|
|
CurMainSize:=0;
|
|
|
- CurMainMargin:=0;
|
|
|
|
|
|
// add elements to the line until full
|
|
|
StartLine;
|
|
|
NodeIndex:=0;
|
|
|
- FlexNode:=nil;
|
|
|
+ Item:=nil;
|
|
|
try
|
|
|
while NodeIndex<Node.NodeCount do
|
|
|
begin
|
|
@@ -1064,44 +1239,25 @@ begin
|
|
|
end;
|
|
|
|
|
|
if FLineItems=nil then FLineItems:=TFPList.Create;
|
|
|
- FlexNode:=TFlexItem.Create;
|
|
|
- ComputeChildAttributes(FlexNode,ChildEl);
|
|
|
+ Item:=TFlexItem.Create;
|
|
|
+ ComputeChildAttributes(Item,ChildEl);
|
|
|
|
|
|
if FLineItems.Count>0 then
|
|
|
begin
|
|
|
- Fits:=true;
|
|
|
- if (FLineItems.Count>0) and (FlexWrap<>CSSRegistry.kwNoWrap) then
|
|
|
+ if MainIsRow then
|
|
|
+ NewMainSize:=CurMainSize+MainGap
|
|
|
+ +Item.MarginRight+Item.Basis+Item.MarginLeft
|
|
|
+ else
|
|
|
+ NewMainSize:=CurMainSize+MainGap
|
|
|
+ +Item.MarginBottom+Item.Basis+Item.MarginTop;
|
|
|
+
|
|
|
+ if (FLineItems.Count=1) or (FlexWrap=CSSRegistry.kwNoWrap)
|
|
|
+ or (NewMainSize<=MaxMainSize) then
|
|
|
begin
|
|
|
- // todo check if node fits into line
|
|
|
- end;
|
|
|
-
|
|
|
- if Fits then
|
|
|
- begin
|
|
|
- case FlexDirection of
|
|
|
- CSSRegistry.kwRow:
|
|
|
- begin
|
|
|
- CurMainSize:=CurMainSize+MainGap+CurMainMargin+FlexNode.MarginLeft+FlexNode.Basis;
|
|
|
- CurMainMargin:=FlexNode.MarginRight;
|
|
|
- end;
|
|
|
- CSSRegistry.kwRowReverse:
|
|
|
- begin
|
|
|
- CurMainSize:=CurMainSize+MainGap+CurMainMargin+FlexNode.MarginRight+FlexNode.Basis;
|
|
|
- CurMainMargin:=FlexNode.MarginLeft;
|
|
|
- end;
|
|
|
- CSSRegistry.kwColumn:
|
|
|
- begin
|
|
|
- CurMainSize:=CurMainSize+MainGap+CurMainMargin+FlexNode.MarginTop+FlexNode.Basis;
|
|
|
- CurMainMargin:=FlexNode.MarginBottom;
|
|
|
- end;
|
|
|
- CSSRegistry.kwColumnReverse:
|
|
|
- begin
|
|
|
- CurMainSize:=CurMainSize+MainGap+CurMainMargin+FlexNode.MarginBottom+FlexNode.Basis;
|
|
|
- CurMainMargin:=FlexNode.MarginTop;
|
|
|
- end;
|
|
|
- end;
|
|
|
+ CurMainSize:=NewMainSize;
|
|
|
end else begin
|
|
|
- FlexLineMainDirection(MaxMainSize,MainGap);
|
|
|
- FlexLineCrossDirection;
|
|
|
+ FlexLineMainDirection(MaxMainSize,MainGap,Commit,NewContentWidth,NewContentHeight);
|
|
|
+ FlexLineCrossDirection(Commit,NewContentWidth,NewContentHeight);
|
|
|
PlaceLineItems;
|
|
|
ClearLineItems;
|
|
|
end;
|
|
@@ -1110,29 +1266,11 @@ begin
|
|
|
if FLineItems.Count=0 then
|
|
|
begin
|
|
|
// first element in line
|
|
|
- FLineItems.Add(FlexNode);
|
|
|
- case FlexDirection of
|
|
|
- CSSRegistry.kwRow:
|
|
|
- begin
|
|
|
- CurMainSize:=FlexNode.MarginLeft+FlexNode.Basis;
|
|
|
- CurMainMargin:=FlexNode.MarginRight;
|
|
|
- end;
|
|
|
- CSSRegistry.kwRowReverse:
|
|
|
- begin
|
|
|
- CurMainSize:=FlexNode.MarginRight+FlexNode.Basis;
|
|
|
- CurMainMargin:=FlexNode.MarginLeft;
|
|
|
- end;
|
|
|
- CSSRegistry.kwColumn:
|
|
|
- begin
|
|
|
- CurMainSize:=FlexNode.MarginTop+FlexNode.Basis;
|
|
|
- CurMainMargin:=FlexNode.MarginBottom;
|
|
|
- end;
|
|
|
- CSSRegistry.kwColumnReverse:
|
|
|
- begin
|
|
|
- CurMainSize:=FlexNode.MarginBottom+FlexNode.Basis;
|
|
|
- CurMainMargin:=FlexNode.MarginTop;
|
|
|
- end;
|
|
|
- end;
|
|
|
+ FLineItems.Add(Item);
|
|
|
+ if MainIsRow then
|
|
|
+ CurMainSize:=Item.MarginRight+Item.Basis+Item.MarginLeft
|
|
|
+ else
|
|
|
+ CurMainSize:=Item.MarginTop+Item.Basis+Item.MarginBottom;
|
|
|
end;
|
|
|
|
|
|
|
|
@@ -1141,7 +1279,7 @@ begin
|
|
|
EndLine(Commit);
|
|
|
|
|
|
finally
|
|
|
- FlexNode.Free;
|
|
|
+ Item.Free;
|
|
|
end;
|
|
|
|
|
|
end;
|
|
@@ -1220,22 +1358,39 @@ end;
|
|
|
procedure TFLLineLayouter.PlaceLineItems;
|
|
|
var
|
|
|
i: Integer;
|
|
|
- LineNode: TLineItem;
|
|
|
+ Item: TLineItem;
|
|
|
ChildNode: TSimpleFresnelLayoutNode;
|
|
|
ChildEl: TFresnelElement;
|
|
|
+ aWidth, aHeight: TFresnelLength;
|
|
|
begin
|
|
|
for i:=0 to FLineItems.Count-1 do
|
|
|
begin
|
|
|
- LineNode:=TLineItem(FLineItems[i]);
|
|
|
- ChildNode:=LineNode.Node;
|
|
|
+ Item:=TLineItem(FLineItems[i]);
|
|
|
+ ChildNode:=Item.Node;
|
|
|
ChildEl:=ChildNode.Element;
|
|
|
|
|
|
- ChildEl.ComputedAttribute[fcaLeft]:=FloatToCSSPx(LineNode.BorderBox.Left);
|
|
|
- ChildEl.ComputedAttribute[fcaRight]:=FloatToCSSPx(LineNode.BorderBox.Right);
|
|
|
- ChildEl.ComputedAttribute[fcaTop]:=FloatToCSSPx(LineNode.BorderBox.Top);
|
|
|
- ChildEl.ComputedAttribute[fcaBottom]:=FloatToCSSPx(LineNode.BorderBox.Bottom);
|
|
|
- ChildEl.ComputedAttribute[fcaWidth]:=FloatToCSSPx(LineNode.ContentBoxWidth);
|
|
|
- ChildEl.ComputedAttribute[fcaHeight]:=FloatToCSSPx(LineNode.ContentBoxHeight);
|
|
|
+ ChildEl.ComputedAttribute[fcaLeft]:=FloatToCSSPx(Item.MarginBox.Left);
|
|
|
+ ChildEl.ComputedAttribute[fcaRight]:=FloatToCSSPx(Item.MarginBox.Right);
|
|
|
+ ChildEl.ComputedAttribute[fcaTop]:=FloatToCSSPx(Item.MarginBox.Top);
|
|
|
+ ChildEl.ComputedAttribute[fcaBottom]:=FloatToCSSPx(Item.MarginBox.Bottom);
|
|
|
+
|
|
|
+ aWidth:=Item.ContentBoxWidth;
|
|
|
+ aHeight:=Item.ContentBoxHeight;
|
|
|
+ case ChildEl.ComputedBoxSizing of
|
|
|
+ CSSRegistry.kwBorderBox:
|
|
|
+ begin
|
|
|
+ aWidth:=aWidth+Item.BorderLeft+Item.PaddingLeft+Item.PaddingRight+Item.BorderRight;
|
|
|
+ aHeight:=aHeight+Item.BorderTop+Item.PaddingTop+Item.PaddingBottom+Item.BorderBottom;
|
|
|
+ end;
|
|
|
+ CSSRegistry.kwPaddingBox:
|
|
|
+ begin
|
|
|
+ aWidth:=aWidth+Item.PaddingLeft+Item.PaddingRight;
|
|
|
+ aHeight:=aHeight+Item.PaddingTop+Item.PaddingBottom;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
+ ChildEl.ComputedAttribute[fcaWidth]:=FloatToCSSPx(aWidth);
|
|
|
+ ChildEl.ComputedAttribute[fcaHeight]:=FloatToCSSPx(aHeight);
|
|
|
|
|
|
//writeln(
|
|
|
// 'TFLBlockFormattingContext.PlaceLineNodes '+ChildEl.GetPath+
|