Browse Source

dom: using font width constants

mattias 1 year ago
parent
commit
a10e5cb3d8
3 changed files with 115 additions and 45 deletions
  1. 106 40
      src/base/fresnel.dom.pas
  2. 7 4
      tests/base/TCFresnelCSS.pas
  3. 2 1
      tests/base/TCFresnelFlowLayout.pas

+ 106 - 40
src/base/fresnel.dom.pas

@@ -312,7 +312,7 @@ type
   TFresnelElementAttrDesc = class(TCSSAttributeDesc)
   TFresnelElementAttrDesc = class(TCSSAttributeDesc)
   public
   public
     type
     type
-      TComputeEvent = procedure(Desc: TFresnelElementAttrDesc; El: TFresnelElement;
+      TComputeEvent = procedure(El: TFresnelElement;
                                 var Value: string; // returns empty for invalid
                                 var Value: string; // returns empty for invalid
                                 out Complete: boolean) of object;
                                 out Complete: boolean) of object;
       TGetAsStringEvent = function(El: TFresnelElement): string of object;
       TGetAsStringEvent = function(El: TFresnelElement): string of object;
@@ -447,6 +447,7 @@ type
     function GetMarginInline(El: TFresnelElement): string; virtual;
     function GetMarginInline(El: TFresnelElement): string; virtual;
     function GetOverflow(El: TFresnelElement): string; virtual;
     function GetOverflow(El: TFresnelElement): string; virtual;
     function GetPadding(El: TFresnelElement): string; virtual;
     function GetPadding(El: TFresnelElement): string; virtual;
+
   public
   public
     // keywords
     // keywords
     const
     const
@@ -596,7 +597,47 @@ type
       afRepeatingLinearGradient = afConicGradient+1; // repeating-linear-gradient
       afRepeatingLinearGradient = afConicGradient+1; // repeating-linear-gradient
       afRepeatingRadialGradient = afRepeatingLinearGradient+1; // repeating-radial-gradient
       afRepeatingRadialGradient = afRepeatingLinearGradient+1; // repeating-radial-gradient
       afRepeatingConicGradient = afRepeatingRadialGradient+1; // repeating-conic-gradient
       afRepeatingConicGradient = afRepeatingRadialGradient+1; // repeating-conic-gradient
-
+  public
+    // font-width
+    type
+      TFontWidthName = (
+        fntwnUltraCondensed,
+        fntwnExtraCondensed,
+        fntwnCondensed,
+        fntwnSemiCondensed,
+        fntwnNormal,
+        fntwnSemiExpanded,
+        fntwnExpanded,
+        fntwnExtraExpanded,
+        fntwnUltraExpanded
+        );
+      TFontWidthNames = set of TFontWidthName;
+    const
+      FontWidths: array[TFontWidthName] of TFresnelLength = (
+        0.5, // UltraCondensed
+        0.625, // ExtraCondensed
+        0.75, // Condensed
+        0.875, // SemiCondensed
+        1, // Normal
+        1.125, // SemiExpanded
+        1.25, // Expanded
+        1.5, // ExtraExpanded
+        2 // UltraExpanded
+        );
+      FontWidthKeywords: array[TFontWidthName] of TCSSNumericalID = (
+        kwUltraCondensed,
+        kwExtraCondensed,
+        kwCondensed,
+        kwSemiCondensed,
+        kwNormal,
+        kwSemiExpanded,
+        kwExpanded,
+        kwExtraExpanded,
+        kwUltraExpanded
+        );
+
+      function RoundFontWidth(aWidth: TFresnelLength): TFontWidthName; virtual;
+      function RoundFontWidthToKeyword(aWidth: TFresnelLength): TCSSNumericalID; virtual;
   public
   public
     FresnelAttrIDBase: TCSSNumericalID;
     FresnelAttrIDBase: TCSSNumericalID;
     FresnelAttrs: array[TFresnelCSSAttribute] of TFresnelCSSAttrDesc;
     FresnelAttrs: array[TFresnelCSSAttribute] of TFresnelCSSAttrDesc;
@@ -2706,31 +2747,34 @@ function TFresnelCSSRegistry.GetFont(El: TFresnelElement): string;
 var
 var
   aSize, aWeight, aLineHeight: TFresnelLength;
   aSize, aWeight, aLineHeight: TFresnelLength;
   aFamily, aStyle, aVariant: String;
   aFamily, aStyle, aVariant: String;
+  aWidth: TCSSNumericalID;
 begin
 begin
   Result:='';
   Result:='';
 
 
   aSize:=El.Font.GetSize;
   aSize:=El.Font.GetSize;
   aFamily:=El.Font.GetFamily;
   aFamily:=El.Font.GetFamily;
   aStyle:=El.Font.GetStyle;
   aStyle:=El.Font.GetStyle;
-
   aVariant:=El.Font.GetVariant;
   aVariant:=El.Font.GetVariant;
+  aWeight:=El.Font.GetWeight;
+  aLineHeight:=El.GetComputedLength(fcaLineHeight);
+
   case aVariant of
   case aVariant of
   'normal','small-caps': ; // only these are allowed in font shorthand
   'normal','small-caps': ; // only these are allowed in font shorthand
   else aVariant:='';
   else aVariant:='';
   end;
   end;
 
 
-  aWeight:=El.Font.GetWeight;
-  // todo font-width, must be a single keyword
-  aLineHeight:=El.GetComputedLength(fcaLineHeight);
-
   // style, variant and weight must preced size
   // style, variant and weight must preced size
   Add(aStyle,FresnelAttrs[fcaFontStyle].InitialValue);
   Add(aStyle,FresnelAttrs[fcaFontStyle].InitialValue);
   Add(aVariant,FresnelAttrs[fcaFontVariant].InitialValue);
   Add(aVariant,FresnelAttrs[fcaFontVariant].InitialValue);
   Add(FloatToCSSStr(aWeight),'');
   Add(FloatToCSSStr(aWeight),'');
 
 
   // font-size/line-height
   // font-size/line-height
-  Add(FloatToCSSStr(aSize),'');
-  Result+='/'+FloatToCSSStr(aLineHeight);
+  Add(FloatToCSSPx(aSize),'');
+  Result+='/'+FloatToCSSPx(aLineHeight);
+
+  aWidth:=RoundFontWidthToKeyword(El.Font.GetWidth);
+  if aWidth<>kwNormal then
+    Result+=' '+Keywords[aWidth];
 
 
   Add(aFamily,'');
   Add(aFamily,'');
 end;
 end;
@@ -2907,6 +2951,22 @@ begin
   Result:=GetSideLengths(El,fcaPaddingTop);
   Result:=GetSideLengths(El,fcaPaddingTop);
 end;
 end;
 
 
+function TFresnelCSSRegistry.RoundFontWidth(aWidth: TFresnelLength): TFontWidthName;
+var
+  fw: TFontWidthName;
+begin
+  fw:=Low(TFontWidthName);
+  for fw:=Low(TFontWidthName) to Pred(high(TFontWidthName)) do
+    if aWidth<(FontWidths[fw]+FontWidths[Succ(fw)])/2 then
+      exit(fw);
+  Result:=high(TFontWidthName);
+end;
+
+function TFresnelCSSRegistry.RoundFontWidthToKeyword(aWidth: TFresnelLength): TCSSNumericalID;
+begin
+  Result:=FontWidthKeywords[RoundFontWidth(aWidth)];
+end;
+
 constructor TFresnelCSSRegistry.Create;
 constructor TFresnelCSSRegistry.Create;
 begin
 begin
   Attribute_ClassOf:=TFresnelCSSAttrDesc;
   Attribute_ClassOf:=TFresnelCSSAttrDesc;
@@ -4618,7 +4678,7 @@ function TFresnelElement.GetComputedLength(Attr: TFresnelCSSAttribute; UseNaNOnF
 
 
   function GetIsHorizontal: boolean;
   function GetIsHorizontal: boolean;
   begin
   begin
-    case Attr of
+    Result:=Attr in [
       fcaLeft,
       fcaLeft,
       fcaRight,
       fcaRight,
       fcaMinWidth,
       fcaMinWidth,
@@ -4628,13 +4688,14 @@ function TFresnelElement.GetComputedLength(Attr: TFresnelCSSAttribute; UseNaNOnF
       fcaBorderRightWidth,
       fcaBorderRightWidth,
       fcaMarginLeft,
       fcaMarginLeft,
       fcaMarginRight,
       fcaMarginRight,
+      fcaMarginTop, // margin-top, -bottom percentage uses the container width
+      fcaMarginBottom,
       fcaPaddingLeft,
       fcaPaddingLeft,
       fcaPaddingRight,
       fcaPaddingRight,
+      fcaPaddingTop, // padding-top, -bottom percentage uses the container width
+      fcaPaddingBottom,
       fcaBackgroundPositionX,
       fcaBackgroundPositionX,
-      fcaBackgroundSize:
-        exit(true);
-    end;
-    Result:=false;
+      fcaBackgroundSize];
   end;
   end;
 
 
 var
 var
@@ -4766,7 +4827,7 @@ begin
   writeln('TFresnelElement.WriteComputedAttributes ',Title,' ',GetPath,'================');
   writeln('TFresnelElement.WriteComputedAttributes ',Title,' ',GetPath,'================');
   for Attr in TFresnelCSSAttribute do
   for Attr in TFresnelCSSAttribute do
   begin
   begin
-    writeln('TFresnelElement.WriteComputedAttributes ',Attr);
+    //writeln('TFresnelElement.WriteComputedAttributes ',Attr);
     CurValue:=GetComputedString(Attr);
     CurValue:=GetComputedString(Attr);
     DefValue:=GetUnsetCSSString(Attr);
     DefValue:=GetUnsetCSSString(Attr);
     if CurValue<>DefValue then
     if CurValue<>DefValue then
@@ -5436,15 +5497,15 @@ begin
       case aComp.Kind of
       case aComp.Kind of
       rvkKeyword:
       rvkKeyword:
         case aComp.KeywordID of
         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;
+        CSSRegistry.kwUltraCondensed: FFontDesc.Width:=CSSRegistry.FontWidths[fntwnUltraCondensed];
+        CSSRegistry.kwExtraCondensed: FFontDesc.Width:=CSSRegistry.FontWidths[fntwnExtraCondensed];
+        CSSRegistry.kwCondensed: FFontDesc.Width:=CSSRegistry.FontWidths[fntwnCondensed];
+        CSSRegistry.kwSemiCondensed: FFontDesc.Width:=CSSRegistry.FontWidths[fntwnSemiCondensed];
+        CSSRegistry.kwNormal: FFontDesc.Width:=CSSRegistry.FontWidths[fntwnNormal];
+        CSSRegistry.kwSemiExpanded: FFontDesc.Width:=CSSRegistry.FontWidths[fntwnSemiExpanded];
+        CSSRegistry.kwExpanded: FFontDesc.Width:=CSSRegistry.FontWidths[fntwnExpanded];
+        CSSRegistry.kwExtraExpanded: FFontDesc.Width:=CSSRegistry.FontWidths[fntwnExtraExpanded];
+        CSSRegistry.kwUltraExpanded: FFontDesc.Width:=CSSRegistry.FontWidths[fntwnUltraExpanded];
         end;
         end;
       rvkFloat:
       rvkFloat:
         if (aComp.FloatUnit=cuPercent) and (aComp.Float>=0) then
         if (aComp.FloatUnit=cuPercent) and (aComp.Float>=0) then
@@ -5762,17 +5823,21 @@ function TFresnelElement.ComputeAttribute(aDesc: TCSSAttributeDesc; var aValue:
   ): TCSSAttributeValue.TState;
   ): TCSSAttributeValue.TState;
 var
 var
   ElAttrDesc: TFresnelElementAttrDesc;
   ElAttrDesc: TFresnelElementAttrDesc;
+  Complete: boolean;
 begin
 begin
   if aValue='' then exit(cavsInvalid);
   if aValue='' then exit(cavsInvalid);
-
   Result:=cavsComputed;
   Result:=cavsComputed;
-
   if aDesc is TFresnelElementAttrDesc then
   if aDesc is TFresnelElementAttrDesc then
   begin
   begin
     ElAttrDesc:=TFresnelElementAttrDesc(aDesc);
     ElAttrDesc:=TFresnelElementAttrDesc(aDesc);
     if ElAttrDesc.OnCompute<>nil then
     if ElAttrDesc.OnCompute<>nil then
     begin
     begin
-
+      ElAttrDesc.OnCompute(Self,aValue,Complete);
+      if aValue='' then exit(cavsInvalid);
+      if Complete then
+        exit(cavsComputed)
+      else
+        exit(cavsBaseKeywords);
     end;
     end;
   end;
   end;
 end;
 end;
@@ -5987,7 +6052,7 @@ var
   AttrDesc: TCSSAttributeDesc;
   AttrDesc: TCSSAttributeDesc;
   aComp: TCSSResCompValue;
   aComp: TCSSResCompValue;
   s: TCSSString;
   s: TCSSString;
-  UseInherits, Complete: Boolean;
+  Complete, UseInherit: Boolean;
   AttrID: TCSSNumericalID;
   AttrID: TCSSNumericalID;
 begin
 begin
   Exclude(FStates,fesFontDescValid);
   Exclude(FStates,fesFontDescValid);
@@ -5998,12 +6063,13 @@ begin
   // Note: var() and shorthands are already substituted
   // Note: var() and shorthands are already substituted
 
 
   // apply base keywords 'initial', 'inherit', 'unset', ...
   // apply base keywords 'initial', 'inherit', 'unset', ...
-  for i:=length(FCSSValues.Values)-1 downto 0 do
+  for i:=0 to length(FCSSValues.Values)-1 do
   begin
   begin
     aValue:=FCSSValues.Values[i];
     aValue:=FCSSValues.Values[i];
     if aValue.State<>cavsSource then continue;
     if aValue.State<>cavsSource then continue;
     AttrID:=aValue.AttrID;
     AttrID:=aValue.AttrID;
-    if AttrID>=CSSRegistry.AttributeCount then continue;
+    if AttrID>=CSSRegistry.AttributeCount then
+      continue; // custom attributes are not parsed, their values were already copied
     AttrDesc:=CSSRegistry.Attributes[AttrID];
     AttrDesc:=CSSRegistry.Attributes[AttrID];
     s:=aValue.Value;
     s:=aValue.Value;
     {$IFDEF VerboseCSSAttr}
     {$IFDEF VerboseCSSAttr}
@@ -6016,29 +6082,29 @@ begin
       aValue.State:=cavsInvalid;
       aValue.State:=cavsInvalid;
       continue;
       continue;
     end;
     end;
+    aValue.State:=cavsBaseKeywords;
+
     if aComp.Kind<>rvkKeyword then continue;
     if aComp.Kind<>rvkKeyword then continue;
-    UseInherits:=true;
+    UseInherit:=false;
     case aComp.KeywordID of
     case aComp.KeywordID of
     CSSKeywordInitial:
     CSSKeywordInitial:
-      UseInherits:=false;
+      UseInherit:=false;
     CSSKeywordInherit:
     CSSKeywordInherit:
-      UseInherits:=true;
+      UseInherit:=true;
     CSSKeywordUnset,
     CSSKeywordUnset,
     CSSKeywordRevert, CSSKeywordRevertLayer:
     CSSKeywordRevert, CSSKeywordRevertLayer:
-      UseInherits:=AttrDesc.Inherits;
-    else continue;
+      UseInherit:=AttrDesc.Inherits;
+    else
+      continue;
     end;
     end;
-    if UseInherits=AttrDesc.Inherits then
+    if UseInherit=AttrDesc.Inherits then
     begin
     begin
       // unset
       // unset
       aValue.State:=cavsInvalid;
       aValue.State:=cavsInvalid;
-      continue;
-    end else if UseInherits and (Parent<>nil) then begin
+    end else if UseInherit and (Parent<>nil) then begin
       aValue.Value:=Parent.GetCSSString(aValue.AttrID,false,Complete);
       aValue.Value:=Parent.GetCSSString(aValue.AttrID,false,Complete);
-      aValue.State:=cavsBaseKeywords;
     end else begin
     end else begin
       aValue.Value:=AttrDesc.InitialValue;
       aValue.Value:=AttrDesc.InitialValue;
-      aValue.State:=cavsBaseKeywords;
     end;
     end;
   end;
   end;
 
 

+ 7 - 4
tests/base/TCFresnelCSS.pas

@@ -583,7 +583,7 @@ begin
   Body.Name:='Body';
   Body.Name:='Body';
   Body.Parent:=Viewport;
   Body.Parent:=Viewport;
   Viewport.Draw;
   Viewport.Draw;
-  Body.WriteComputedAttributes('Body');
+  //Body.WriteComputedAttributes('Body');
 end;
 end;
 
 
 procedure TTestFresnelCSS.TestGetStyleAttr_OneValue;
 procedure TTestFresnelCSS.TestGetStyleAttr_OneValue;
@@ -764,13 +764,14 @@ var
 begin
 begin
   Viewport.Stylesheet.Text:=LinesToStr([
   Viewport.Stylesheet.Text:=LinesToStr([
     'body {',
     'body {',
-    'font-family:arial;',
+    'font-family:Arial;',
     'font-kerning:normal;',
     'font-kerning:normal;',
     'font-size:12px;',
     'font-size:12px;',
     'font-style:italic;',
     'font-style:italic;',
     'font-weight:250;',
     'font-weight:250;',
     'font-width:condensed;',
     'font-width:condensed;',
     'font-variant:normal;',
     'font-variant:normal;',
+    'line-height:20px;',
     '}']);
     '}']);
   Body:=TBody.Create(Viewport);
   Body:=TBody.Create(Viewport);
   Body.Name:='Body';
   Body.Name:='Body';
@@ -778,8 +779,8 @@ begin
 
 
   Viewport.ApplyCSS;
   Viewport.ApplyCSS;
 
 
-  AssertEquals('Body.Font.GetFamily','arial',Body.Font.GetFamily);
-  AssertEquals('Body.GetComputedString(fcaFontFamily)','arial',Body.GetComputedString(fcaFontFamily));
+  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.Font.GetKerning','normal',FresnelCSSKerningNames[Body.Font.GetKerning]);
   AssertEquals('Body.GetComputedString(fcaFontKerning)','normal',Body.GetComputedString(fcaFontKerning));
   AssertEquals('Body.GetComputedString(fcaFontKerning)','normal',Body.GetComputedString(fcaFontKerning));
@@ -799,6 +800,8 @@ begin
 
 
   AssertEquals('Body.Font.GetVariant','normal',Body.Font.GetVariant);
   AssertEquals('Body.Font.GetVariant','normal',Body.Font.GetVariant);
   AssertEquals('Body.GetComputedString(fcaFontVariant)','normal',Body.GetComputedString(fcaFontVariant));
   AssertEquals('Body.GetComputedString(fcaFontVariant)','normal',Body.GetComputedString(fcaFontVariant));
+
+  AssertEquals('Body.GetComputedString(fcaFont)','italic 250 12px/20px condensed Arial',Body.GetComputedString(fcaFont));
 end;
 end;
 
 
 procedure TTestFresnelCSS.Test_Overflow_AsString;
 procedure TTestFresnelCSS.Test_Overflow_AsString;

+ 2 - 1
tests/base/TCFresnelFlowLayout.pas

@@ -15,6 +15,8 @@ type
   published
   published
     procedure TestFlowLayout_BodyDiv;
     procedure TestFlowLayout_BodyDiv;
     procedure TestFlowLayout_SliderRangePoint;
     procedure TestFlowLayout_SliderRangePoint;
+    // todo: test padding-left,right,top,bottom percentage uses container's width
+    // todo: test margin-left,right,top,bottom percentage uses container's width
   end;
   end;
 
 
 
 
@@ -55,7 +57,6 @@ begin
   AssertEquals('Div1.GetComputedString(fcaPosition)','static',Div1.GetComputedString(fcaPosition));
   AssertEquals('Div1.GetComputedString(fcaPosition)','static',Div1.GetComputedString(fcaPosition));
   AssertEquals('Div1.GetComputedString(fcaZIndex)','auto',Div1.GetComputedString(fcaZIndex));
   AssertEquals('Div1.GetComputedString(fcaZIndex)','auto',Div1.GetComputedString(fcaZIndex));
 
 
-
   AssertEquals('Body.GetComputedString(fcaBoxSizing)','content-box',Body.GetComputedString(fcaBoxSizing));
   AssertEquals('Body.GetComputedString(fcaBoxSizing)','content-box',Body.GetComputedString(fcaBoxSizing));
   AssertEquals('Body.GetComputedString(fcaDisplay)','block',Body.GetComputedString(fcaDisplay));
   AssertEquals('Body.GetComputedString(fcaDisplay)','block',Body.GetComputedString(fcaDisplay));
   AssertEquals('Body.GetComputedString(fcaFloat)','none',Body.GetComputedString(fcaFloat));
   AssertEquals('Body.GetComputedString(fcaFloat)','none',Body.GetComputedString(fcaFloat));