Răsfoiți Sursa

dom: added font-width, changed font kerning to enum

mattias 11 luni în urmă
părinte
comite
3da1a8ae6d

+ 1 - 1
demo/Slider/MainUnit.pas

@@ -38,7 +38,7 @@ begin
     Style:='width: 150px';
     MinPosition:=0;
     MaxPosition:=100;
-    Position:=30;
+    SliderPosition:=30;
     Parent:=Self;
   end;
 end;

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

@@ -272,7 +272,7 @@ end;
 
 class function TBody.GetCSSTypeStyle: TCSSString;
 begin
-  Result:='body { background-color: white; color: black; display: block; position: absolute; }';
+  Result:='body { background-color: white; color: black; display: block; position: static; }';
 end;
 
 

+ 249 - 103
src/base/fresnel.dom.pas

@@ -104,9 +104,10 @@ type
     fcaFontFamily,
     fcaFontKerning, // auto|normal|none
     fcaFontSize,  // units like em depend on this, medium|xx-small|x-small|small|large|x-large|xx-large|smaller|larger|LengthUnit|%
-    fcaFontStretch, // normal, |semi|extra|ultra-condensed, |semi|extra|ultra-expanded,
     fcaFontStyle, // normal|italic|oblique
     fcaFontWeight, // normal|bold|bolder|lighter|number
+    fcaFontWidth, // normal, |semi|extra|ultra-condensed, |semi|extra|ultra-expanded,
+    fcaFontStretch, // shorthand for font-width
     fcaFontVariant, // actually a shorthand - not yet supported
     fcaLineHeight,
     fcaFont, // shorthand for font-family, -size, -stretch, - style, -variant, -weight, line-height
@@ -159,10 +160,10 @@ const
     'overflow-y',
     'overflow',
     'clear',
-    'left',
     'top',
     'right',
     'bottom',
+    'left',
     'min-width',
     'max-width',
     'min-height',
@@ -198,9 +199,10 @@ const
     'font-family',
     'font-kerning',
     'font-size',
-    'font-stretch',
     'font-style',
     'font-weight',
+    'font-width',
+    'font-stretch',
     'font-variant',
     'line-height',
     'font',
@@ -257,6 +259,19 @@ type
     );
   TFresnelCSSCorners = set of TFresnelCSSCorner;
 
+  TFresnelCSSKerning = (
+    fckAuto,
+    fckNormal,
+    fckNone
+    );
+
+const
+  FresnelCSSKerningNames: array[TFresnelCSSKerning] of string = (
+    'auto',
+    'normal',
+    'none'
+    );
+
 type
   TFresnelCSSPseudoClass = (
     fcpcHover
@@ -350,10 +365,10 @@ type
     function CheckFontFamily(Resolver: TCSSBaseResolver): boolean; virtual;
     function CheckFontKerning(Resolver: TCSSBaseResolver): boolean; virtual;
     function CheckFontSize(Resolver: TCSSBaseResolver): boolean; virtual;
-    function CheckFontStretch(Resolver: TCSSBaseResolver): boolean; virtual;
     function CheckFontStyle(Resolver: TCSSBaseResolver): boolean; virtual;
-    function CheckFontWeight(Resolver: TCSSBaseResolver): boolean; virtual;
     function CheckFontVariant(Resolver: TCSSBaseResolver): boolean; virtual;
+    function CheckFontWeight(Resolver: TCSSBaseResolver): boolean; virtual;
+    function CheckFontWidth(Resolver: TCSSBaseResolver): boolean; virtual;
     function CheckLineHeight(Resolver: TCSSBaseResolver): boolean; virtual;
     function CheckFont(Resolver: TCSSBaseResolver): boolean; virtual;
     function CheckTextShadow(Resolver: TCSSBaseResolver): boolean; virtual;
@@ -382,7 +397,7 @@ type
     function ReadBackground(Resolver: TCSSBaseResolver; Check: boolean;
       out aAttachment, aClip, aColor, aImage, aOrigin, aPositionX, aPositionY, aRepeat, aSize: TCSSString): boolean; virtual;
     function ReadFont(Resolver: TCSSBaseResolver; Check: boolean;
-      out aSystemFont: TCSSNumericalID; out aFamily, aStyle, aVariant, aWeight, aStretch, aSize, aLineHeight: TCSSString): boolean; virtual;
+      out aSystemFont: TCSSNumericalID; out aFamily, aStyle, aVariant, aWeight, aWidth, aSize, aLineHeight: TCSSString): boolean; virtual;
     function IsColor(const ResValue: TCSSResCompValue): boolean; virtual;
     procedure SplitLonghandSides(var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray;
       Top, Right, Bottom, Left: TFresnelCSSAttribute; const Found: TCSSStringArray);
@@ -398,6 +413,7 @@ type
     procedure SplitBorderStyle(Resolver: TCSSBaseResolver; var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray); virtual;
     procedure SplitBorderWidth(Resolver: TCSSBaseResolver; var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray); virtual;
     procedure SplitFont(Resolver: TCSSBaseResolver; var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray); virtual; // todo systemfont
+    procedure SplitFontStretch(Resolver: TCSSBaseResolver; var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray); virtual; // todo systemfont
     procedure SplitMargin(Resolver: TCSSBaseResolver; var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray); virtual;
     procedure SplitMarginBlock(Resolver: TCSSBaseResolver; var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray); virtual;
     procedure SplitMarginInline(Resolver: TCSSBaseResolver; var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray); virtual;
@@ -419,7 +435,13 @@ type
     function GetBorderWidth(El: TFresnelElement): string; virtual;
     function GetSideLengths(El: TFresnelElement; LeftAttr: TFresnelCSSAttribute): string; virtual;
     function GetFont(El: TFresnelElement): string; virtual;
+    function GetFontFamily(El: TFresnelElement): string; virtual;
+    function GetFontKerning(El: TFresnelElement): string; virtual;
     function GetFontSize(El: TFresnelElement): string; virtual;
+    function GetFontStyle(El: TFresnelElement): string; virtual;
+    function GetFontVariant(El: TFresnelElement): string; virtual;
+    function GetFontWidth(El: TFresnelElement): string; virtual;
+    function GetFontWeight(El: TFresnelElement): string; virtual;
     function GetMargin(El: TFresnelElement): string; virtual;
     function GetMarginBlock(El: TFresnelElement): string; virtual;
     function GetMarginInline(El: TFresnelElement): string; virtual;
@@ -495,7 +517,8 @@ type
       kwInlineFlow = kwInlineEnd+1; // inline-flow
       kwInlineStart = kwInlineFlow+1; // inline-start
       kwInset = kwInlineStart+1;
-      kwLarge = kwInset+1;
+      kwItalic = kwInset+1;
+      kwLarge = kwItalic+1;
       kwLarger = kwLarge+1;
       kwLeft = kwLarger+1;
       kwLighter = kwLeft+1;
@@ -517,7 +540,8 @@ type
       kwNSResize = kwNResize+1; // ns-resize
       kwNWResize = kwNSResize+1; // nw-resize
       kwNWSEResize = kwNWResize+1; // nwse-resize
-      kwOutset = kwNWSEResize+1;
+      kwOblique = kwNWSEResize+1;
+      kwOutset = kwOblique+1;
       kwPaddingBox = kwOutset+1; // padding-box
       kwPointer = kwPaddingBox+1;
       kwProgress = kwPointer+1;
@@ -604,7 +628,7 @@ type
     Chk_FontFeatureSettings_KeywordIDs: TCSSNumericalIDArray;
     Chk_FontKerning_KeywordIDs: TCSSNumericalIDArray;
     Chk_FontSize_Dim: TCSSCheckAttrParams_Dimension;
-    Chk_FontStretch_Dim: TCSSCheckAttrParams_Dimension;
+    Chk_FontWidth_Dim: TCSSCheckAttrParams_Dimension;
     Chk_FontStyle_KeywordIDs: TCSSNumericalIDArray;
     Chk_FontWeight_Dim: TCSSCheckAttrParams_Dimension;
     Chk_FontVariant_KeywordIDs: TCSSNumericalIDArray;
@@ -682,11 +706,12 @@ type
   IFresnelFont = interface
     ['{6B53C662-5598-419B-996B-7E839271B64E}']
     function GetFamily: string;
-    function GetKerning: string;
-    function GetSize: TFresnelLength;
+    function GetKerning: TFresnelCSSKerning;
+    function GetSize: TFresnelLength; // in pixel
     function GetStyle: string;
     function GetVariant: string;
-    function GetWeight: TFresnelLength;
+    function GetWeight: TFresnelLength; // 0..750
+    function GetWidth: TFresnelLength; // in percent
     function TextSize(const aText: string): TFresnelPoint;
     function TextSizeMaxWidth(const aText: string; MaxWidth: TFresnelLength): TFresnelPoint;
     function GetTool: TObject;
@@ -722,11 +747,12 @@ type
 
   TFresnelFontDesc = record
     Family: string;
-    Kerning: string;
-    Size: TFresnelLength;
+    Kerning: TFresnelCSSKerning;
+    Size: TFresnelLength; // in pixel
     Style: string;
     Variant_: string;
-    Weight: TFresnelLength;
+    Weight: TFresnelLength; // 100..750
+    Width: TFresnelLength; // in percent
     function Compare(const Desc: TFresnelFontDesc): integer;
     class function CompareDescriptors(const A, B: TFresnelFontDesc): integer; static;
   end;
@@ -1347,14 +1373,15 @@ begin
   Result:=Resolver.CheckAttribute_Dimension(Chk_FontSize_Dim);
 end;
 
-function TFresnelCSSRegistry.CheckFontStretch(Resolver: TCSSBaseResolver): boolean;
+function TFresnelCSSRegistry.CheckFontStyle(Resolver: TCSSBaseResolver): boolean;
 begin
-  Result:=Resolver.CheckAttribute_Dimension(Chk_FontStretch_Dim);
+  Result:=Resolver.CheckAttribute_Keyword(Chk_FontStyle_KeywordIDs);
 end;
 
-function TFresnelCSSRegistry.CheckFontStyle(Resolver: TCSSBaseResolver): boolean;
+function TFresnelCSSRegistry.CheckFontVariant(Resolver: TCSSBaseResolver): boolean;
 begin
-  Result:=Resolver.CheckAttribute_Keyword(Chk_FontStyle_KeywordIDs);
+  // not yet supported
+  Result:=Resolver.CheckAttribute_Keyword(Chk_FontVariant_KeywordIDs);
 end;
 
 function TFresnelCSSRegistry.CheckFontWeight(Resolver: TCSSBaseResolver): boolean;
@@ -1362,10 +1389,9 @@ begin
   Result:=Resolver.CheckAttribute_Dimension(Chk_FontWeight_Dim);
 end;
 
-function TFresnelCSSRegistry.CheckFontVariant(Resolver: TCSSBaseResolver): boolean;
+function TFresnelCSSRegistry.CheckFontWidth(Resolver: TCSSBaseResolver): boolean;
 begin
-  // not yet supported
-  Result:=Resolver.CheckAttribute_Keyword(Chk_FontVariant_KeywordIDs);
+  Result:=Resolver.CheckAttribute_Dimension(Chk_FontWidth_Dim);
 end;
 
 function TFresnelCSSRegistry.CheckLineHeight(Resolver: TCSSBaseResolver): boolean;
@@ -1376,9 +1402,9 @@ end;
 function TFresnelCSSRegistry.CheckFont(Resolver: TCSSBaseResolver): boolean;
 var
   aSystemFont: TCSSNumericalID;
-  aFamily, aStyle, aVariant, aWeight, aStretch, aSize, aLineHeight: TCSSString;
+  aFamily, aStyle, aVariant, aWeight, aWidth, aSize, aLineHeight: TCSSString;
 begin
-  Result:=ReadFont(Resolver,true, aSystemFont, aFamily, aStyle, aVariant, aWeight, aStretch,
+  Result:=ReadFont(Resolver,true, aSystemFont, aFamily, aStyle, aVariant, aWeight, aWidth,
     aSize, aLineHeight);
 end;
 
@@ -2052,7 +2078,7 @@ begin
 end;
 
 function TFresnelCSSRegistry.ReadFont(Resolver: TCSSBaseResolver; Check: boolean; out
-  aSystemFont: TCSSNumericalID; out aFamily, aStyle, aVariant, aWeight, aStretch, aSize,
+  aSystemFont: TCSSNumericalID; out aFamily, aStyle, aVariant, aWeight, aWidth, aSize,
   aLineHeight: TCSSString): boolean;
 var
   KW: TCSSNumericalID;
@@ -2066,7 +2092,7 @@ begin
   aStyle:='';
   aVariant:='';
   aWeight:='';
-  aStretch:='';
+  aWidth:='';
   aLineHeight:='';
 
   if Resolver.CurComp.Kind=rvkKeyword then
@@ -2118,11 +2144,11 @@ begin
           aWeight:=Resolver.GetCompString;
           Used:=true;
         end
-        else if Resolver.IsKeywordIn(KW,Chk_FontStretch_Dim.AllowedKeywordIDs) then
+        else if Resolver.IsKeywordIn(KW,Chk_FontWidth_Dim.AllowedKeywordIDs) then
         begin
-          if aStretch>'' then
+          if aWidth>'' then
             exit; // todo warn
-          aStretch:=Resolver.GetCompString;
+          aWidth:=Resolver.GetCompString;
           Used:=true;
         end
       end;
@@ -2437,9 +2463,9 @@ procedure TFresnelCSSRegistry.SplitFont(Resolver: TCSSBaseResolver;
   var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray);
 var
   aSystemFont: TCSSNumericalID;
-  aFamily, aStyle, aVariant, aWeight, aStretch, aSize, aLineHeight: TCSSString;
+  aFamily, aStyle, aVariant, aWeight, aWidth, aSize, aLineHeight: TCSSString;
 begin
-  if not ReadFont(Resolver,false, aSystemFont, aFamily, aStyle, aVariant, aWeight, aStretch, aSize,
+  if not ReadFont(Resolver,false, aSystemFont, aFamily, aStyle, aVariant, aWeight, aWidth, aSize,
     aLineHeight) then exit;
 
   if aSystemFont>0 then
@@ -2456,8 +2482,8 @@ begin
     Values[2]:=aVariant;
     AttrIDs[3]:=FresnelAttrs[fcaFontWeight].Index;
     Values[3]:=aWeight;
-    AttrIDs[4]:=FresnelAttrs[fcaFontStretch].Index;
-    Values[4]:=aStretch;
+    AttrIDs[4]:=FresnelAttrs[fcaFontWidth].Index;
+    Values[4]:=aWidth;
     AttrIDs[5]:=FresnelAttrs[fcaFontSize].Index;
     Values[5]:=aSize;
     AttrIDs[6]:=FresnelAttrs[fcaLineHeight].Index;
@@ -2465,6 +2491,15 @@ begin
   end;
 end;
 
+procedure TFresnelCSSRegistry.SplitFontStretch(Resolver: TCSSBaseResolver;
+  var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray);
+begin
+  SetLength(AttrIDs,1);
+  AttrIDs[0]:=FresnelAttrs[fcaFontWidth].Index;
+  SetLength(Values,1);
+  Values[0]:=Resolver.CurValue;
+end;
+
 procedure TFresnelCSSRegistry.SplitMargin(Resolver: TCSSBaseResolver;
   var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray);
 var
@@ -2700,11 +2735,41 @@ begin
   Add(aFamily,'');
 end;
 
+function TFresnelCSSRegistry.GetFontFamily(El: TFresnelElement): string;
+begin
+  Result:=El.Font.GetFamily;
+end;
+
+function TFresnelCSSRegistry.GetFontKerning(El: TFresnelElement): string;
+begin
+  Result:=FresnelCSSKerningNames[El.Font.GetKerning];
+end;
+
 function TFresnelCSSRegistry.GetFontSize(El: TFresnelElement): string;
 begin
   Result:=FloatToCSSPx(El.Font.GetSize);
 end;
 
+function TFresnelCSSRegistry.GetFontStyle(El: TFresnelElement): string;
+begin
+  Result:=El.Font.GetStyle;
+end;
+
+function TFresnelCSSRegistry.GetFontVariant(El: TFresnelElement): string;
+begin
+  Result:=El.Font.GetVariant;
+end;
+
+function TFresnelCSSRegistry.GetFontWidth(El: TFresnelElement): string;
+begin
+  Result:=FloatToCSSStr(El.Font.GetWidth*100)+'%';
+end;
+
+function TFresnelCSSRegistry.GetFontWeight(El: TFresnelElement): string;
+begin
+  Result:=FloatToCSSStr(El.Font.GetWeight);
+end;
+
 function TFresnelCSSRegistry.GetMargin(El: TFresnelElement): string;
 var
   Margins: array[TFresnelCSSSide] of TFresnelLength;
@@ -2895,7 +2960,7 @@ begin
   AddKW(kwCollapse,'collapse'); // e.g. visible
   AddKW(kwColResize,'col-resize'); // e.g. cursor
   AddKW(kwCommonLigatures,'common-ligatures'); // e.g. font-variant
-  AddKW(kwCondensed,'condensed'); // e.g. font-stretch
+  AddKW(kwCondensed,'condensed'); // e.g. font-width
   AddKW(kwContain,'contain'); // e.g. background-size
   AddKW(kwContentBox,'content-box'); // e.g. box-sizing
   AddKW(kwContents,'contents'); // e.g. display
@@ -2910,9 +2975,9 @@ begin
   AddKW(kwDouble,'double'); // e.g. border-style
   AddKW(kwEResize,'e-resize'); // e.g. cursor
   AddKW(kwEWResize,'ew-resize'); // e.g. cursor
-  AddKW(kwExpanded,'expanded'); // e.g. font-stretch
-  AddKW(kwExtraCondensed,'extra-condensed'); // e.g. font-stretch
-  AddKW(kwExtraExpanded,'extra-expanded'); // e.g. font-stretch
+  AddKW(kwExpanded,'expanded'); // e.g. font-width
+  AddKW(kwExtraCondensed,'extra-condensed'); // e.g. font-width
+  AddKW(kwExtraExpanded,'extra-expanded'); // e.g. font-width
   AddKW(kwFitContent,'fit-content'); // e.g. width, min-width
   AddKW(kwFixed,'fixed'); // e.g. position, background-attachment
   AddKW(kwFlex,'flex'); // e.g. display
@@ -2932,6 +2997,7 @@ begin
   AddKW(kwInlineFlow,'inline-flow'); // e.g. display
   AddKW(kwInlineStart,'inline-start'); // e.g. clear, float
   AddKW(kwInset,'inset'); // e.g. border-style
+  AddKW(kwItalic,'italic'); // e.g. font-style
   AddKW(kwLarge,'large'); // e.g. font-size
   AddKW(kwLarger,'larger'); // e.g. font-size
   AddKW(kwLeft,'left'); // e.g. clear, float
@@ -2954,6 +3020,7 @@ begin
   AddKW(kwNSResize,'ns-resize'); // e.g. cursor
   AddKW(kwNWResize,'nw-resize'); // e.g. cursor
   AddKW(kwNWSEResize,'nwse-resize'); // e.g. cursor
+  AddKW(kwOblique,'oblique'); // e.g. font-style
   AddKW(kwOutset,'outset'); // e.g. border-style
   AddKW(kwPaddingBox,'padding-box'); // e.g. background-origin
   AddKW(kwPointer,'pointer'); // e.g. cursor
@@ -2968,8 +3035,8 @@ begin
   AddKW(kwRowResize,'row-resize'); // e.g. cursor
   AddKW(kwRTL,'rtl'); // e.g. direction
   AddKW(kwScroll,'scroll'); // e.g. overflow-x, background-attachment
-  AddKW(kwSemiCondensed,'semi-condensed'); // e.g. font-stretch
-  AddKW(kwSemiExpanded,'semi-expanded'); // e.g. font-stretch
+  AddKW(kwSemiCondensed,'semi-condensed'); // e.g. font-width
+  AddKW(kwSemiExpanded,'semi-expanded'); // e.g. font-width
   AddKW(kwSEResize,'se-resize'); // e.g. cursor
   AddKW(kwSmall,'small'); // e.g. font-size
   AddKW(kwSmallCaps,'small-caps'); // e.g. font-variant
@@ -2987,8 +3054,8 @@ begin
   AddKW(kwThin,'thin'); // e.g. border-left-width
   AddKW(kwTo,'to'); // e.g. background-image
   AddKW(kwTop,'top'); // e.g. clear
-  AddKW(kwUltraCondensed,'ultra-condensed'); // e.g. font-stretch
-  AddKW(kwUltraExpanded,'ultra-expanded'); // e.g. font-stretch
+  AddKW(kwUltraCondensed,'ultra-condensed'); // e.g. font-width
+  AddKW(kwUltraExpanded,'ultra-expanded'); // e.g. font-width
   AddKW(kwVerticalText,'vertical-text'); // e.g. cursor
   AddKW(kwVisible,'visible'); // e.g. overflow-x, visible
   AddKW(kwWait,'wait'); // e.g. cursor
@@ -3043,6 +3110,7 @@ begin
   AddFresnelLonghand(fcaZIndex,false,@CheckZIndex,'auto');
   Chk_ZIndex_Dim.AllowNegative:=true;
   Chk_ZIndex_Dim.AllowedKeywordIDs:=[kwAuto];
+  Chk_ZIndex_Dim.AllowedUnits:=[cuNone];
 
   // overflow
   AddFresnelLonghand(fcaOverflowX,false,@CheckOverflowXY,'visible');
@@ -3149,9 +3217,11 @@ begin
   AddFresnelLonghand(fcaFontFeatureSettings,true,@CheckFontFeatureSettings,'normal');
   Chk_FontFeatureSettings_KeywordIDs:=[kwNormal];
   // font-family
-  AddFresnelLonghand(fcaFontFamily,true,@CheckFontFamily);
+  Desc:=AddFresnelLonghand(fcaFontFamily,true,@CheckFontFamily);
+  Desc.OnAsString:=@GetFontFamily;
   // font-kerning
-  AddFresnelLonghand(fcaFontKerning,true,@CheckFontKerning,'auto');
+  Desc:=AddFresnelLonghand(fcaFontKerning,true,@CheckFontKerning,'auto');
+  Desc.OnAsString:=@GetFontKerning;
   Chk_FontKerning_KeywordIDs:=[kwAuto,kwNormal,kwNone];
   // font-size
   Desc:=AddFresnelLonghand(fcaFontSize,true,@CheckFontSize,'medium');
@@ -3160,21 +3230,28 @@ begin
   Chk_FontSize_Dim.AllowFrac:=true;
   Chk_FontSize_Dim.AllowedKeywordIDs:=[kwXXSmall,kwXSmall,kwSmall,kwSmaller,kwMedium,
     kwLarge,kwLarger,kwXLarge,kwXXLarge,kwXXXLarge];
-  // font-stretch
-  AddFresnelLonghand(fcaFontStretch,true,@CheckFontStretch,'normal');
-  Chk_FontStretch_Dim.AllowedUnits:=[cuPercent];
-  Chk_FontStretch_Dim.AllowFrac:=true;
-  Chk_FontStretch_Dim.AllowedKeywordIDs:=[kwNormal,
-    kwCondensed,kwSemiCondensed,kwExtraCondensed,kwUltraCondensed,
-    kwExpanded,kwSemiExpanded,kwExtraExpanded,kwUltraExpanded];
   // font-style
-  AddFresnelLonghand(fcaFontStyle,true,@CheckFontStyle,'normal');
-  Chk_FontStyle_KeywordIDs:=[kwAuto,kwNormal,kwNone];
+  Desc:=AddFresnelLonghand(fcaFontStyle,true,@CheckFontStyle,'normal');
+  Desc.OnAsString:=@GetFontStyle;
+  Chk_FontStyle_KeywordIDs:=[kwNormal,kwItalic,kwOblique];
   // font-weight
-  AddFresnelLonghand(fcaFontWeight,true,@CheckFontWeight,'normal');
-  Chk_FontWeight_Dim.AllowedKeywordIDs:=[kwNone,kwBold,kwBolder,kwLighter];
+  Desc:=AddFresnelLonghand(fcaFontWeight,true,@CheckFontWeight,'normal');
+  Desc.OnAsString:=@GetFontWeight;
+  Chk_FontWeight_Dim.AllowedKeywordIDs:=[kwNormal,kwBold,kwBolder,kwLighter];
+  Chk_FontWeight_Dim.AllowedUnits:=[cuNone];
+  // font-width
+  Desc:=AddFresnelLonghand(fcaFontWidth,true,@CheckFontWidth,'normal');
+  Desc.OnAsString:=@GetFontWidth;
+  Chk_FontWidth_Dim.AllowedUnits:=[cuPercent];
+  Chk_FontWidth_Dim.AllowFrac:=true;
+  Chk_FontWidth_Dim.AllowedKeywordIDs:=[kwNormal,
+    kwCondensed,kwSemiCondensed,kwExtraCondensed,kwUltraCondensed,
+    kwExpanded,kwSemiExpanded,kwExtraExpanded,kwUltraExpanded];
+  // font-stretch
+  AddFresnelShorthand(fcaFontStretch,@CheckFontWidth,@SplitFontStretch,@GetFontWidth,[fcaFontWidth]);
   // font-variant
-  AddFresnelLonghand(fcaFontVariant,true,@CheckFontVariant,'normal');
+  Desc:=AddFresnelLonghand(fcaFontVariant,true,@CheckFontVariant,'normal');
+  Desc.OnAsString:=@GetFontVariant;
   Chk_FontVariant_KeywordIDs:=[kwNormal,kwNone,kwSmallCaps,kwCommonLigatures];
   // line-height
   AddFresnelLonghand(fcaLineHeight,true,@CheckLineHeight,'normal');
@@ -3487,7 +3564,7 @@ function TFresnelFontDesc.Compare(const Desc: TFresnelFontDesc): integer;
 begin
   Result:=CompareText(Family,Desc.Family);
   if Result<>0 then exit;
-  Result:=CompareText(Kerning,Desc.Kerning);
+  Result:=CompareValue(ord(Kerning),ord(Desc.Kerning));
   if Result<>0 then exit;
   Result:=CompareValue(Size,Desc.Size);
   if Result<>0 then exit;
@@ -3496,6 +3573,8 @@ begin
   Result:=CompareText(Variant_,Desc.Variant_);
   if Result<>0 then exit;
   Result:=CompareValue(Weight,Desc.Weight);
+  if Result<>0 then exit;
+  Result:=CompareValue(Width,Desc.Width);
 end;
 
 class function TFresnelFontDesc.CompareDescriptors(const A, B: TFresnelFontDesc
@@ -4547,8 +4626,6 @@ function TFresnelElement.GetComputedLength(Attr: TFresnelCSSAttribute; UseNaNOnF
       fcaWidth,
       fcaBorderLeftWidth,
       fcaBorderRightWidth,
-      fcaBorderTopWidth,
-      fcaBorderBottomWidth,
       fcaMarginLeft,
       fcaMarginRight,
       fcaPaddingLeft,
@@ -5226,21 +5303,23 @@ function TFresnelElement.GetFont: IFresnelFont;
     if aRatio<=0.6 then
       Result:=aParentSize * 0.89
     else if aRatio<=0.75 then
-      Result:=aViewportSize * 0.6
+      Result:=aParentSize * 0.6
     else if aRatio<=0.89 then
-      Result:=aViewportSize * 0.75
+      Result:=aParentSize * 0.75
     else if aRatio<=1.0 then
-      Result:=aViewportSize * 0.89
+      Result:=aParentSize * 0.89
     else if aRatio<=1.2 then
-      Result:=aViewportSize * 1.0
+      Result:=aParentSize * 1.0
     else if aRatio<=1.5 then
-      Result:=aViewportSize * 1.2
+      Result:=aParentSize * 1.2
     else if aRatio<=2 then
-      Result:=aViewportSize * 1.5
+      Result:=aParentSize * 1.5
     else if aRatio<=3 then
-      Result:=aViewportSize * 2.0
+      Result:=aParentSize * 2.0
+    else if aRatio<=4.5 then
+      Result:=aParentSize * 3.0
     else
-      Result:=aViewportSize * 3.0;
+      Result:=aParentSize * 4.5;
   end;
 
   function GetLarger: TFresnelLength;
@@ -5251,23 +5330,23 @@ function TFresnelElement.GetFont: IFresnelFont;
     aViewportSize:=GetViewportFontSize;
     aRatio:=aParentSize / aViewportSize;
     if aRatio>3.0 then
-      Result:=aParentSize * 1.5
+      Result:=aParentSize * 4.5
     else if aRatio>2.0 then
-      Result:=aViewportSize * 3.0
+      Result:=aParentSize * 3.0
     else if aRatio>1.5 then
-      Result:=aViewportSize * 2.0
+      Result:=aParentSize * 2.0
     else if aRatio>1.2 then
-      Result:=aViewportSize * 1.5
+      Result:=aParentSize * 1.5
     else if aRatio>1.0 then
-      Result:=aViewportSize * 1.2
+      Result:=aParentSize * 1.2
     else if aRatio>=0.89 then
-      Result:=aViewportSize * 1.0
+      Result:=aParentSize * 1.0
     else if aRatio>=0.75 then
-      Result:=aViewportSize * 0.89
+      Result:=aParentSize * 0.89
     else if aRatio>=0.6 then
-      Result:=aViewportSize * 0.75
+      Result:=aParentSize * 0.75
     else
-      Result:=aViewportSize * 0.6;
+      Result:=aParentSize * 0.6;
   end;
 
 var
@@ -5279,31 +5358,54 @@ begin
     exit(FFont);
   Include(FStates,fesFontDescValid);
 
-  FFontDesc.Family:=GetComputedString(fcaFontFamily);
-  FFontDesc.Style:=GetComputedString(fcaFontStyle);
-  FFontDesc.Variant_:=GetComputedString(fcaFontVariant);
-  // todo: font stretch and variant
-  FFontDesc.Kerning:=GetComputedString(fcaFontKerning);
+  FFontDesc:=Default(TFresnelFontDesc);
+  s:=GetCSSString(CSSRegistry.FresnelAttrs[fcaFontFamily].Index,false,Complete);
+  FFontDesc.Family:=s;
+  s:=GetCSSString(CSSRegistry.FresnelAttrs[fcaFontStyle].Index,false,Complete);
+  FFontDesc.Style:=s;
+  s:=GetCSSString(CSSRegistry.FresnelAttrs[fcaFontVariant].Index,false,Complete);
+  FFontDesc.Variant_:=s;
+
+  // font-kerning
+  FFontDesc.Kerning:=fckAuto;
+  if Parent<>nil then
+  begin
+    s:=GetCSSString(CSSRegistry.FresnelAttrs[fcaFontKerning].Index,false,Complete);
+    aComp.EndP:=PChar(s);
+    if Resolver.ReadComp(aComp) then
+    begin
+      case aComp.Kind of
+      rvkKeyword:
+        case aComp.KeywordID of
+        CSSRegistry.kwAuto: FFontDesc.Kerning:=fckAuto;
+        CSSRegistry.kwNormal: FFontDesc.Kerning:=fckNormal;
+        CSSRegistry.kwNone: FFontDesc.Kerning:=fckNone;
+        end;
+      end;
+    end;
+  end;
 
+  // font-size
   FFontDesc.Size:=FresnelDefaultFontSize;
-  s:=GetCSSString(CSSRegistry.FresnelAttrs[fcaFontSize].Index,false,Complete);
   if Parent<>nil then
   begin
+    s:=GetCSSString(CSSRegistry.FresnelAttrs[fcaFontSize].Index,false,Complete);
     aComp.EndP:=PChar(s);
     if Resolver.ReadComp(aComp) then
     begin
       case aComp.Kind of
       rvkKeyword:
-        case s of
-        'xx-small': FFontDesc.Size:=GetViewportFontSize*0.6;
-        'x-small': FFontDesc.Size:=GetViewportFontSize*0.75;
-        'smaller': FFontDesc.Size:=GetSmaller;
-        'small': FFontDesc.Size:=GetViewportFontSize*0.89;
-        'medium': FFontDesc.Size:=GetViewportFontSize;
-        'large': FFontDesc.Size:=GetViewportFontSize*1.2;
-        'larger': FFontDesc.Size:=GetLarger;
-        'x-large': FFontDesc.Size:=GetViewportFontSize*2;
-        'xx-large': FFontDesc.Size:=GetViewportFontSize*3;
+        case aComp.KeywordID of
+        CSSRegistry.kwXXSmall: FFontDesc.Size:=GetViewportFontSize*0.6;
+        CSSRegistry.kwXSmall: FFontDesc.Size:=GetViewportFontSize*0.75;
+        CSSRegistry.kwSmaller: FFontDesc.Size:=GetSmaller;
+        CSSRegistry.kwSmall: FFontDesc.Size:=GetViewportFontSize*0.89;
+        CSSRegistry.kwMedium: FFontDesc.Size:=GetViewportFontSize;
+        CSSRegistry.kwLarge: FFontDesc.Size:=GetViewportFontSize*1.2;
+        CSSRegistry.kwLarger: FFontDesc.Size:=GetLarger;
+        CSSRegistry.kwXLarge: FFontDesc.Size:=GetViewportFontSize*2;
+        CSSRegistry.kwXXLarge: FFontDesc.Size:=GetViewportFontSize*3;
+        CSSRegistry.kwXXXLarge: FFontDesc.Size:=GetViewportFontSize*4.5;
         end;
       rvkFloat:
         if aComp.FloatUnit=cu_px then
@@ -5323,29 +5425,72 @@ begin
   if FFontDesc.Size<ViewPort.FontMinSize then
     FFontDesc.Size:=ViewPort.FontMinSize;
 
-  s:=GetComputedString(fcaFontWeight);
-  case s of
-  'normal': FFontDesc.Weight:=FresnelFontWeightNormal;
-  'bold': FFontDesc.Weight:=700;
-  'lighter': FFontDesc.Weight:=300;
-  'bolder': FFontDesc.Weight:=500;
-  else
-    if not CSSStrToFloat(s,FFontDesc.Weight) then
-      FFontDesc.Weight:=FresnelFontWeightNormal;
+  // font-width
+  FFontDesc.Width:=1;
+  if Parent<>nil then
+  begin
+    s:=GetCSSString(CSSRegistry.FresnelAttrs[fcaFontWidth].Index,false,Complete);
+    aComp.EndP:=PChar(s);
+    if Resolver.ReadComp(aComp) then
+    begin
+      case aComp.Kind of
+      rvkKeyword:
+        case aComp.KeywordID of
+        CSSRegistry.kwUltraCondensed: FFontDesc.Width:=0.5;
+        CSSRegistry.kwExtraCondensed: FFontDesc.Width:=0.625;
+        CSSRegistry.kwCondensed: FFontDesc.Width:=0.75;
+        CSSRegistry.kwSemiCondensed: FFontDesc.Width:=0.875;
+        CSSRegistry.kwNormal: FFontDesc.Width:=1;
+        CSSRegistry.kwSemiExpanded: FFontDesc.Width:=1.125;
+        CSSRegistry.kwExpanded: FFontDesc.Width:=1.25;
+        CSSRegistry.kwExtraExpanded: FFontDesc.Width:=1.5;
+        CSSRegistry.kwUltraExpanded: FFontDesc.Width:=2;
+        end;
+      rvkFloat:
+        if (aComp.FloatUnit=cuPercent) and (aComp.Float>=0) then
+          FFontDesc.Width:=aComp.Float/100;
+      end;
+    end;
   end;
 
+  // font-weight
+  FFontDesc.Weight:=FresnelFontWeightNormal;
+  if Parent<>nil then
+  begin
+    s:=GetCSSString(CSSRegistry.FresnelAttrs[fcaFontWeight].Index,false,Complete);
+    aComp.EndP:=PChar(s);
+    if Resolver.ReadComp(aComp) then
+    begin
+      case aComp.Kind of
+      rvkKeyword:
+        case aComp.KeywordID of
+        CSSRegistry.kwNormal: FFontDesc.Weight:=FresnelFontWeightNormal;
+        CSSRegistry.kwBold: FFontDesc.Weight:=700;
+        CSSRegistry.kwLighter: FFontDesc.Weight:=300;
+        CSSRegistry.kwBolder: FFontDesc.Weight:=500;
+        end;
+      rvkFloat:
+        if (aComp.FloatUnit=cuNone) and (aComp.Float>=100) and (aComp.Float<=1000) then
+          FFontDesc.Weight:=aComp.Float;
+      end;
+    end;
+  end;
+
+  // check if changed
   if FFont<>nil then
   begin
     if (FFont.GetFamily=FFontDesc.Family)
+        and (FFont.GetKerning=FFontDesc.Kerning)
+        and (FFont.GetSize=FFontDesc.Size)
         and (FFont.GetStyle=FFontDesc.Style)
         and (FFont.GetVariant=FFontDesc.Variant_)
         and (FFont.GetWeight=FFontDesc.Weight)
-        and (FFont.GetSize=FFontDesc.Size)
-        and (FFont.GetKerning=FFontDesc.Kerning) then
+        and (FFont.GetWidth=FFontDesc.Width) then
       exit(FFont); // still valid
     FFont:=nil;
   end;
 
+  // allocate
   FFont:=ViewPort.AllocateFont(FFontDesc);
   Result:=FFont;
   if FFont<>nil then
@@ -5857,13 +6002,14 @@ begin
   begin
     aValue:=FCSSValues.Values[i];
     if aValue.State<>cavsSource then continue;
-    s:=aValue.Value;
     AttrID:=aValue.AttrID;
     if AttrID>=CSSRegistry.AttributeCount then continue;
     AttrDesc:=CSSRegistry.Attributes[AttrID];
+    s:=aValue.Value;
     {$IFDEF VerboseCSSAttr}
     writeln('TFresnelElement.ComputeCSSValues ',Name,':',ClassName,' i=',i,'/',length(FCSSValues.Values),' ',AttrDesc.Name,': ',s,';');
     {$ENDIF}
+
     aComp.EndP:=PChar(s);
     if not Resolver.ReadComp(aComp) then
     begin

+ 18 - 8
src/skia/fresnel.skiarenderer.pas

@@ -47,7 +47,7 @@ type
     Engine: TFresnelSkiaFontEngine;
     SKTypeFace: ISkTypeface;
     CSSFamily: string;
-    CSSKerning: string;
+    CSSKerning: TFresnelCSSKerning;
     CSSStyle: string;
     CSSVariant_: string;
     CSSWeight: TFresnelLength;
@@ -67,13 +67,15 @@ type
     SKFont: ISkFont;
     SKMetrics: TSkFontMetrics;
     CSSSize: TFresnelLength;
+    CSSWidth: TFresnelLength;
     destructor Destroy; override;
     function GetFamily: string;
-    function GetKerning: string;
+    function GetKerning: TFresnelCSSKerning;
     function GetSize: TFresnelLength;
     function GetStyle: string;
     function GetVariant: string;
     function GetWeight: TFresnelLength;
+    function GetWidth: TFresnelLength;
     function TextSize(const aText: string): TFresnelPoint; virtual;
     function TextSizeMaxWidth(const aText: string; MaxWidth: TFresnelLength
       ): TFresnelPoint; virtual;
@@ -185,6 +187,8 @@ begin
   Result:=CompareFresnelSkiaTypeFace(Font1.TypeFace,Font2.TypeFace);
   if Result<>0 then exit;
   Result:=CompareValue(Font1.CSSSize,Font2.CSSSize);
+  if Result<>0 then exit;
+  Result:=CompareValue(Font1.CSSWidth,Font2.CSSWidth);
 end;
 
 function CompareFresnelSkiaTypeFace(Item1, Item2: Pointer): integer;
@@ -194,7 +198,7 @@ var
 begin
   Result:=CompareText(Face1.CSSFamily,Face2.CSSFamily);
   if Result<>0 then exit;
-  Result:=CompareText(Face1.CSSKerning,Face2.CSSKerning);
+  Result:=CompareValue(ord(Face1.CSSKerning),ord(Face2.CSSKerning));
   if Result<>0 then exit;
   Result:=CompareText(Face1.CSSStyle,Face2.CSSStyle);
   if Result<>0 then exit;
@@ -220,13 +224,13 @@ var
 begin
   Result:=CompareText(Desc^.Family,Face.CSSFamily);
   if Result<>0 then exit;
-  Result:=CompareText(Desc^.Kerning,Face.CSSKerning);
+  Result:=CompareValue(ord(Desc^.Kerning),ord(Face.CSSKerning));
   if Result<>0 then exit;
   Result:=CompareText(Desc^.Style,Face.CSSStyle);
   if Result<>0 then exit;
-  Result:=CompareText(Desc^.Variant_,Face.CSSVariant_);
-  if Result<>0 then exit;
   Result:=CompareValue(Desc^.Weight,Face.CSSWeight);
+  if Result<>0 then exit;
+  Result:=CompareText(Desc^.Variant_,Face.CSSVariant_);
 end;
 
 { TFresnelSkiaTypeFace }
@@ -268,7 +272,7 @@ begin
   Result:=TypeFace.CSSFamily;
 end;
 
-function TFresnelSkiaFont.GetKerning: string;
+function TFresnelSkiaFont.GetKerning: TFresnelCSSKerning;
 begin
   Result:=Typeface.CSSKerning;
 end;
@@ -293,6 +297,11 @@ begin
   Result:=TypeFace.CSSWeight;
 end;
 
+function TFresnelSkiaFont.GetWidth: TFresnelLength;
+begin
+  Result:=CSSWidth;
+end;
+
 function TFresnelSkiaFont.TextSize(const aText: string): TFresnelPoint;
 begin
   Result:=Engine.TextSize(Self,aText);
@@ -424,9 +433,10 @@ begin
   aFont.Engine:=Self;
   aFont._AddRef;
   aFont.CSSSize:=Desc.Size;
+  aFont.CSSWidth:=Desc.Width;
   aFont.TypeFace:=aTypeFace;
   FFonts.Add(aFont);
-  aFont.SKFont := TSkFont.Create(aTypeface.SKTypeFace, Desc.Size, 1);
+  aFont.SKFont := TSkFont.Create(aTypeface.SKTypeFace, Desc.Size, Desc.Width);
   aFont.SKFont.Edging := TSkFontEdging.AntiAlias;
   aFont.SKFont.GetMetrics(aFont.SKMetrics);
 

+ 57 - 7
tests/base/TCFresnelCSS.pas

@@ -29,10 +29,11 @@ type
     Desc: TFresnelFontDesc;
     function GetDescription: String;
     function GetFamily: string;
-    function GetKerning: string;
+    function GetKerning: TFresnelCSSKerning;
     function GetSize: double;
     function GetStyle: string;
     function GetVariant: string;
+    function GetWidth: double;
     function GetWeight: double;
     function TextSize(const aText: string): TFresnelPoint;
     function TextSizeMaxWidth(const aText: string; MaxWidth: TFresnelLength): TFresnelPoint;
@@ -124,6 +125,7 @@ type
 
     procedure Test_FontSize_Percentage;
     procedure Test_FontSize_AsString;
+    procedure Test_Font_AsString;
     procedure Test_Overflow_AsString;
     procedure Test_BorderColor_AsString;
     procedure Test_BorderStyle_AsString;
@@ -296,12 +298,12 @@ begin
   Result:=Desc.Family;
 end;
 
-function TTestFont.GetKerning: string;
+function TTestFont.GetKerning: TFresnelCSSKerning;
 begin
   Result:=Desc.Kerning;
 end;
 
-function TTestFont.GetSize: Double;
+function TTestFont.GetSize: double;
 begin
   Result:=Desc.Size;
 end;
@@ -316,6 +318,11 @@ begin
   Result:=Desc.Variant_;
 end;
 
+function TTestFont.GetWidth: double;
+begin
+  Result:=Desc.Width;
+end;
+
 function TTestFont.GetWeight: double;
 begin
   Result:=Desc.Weight;
@@ -730,8 +737,8 @@ begin
   Div1.Parent:=Body;
 
   Viewport.ApplyCSS;
-  AssertEquals('Body.GetComputedFontSize',Body.Font.GetSize,30);
-  AssertEquals('Div1.GetComputedFontSize',Div1.Font.GetSize,60);
+  AssertEquals('Body.Font.GetSize',Body.Font.GetSize,30);
+  AssertEquals('Div1.Font.GetSize',Div1.Font.GetSize,60);
 end;
 
 procedure TTestFresnelCSS.Test_FontSize_AsString;
@@ -747,8 +754,51 @@ begin
   Body.Parent:=Viewport;
 
   Viewport.ApplyCSS;
-  AssertEquals('Body.GetComputedFontSize',30,Body.Font.GetSize);
-  AssertEquals('Body.GetComputedFontSize','30px',Body.GetComputedString(fcaFontSize));
+  AssertEquals('Body.Font.GetSize',30,Body.Font.GetSize);
+  AssertEquals('Body.GetComputedString(fcaFontSize)','30px',Body.GetComputedString(fcaFontSize));
+end;
+
+procedure TTestFresnelCSS.Test_Font_AsString;
+var
+  Body: TBody;
+begin
+  Viewport.Stylesheet.Text:=LinesToStr([
+    'body {',
+    'font-family:arial;',
+    'font-kerning:normal;',
+    'font-size:12px;',
+    'font-style:italic;',
+    'font-weight:250;',
+    'font-width:condensed;',
+    'font-variant:normal;',
+    '}']);
+  Body:=TBody.Create(Viewport);
+  Body.Name:='Body';
+  Body.Parent:=Viewport;
+
+  Viewport.ApplyCSS;
+
+  AssertEquals('Body.Font.GetFamily','arial',Body.Font.GetFamily);
+  AssertEquals('Body.GetComputedString(fcaFontFamily)','arial',Body.GetComputedString(fcaFontFamily));
+
+  AssertEquals('Body.Font.GetKerning','normal',FresnelCSSKerningNames[Body.Font.GetKerning]);
+  AssertEquals('Body.GetComputedString(fcaFontKerning)','normal',Body.GetComputedString(fcaFontKerning));
+
+  AssertEquals('Body.Font.GetSize',12,Body.Font.GetSize);
+  AssertEquals('Body.GetComputedString(fcaFontSize)','12px',Body.GetComputedString(fcaFontSize));
+
+  AssertEquals('Body.Font.GetStyle','italic',Body.Font.GetStyle);
+  AssertEquals('Body.GetComputedString(fcaFontStyle)','italic',Body.GetComputedString(fcaFontStyle));
+
+  AssertEquals('Body.Font.GetWeight',250,Body.Font.GetWeight);
+  AssertEquals('Body.GetComputedString(fcaFontWeight)','250',Body.GetComputedString(fcaFontWeight));
+
+  AssertEquals('Body.Font.GetWidth',0.75,Body.Font.GetWidth);
+  AssertEquals('Body.GetComputedString(fcaFontWidth)','75%',Body.GetComputedString(fcaFontWidth));
+  AssertEquals('Body.GetComputedString(fcaFontStretch)','75%',Body.GetComputedString(fcaFontStretch));
+
+  AssertEquals('Body.Font.GetVariant','normal',Body.Font.GetVariant);
+  AssertEquals('Body.GetComputedString(fcaFontVariant)','normal',Body.GetComputedString(fcaFontVariant));
 end;
 
 procedure TTestFresnelCSS.Test_Overflow_AsString;

+ 147 - 0
tests/base/TCFresnelFlowLayout.pas

@@ -0,0 +1,147 @@
+unit TCFresnelFlowLayout;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, testregistry, TCFresnelCSS, Fresnel.Controls, Fresnel.DOM;
+
+type
+
+  { TTestFresnelFlowLayout }
+
+  TTestFresnelFlowLayout = class(TCustomTestFresnelCSS)
+  published
+    procedure TestFlowLayout_BodyDiv;
+    procedure TestFlowLayout_SliderRangePoint;
+  end;
+
+
+implementation
+
+{ TTestFresnelFlowLayout }
+
+procedure TTestFresnelFlowLayout.TestFlowLayout_BodyDiv;
+var
+  Body: TBody;
+  Div1: TDiv;
+begin
+  Body:=TBody.Create(Viewport);
+  Body.Name:='Body';
+  Body.Parent:=Viewport;
+
+  Div1:=TDiv.Create(Viewport);
+  Div1.Name:='Div1';
+  Div1.Parent:=Body;
+
+  Viewport.Stylesheet.Text:=LinesToStr([
+  '#Div1 { width: 20px; height: 10px; }'
+  ]);
+
+  Viewport.Draw;
+  AssertEquals('Div1.Rendered',true,Div1.Rendered);
+  AssertEquals('Div1.GetComputedString(fcaWidth)','20px',Div1.GetComputedString(fcaWidth));
+  AssertEquals('Div1.GetComputedString(fcaHeight)','10px',Div1.GetComputedString(fcaHeight));
+  AssertEquals('Div1.GetComputedString(fcaLeft)','0px',Div1.GetComputedString(fcaLeft));
+  AssertEquals('Div1.GetComputedString(fcaTop)','0px',Div1.GetComputedString(fcaTop));
+  AssertEquals('Div1.GetComputedString(fcaRight)','20px',Div1.GetComputedString(fcaRight));
+  AssertEquals('Div1.GetComputedString(fcaBottom)','10px',Div1.GetComputedString(fcaBottom));
+
+  AssertEquals('Div1.GetComputedString(fcaBoxSizing)','content-box',Div1.GetComputedString(fcaBoxSizing));
+  AssertEquals('Div1.GetComputedString(fcaDisplay)','block',Div1.GetComputedString(fcaDisplay));
+  AssertEquals('Div1.GetComputedString(fcaFloat)','none',Div1.GetComputedString(fcaFloat));
+  AssertEquals('Div1.GetComputedString(fcaLineHeight)','normal',Div1.GetComputedString(fcaLineHeight));
+  AssertEquals('Div1.GetComputedString(fcaPosition)','static',Div1.GetComputedString(fcaPosition));
+  AssertEquals('Div1.GetComputedString(fcaZIndex)','auto',Div1.GetComputedString(fcaZIndex));
+
+
+  AssertEquals('Body.GetComputedString(fcaBoxSizing)','content-box',Body.GetComputedString(fcaBoxSizing));
+  AssertEquals('Body.GetComputedString(fcaDisplay)','block',Body.GetComputedString(fcaDisplay));
+  AssertEquals('Body.GetComputedString(fcaFloat)','none',Body.GetComputedString(fcaFloat));
+  AssertEquals('Body.GetComputedString(fcaLineHeight)','normal',Body.GetComputedString(fcaLineHeight));
+  AssertEquals('Body.GetComputedString(fcaPosition)','static',Body.GetComputedString(fcaPosition));
+  AssertEquals('Body.GetComputedString(fcaZIndex)','auto',Body.GetComputedString(fcaZIndex));
+
+  AssertEquals('Body.GetComputedString(fcaLeft)','0px',Body.GetComputedString(fcaLeft));
+  AssertEquals('Body.GetComputedString(fcaTop)','0px',Body.GetComputedString(fcaTop));
+  AssertEquals('Body.GetComputedString(fcaRight)','800px',Body.GetComputedString(fcaRight));
+  AssertEquals('Body.GetComputedString(fcaBottom)','10px',Body.GetComputedString(fcaBottom));
+  AssertEquals('Body.GetComputedString(fcaWidth)','800px',Body.GetComputedString(fcaWidth));
+  AssertEquals('Body.GetComputedString(fcaHeight)','10px',Body.GetComputedString(fcaHeight));
+
+end;
+
+procedure TTestFresnelFlowLayout.TestFlowLayout_SliderRangePoint;
+var
+  Body: TBody;
+  SliderDiv, RangeDiv, PointDiv: TDiv;
+begin
+  Body:=TBody.Create(Viewport);
+  Body.Name:='Body';
+  Body.Parent:=Viewport;
+
+  SliderDiv:=TDiv.Create(Viewport);
+  SliderDiv.Name:='SliderDiv';
+  SliderDiv.Parent:=Body;
+
+  RangeDiv:=TDiv.Create(Viewport);
+  RangeDiv.Name:='RangeDiv';
+  RangeDiv.Parent:=SliderDiv;
+
+  PointDiv:=TDiv.Create(Viewport);
+  PointDiv.Name:='PointDiv';
+  PointDiv.Parent:=SliderDiv;
+
+  Viewport.Stylesheet.Text:=LinesToStr([
+    '#SliderDiv {',
+    '  margin: 7px 0 5px;',
+    '  position: relative;',
+    '  border: 1px solid #5080e0;',
+    '  height: 9px;',
+    '  width: 100%;',
+    '}',
+    '#RangeDiv {',
+    '  display: block;',
+    '  position: absolute;',
+    '  z-index: 1;',
+    '  font-size: .7em;',
+    '  border: 0;',
+    '  top: 0;',
+    '  height: 100%;',
+    '  width: 50%;',
+    '}',
+    '#PointDiv {',
+    '  position: absolute;',
+    '  z-index: 2;',
+    '  width: 15px;',
+    '  height: 15px;',
+    '  border: 1px solid #385590;',
+    '  border-radius: 50%;',
+    '  top: -.3em;',
+    '  margin-left: -.6em;',
+    '  left: 51%;',
+    '}']);
+
+  Viewport.Draw;
+  AssertEquals('SliderDiv.Rendered',true,SliderDiv.Rendered);
+  AssertEquals('SliderDiv.GetComputedString(fcaPosition)','relative',SliderDiv.GetComputedString(fcaPosition));
+  AssertEquals('SliderDiv.RenderedBorderBox.Left',0,SliderDiv.RenderedBorderBox.Left);
+  AssertEquals('SliderDiv.RenderedBorderBox.Top',7,SliderDiv.RenderedBorderBox.Top);
+  AssertEquals('SliderDiv.RenderedBorderBox.Right',802,SliderDiv.RenderedBorderBox.Right);
+  AssertEquals('SliderDiv.RenderedBorderBox.Bottom',18,SliderDiv.RenderedBorderBox.Bottom);
+
+  AssertEquals('RangeDiv.GetComputedString(fcaDisplay)','block',RangeDiv.GetComputedString(fcaDisplay));
+  AssertEquals('RangeDiv.GetComputedString(fcaPosition)','absolute',RangeDiv.GetComputedString(fcaPosition));
+  AssertEquals('RangeDiv.GetComputedString(fcaZIndex)','1',RangeDiv.GetComputedString(fcaZIndex));
+
+  AssertEquals('PointDiv.Rendered',true,PointDiv.Rendered);
+  AssertEquals('PointDiv.GetComputedString(fcaPosition)','absolute',PointDiv.GetComputedString(fcaPosition));
+  AssertEquals('PointDiv.GetComputedString(fcaZIndex)','2',PointDiv.GetComputedString(fcaZIndex));
+
+end;
+
+Initialization
+  RegisterTests([TTestFresnelFlowLayout]);
+end.
+

+ 4 - 0
tests/base/TestFresnelBase.lpi

@@ -74,6 +74,10 @@
         <IsPartOfProject Value="True"/>
         <UnitName Value="TCTextLayout"/>
       </Unit>
+      <Unit>
+        <Filename Value="TCFresnelFlowLayout.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
     </Units>
   </ProjectOptions>
   <CompilerOptions>

+ 2 - 1
tests/base/TestFresnelBase.lpr

@@ -11,7 +11,8 @@ program TestFresnelBase;
 {$mode objfpc}{$H+}
 
 uses
-  Classes, consoletestrunner, TCFresnelCSS, TCFresnelBaseEvents, TCFresnelImages, TCTextLayout;
+  Classes, consoletestrunner, TCFresnelCSS, TCFresnelBaseEvents, TCFresnelImages, TCTextLayout,
+  TCFresnelFlowLayout;
 
 type