Browse Source

TFresnelElement: added ViewportConnected to free resources on disconnect

mattias 1 year ago
parent
commit
380926481e
1 changed files with 52 additions and 21 deletions
  1. 52 21
      src/base/fresnel.dom.pas

+ 52 - 21
src/base/fresnel.dom.pas

@@ -390,18 +390,25 @@ type
   { TFresnelElement }
 
   TFresnelElement = class(TFresnelComponent, ICSSNode, IFPObserver, IFresnelRenderable)
+  private
+    type
+      TState = (
+        fesFontDescValid,
+        fesHover, // mouse is over this element
+        fesViewportConnected // true if this element or any child is using a resource (e.g. Font) of Viewport
+      );
+      TStates = set of TState;
   private
     FAfterRender: TNotifyEvent;
     FBeforeRender: TNotifyEvent;
     FDOMIndex: integer;
     FFont: IFresnelFont;
-    FHover: boolean;
     FLayoutNode: TFresnelLayoutNode;
     FFontDesc: TFresnelFontDesc;
-    FFontDescValid: boolean;
     FRendered: boolean;
     FRenderedBorderBox: TFresnelRect;
     FRenderedContentBox: TFresnelRect;
+    FStates: TStates;
     // Todo: change to dictionary to reduce mem footprint
     FStandardEvents : Array[0..evtLastEvent] of TEventHandlerItem;
     FEventDispatcher : TFresnelEventDispatcher;
@@ -409,6 +416,7 @@ type
     function GetNodes(Index: integer): TFresnelElement;
     function GetCSSElAttribute(Attr: TFresnelCSSAttribute): string;
     function GetCSSElComputedAttribute(Attr: TFresnelCSSAttribute): string;
+    function GetViewportConnected: boolean;
     procedure SetCSSElComputedAttribute(Attr: TFresnelCSSAttribute; AValue: string);
     function GetCSSRenderedAttribute(Attr: TFresnelCSSAttribute): string;
     procedure SetCSSRenderedAttribute(Attr: TFresnelCSSAttribute; const AValue: string
@@ -419,7 +427,7 @@ type
     procedure SetEventHandler(AIndex: Integer; const AValue: TFresnelEventHandler);
     procedure SetFocusEventHandler(AIndex: Integer; AValue: TFresnelFocusEventHandler);
     procedure SetMouseEventHandler(AIndex: Integer; const AValue: TFresnelMouseEventHandler);
- class var
+  class var
     // Stuff for registering CSS numerical IDs
     FCSSNumericalIDs: array[TCSSNumericalIDKind] of TCSSNumericalIDs;
     FCSSIDToName: array[TCSSNumericalIDKind] of TCSSStringDynArray;
@@ -513,6 +521,7 @@ type
     procedure ComputeCSSAttribute(Attr: TFresnelCSSAttribute); virtual;
     function GetDPI(IsHorizontal: boolean): TFresnelLength; virtual;
     function GetViewport: TFresnelViewport; virtual;
+    procedure SetViewportConnected(AValue: boolean); virtual;
     function ElementAttrToAttrId(Attr: TFresnelCSSAttribute): TCSSNumericalID;
     function GetFont: IFresnelFont; virtual;
     procedure FPOObservedChanged(ASender: TObject; Operation: TFPObservedOperation; Data: Pointer); virtual;
@@ -525,7 +534,6 @@ type
     procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
     procedure SetParentComponent(Value: TComponent); override;
     procedure ChildDestroying(El: TFresnelElement); virtual;
-    procedure ViewportDisconnecting(aViewport: TFresnelViewport); virtual;
     procedure DoRender({%H-}aRenderer: IFresnelRenderer); virtual;
     { IFResnelRenderable }
     Procedure BeforeRender;
@@ -620,6 +628,7 @@ type
     property EventDispatcher : TFresnelEventDispatcher Read FEventDispatcher;
     // font
     property Font: IFresnelFont read GetFont write FFont;
+    property ViewportConnected: boolean read GetViewportConnected write SetViewportConnected; // true for example if using a Font of Viewport
   published
     property CSSClasses: TStrings read FCSSClasses write SetCSSClasses;
     property Style: string read FStyle write SetStyle;
@@ -1388,7 +1397,7 @@ end;
 
 procedure TFresnelViewport.Disconnecting;
 begin
-  ViewportDisconnecting(Self);
+  ViewportConnected:=false;
 end;
 
 function TFresnelViewport.AllocateFont(const Desc: TFresnelFontDesc
@@ -1543,7 +1552,7 @@ function TFresnelElement.GetCSSPseudoClass(Pseudo: TFresnelCSSPseudoClass
 begin
   Result:=false;
   case Pseudo of
-    fcpcHover: Result:=FHover;
+    fcpcHover: Result:=fesHover in FStates;
   end;
 end;
 
@@ -1553,8 +1562,11 @@ begin
   case Pseudo of
     fcpcHover:
       begin
-        if FHover=AValue then exit;
-        FHover:=AValue;
+        if fesHover in FStates=AValue then exit;
+        if AValue then
+          Include(FStates,fesHover)
+        else
+          Exclude(FStates,fesHover);
       end;
   end;
   DomChanged;
@@ -1571,6 +1583,11 @@ begin
   Result:=FCSSComputed[Attr];
 end;
 
+function TFresnelElement.GetViewportConnected: boolean;
+begin
+  Result:=fesViewportConnected in FStates;
+end;
+
 procedure TFresnelElement.SetCSSElComputedAttribute(Attr: TFresnelCSSAttribute;
   AValue: string);
 begin
@@ -1601,7 +1618,6 @@ begin
   Result:=nil;
   if AIndex in evtAllMouse then
     Result:=TFresnelFOcusEventHandler(GetEventHandler(AIndex));
-
 end;
 
 function TFresnelElement.GetMouseEventHandler(AIndex: Integer
@@ -1634,6 +1650,27 @@ begin
     SetEventHandler(AIndex,TFresnelEventHandler(AValue));
 end;
 
+procedure TFresnelElement.SetViewportConnected(AValue: boolean);
+var
+  i: Integer;
+begin
+  if AValue then
+  begin
+    if fesViewportConnected in FStates then exit;
+    // a resource is used -> mark this and all parents
+    Include(FStates,fesViewportConnected);
+    if Parent<>nil then
+      Parent.ViewportConnected:=true;
+  end else begin
+    if not (fesViewportConnected in FStates) then exit;
+    // viewport disconnected -> free resources of this and all children
+    Exclude(FStates,fesViewportConnected);
+    FFont:=nil;
+    for i:=0 to NodeCount-1 do
+      Nodes[i].ViewportConnected:=false;
+  end;
+end;
+
 procedure TFresnelElement.SetCSSClasses(const AValue: TStrings);
 begin
   if FCSSClasses=AValue then Exit;
@@ -2957,6 +2994,7 @@ begin
 
   if FParent<>nil then
   begin
+    ViewportConnected:=false;
     FParent.FChildren.Remove(Self);
     FParent.DomChanged;
   end;
@@ -3821,9 +3859,9 @@ var
   ViewPort: TFresnelViewport;
   s: String;
 begin
-  if FFontDescValid then
+  if fesFontDescValid in FStates then
     exit(FFont);
-  FFontDescValid:=true;
+  Include(FStates,fesFontDescValid);
   FFontDesc.Family:=GetComputedCSSString(fcaFontFamily,true);
   FFontDesc.Style:=GetComputedCSSString(fcaFontStyle,true);
   FFontDesc.Variant_:=GetComputedCSSString(fcaFontVariant,true);
@@ -3871,6 +3909,8 @@ begin
   ViewPort:=GetViewport;
   FFont:=ViewPort.AllocateFont(FFontDesc);
   Result:=FFont;
+  if FFont<>nil then
+    ViewportConnected:=true;
 end;
 
 procedure TFresnelElement.DomChanged;
@@ -3912,15 +3952,6 @@ begin
     FParent.ChildDestroying(El);
 end;
 
-procedure TFresnelElement.ViewportDisconnecting(aViewport: TFresnelViewport);
-var
-  i: Integer;
-begin
-  for i:=0 to NodeCount-1 do
-    Nodes[i].ViewportDisconnecting(aViewport);
-  FFont:=nil;
-end;
-
 procedure TFresnelElement.DoRender(aRenderer: IFresnelRenderer);
 begin
   //
@@ -4605,7 +4636,7 @@ var
   Attr: TFresnelCSSAttribute;
 begin
   // lengths can depend on font-size, so compute it first
-  FFontDescValid:=false;
+  Exclude(FStates,fesFontDescValid);
   ComputeCSSAttribute(fcaFontFamily);
   ComputeCSSAttribute(fcaFontSize);
   ComputeCSSAttribute(fcaFontStyle);