|
@@ -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);
|
|
|
|