Browse Source

dom: started parsing place-content

mattias 11 months ago
parent
commit
8e24676a0e
1 changed files with 584 additions and 10 deletions
  1. 584 10
      src/base/fresnel.dom.pas

+ 584 - 10
src/base/fresnel.dom.pas

@@ -157,6 +157,9 @@ type
     fcaJustifyContent,
     fcaJustifyItems,
     fcaJustifySelf,
+    fcaPlaceContent, // shorthand for [align,justify]-content
+    fcaPlaceItems, // shorthand for [align,justify]-items
+    fcaPlaceSelf, // shorthand for [align,justify]-self
     fcaColumnGap,
     fcaRowGap,
     fcaGap // shorthand for [column,row]-gap
@@ -269,6 +272,9 @@ const
     'justify-content',
     'justify-items',
     'justify-self',
+    'place-content',
+    'place-items',
+    'place-self',
     'column-gap',
     'row-gap',
     'gap'
@@ -434,6 +440,9 @@ type
     function CheckJustifyContent(Resolver: TCSSBaseResolver): boolean; virtual;
     function CheckJustifyItems(Resolver: TCSSBaseResolver): boolean; virtual;
     function CheckJustifySelf(Resolver: TCSSBaseResolver): boolean; virtual;
+    function CheckPlaceContent(Resolver: TCSSBaseResolver): boolean; virtual;
+    function CheckPlaceItems(Resolver: TCSSBaseResolver): boolean; virtual;
+    function CheckPlaceSelf(Resolver: TCSSBaseResolver): boolean; virtual;
     function CheckColumnRowGap(Resolver: TCSSBaseResolver): boolean; virtual;
     function CheckGap(Resolver: TCSSBaseResolver): boolean; virtual;
 
@@ -453,14 +462,22 @@ type
     function ReadAlignContent(Resolver: TCSSBaseResolver; Check: boolean; out MainKW, SubKW: TCSSNumericalID): boolean; virtual;
     function ReadAlignItems(Resolver: TCSSBaseResolver; Check: boolean; out MainKW, SubKW: TCSSNumericalID): boolean; virtual;
     function ReadAlignSelf(Resolver: TCSSBaseResolver; Check: boolean; out MainKW, SubKW: TCSSNumericalID): boolean; virtual;
-    function ReadJustifySelf(Resolver: TCSSBaseResolver; Check: boolean; out MainKW, SubKW: TCSSNumericalID): boolean; virtual;
+    function ReadJustifyContent(Resolver: TCSSBaseResolver; Check: boolean; out MainKW, SubKW: TCSSNumericalID): boolean; virtual;
     function ReadJustifyItems(Resolver: TCSSBaseResolver; Check: boolean; out MainKW, SubKW: TCSSNumericalID): boolean; virtual;
+    function ReadJustifySelf(Resolver: TCSSBaseResolver; Check: boolean; out MainKW, SubKW: TCSSNumericalID): boolean; virtual;
+    function ReadPlaceContent(Resolver: TCSSBaseResolver; Check: boolean;
+      out AlignKW, AlignSubKW, JustifyKW, JustifySubKW: TCSSNumericalID): boolean; virtual;
+    function ReadPlaceItems(Resolver: TCSSBaseResolver; Check: boolean;
+      out AlignKW, AlignSubKW, JustifyKW, JustifySubKW: TCSSNumericalID): boolean; virtual;
+    function ReadPlaceSelf(Resolver: TCSSBaseResolver; Check: boolean;
+      out AlignKW, AlignSubKW, JustifyKW, JustifySubKW: TCSSNumericalID): boolean; virtual;
     function ReadGap(Resolver: TCSSBaseResolver; Check: boolean; out Column, Row: 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);
     procedure SplitLonghandCorners(var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray;
       TopLeft, TopRight, BottomRight, BottomLeft: TFresnelCSSAttribute; const Found: TCSSStringArray);
+    function CombinePlace(SubKW, MainKW: TCSSNumericalID): TCSSString;
 
     // split shorthands
     procedure SplitBackground(Resolver: TCSSBaseResolver; var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray); virtual;
@@ -480,6 +497,9 @@ type
     procedure SplitMarginInline(Resolver: TCSSBaseResolver; var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray); virtual;
     procedure SplitOverflow(Resolver: TCSSBaseResolver; var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray); virtual;
     procedure SplitPadding(Resolver: TCSSBaseResolver; var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray); virtual;
+    procedure SplitPlaceContent(Resolver: TCSSBaseResolver; var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray); virtual;
+    procedure SplitPlaceItems(Resolver: TCSSBaseResolver; var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray); virtual;
+    procedure SplitPlaceSelf(Resolver: TCSSBaseResolver; var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray); virtual;
 
     // get computed attribute as string
     function GetBackground(El: TFresnelElement): string; virtual;
@@ -511,6 +531,9 @@ type
     function GetMarginInline(El: TFresnelElement): string; virtual;
     function GetOverflow(El: TFresnelElement): string; virtual;
     function GetPadding(El: TFresnelElement): string; virtual;
+    function GetPlaceContent(El: TFresnelElement): string; virtual;
+    function GetPlaceItems(El: TFresnelElement): string; virtual;
+    function GetPlaceSelf(El: TFresnelElement): string; virtual;
 
   public
     // keywords
@@ -2079,8 +2102,10 @@ begin
 end;
 
 function TFresnelCSSRegistry.CheckJustifyContent(Resolver: TCSSBaseResolver): boolean;
+var
+  MainKW, SubKW: TCSSNumericalID;
 begin
-  Result:=Resolver.CheckAttribute_Keyword(Chk_JustifyContent_KeywordIDs);
+  Result:=ReadJustifyContent(Resolver,true,MainKW,SubKW);
 end;
 
 function TFresnelCSSRegistry.CheckJustifyItems(Resolver: TCSSBaseResolver): boolean;
@@ -2097,6 +2122,27 @@ begin
   Result:=ReadJustifySelf(Resolver,true,MainKW,SubKW);
 end;
 
+function TFresnelCSSRegistry.CheckPlaceContent(Resolver: TCSSBaseResolver): boolean;
+var
+  AlignKW, AlignSubKW, JustifyKW, JustifySubKW: TCSSNumericalID;
+begin
+  Result:=ReadPlaceContent(Resolver,true,AlignKW, AlignSubKW, JustifyKW, JustifySubKW);
+end;
+
+function TFresnelCSSRegistry.CheckPlaceItems(Resolver: TCSSBaseResolver): boolean;
+var
+  AlignKW, AlignSubKW, JustifyKW, JustifySubKW: TCSSNumericalID;
+begin
+  Result:=ReadPlaceItems(Resolver,true,AlignKW, AlignSubKW, JustifyKW, JustifySubKW);
+end;
+
+function TFresnelCSSRegistry.CheckPlaceSelf(Resolver: TCSSBaseResolver): boolean;
+var
+  AlignKW, AlignSubKW, JustifyKW, JustifySubKW: TCSSNumericalID;
+begin
+  Result:=ReadPlaceSelf(Resolver,true,AlignKW, AlignSubKW, JustifyKW, JustifySubKW);
+end;
+
 function TFresnelCSSRegistry.CheckColumnRowGap(Resolver: TCSSBaseResolver): boolean;
 begin
   Result:=Resolver.CheckAttribute_Dimension(Chk_ColumnRowGap_Dim);
@@ -2493,6 +2539,8 @@ begin
         // todo
         exit;
       end;
+    else
+      exit;
     end;
   until not Resolver.ReadNext;
   if Resolver.CurComp.Kind=rvkInvalid then exit;
@@ -2617,6 +2665,8 @@ begin
         exit(Check)
       else
         exit;
+    else
+      exit;
     end;
   until not Resolver.ReadNext;
   if Resolver.CurComp.Kind=rvkInvalid then exit;
@@ -2791,6 +2841,69 @@ begin
         exit(Check)
       else
         exit;
+    else
+      exit;
+    end;
+  until not Resolver.ReadNext;
+  if Resolver.CurComp.Kind=rvkInvalid then exit;
+
+  Result:=MainKW>0;
+end;
+
+function TFresnelCSSRegistry.ReadJustifyContent(Resolver: TCSSBaseResolver; Check: boolean; out
+  MainKW, SubKW: TCSSNumericalID): boolean;
+var
+  KW: TCSSNumericalID;
+begin
+  Result:=false;
+  MainKW:=0;
+  SubKW:=0;
+  repeat
+    case Resolver.CurComp.Kind of
+    rvkKeyword:
+      begin
+        KW:=Resolver.CurComp.KeywordID;
+        case KW of
+        kwNormal, kwStretch:
+          begin
+            if MainKW>0 then
+              exit;
+            if SubKW>0 then
+              exit;
+            MainKW:=KW;
+          end;
+        kwStart,kwEnd,
+        kwFlexStart,kwFlexEnd,
+        kwCenter,kwLeft,kwRight,
+        kwSpaceAround,kwSpaceBetween,kwSpaceEvenly:
+          begin
+            if MainKW>0 then
+              exit;
+            if (SubKW>0) and not (SubKW in [kwSafe,kwUnsafe]) then
+              exit;
+            MainKW:=KW;
+          end;
+        kwSafe,kwUnsafe:
+          begin
+            if (MainKW>0) and not (MainKW in [kwStart, kwEnd, kwFlexStart, kwFlexEnd,
+                kwCenter,kwLeft,kwRight,
+                kwSpaceAround,kwSpaceBetween,kwSpaceEvenly]) then
+              exit;
+            if SubKW>0 then
+              exit;
+            SubKW:=KW;
+          end;
+        else
+          exit;
+        end;
+      end;
+    rvkFunction:
+      if Resolver.CurComp.FunctionID=afVar then
+        exit(Check)
+      else
+        exit;
+    else
+      exit;
     end;
   until not Resolver.ReadNext;
   if Resolver.CurComp.Kind=rvkInvalid then exit;
@@ -2867,6 +2980,8 @@ begin
         exit(Check)
       else
         exit;
+    else
+      exit;
     end;
   until not Resolver.ReadNext;
   if Resolver.CurComp.Kind=rvkInvalid then exit;
@@ -3022,6 +3137,373 @@ begin
   Result:=true;
 end;
 
+function TFresnelCSSRegistry.ReadPlaceContent(Resolver: TCSSBaseResolver; Check: boolean; out
+  AlignKW, AlignSubKW, JustifyKW, JustifySubKW: TCSSNumericalID): boolean;
+var
+  KW: TCSSNumericalID;
+begin
+  Result:=false;
+  AlignKW:=0;
+  AlignSubKW:=0;
+  JustifyKW:=0;
+  JustifySubKW:=0;
+  repeat
+    case Resolver.CurComp.Kind of
+    rvkKeyword:
+      begin
+        KW:=Resolver.CurComp.KeywordID;
+        case KW of
+        kwNormal, kwStretch:
+          if AlignKW=0 then
+          begin
+            if AlignSubKW>0 then
+              exit;
+            AlignKW:=KW;
+          end else if JustifyKW=0 then
+          begin
+            if JustifySubKW>0 then
+              exit;
+            JustifyKW:=KW;
+          end else
+            exit;
+        kwStart,kwEnd,
+        kwFlexStart,kwFlexEnd,
+        kwCenter,
+        kwSpaceAround,kwSpaceBetween,kwSpaceEvenly:
+          if AlignKW=0 then
+          begin
+            if not (AlignSubKW in [0,kwSafe,kwUnsafe]) then
+              exit;
+            AlignKW:=KW;
+          end else if JustifyKW=0 then
+          begin
+            if not (JustifySubKW in [0,kwSafe,kwUnsafe]) then
+              exit;
+            JustifyKW:=KW;
+          end else
+            exit;
+        kwLeft,kwRight:
+          if JustifyKW=0 then
+          begin
+            if not (JustifySubKW in [0,kwSafe,kwUnsafe]) then
+              exit;
+            JustifyKW:=KW;
+          end else
+            exit;
+        kwSafe,kwUnsafe:
+          if AlignKW=0 then
+          begin
+            if AlignSubKW>0 then
+              exit;
+            AlignSubKW:=KW;
+          end else if JustifyKW=0 then
+          begin
+            if JustifySubKW>0 then
+              exit;
+            JustifySubKW:=KW;
+          end else
+            exit;
+        kwFirst,kwLast:
+          if JustifyKW>0 then
+            exit
+          else if JustifySubKW>0 then
+            exit
+          else
+            JustifySubKW:=KW;
+        kwBaseline:
+          if JustifyKW>0 then
+            exit
+          else if not (JustifySubKW in [0,kwFirst,kwLast]) then
+            exit
+          else
+            JustifyKW:=KW;
+        else
+          exit;
+        end;
+      end;
+    rvkFunction:
+      if Resolver.CurComp.FunctionID=afVar then
+        exit(Check)
+      else
+        exit;
+    else
+      exit;
+    end;
+  until not Resolver.ReadNext;
+  if Resolver.CurComp.Kind=rvkInvalid then exit;
+
+  if AlignKW=0 then
+  begin
+    if AlignSubKW>0 then
+      exit;
+    case JustifyKW of
+    kwLeft: AlignKW:=kwStart;
+    kwRight: AlignKW:=kwEnd;
+    kwBaseline:
+      if JustifySubKW=kwLast then
+        AlignKW:=kwEnd
+      else
+        AlignKW:=kwStart;
+    else
+      exit;
+    end;
+  end;
+  if JustifyKW=0 then
+  begin
+    if JustifySubKW>0 then
+      exit;
+    JustifyKW:=AlignKW;
+    JustifySubKW:=AlignSubKW;
+  end;
+
+  Result:=true;
+end;
+
+function TFresnelCSSRegistry.ReadPlaceItems(Resolver: TCSSBaseResolver; Check: boolean; out
+  AlignKW, AlignSubKW, JustifyKW, JustifySubKW: TCSSNumericalID): boolean;
+var
+  KW: TCSSNumericalID;
+begin
+  Result:=false;
+  AlignKW:=0;
+  AlignSubKW:=0;
+  JustifyKW:=0;
+  JustifySubKW:=0;
+  repeat
+    case Resolver.CurComp.Kind of
+    rvkKeyword:
+      begin
+        KW:=Resolver.CurComp.KeywordID;
+        case KW of
+        kwNormal, kwStretch, kwAnchorCenter:
+          if AlignKW=0 then
+          begin
+            if AlignSubKW>0 then
+              exit;
+            AlignKW:=KW;
+          end else if JustifyKW=0 then
+          begin
+            if JustifySubKW>0 then
+              exit;
+            JustifyKW:=KW;
+          end else
+            exit;
+        kwStart,kwEnd,
+        kwFlexStart,kwFlexEnd,
+        kwCenter,
+        kwSpaceAround,kwSpaceBetween,kwSpaceEvenly:
+          if AlignKW=0 then
+          begin
+            if not (AlignSubKW in [0,kwSafe,kwUnsafe]) then
+              exit;
+            AlignKW:=KW;
+          end else if JustifyKW=0 then
+          begin
+            if not (JustifySubKW in [0,kwSafe,kwUnsafe]) then
+              exit;
+            JustifyKW:=KW;
+          end else
+            exit;
+        kwLeft,kwRight,kwLegacy:
+          if JustifyKW=0 then
+          begin
+            if not (JustifySubKW in [0,kwSafe,kwUnsafe]) then
+              exit;
+            JustifyKW:=KW;
+          end else
+            exit;
+        kwSafe,kwUnsafe:
+          if AlignKW=0 then
+          begin
+            if AlignSubKW>0 then
+              exit;
+            AlignSubKW:=KW;
+          end else if JustifyKW=0 then
+          begin
+            if JustifySubKW>0 then
+              exit;
+            JustifySubKW:=KW;
+          end else
+            exit;
+        kwFirst,kwLast:
+          if JustifyKW>0 then
+            exit
+          else if JustifySubKW>0 then
+            exit
+          else
+            JustifySubKW:=KW;
+        kwBaseline:
+          if JustifyKW>0 then
+            exit
+          else if not (JustifySubKW in [0,kwFirst,kwLast]) then
+            exit
+          else
+            JustifyKW:=KW;
+        else
+          exit;
+        end;
+      end;
+    rvkFunction:
+      if Resolver.CurComp.FunctionID=afVar then
+        exit(Check)
+      else
+        exit;
+    else
+      exit;
+    end;
+  until not Resolver.ReadNext;
+  if Resolver.CurComp.Kind=rvkInvalid then exit;
+
+  if AlignKW=0 then
+  begin
+    if AlignSubKW>0 then
+      exit;
+    case JustifyKW of
+    kwLeft: AlignKW:=kwStart;
+    kwRight: AlignKW:=kwEnd;
+    kwBaseline:
+      if JustifySubKW=kwLast then
+        AlignKW:=kwEnd
+      else
+        AlignKW:=kwStart;
+    else
+      exit;
+    end;
+  end;
+  if JustifyKW=0 then
+  begin
+    if JustifySubKW>0 then
+      exit;
+    JustifyKW:=AlignKW;
+    JustifySubKW:=AlignSubKW;
+  end;
+
+  Result:=true;
+end;
+
+function TFresnelCSSRegistry.ReadPlaceSelf(Resolver: TCSSBaseResolver; Check: boolean; out AlignKW,
+  AlignSubKW, JustifyKW, JustifySubKW: TCSSNumericalID): boolean;
+var
+  KW: TCSSNumericalID;
+begin
+  Result:=false;
+  AlignKW:=0;
+  AlignSubKW:=0;
+  JustifyKW:=0;
+  JustifySubKW:=0;
+  repeat
+    case Resolver.CurComp.Kind of
+    rvkKeyword:
+      begin
+        KW:=Resolver.CurComp.KeywordID;
+        case KW of
+        kwAuto, kwNormal, kwStretch, kwAnchorCenter:
+          if AlignKW=0 then
+          begin
+            if AlignSubKW>0 then
+              exit;
+            AlignKW:=KW;
+          end else if JustifyKW=0 then
+          begin
+            if JustifySubKW>0 then
+              exit;
+            JustifyKW:=KW;
+          end else
+            exit;
+        kwStart,kwEnd,
+        kwFlexStart,kwFlexEnd,
+        kwSelfStart,kwSelfEnd,
+        kwCenter,
+        kwSpaceAround,kwSpaceBetween,kwSpaceEvenly:
+          if AlignKW=0 then
+          begin
+            if not (AlignSubKW in [0,kwSafe,kwUnsafe]) then
+              exit;
+            AlignKW:=KW;
+          end else if JustifyKW=0 then
+          begin
+            if not (JustifySubKW in [0,kwSafe,kwUnsafe]) then
+              exit;
+            JustifyKW:=KW;
+          end else
+            exit;
+        kwLeft,kwRight:
+          if JustifyKW=0 then
+          begin
+            if not (JustifySubKW in [0,kwSafe,kwUnsafe]) then
+              exit;
+            JustifyKW:=KW;
+          end else
+            exit;
+        kwSafe,kwUnsafe:
+          if AlignKW=0 then
+          begin
+            if AlignSubKW>0 then
+              exit;
+            AlignSubKW:=KW;
+          end else if JustifyKW=0 then
+          begin
+            if JustifySubKW>0 then
+              exit;
+            JustifySubKW:=KW;
+          end else
+            exit;
+        kwFirst,kwLast:
+          if JustifyKW>0 then
+            exit
+          else if JustifySubKW>0 then
+            exit
+          else
+            JustifySubKW:=KW;
+        kwBaseline:
+          if JustifyKW>0 then
+            exit
+          else if not (JustifySubKW in [0,kwFirst,kwLast]) then
+            exit
+          else
+            JustifyKW:=KW;
+        else
+          exit;
+        end;
+      end;
+    rvkFunction:
+      if Resolver.CurComp.FunctionID=afVar then
+        exit(Check)
+      else
+        exit;
+    else
+      exit;
+    end;
+  until not Resolver.ReadNext;
+  if Resolver.CurComp.Kind=rvkInvalid then exit;
+
+  if AlignKW=0 then
+  begin
+    if AlignSubKW>0 then
+      exit;
+    case JustifyKW of
+    kwLeft: AlignKW:=kwStart;
+    kwRight: AlignKW:=kwEnd;
+    kwBaseline:
+      if JustifySubKW=kwLast then
+        AlignKW:=kwEnd
+      else
+        AlignKW:=kwStart;
+    else
+      exit;
+    end;
+  end;
+  if JustifyKW=0 then
+  begin
+    if JustifySubKW>0 then
+      exit;
+    JustifyKW:=AlignKW;
+    JustifySubKW:=AlignSubKW;
+  end;
+
+  Result:=true;
+end;
+
 procedure TFresnelCSSRegistry.SplitOverflow(Resolver: TCSSBaseResolver;
   var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray);
 var
@@ -3458,6 +3940,48 @@ begin
     fcaPaddingTop,fcaPaddingRight,fcaPaddingBottom,fcaPaddingLeft,Found);
 end;
 
+procedure TFresnelCSSRegistry.SplitPlaceContent(Resolver: TCSSBaseResolver;
+  var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray);
+var
+  AlignKW, AlignSubKW, JustifyKW, JustifySubKW: TCSSNumericalID;
+begin
+  if not ReadPlaceContent(Resolver,false,AlignKW, AlignSubKW, JustifyKW, JustifySubKW) then exit;
+  SetLength(AttrIDs,2);
+  AttrIDs[0]:=FresnelAttrs[fcaAlignContent].Index;
+  AttrIDs[1]:=FresnelAttrs[fcaJustifyContent].Index;
+  SetLength(Values,2);
+  Values[0]:=CombinePlace(AlignSubKW,AlignKW);
+  Values[1]:=CombinePlace(JustifySubKW,JustifyKW);
+end;
+
+procedure TFresnelCSSRegistry.SplitPlaceItems(Resolver: TCSSBaseResolver;
+  var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray);
+var
+  AlignKW, AlignSubKW, JustifyKW, JustifySubKW: TCSSNumericalID;
+begin
+  if not ReadPlaceItems(Resolver,false,AlignKW, AlignSubKW, JustifyKW, JustifySubKW) then exit;
+  SetLength(AttrIDs,2);
+  AttrIDs[0]:=FresnelAttrs[fcaAlignItems].Index;
+  AttrIDs[1]:=FresnelAttrs[fcaJustifyItems].Index;
+  SetLength(Values,2);
+  Values[0]:=CombinePlace(AlignSubKW,AlignKW);
+  Values[1]:=CombinePlace(JustifySubKW,JustifyKW);
+end;
+
+procedure TFresnelCSSRegistry.SplitPlaceSelf(Resolver: TCSSBaseResolver;
+  var AttrIDs: TCSSNumericalIDArray; var Values: TCSSStringArray);
+var
+  AlignKW, AlignSubKW, JustifyKW, JustifySubKW: TCSSNumericalID;
+begin
+  if not ReadPlaceSelf(Resolver,false,AlignKW, AlignSubKW, JustifyKW, JustifySubKW) then exit;
+  SetLength(AttrIDs,2);
+  AttrIDs[0]:=FresnelAttrs[fcaAlignSelf].Index;
+  AttrIDs[1]:=FresnelAttrs[fcaJustifySelf].Index;
+  SetLength(Values,2);
+  Values[0]:=CombinePlace(AlignSubKW,AlignKW);
+  Values[1]:=CombinePlace(JustifySubKW,JustifyKW);
+end;
+
 function TFresnelCSSRegistry.GetBackground(El: TFresnelElement): string;
 begin
   Result:='';
@@ -3814,6 +4338,33 @@ begin
   Result:=GetSideLengths(El,fcaPaddingTop);
 end;
 
+function TFresnelCSSRegistry.GetPlaceContent(El: TFresnelElement): string;
+var
+  anAlign, aJustify: String;
+begin
+  anAlign:=El.GetComputedString(fcaAlignContent);
+  aJustify:=El.GetComputedString(fcaJustifyContent);
+  Result:=anAlign+' '+aJustify;
+end;
+
+function TFresnelCSSRegistry.GetPlaceItems(El: TFresnelElement): string;
+var
+  anAlign, aJustify: String;
+begin
+  anAlign:=El.GetComputedString(fcaAlignItems);
+  aJustify:=El.GetComputedString(fcaJustifyItems);
+  Result:=anAlign+' '+aJustify;
+end;
+
+function TFresnelCSSRegistry.GetPlaceSelf(El: TFresnelElement): string;
+var
+  anAlign, aJustify: String;
+begin
+  anAlign:=El.GetComputedString(fcaAlignSelf);
+  aJustify:=El.GetComputedString(fcaJustifySelf);
+  Result:=anAlign+' '+aJustify;
+end;
+
 function TFresnelCSSRegistry.RoundFontWidth(aWidth: TFresnelLength): TFontWidthName;
 var
   fw: TFontWidthName;
@@ -4375,18 +4926,33 @@ begin
 
   // justify-content
   AddFresnelLonghand(fcaJustifyContent,false,@CheckJustifyContent,'normal');
-  Chk_JustifyContent_KeywordIDs:=[kwNormal,kwStart,kwEnd,kwFlexStart,kwFlexEnd,kwCenter,kwLeft,kwRight,
-    kwSpaceBetween,kwSpaceAround,kwSpaceEvenly,kwStretch,kwSafe,kwUnsafe];
+  Chk_JustifyContent_KeywordIDs:=[kwNormal,kwStretch,
+    kwStart,kwEnd,kwFlexStart,kwFlexEnd,kwCenter,kwLeft,kwRight,
+    kwSpaceBetween,kwSpaceAround,kwSpaceEvenly,
+    kwSafe,kwUnsafe];
   // justify-items
   AddFresnelLonghand(fcaJustifyItems,false,@CheckJustifyItems,'legacy');
-  Chk_JustifyItems_KeywordIDs:=[kwLegacy,kwNormal,kwStart,kwEnd,kwFlexStart,kwFlexEnd,
-    kwSelfStart,kwSelfEnd,kwCenter,kwLeft,kwRight,kwBaseline,kwFirst,kwLast,kwStretch,
-    kwAnchorCenter,kwSafe,kwUnsafe];
+  Chk_JustifyItems_KeywordIDs:=[kwLegacy,kwNormal,kwStretch,kwAnchorCenter,
+    kwStart,kwEnd,kwFlexStart,kwFlexEnd,kwSelfStart,kwSelfEnd,
+    kwCenter,kwLeft,kwRight,
+    kwSafe,kwUnsafe,
+    kwBaseline,kwFirst,kwLast];
   // justify-self
   AddFresnelLonghand(fcaJustifySelf,false,@CheckJustifySelf,'auto');
-  Chk_JustifySelf_KeywordIDs:=[kwAuto,kwNormal,kwStart,kwEnd,kwFlexStart,kwFlexEnd,
-    kwSelfStart,kwSelfEnd,kwCenter,kwLeft,kwRight,kwBaseline,kwFirst,kwLast,kwStretch,
-    kwAnchorCenter,kwSafe,kwUnsafe];
+  Chk_JustifySelf_KeywordIDs:=[kwAuto,kwNormal,kwStretch,kwAnchorCenter,
+    kwStart,kwEnd,kwFlexStart,kwFlexEnd,kwSelfStart,kwSelfEnd,
+    kwCenter,kwLeft,kwRight,
+    kwSafe,kwUnsafe,
+    kwBaseline,kwFirst,kwLast];
+
+  // place-content
+  AddFresnelShorthand(fcaPlaceContent,@CheckPlaceContent,@SplitPlaceContent,@GetPlaceContent,
+    [fcaAlignContent,fcaJustifyContent]);
+  AddFresnelShorthand(fcaPlaceItems,@CheckPlaceItems,@SplitPlaceItems,@GetPlaceItems,
+    [fcaAlignItems,fcaJustifyItems]);
+  AddFresnelShorthand(fcaPlaceSelf,@CheckPlaceSelf,@SplitPlaceSelf,@GetPlaceSelf,
+    [fcaAlignSelf,fcaJustifySelf]);
+
 
   // column-gap
   AddFresnelLonghand(fcaColumnGap,false,@CheckColumnRowGap,'normal');
@@ -4468,6 +5034,14 @@ begin
     Found);
 end;
 
+function TFresnelCSSRegistry.CombinePlace(SubKW, MainKW: TCSSNumericalID): TCSSString;
+begin
+  if SubKW>0 then
+    Result:=Keywords[SubKW]+' '+Keywords[MainKW]
+  else
+    Result:=Keywords[MainKW];
+end;
+
 function TFresnelCSSRegistry.AddFresnelPseudoClass(Pseudo: TFresnelCSSPseudoClass
   ): TFresnelCSSPseudoClassDesc;
 begin