mattias 3 weken geleden
bovenliggende
commit
a4e32906ad
4 gewijzigde bestanden met toevoegingen van 117 en 50 verwijderingen
  1. 1 1
      src/base/fresnel.dom.pas
  2. 28 14
      src/base/fresnel.layouter.pas
  3. 1 15
      src/base/fresnel.textlayouter.pas
  4. 87 20
      tests/base/TCFlowLayout.pas

+ 1 - 1
src/base/fresnel.dom.pas

@@ -1174,7 +1174,7 @@ type
     function FitHeight(aHeight: TFresnelLength): TFresnelLength;
     procedure ResetUsedLengths; virtual;
     property Element: TFresnelElement read FElement write SetElement;
-    // rendering order (z-index layout)
+    // sort for rendering order (z-index layout)
     {$IF FPC_FULLVERSION>=30301}
     procedure SortNodes(const Compare: TListSortComparer_Context; Context: Pointer = nil); virtual;
     {$ELSE}

+ 28 - 14
src/base/fresnel.layouter.pas

@@ -288,7 +288,7 @@ begin
       Size:=GetIntrinsicContentSize(flmMax,MaxWidth,MaxHeight);
       Node.ApplyScrollSize(Size);
       {$IFDEF VerboseFresnelScrolling}
-      writeln('TFLNodeLayouter.Apply "',Node.Element.Name,'" IntrinsicContentSize: Size=',FloatToCSSStr(Size.Width),'x',FloatToCSSStr(Size.Height),' ScrollSize=',FloatToCSSStr(Size.ScrollWidth),'x',FloatToCSSStr(Size.ScrollHeight),' NeedGutterHorz=',Size.NeedGutterHorizontal,' Vert=',Size.NeedGutterVertical,' Gutter:L=',FloatToCSSStr(Node.ScrollGutterLeft),',R=',FloatToCSSStr(Node.ScrollGutterRight),',T=',FloatToCSSStr(Node.ScrollGutterTop),',B=',FloatToCSSStr(Node.ScrollGutterBottom));
+      writeln('TFLNodeLayouter.Apply "',Node.Element.Name,'" IntrinsicContentSize: Size=',FloatToCSSStr(Size.Width),'x',FloatToCSSStr(Size.Height),' ScrollSize=',FloatToCSSStr(Size.OverflowWidth),'x',FloatToCSSStr(Size.OverflowHeight),' NeedGutterHorz=',Size.NeedGutterHorizontal,' Vert=',Size.NeedGutterVertical,' Gutter:L=',FloatToCSSStr(Node.ScrollGutterLeft),',R=',FloatToCSSStr(Node.ScrollGutterRight),',T=',FloatToCSSStr(Node.ScrollGutterTop),',B=',FloatToCSSStr(Node.ScrollGutterBottom));
       {$ENDIF}
     end;
 
@@ -311,7 +311,7 @@ begin
     {$ENDIF}
     Size:=ComputeLayoutContent(flmMax,AvailWidth,AvailHeight,true);
     {$IFDEF VerboseFresnelScrolling}
-    writeln('TFLNodeLayouter.Apply "',Node.Element.Name,'" Size: ',FloatToCSSStr(Size.Width),'x',FloatToCSSStr(Size.Height),' Scroll: ',FloatToCSSStr(Size.ScrollWidth),'x',FloatToCSSStr(Size.ScrollWidth));
+    writeln('TFLNodeLayouter.Apply "',Node.Element.Name,'" Size: ',FloatToCSSStr(Size.Width),'x',FloatToCSSStr(Size.Height),' Scroll: ',FloatToCSSStr(Size.OverflowWidth),'x',FloatToCSSStr(Size.OverflowHeight));
     {$ENDIF}
     if IsNan(Node.Width) then
     begin
@@ -500,7 +500,7 @@ var
 
 var
   GutterVertical, GutterHorizontal: TFresnelLayoutNode.TGutterMode;
-  HasMaxWidth, HasMaxHeight, Done: Boolean;
+  HasMaxWidth, HasMaxHeight: Boolean;
   aClientHeight, aClientWidth: TFresnelLength;
 
   procedure CheckOverflowX;
@@ -515,8 +515,11 @@ var
         Result.NeedGutterHorizontal:=true;
         GutterHorizontal:=gmAlways;
         Node.GetScrollGutterWidths(true,GutterTop,GutterBottom);
-        aClientHeight:=aClientHeight-GutterTop-GutterBottom;
-        if aClientHeight<0 then aClientHeight:=0;
+        if HasMaxHeight then
+        begin
+          aClientHeight:=aClientHeight-GutterTop-GutterBottom;
+          if aClientHeight<0 then aClientHeight:=0;
+        end;
         Result.Height:=Result.Height+GutterTop+GutterBottom;
       end;
     end;
@@ -534,8 +537,11 @@ var
         Result.NeedGutterVertical:=true;
         GutterVertical:=gmAlways;
         Node.GetScrollGutterWidths(false,GutterLeft,GutterRight);
-        aClientWidth:=aClientWidth-GutterLeft-GutterRight;
-        if aClientWidth<0 then aClientWidth:=0;
+        if HasMaxWidth then
+        begin
+          aClientWidth:=aClientWidth-GutterLeft-GutterRight;
+          if aClientWidth<0 then aClientWidth:=0;
+        end;
         Result.Width:=Result.Width+GutterLeft+GutterRight;
       end;
     end;
@@ -566,7 +572,6 @@ begin
     exit;
   end;
 
-  Done:=false;
   if aWithScroll then
   begin
     // consider gutters
@@ -614,11 +619,8 @@ begin
         end;
       end;
     end;
-    Done:=true;
-  end;
-
-  if not Done then
-  begin
+  end else begin
+    // no gutters
     Result:=ComputeLayoutContent(aMode,aMaxWidth,aMaxHeight,false);
     //writeln('TFLNodeLayouter.GetIntrinsicContentSize ',Node.Element.Name,' ',aMode,' ',FloatToCSSStr(aMaxWidth),' ',FloatToCSSStr(aMaxHeight),' Computed=',Result.ToString);
   end;
@@ -2301,6 +2303,7 @@ var
   i: Integer;
   Node: TUsedLayoutNode;
   ChildEl: TFresnelElement;
+  Size: TFreIntrinsicContentSize;
 begin
   Node:=TUsedLayoutNode(El.LayoutNode);
   if Node.SkipLayout then exit;
@@ -2318,7 +2321,18 @@ begin
   end;
 
   if Node.Layouter<>nil then
-    Node.Layouter.Apply;
+    Node.Layouter.Apply
+  else begin
+    Size:=Node.GetIntrinsicContentSize(flmMax,Node.Width,Node.Height);
+    if Node.Width<Size.OverflowWidth then
+      Node.ScrollWidth:=Size.OverflowWidth
+    else
+      Node.ScrollWidth:=Node.Width;
+    if Node.Height<Size.OverflowHeight then
+      Node.ScrollHeight:=Size.OverflowHeight
+    else
+      Node.ScrollHeight:=Node.Height;
+  end;
 
   for i:=0 to El.NodeCount-1 do
     Layout(El.Nodes[i]);

+ 1 - 15
src/base/fresnel.textlayouter.pas

@@ -103,21 +103,14 @@ Type
     procedure SetColor(AValue: TColor);
     procedure SetFPColor(AValue: TFPColor);
     procedure SetName(const AValue: String);
-    procedure SetSize(AValue: Smallint);
-
+    procedure SetSize(AValue: SmallInt);
   public
     constructor Create(aOwner : TPersistent); virtual;
-
     procedure Assign(Source: TPersistent); override;
-
     procedure Changed; virtual;
-
     function Clone(aOwner : TPersistent=nil): TTextFont;
-
     function IsSameFont(aFont : TTextFont) : Boolean; virtual;
-
     property FPColor : TFPColor Read FColor write SetFPColor;
-
   published
     // In name
     property Name : TFontNameString Read FName Write SetName;
@@ -156,7 +149,6 @@ Type
 
   { TTextMeasurer }
 
-
   TTextMeasurer = class abstract (TObject)
   private
     FLayouter: TTextLayouter;
@@ -172,7 +164,6 @@ Type
     function LineHeight : TTextUnits;
     function WhitespaceWidth : TTextUnits;
     Property Layouter : TTextLayouter Read FLayouter;
-
   end;
   TTextMeasurerClass = Class of TTextMeasurer;
 
@@ -196,14 +187,12 @@ Type
     Property FontName : String Read FFontName;
   end;
 
-
   { TTextBlock }
 
   TTextBlock = Class(TObject)
   private
     FLayouter : TTextLayouter;
     function GetText: TTextString;
-
   public
     LayoutPos: TTextPoint;
     Size : TTextMeasures;
@@ -245,7 +234,6 @@ Type
     Property Block [aIndex : Integer] : TTextBlock Read GetBlock; default;
   end;
 
-
   { TTextRange }
 
   TTextRange = class(TCollectionItem)
@@ -443,7 +431,6 @@ Type
 Function SplitPoint(aOffset, aSpaces : SizeInt) : TTextSplitPoint;
 
 
-
 implementation
 
 resourcestring
@@ -1974,7 +1961,6 @@ var
   i: integer;
   tb: TTextBlock;
   lLastYPos: TTextUnits;
-  lTotalHeight: TTextUnits;
   lYOffset: TTextUnits;
 begin
   if FBlocks.Count = 0 then

+ 87 - 20
tests/base/TCFlowLayout.pas

@@ -13,18 +13,22 @@ type
 
   TTestFlowLayout = class(TCustomTestFresnelCSS)
   published
-    procedure TestFlowLayout_BodyDiv;
-    procedure TestFlowLayout_Slider_WithoutRangePoint;
-    procedure TestFlowLayout_SliderRangePoint;
-
-    procedure TestMarginPercentage;
-    procedure TestPaddingPercentage;
-    procedure TestPositionAbsolute_Right_WidthAuto;
-    procedure TestPositionAbsolute_DivDefaultPosBehindStatic;
-    procedure TestPositionAbsolute_DivDefaultPosBehindRelative;
-    procedure TestPositionAbsolute_Left_ScrollWidth;
+    procedure TestFL_BodyDiv;
+    procedure TestFL_Slider_WithoutRangePoint;
+    procedure TestFL_SliderRangePoint;
+
+    procedure TestFL_MarginPercentage;
+    procedure TestFL_PaddingPercentage;
+    procedure TestFL_PositionAbsolute_Right_WidthAuto;
+    procedure TestFL_PositionAbsolute_DivDefaultPosBehindStatic;
+    procedure TestFL_PositionAbsolute_DivDefaultPosBehindRelative;
+
+    // scroll
+    procedure TestFL_PositionAbsolute_Left_ScrollWidth;
+    procedure TestFL_OverflowSizeNested; // todo
     // todo procedure TestPositionAbsolute_DivTop100Percent;
-    // todo: test break line
+
+    // todo: test break line aka fragments
   end;
 
 
@@ -32,7 +36,7 @@ implementation
 
 { TTestFlowLayout }
 
-procedure TTestFlowLayout.TestFlowLayout_BodyDiv;
+procedure TTestFlowLayout.TestFL_BodyDiv;
 var
   Body: TBody;
   Div1: TDiv;
@@ -88,7 +92,7 @@ begin
   AssertEquals('Div1.UsedBorderBox.Bottom',10,r.Bottom);
 end;
 
-procedure TTestFlowLayout.TestFlowLayout_Slider_WithoutRangePoint;
+procedure TTestFlowLayout.TestFL_Slider_WithoutRangePoint;
 var
   Body: TBody;
   SliderDiv: TDiv;
@@ -119,7 +123,7 @@ begin
   AssertEquals('SliderDiv.UsedBorderBox.Bottom',18,SliderDiv.UsedBorderBox.Bottom);
 end;
 
-procedure TTestFlowLayout.TestFlowLayout_SliderRangePoint;
+procedure TTestFlowLayout.TestFL_SliderRangePoint;
 var
   Body: TBody;
   SliderDiv, RangeDiv, PointDiv: TDiv;
@@ -245,7 +249,7 @@ begin
   AssertEquals('PointDiv.UsedContentBox.Bottom',13,PointDiv.UsedContentBox.Bottom);
 end;
 
-procedure TTestFlowLayout.TestMarginPercentage;
+procedure TTestFlowLayout.TestFL_MarginPercentage;
 var
   Body: TBody;
   Div1: TDiv;
@@ -283,7 +287,7 @@ begin
   AssertEquals('Div1.UsedBorderBox.Bottom',50,Div1.UsedBorderBox.Bottom);
 end;
 
-procedure TTestFlowLayout.TestPaddingPercentage;
+procedure TTestFlowLayout.TestFL_PaddingPercentage;
 var
   Body: TBody;
   Div1: TDiv;
@@ -321,7 +325,7 @@ begin
   AssertEquals('Div1.UsedContentBox.Bottom',50,Div1.UsedContentBox.Bottom);
 end;
 
-procedure TTestFlowLayout.TestPositionAbsolute_Right_WidthAuto;
+procedure TTestFlowLayout.TestFL_PositionAbsolute_Right_WidthAuto;
 var
   Body: TBody;
   Div1, Div2, Div3: TDiv;
@@ -407,7 +411,7 @@ begin
   AssertEquals('Div2.LayoutNode.Height',52,Div2.LayoutNode.Height);
 end;
 
-procedure TTestFlowLayout.TestPositionAbsolute_DivDefaultPosBehindStatic;
+procedure TTestFlowLayout.TestFL_PositionAbsolute_DivDefaultPosBehindStatic;
 var
   Body: TBody;
   Div1: TDiv;
@@ -474,7 +478,7 @@ begin
   AssertEquals('Div1.UsedBorderBox.Top',23,Div1.UsedBorderBox.Top);
 end;
 
-procedure TTestFlowLayout.TestPositionAbsolute_DivDefaultPosBehindRelative;
+procedure TTestFlowLayout.TestFL_PositionAbsolute_DivDefaultPosBehindRelative;
 var
   Body: TBody;
   Div1: TDiv;
@@ -533,7 +537,7 @@ begin
   AssertEquals('Div1.UsedBorderBox.Top',23,Div1.UsedBorderBox.Top);
 end;
 
-procedure TTestFlowLayout.TestPositionAbsolute_Left_ScrollWidth;
+procedure TTestFlowLayout.TestFL_PositionAbsolute_Left_ScrollWidth;
 var
   Body: TBody;
   Div1: TDiv;
@@ -582,6 +586,69 @@ begin
   AssertEquals('Body.LayoutNode.ScrollHeight',34,Body.LayoutNode.ScrollHeight);
 end;
 
+procedure TTestFlowLayout.TestFL_OverflowSizeNested;
+var
+  Div1, Div2, Div3, Div4: TDiv;
+begin
+  // test, if overflow size is propagated, except when clipping
+  exit;
+
+  Div1:=TDiv.Create(Viewport);
+  Div1.Name:='Div1';
+  Div1.Parent:=Viewport;
+
+  Div2:=TDiv.Create(Viewport);
+  Div2.Name:='Div2';
+  Div2.Parent:=Div1;
+
+  Div3:=TDiv.Create(Viewport);
+  Div3.Name:='Div3';
+  Div3.Parent:=Div2;
+
+  Div4:=TDiv.Create(Viewport);
+  Div4.Name:='Div4';
+  Div4.Parent:=Div3;
+
+  Viewport.Stylesheet.Text:=LinesToStr([
+    'div {',
+    '  margin: 2px;',
+    '  border: 1px;',
+    '  padding: 7px;',
+    '}',
+    '#Div1 {',
+    '  width: 50px;',
+    '  height: 50px;',
+    '  overflow: auto;',
+    '}',
+    // Div2 fits into Div1, but its content does not
+    '#Div2 {',
+    '  width: 30px;',
+    '  height: 20px;',
+    '}',
+    // Div3 causes Div1 to scroll, but only for its size, not its clipped content
+    '#Div3 {',
+    '  width: 100px;',
+    '  height: 100px;',
+    '  overflow: auto;',
+    '}',
+    // Div4 causes Div3 to scroll
+    '#Div4 {',
+    '  width: 200px;',
+    '  height: 200px;',
+    '}']);
+
+  Viewport.Draw;
+  AssertEquals('Div4.UsedBorderBox.Width',216,Div4.UsedBorderBox.Width);
+  AssertEquals('Div4.UsedBorderBox.Height',216,Div4.UsedBorderBox.Height);
+  AssertEquals('Div4.ScrollWidth',200,Div4.ScrollWidth);
+  AssertEquals('Div4.ScrollHeight',200,Div4.ScrollHeight);
+
+  AssertEquals('Div3.UsedBorderBox.Width',116,Div3.UsedBorderBox.Width);
+  AssertEquals('Div3.UsedBorderBox.Height',116,Div3.UsedBorderBox.Height);
+  AssertEquals('Div3.ScrollWidth',220,Div3.ScrollWidth);
+  AssertEquals('Div3.ScrollHeight',220,Div3.ScrollHeight);
+end;
+
 Initialization
   RegisterTests([TTestFlowLayout]);
 end.