Browse Source

added TPseudoElement

mattias 6 tháng trước cách đây
mục cha
commit
6de309643b
2 tập tin đã thay đổi với 162 bổ sung7 xóa
  1. 1 1
      src/base/fcl-css/fpcssresparser.pas
  2. 161 6
      src/base/fresnel.dom.pas

+ 1 - 1
src/base/fcl-css/fpcssresparser.pas

@@ -358,7 +358,7 @@ type
 
   TCSSPseudoElementDesc = class(TCSSRegistryNamedItem)
   public
-    Attributes: array of TCSSAttributeDesc; // allowed attributes
+    Attributes: TCSSAttributeDescArray; // allowed attributes
     IsFunction: boolean;
   end;
   TCSSPseudoElementDescClass = class of TCSSPseudoElementDesc;

+ 161 - 6
src/base/fresnel.dom.pas

@@ -843,6 +843,9 @@ type
       ): TFresnelCSSAttrDesc; virtual; overload;
     // register pseudo classes
     function AddFresnelPseudoClass(Pseudo: TFresnelCSSPseudoClass): TFresnelCSSPseudoClassDesc; virtual; overload;
+    // register pseudo element
+    function AddFresnelPseudoElement(const aName: TCSSString;
+      const AllowedAttribs: TFresnelCSSAttributeArray): TCSSPseudoElementDesc; virtual; overload;
   end;
 
   TFresnelLayoutMode = (
@@ -1011,6 +1014,8 @@ type
     Colors: TColorPercentageArray;
   end;
 
+  TPseudoElement = class;
+
   { TFresnelElement }
 
   TFresnelElement = class(TFresnelComponent, ICSSNode, IFPObserver, IFresnelRenderable)
@@ -1020,7 +1025,8 @@ type
         fesFontDescValid,
         fesHover, // mouse is over this element
         fesStyleChanged, // StyleElement needs update
-        fesViewportConnected // true if this element or any child is using a resource (e.g. Font) of Viewport
+        fesViewportConnected, // true if this element or any child is using a resource (e.g. Font) of Viewport
+        fesPseudoElement
       );
       TStates = set of TState;
   private
@@ -1044,6 +1050,8 @@ type
     FUsedContentBox: TFresnelRect;
     function GetNodeCount: integer;
     function GetNodes(Index: integer): TFresnelElement;
+    function GetPeudoNodeCount: integer;
+    function GetPseudoNodes(Index: integer): TPseudoElement;
     function GetViewportConnected: boolean;
     function GetEventHandler(AIndex: Integer): TFresnelEventHandler;
     function GetFocusEventHandler(AIndex: Integer): TFresnelFocusEventHandler;
@@ -1053,6 +1061,7 @@ type
     procedure SetMouseEventHandler(AIndex: Integer; const AValue: TFresnelMouseEventHandler);
   protected
     FChildren: TFPList; // list of TFresnelElement
+    FPseudoChildren: TFPList; // list of TPseudoElement
     FCSSClasses: TStrings;
     FCSSValues: TCSSAttributeValues;
     FComputedDisplayInside: TCSSNumericalID;
@@ -1111,6 +1120,8 @@ type
     property Parent: TFresnelElement read FParent write SetParent;
     property NodeCount: integer read GetNodeCount;
     property Nodes[Index: integer]: TFresnelElement read GetNodes; default;
+    property PseudoNodeCount: integer read GetPeudoNodeCount;
+    property PseudoNodes[Index: integer]: TPseudoElement read GetPseudoNodes;
     // CSS
     class function CSSTypeID: TCSSNumericalID; virtual; abstract;
     class function CSSTypeName: TCSSString; virtual; abstract;
@@ -1239,6 +1250,35 @@ type
   TFresnelElementClass = class of TFresnelElement;
   TFresnelElementArray = array of TFresnelElement;
 
+  { TPseudoElement }
+
+  TPseudoElement = class(TFresnelElement)
+  public
+    constructor Create(AOwner: TComponent); override;
+    { ICSSNode }
+    // CSS identifier implementation of ICSSNode
+    function GetCSSID: TCSSString; override;
+    function GetCSSTypeName: TCSSString; override;
+    function GetCSSTypeID: TCSSNumericalID; override;
+    // CSS parent implementation of ICSSNode
+    function GetCSSIndex: integer; override;
+    // CSS siblings implementation of ICSSNode
+    function GetCSSNextSibling: ICSSNode; override;
+    function GetCSSPreviousSibling: ICSSNode; override;
+    function GetCSSNextOfType: ICSSNode; override;
+    function GetCSSPreviousOfType: ICSSNode; override;
+  end;
+
+  { TPseudoElSelection }
+
+  TPseudoElSelection = class(TPseudoElement)
+  private
+    class var FFresnelSelectionTypeID: TCSSNumericalID;
+  public
+    function GetCSSPseudoElementID: TCSSNumericalID; override;
+    function GetCSSPseudoElementName: TCSSString; override;
+  end;
+
   { TReplacedElement - base class for elements with special content and no child elements, e.g. label, video }
 
   TReplacedElement = class(TFresnelElement)
@@ -4602,6 +4642,7 @@ procedure TFresnelCSSRegistry.Init;
 var
   Desc: TFresnelCSSAttrDesc;
   PseudoCl: TFresnelCSSPseudoClass;
+  PseElDesc: TCSSPseudoElementDesc;
 begin
   inherited Init;
 
@@ -5158,6 +5199,10 @@ begin
   // pseudo classes - - - - - - - - - - - - - - - - - - - - - -
   for PseudoCl in TFresnelCSSPseudoClass do
     AddFresnelPseudoClass(PseudoCl);
+
+  // pseudo elements - - - - - - - - - - - - - - - - - - - - - -
+  PseElDesc:=AddFresnelPseudoElement('selection',[fcaColor,fcaBackgroundColor,fcaTextShadow]);
+  TPseudoElSelection.FFresnelSelectionTypeID:=PseElDesc.Index;
 end;
 
 function TFresnelCSSRegistry.AddFresnelAttr(Attr: TFresnelCSSAttribute;
@@ -5252,6 +5297,17 @@ begin
   FresnelPseudoClasses[Pseudo]:=Result;
 end;
 
+function TFresnelCSSRegistry.AddFresnelPseudoElement(const aName: TCSSString;
+  const AllowedAttribs: TFresnelCSSAttributeArray): TCSSPseudoElementDesc;
+var
+  i: Integer;
+begin
+  Result:=AddPseudoElement(aName);
+  SetLength(Result.Attributes,length(AllowedAttribs));
+  for i:=0 to length(AllowedAttribs)-1 do
+    Result.Attributes[i]:=FresnelAttrs[AllowedAttribs[i]];
+end;
+
 function TFresnelCSSRegistry.IsColor(const ResValue: TCSSResCompValue): boolean;
 var
   KW: TCSSNumericalID;
@@ -5650,6 +5706,7 @@ procedure TFresnelViewport.ApplyCSS;
   procedure TraverseCSS(El: TFresnelElement);
   var
     i: Integer;
+    PE: TPseudoElement;
   begin
     //writeln('Traverse ',El.ClassName,' CSSTypeName=',El.CSSTypeName);
     if El<>Self then
@@ -5662,13 +5719,19 @@ procedure TFresnelViewport.ApplyCSS;
 
     for i:=0 to El.NodeCount-1 do
       TraverseCSS(El.Nodes[i]);
+    for i:=0 to El.PseudoNodeCount-1 do
+    begin
+      PE:=El.PseudoNodes[i];
+      PE.FResolver:=Resolver;
+      PE.FViewPort:=Self;
+    end;
   end;
 
 begin
   //writeln('TFresnelViewport.ApplyCSS ',Name,' Width=',FloatToCSSStr(Width),',Height=',FloatToCSSStr(Height));
   DomModified:=false;
   if NodeCount>1 then
-    CSSWarning(20221018152912,'TFresnelViewport.ApplyCSS NodeCount='+IntToStr(NodeCount));
+    CSSWarning(20221018152912,'TFresnelViewport.ApplyCSS more than 1 root element: NodeCount='+IntToStr(NodeCount));
   ClearCSSValues;
   InitResolver;
   //writeln('TFresnelViewport.ApplyCSS ',StylesheetElements.ClassName);
@@ -6202,6 +6265,8 @@ begin
     FFont:=nil;
     for i:=0 to NodeCount-1 do
       Nodes[i].ViewportConnected:=false;
+    for i:=0 to PseudoNodeCount-1 do
+      PseudoNodes[i].ViewportConnected:=false;
   end;
 end;
 
@@ -6225,6 +6290,16 @@ begin
   Result:=TFresnelElement(FChildren[Index]);
 end;
 
+function TFresnelElement.GetPeudoNodeCount: integer;
+begin
+  Result:=FPseudoChildren.Count;
+end;
+
+function TFresnelElement.GetPseudoNodes(Index: integer): TPseudoElement;
+begin
+  Result:=TPseudoElement(FPseudoChildren[Index]);
+end;
+
 procedure TFresnelElement.SetParent(const AValue: TFresnelElement);
 begin
   if FParent=AValue then Exit;
@@ -6236,17 +6311,25 @@ begin
     ViewportConnected:=false;
     FResolver:=nil;
     FViewPort:=nil;
-    Parent.FChildren.Remove(Self);
-    Parent.DomChanged;
+    if fesPseudoElement in FStates then
+      Parent.FPseudoChildren.Remove(Self)
+    else begin
+      Parent.FChildren.Remove(Self);
+      Parent.DomChanged;
+    end;
   end;
   FParent:=AValue;
   if FParent<>nil then
   begin
-    Parent.FChildren.Add(Self);
+    if fesPseudoElement in FStates then
+      Parent.FPseudoChildren.Add(Self)
+    else
+      Parent.FChildren.Add(Self);
     FreeNotification(FParent);
     FResolver:=Parent.Resolver;
     FViewPort:=Parent.FViewPort;
-    Parent.DomChanged;
+    if fesPseudoElement in FStates then
+      Parent.DomChanged;
   end;
 end;
 
@@ -6280,6 +6363,8 @@ begin
       FParent:=nil;
     if FChildren<>nil then
       FChildren.Remove(AComponent);
+    if FPseudoChildren<>nil then
+      FPseudoChildren.Remove(AComponent);
   end;
 end;
 
@@ -7756,6 +7841,7 @@ constructor TFresnelElement.Create(AOwner: TComponent);
 begin
   inherited Create(AOwner);
   FChildren:=TFPList.Create;
+  FPseudoChildren:=TFPList.Create;
   FCSSClasses:=TStringList.Create;
   FCSSClasses.Delimiter:=' ';
   FCSSClasses.FPOAttachObserver(Self);
@@ -7763,9 +7849,14 @@ begin
 end;
 
 destructor TFresnelElement.Destroy;
+var
+  i: Integer;
 begin
   Clear;
+  for i:=PseudoNodeCount-1 downto 0 do
+    PseudoNodes[i].Parent:=nil;
   FreeAndNil(FLayoutNode);
+  FreeAndNil(FPseudoChildren);
   FreeAndNil(FChildren);
   FreeAndNil(FCSSValues);
   FreeAndNil(FCSSClasses);
@@ -7786,6 +7877,7 @@ begin
   for i:=NodeCount-1 downto 0 do
     Nodes[i].Parent:=nil;
   FChildren.Clear;
+  // keep pseudo elements
 end;
 
 function TFresnelElement.GetRoot: TFresnelElement;
@@ -7997,6 +8089,8 @@ begin
   FreeAndNil(FCSSValues);
   for i:=0 to NodeCount-1 do
     Nodes[i].ClearCSSValues;
+  for i:=0 to PseudoNodeCount-1 do
+    PseudoNodes[i].ClearCSSValues;
 end;
 
 function TFresnelElement.HasCSSExplicitAttribute(const AttrID: TCSSNumericalID
@@ -8273,6 +8367,66 @@ begin
   if Layouter<>nil then ;
 end;
 
+{ TPseudoElement }
+
+constructor TPseudoElement.Create(AOwner: TComponent);
+begin
+  Include(FStates,fesPseudoElement);
+  inherited Create(AOwner);
+end;
+
+function TPseudoElement.GetCSSID: TCSSString;
+begin
+  Result:='';
+end;
+
+function TPseudoElement.GetCSSTypeName: TCSSString;
+begin
+  Result:='';
+end;
+
+function TPseudoElement.GetCSSTypeID: TCSSNumericalID;
+begin
+  Result:=CSSIDNone;
+end;
+
+function TPseudoElement.GetCSSIndex: integer;
+begin
+  Result:=-1;
+end;
+
+function TPseudoElement.GetCSSNextSibling: ICSSNode;
+begin
+  Result:=nil;
+end;
+
+function TPseudoElement.GetCSSPreviousSibling: ICSSNode;
+begin
+  Result:=nil;
+end;
+
+function TPseudoElement.GetCSSNextOfType: ICSSNode;
+begin
+  Result:=nil;
+end;
+
+function TPseudoElement.GetCSSPreviousOfType: ICSSNode;
+begin
+  Result:=nil;
+end;
+
+{ TPseudoElSelection }
+
+function TPseudoElSelection.GetCSSPseudoElementID: TCSSNumericalID;
+begin
+  Result:=FFresnelSelectionTypeID;
+end;
+
+function TPseudoElSelection.GetCSSPseudoElementName: TCSSString;
+begin
+  Result:='selection';
+end;
+
 { TReplacedElement }
 
 function TReplacedElement.AcceptChildrenAtDesignTime: boolean;
@@ -8283,6 +8437,7 @@ end;
 initialization
   CSSRegistry:=TFresnelCSSRegistry.Create;
   CSSRegistry.Init;
+
 finalization
   FreeAndNil(CSSRegistry);