|
@@ -11,14 +11,14 @@ ToDo:
|
|
|
- speed up GetCSSDepth
|
|
|
- speed up GetCSSNextOfType
|
|
|
- speed up GetCSSPreviousOfType
|
|
|
-- invalid CSS values must be skipped, so validity check must be done during css resolver
|
|
|
- e.g. negative border-left-width is ignored
|
|
|
--
|
|
|
+
|
|
|
}
|
|
|
unit FresnelDOM;
|
|
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
|
+{$IF FPC_FULLVERSION>30300}
|
|
|
{$WARN 6060 off} // Case statement does not handle all possible cases
|
|
|
+{$ENDIF}
|
|
|
|
|
|
interface
|
|
|
|
|
@@ -283,7 +283,7 @@ type
|
|
|
|
|
|
{ TFresnelElement }
|
|
|
|
|
|
- TFresnelElement = class(TComponent, ICSSNode)
|
|
|
+ TFresnelElement = class(TComponent, ICSSNode, IFPObserver)
|
|
|
private
|
|
|
function GetCSSPseudo(Pseudo: TFresnelCSSPseudo): string;
|
|
|
function GetNodeCount: integer;
|
|
@@ -390,6 +390,8 @@ type
|
|
|
function GetRoot: TFresnelElement;
|
|
|
function GetPath: string; virtual;
|
|
|
function AcceptChildrenAtDesignTime: boolean; virtual;
|
|
|
+ procedure FPOObservedChanged(ASender: TObject; Operation: TFPObservedOperation; Data: Pointer); virtual;
|
|
|
+ procedure DomChanged; virtual;
|
|
|
property Parent: TFresnelElement read FParent write SetParent;
|
|
|
property NodeCount: integer read GetNodeCount;
|
|
|
property Nodes[Index: integer]: TFresnelElement read GetNodes; default;
|
|
@@ -450,10 +452,8 @@ type
|
|
|
procedure UpdateRenderedAttributes; virtual;
|
|
|
function GetRenderedCSSLength(Attr: TFresnelCSSAttribute; UseInherited: boolean; UseNaNOnFail: boolean = false): TFresnelLength; virtual; // on fail returns NaN
|
|
|
function GetRenderedCSString(Attr: TFresnelCSSAttribute; UseInherited: boolean): string; virtual;
|
|
|
- //function GetRenderedContentBox: TFresnelRect; virtual;
|
|
|
- //function GetRenderedBorderBox: TFresnelRect; virtual;
|
|
|
- property RenderedBorderBox: TFresnelRect read FRenderedBorderBox write FRenderedBorderBox;
|
|
|
property Rendered: boolean read FRendered write FRendered;
|
|
|
+ property RenderedBorderBox: TFresnelRect read FRenderedBorderBox write FRenderedBorderBox; // relative to layout parent
|
|
|
property CSSRenderedAttribute[Attr: TFresnelCSSAttribute]: string read GetCSSRenderedAttribute write SetCSSRenderedAttribute;
|
|
|
// font
|
|
|
property Font: IFresnelFont read GetFont write FFont;
|
|
@@ -487,6 +487,7 @@ type
|
|
|
FCSSResolver: TCSSResolver;
|
|
|
FFontEngine: TFresnelFontEngine;
|
|
|
FLayouter: TFresnelLayouter;
|
|
|
+ FOnDomChanged: TNotifyEvent;
|
|
|
FStylesheetElements: TCSSElement;
|
|
|
FStylesheet: TStrings;
|
|
|
FDPI: array[boolean] of TFresnelLength;
|
|
@@ -525,7 +526,9 @@ type
|
|
|
destructor Destroy; override;
|
|
|
procedure ApplyCSS; virtual;
|
|
|
procedure ClearCSSValues; override;
|
|
|
+ procedure DomChanged; override;
|
|
|
function AllocateFont(const Desc: TFresnelFontDesc): IFresnelFont; virtual;
|
|
|
+ function GetElementAt(const x, y: TFresnelLength): TFresnelElement; virtual;
|
|
|
property DPI[IsHorizontal: boolean]: TFresnelLength read GetDPI write SetDPI;
|
|
|
property FontMinSize: TFresnelLength read FFontMinSize write SetFontMinSize;
|
|
|
property ScrollbarWidth[IsHorizontal: boolean]: TFresnelLength read GetScrollbarWidth write SetScrollbarWidth;
|
|
@@ -538,6 +541,12 @@ type
|
|
|
property MaxPreferredWidth: TFresnelLength read GetMaxPreferredWidth write SetMaxPreferredWidth;
|
|
|
property Layouter: TFresnelLayouter read FLayouter write FLayouter;
|
|
|
property FontEngine: TFresnelFontEngine read FFontEngine write FFontEngine;
|
|
|
+ property OnDomChanged: TNotifyEvent read FOnDomChanged write FOnDomChanged;
|
|
|
+ end;
|
|
|
+
|
|
|
+ IFresnelStreamRoot = interface
|
|
|
+ ['{A53F44CF-3BFB-42F6-A711-8C555E835E7F}']
|
|
|
+ function GetViewport: TFresnelViewport;
|
|
|
end;
|
|
|
|
|
|
const
|
|
@@ -916,6 +925,12 @@ begin
|
|
|
FCSSComputed[fcaFontSize]:='12';
|
|
|
end;
|
|
|
|
|
|
+procedure TFresnelViewport.DomChanged;
|
|
|
+begin
|
|
|
+ if assigned(OnDomChanged) then
|
|
|
+ OnDomChanged(Self);
|
|
|
+end;
|
|
|
+
|
|
|
function TFresnelViewport.AllocateFont(const Desc: TFresnelFontDesc
|
|
|
): IFresnelFont;
|
|
|
begin
|
|
@@ -925,6 +940,41 @@ begin
|
|
|
raise EFresnelFont.Create('TFresnelViewport.AllocateFont no FontEngine');
|
|
|
end;
|
|
|
|
|
|
+function TFresnelViewport.GetElementAt(const x, y: TFresnelLength
|
|
|
+ ): TFresnelElement;
|
|
|
+
|
|
|
+ function Check(Node: TFresnelLayoutNode; const dx, dy: TFresnelLength): TFresnelElement;
|
|
|
+ var
|
|
|
+ El: TFresnelElement;
|
|
|
+ i: Integer;
|
|
|
+ aLeft, aTop: TFresnelLength;
|
|
|
+ BorderBox: TFresnelRect;
|
|
|
+ begin
|
|
|
+ Result:=nil;
|
|
|
+ if Node=nil then exit;
|
|
|
+ El:=Node.Element;
|
|
|
+ if not El.Rendered then exit;
|
|
|
+ if Node.NodeCount>0 then begin
|
|
|
+ aLeft:=El.GetRenderedCSSLength(fcaLeft,false);
|
|
|
+ aTop:=El.GetRenderedCSSLength(fcaTop,false);
|
|
|
+ for i:=Node.NodeCount-1 downto 0 do
|
|
|
+ begin
|
|
|
+ Result:=Check(Node.Nodes[i],dx+aLeft,dy+aTop);
|
|
|
+ if Result<>nil then exit;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ BorderBox:=El.RenderedBorderBox;
|
|
|
+ if (x>=BorderBox.Left+dx) and (y>=BorderBox.Top+dy)
|
|
|
+ and (x<=BorderBox.Right+dx) and (y<=BorderBox.Right+dy) then
|
|
|
+ Result:=El
|
|
|
+ else
|
|
|
+ Result:=nil;
|
|
|
+ end;
|
|
|
+
|
|
|
+begin
|
|
|
+ Result:=Check(LayoutNode,0,0);
|
|
|
+end;
|
|
|
+
|
|
|
constructor TFresnelViewport.Create(AOwner: TComponent);
|
|
|
begin
|
|
|
inherited Create(AOwner);
|
|
@@ -986,6 +1036,7 @@ begin
|
|
|
FCSSClasses.Assign(AValue);
|
|
|
FCSSClasses.Delimiter:=' ';
|
|
|
end;
|
|
|
+ DomChanged;
|
|
|
end;
|
|
|
|
|
|
function TFresnelElement.GetCSSPseudo(
|
|
@@ -1869,12 +1920,14 @@ begin
|
|
|
if FParent<>nil then
|
|
|
begin
|
|
|
FParent.FChildren.Remove(Self);
|
|
|
+ FParent.DomChanged;
|
|
|
end;
|
|
|
FParent:=AValue;
|
|
|
if FParent<>nil then
|
|
|
begin
|
|
|
FParent.FChildren.Add(Self);
|
|
|
FreeNotification(FParent);
|
|
|
+ FParent.DomChanged;
|
|
|
end;
|
|
|
end;
|
|
|
|
|
@@ -1894,6 +1947,7 @@ begin
|
|
|
finally
|
|
|
aParser.Free;
|
|
|
end;
|
|
|
+ DomChanged;
|
|
|
end;
|
|
|
|
|
|
procedure TFresnelElement.SetStyleElements(const AValue: TCSSElement);
|
|
@@ -1901,6 +1955,7 @@ begin
|
|
|
if FStyleElements=AValue then Exit;
|
|
|
FreeAndNil(FStyleElements);
|
|
|
FStyleElements:=AValue;
|
|
|
+ DomChanged;
|
|
|
end;
|
|
|
|
|
|
class function TFresnelElement.RegisterCSSType(const aName: string
|
|
@@ -2391,15 +2446,29 @@ begin
|
|
|
Result:=FFont;
|
|
|
end;
|
|
|
|
|
|
+procedure TFresnelElement.DomChanged;
|
|
|
+begin
|
|
|
+ if FParent<>nil then
|
|
|
+ FParent.DomChanged;
|
|
|
+end;
|
|
|
+
|
|
|
function TFresnelElement.HasParent: Boolean;
|
|
|
begin
|
|
|
Result:=Parent<>nil;
|
|
|
end;
|
|
|
|
|
|
procedure TFresnelElement.SetParentComponent(Value: TComponent);
|
|
|
+var
|
|
|
+ aStreamRoot: IFresnelStreamRoot;
|
|
|
begin
|
|
|
+ debugln(['TFresnelElement.SetParentComponent Self=',DbgSName(Self),' NewParent=',DbgSName(Value)]);
|
|
|
if Value is TFresnelElement then
|
|
|
Parent:=TFresnelElement(Value)
|
|
|
+ else if Supports(Value,IFresnelStreamRoot,aStreamRoot) then
|
|
|
+ begin
|
|
|
+ debugln(['TFresnelElement.SetParentComponent Self=',DbgSName(Self),' redirecting to viewport']);
|
|
|
+ Parent:=aStreamRoot.GetViewport;
|
|
|
+ end
|
|
|
else
|
|
|
raise EFresnel.Create('TFresnelElement.SetParentComponent Self='+DbgSName(Self)+' NewParentComponent='+DbgSName(Value));
|
|
|
end;
|
|
@@ -2429,11 +2498,13 @@ begin
|
|
|
FChildren:=TFPList.Create;
|
|
|
FCSSClasses:=TStringList.Create;
|
|
|
FCSSClasses.Delimiter:=' ';
|
|
|
+ FCSSClasses.FPOAttachObserver(Self);
|
|
|
end;
|
|
|
|
|
|
destructor TFresnelElement.Destroy;
|
|
|
begin
|
|
|
Clear;
|
|
|
+ FCSSClasses.FPOAttachObserver(Self);
|
|
|
FreeAndNil(FLayoutNode);
|
|
|
FreeAndNil(FChildren);
|
|
|
FreeAndNil(FCSSClasses);
|
|
@@ -2474,6 +2545,13 @@ begin
|
|
|
Result:=true;
|
|
|
end;
|
|
|
|
|
|
+procedure TFresnelElement.FPOObservedChanged(ASender: TObject;
|
|
|
+ Operation: TFPObservedOperation; Data: Pointer);
|
|
|
+begin
|
|
|
+ if ASender=FCSSClasses then
|
|
|
+ DomChanged;
|
|
|
+end;
|
|
|
+
|
|
|
class constructor TFresnelElement.InitFresnelElementClass;
|
|
|
var
|
|
|
Kind: TCSSNumericalIDKind;
|