|
@@ -20,26 +20,81 @@ unit Fresnel.DOM;
|
|
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
|
{$WARN 6060 off} // Case statement does not handle all possible cases
|
|
|
+{$ModeSwitch AdvancedRecords}
|
|
|
|
|
|
interface
|
|
|
|
|
|
uses
|
|
|
- Classes, SysUtils, Math, FPImage, sortbase,
|
|
|
+ Classes, SysUtils, Math, Types, FPImage, sortbase,
|
|
|
fpCSSResolver, fpCSSTree, fpCSSParser, fcl.events, fresnel.events,
|
|
|
LazLoggerBase;
|
|
|
|
|
|
type
|
|
|
- TFresnelLength = double;
|
|
|
- TFresnelPoint = record
|
|
|
- X, Y: TFresnelLength;
|
|
|
- end;
|
|
|
- TFresnelRect = record
|
|
|
- Left, Top, Right, Bottom: TFresnelLength;
|
|
|
- end;
|
|
|
+ { EFresnel }
|
|
|
|
|
|
EFresnel = class(Exception)
|
|
|
end;
|
|
|
|
|
|
+ TFresnelLength = double;
|
|
|
+ TArray4FresnelLength = array[0..3] of TFresnelLength;
|
|
|
+
|
|
|
+ { TFresnelPoint }
|
|
|
+
|
|
|
+ TFresnelPoint = packed record
|
|
|
+ X, Y: TFresnelLength;
|
|
|
+ class function PointInCircle(const aPoint, aCenter: TFresnelPoint; const aRadius: TFresnelLength): Boolean; static; inline;
|
|
|
+ class function Zero: TFresnelPoint; static; inline;
|
|
|
+ class operator + (const p1, p2: TFresnelPoint): TFresnelPoint;
|
|
|
+ class operator - (const p1, p2: TFresnelPoint): TFresnelPoint;
|
|
|
+ class operator <> (const p1, p2: TFresnelPoint): Boolean;
|
|
|
+ class operator = (const p1, p2: TFresnelPoint): Boolean;
|
|
|
+ function Add(const p: TFresnelPoint): TFresnelPoint;
|
|
|
+ function Angle(const p: TFresnelPoint): TFresnelLength;
|
|
|
+ function Distance(const p: TFresnelPoint): TFresnelLength;
|
|
|
+ function IsZero: Boolean;
|
|
|
+ function Subtract(const p: TFresnelPoint): TFresnelPoint;
|
|
|
+ procedure Offset(const dx,dy: TFresnelLength);
|
|
|
+ procedure Offset(const p: TFresnelPoint);
|
|
|
+ procedure SetLocation(const ax, ay: TFresnelLength);
|
|
|
+ procedure SetLocation(const p: TFresnelPoint);
|
|
|
+ end;
|
|
|
+
|
|
|
+ { TFresnelRect }
|
|
|
+
|
|
|
+ TFresnelRect = packed record
|
|
|
+ procedure Clear;
|
|
|
+ constructor Create(const ALeft, ATop, ARight, ABottom: TFresnelLength);
|
|
|
+ class operator = (const L, R: TFresnelRect): Boolean;
|
|
|
+ class operator <> (const L, R: TFresnelRect): Boolean;
|
|
|
+ class operator + (const L, R: TFresnelRect): TFresnelRect; // union
|
|
|
+ class operator * (const L, R: TFresnelRect): TFresnelRect; // intersection
|
|
|
+ class function Empty: TFresnelRect; static;
|
|
|
+ procedure NormalizeRect;
|
|
|
+ function IsEmpty: Boolean;
|
|
|
+ function Contains(const P: TFresnelPoint): Boolean;
|
|
|
+ function Contains(const R: TFresnelRect): Boolean;
|
|
|
+ function Contains(const ax, ay: TFresnelLength): Boolean;
|
|
|
+ function IntersectsWith(const R: TFresnelRect): Boolean;
|
|
|
+ class function Intersect(const R1, R2: TFresnelRect): TFresnelRect; static;
|
|
|
+ procedure Intersect(const R: TFresnelRect);
|
|
|
+ class function Union(const R1, R2: TFresnelRect): TFresnelRect; static;
|
|
|
+ procedure Union(const R: TFresnelRect);
|
|
|
+ class function Union(const Points: array of TFresnelPoint): TFresnelRect; static;
|
|
|
+ procedure Offset(const DX, DY: TFresnelLength);
|
|
|
+ procedure Offset(const DP: TFresnelPoint);
|
|
|
+ procedure SetLocation(const X, Y: TFresnelLength);
|
|
|
+ procedure SetLocation(const P: TFresnelPoint);
|
|
|
+ procedure Inflate(const DX, DY: TFresnelLength);
|
|
|
+ procedure Inflate(const DL, DT, DR, DB: TFresnelLength);
|
|
|
+ function CenterPoint: TFresnelPoint;
|
|
|
+ public
|
|
|
+ case Longint of
|
|
|
+ 0: (Left, Top, Right, Bottom: TFresnelLength);
|
|
|
+ 1: (TopLeft, BottomRight: TFresnelPoint);
|
|
|
+ 2: (Vector: TArray4FresnelLength);
|
|
|
+ end;
|
|
|
+
|
|
|
+ { EFresnelFont }
|
|
|
|
|
|
EFresnelFont = class(EFresnel)
|
|
|
end;
|
|
@@ -303,6 +358,7 @@ type
|
|
|
FFontDescValid: boolean;
|
|
|
FRendered: boolean;
|
|
|
FRenderedBorderBox: TFresnelRect;
|
|
|
+ FRenderedContentBox: TFresnelRect;
|
|
|
// Todo: change to dictionary to reduce mem footprint
|
|
|
FStandardEvents : Array[0..MaxFresnelEvents] of TEventHandlerItem;
|
|
|
FEventDispatcher : TFresnelEventDispatcher;
|
|
@@ -462,6 +518,7 @@ type
|
|
|
function GetRenderedCSString(Attr: TFresnelCSSAttribute; UseInherited: boolean): string; virtual;
|
|
|
property Rendered: boolean read FRendered write FRendered;
|
|
|
property RenderedBorderBox: TFresnelRect read FRenderedBorderBox write FRenderedBorderBox; // relative to layout parent
|
|
|
+ property RenderedContentBox: TFresnelRect read FRenderedContentBox write FRenderedContentBox; // relative to layout parent
|
|
|
property CSSRenderedAttribute[Attr: TFresnelCSSAttribute]: string read GetCSSRenderedAttribute write SetCSSRenderedAttribute;
|
|
|
// Events
|
|
|
Procedure AddEventListener(aID : TEventID; aHandler : TFresnelEventHandler);
|
|
@@ -598,6 +655,9 @@ function CompareFresnelRect(const A, B: TFresnelRect): integer;
|
|
|
function FPColorToCSS(const c: TFPColor): string;
|
|
|
function CSSToFPColor(const s: string; out c: TFPColor): boolean;
|
|
|
|
|
|
+function dbgs(const p: TFresnelPoint): string;
|
|
|
+function dbgs(const r: TFresnelRect): string;
|
|
|
+
|
|
|
implementation
|
|
|
|
|
|
function FloatToCSSStr(const f: TFresnelLength): string;
|
|
@@ -808,6 +868,16 @@ begin
|
|
|
Result:=true;
|
|
|
end;
|
|
|
|
|
|
+function dbgs(const p: TFresnelPoint): string;
|
|
|
+begin
|
|
|
+ Result:=FloatToStr(p.X)+','+FloatToStr(p.Y);
|
|
|
+end;
|
|
|
+
|
|
|
+function dbgs(const r: TFresnelRect): string;
|
|
|
+begin
|
|
|
+ Result:=FloatToStr(r.Left)+','+FloatToStr(r.Top)+','+FloatToStr(r.Right)+','+FloatToStr(r.Bottom);
|
|
|
+end;
|
|
|
+
|
|
|
{ TFresnelLayoutNode }
|
|
|
|
|
|
procedure TFresnelLayoutNode.SetElement(const AValue: TFresnelElement);
|
|
@@ -879,6 +949,314 @@ begin
|
|
|
FNodes.Sort(Compare,Context,SortBase.DefaultSortingAlgorithm);
|
|
|
end;
|
|
|
|
|
|
+{ TFresnelPoint }
|
|
|
+
|
|
|
+class function TFresnelPoint.Zero: TFresnelPoint;
|
|
|
+begin
|
|
|
+ Result.x := 0.0;
|
|
|
+ Result.y := 0.0;
|
|
|
+end;
|
|
|
+
|
|
|
+function TFresnelPoint.Add(const p: TFresnelPoint): TFresnelPoint;
|
|
|
+begin
|
|
|
+ Result.x := X+p.X;
|
|
|
+ Result.y := Y+p.Y;
|
|
|
+end;
|
|
|
+
|
|
|
+function TFresnelPoint.Distance(const p: TFresnelPoint): TFresnelLength;
|
|
|
+begin
|
|
|
+ Result := Sqrt(Sqr(p.X-X)+Sqr(p.Y-Y));
|
|
|
+end;
|
|
|
+
|
|
|
+function TFresnelPoint.IsZero: Boolean;
|
|
|
+begin
|
|
|
+ Result:=SameValue(X,0) and SameValue(y,0);
|
|
|
+end;
|
|
|
+
|
|
|
+function TFresnelPoint.Subtract(const p: TFresnelPoint): TFresnelPoint;
|
|
|
+begin
|
|
|
+ Result.x := X-p.X;
|
|
|
+ Result.y := Y-p.Y;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFresnelPoint.SetLocation(const p: TFresnelPoint);
|
|
|
+begin
|
|
|
+ X:=p.X;
|
|
|
+ Y:=p.Y;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFresnelPoint.SetLocation(const ax, ay: TFresnelLength);
|
|
|
+begin
|
|
|
+ X:=ax;
|
|
|
+ Y:=ay;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFresnelPoint.Offset(const p: TFresnelPoint);
|
|
|
+begin
|
|
|
+ X:=X+p.X;
|
|
|
+ Y:=Y+p.Y;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFresnelPoint.Offset(const dx, dy: TFresnelLength);
|
|
|
+begin
|
|
|
+ X:=X+dX;
|
|
|
+ Y:=Y+dY;
|
|
|
+end;
|
|
|
+
|
|
|
+function TFresnelPoint.Angle(const p: TFresnelPoint): TFresnelLength;
|
|
|
+
|
|
|
+ function ArcTan2(const y,x: TFresnelLength): TFresnelLength;
|
|
|
+ begin
|
|
|
+ if x=0 then
|
|
|
+ begin
|
|
|
+ if y=0 then
|
|
|
+ Result:=0.0
|
|
|
+ else if y>0 then
|
|
|
+ Result:=pi/2
|
|
|
+ else
|
|
|
+ Result:=-pi/2;
|
|
|
+ end
|
|
|
+ else
|
|
|
+ begin
|
|
|
+ Result:=ArcTan(y/x);
|
|
|
+ if x<0 then
|
|
|
+ if y<0 then
|
|
|
+ Result:=Result-pi
|
|
|
+ else
|
|
|
+ Result:=Result+pi;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
+begin
|
|
|
+ Result:=ArcTan2(Y-p.Y,X-p.X);
|
|
|
+end;
|
|
|
+
|
|
|
+class function TFresnelPoint.PointInCircle(const aPoint,
|
|
|
+ aCenter: TFresnelPoint; const aRadius: TFresnelLength): Boolean;
|
|
|
+begin
|
|
|
+ Result := aPoint.Distance(aCenter) <= aRadius;
|
|
|
+end;
|
|
|
+
|
|
|
+class operator TFresnelPoint.=(const p1, p2: TFresnelPoint): Boolean;
|
|
|
+begin
|
|
|
+ Result:=SameValue(p1.X,p2.X) and SameValue(p1.Y,p2.Y);
|
|
|
+end;
|
|
|
+
|
|
|
+class operator TFresnelPoint.<>(const p1, p2: TFresnelPoint): Boolean;
|
|
|
+begin
|
|
|
+ Result:=(not SameValue(p1.X,p2.X)) or (not SameValue(p1.Y,p2.Y));
|
|
|
+end;
|
|
|
+
|
|
|
+class operator TFresnelPoint.+(const p1, p2: TFresnelPoint): TFresnelPoint;
|
|
|
+begin
|
|
|
+ Result.X:=p1.X+p2.X;
|
|
|
+ Result.Y:=p1.Y+p2.Y;
|
|
|
+end;
|
|
|
+
|
|
|
+class operator TFresnelPoint.-(const p1, p2: TFresnelPoint): TFresnelPoint;
|
|
|
+begin
|
|
|
+ Result.X:=p1.X-p2.X;
|
|
|
+ Result.Y:=p1.Y-p2.Y;
|
|
|
+end;
|
|
|
+
|
|
|
+{ TFresnelRect }
|
|
|
+
|
|
|
+procedure TFresnelRect.Clear;
|
|
|
+begin
|
|
|
+ Left:=0.0;
|
|
|
+ Top:=0.0;
|
|
|
+ Right:=0.0;
|
|
|
+ Bottom:=0.0;
|
|
|
+end;
|
|
|
+
|
|
|
+constructor TFresnelRect.Create(const ALeft, ATop, ARight,
|
|
|
+ ABottom: TFresnelLength);
|
|
|
+begin
|
|
|
+ Left := ALeft;
|
|
|
+ Top := ATop;
|
|
|
+ Right := ARight;
|
|
|
+ Bottom := ABottom;
|
|
|
+end;
|
|
|
+
|
|
|
+class operator TFresnelRect.=(const L, R: TFresnelRect): Boolean;
|
|
|
+begin
|
|
|
+ Result := SameValue(L.Left,R.Left) and SameValue(L.Right,R.Right)
|
|
|
+ and SameValue(L.Top,R.Top) and SameValue(L.Bottom,R.Bottom);
|
|
|
+end;
|
|
|
+
|
|
|
+class operator TFresnelRect.<>(const L, R: TFresnelRect): Boolean;
|
|
|
+begin
|
|
|
+ Result := (not SameValue(L.Left,R.Left)) and (not SameValue(L.Right,R.Right))
|
|
|
+ and (not SameValue(L.Top,R.Top)) and (not SameValue(L.Bottom,R.Bottom));
|
|
|
+end;
|
|
|
+
|
|
|
+class operator TFresnelRect.+(const L, R: TFresnelRect): TFresnelRect;
|
|
|
+begin
|
|
|
+ Result := TFresnelRect.Union(L, R);
|
|
|
+end;
|
|
|
+
|
|
|
+class operator TFresnelRect.*(const L, R: TFresnelRect): TFresnelRect;
|
|
|
+begin
|
|
|
+ Result := TFresnelRect.Intersect(L, R);
|
|
|
+end;
|
|
|
+
|
|
|
+class function TFresnelRect.Empty: TFresnelRect;
|
|
|
+begin
|
|
|
+ Result := TFresnelRect.Create(0,0,0,0);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFresnelRect.NormalizeRect;
|
|
|
+var
|
|
|
+ h: TFresnelLength;
|
|
|
+begin
|
|
|
+ if Top>Bottom then
|
|
|
+ begin
|
|
|
+ h := Top;
|
|
|
+ Top := Bottom;
|
|
|
+ Bottom := h;
|
|
|
+ end;
|
|
|
+ if Left>Right then
|
|
|
+ begin
|
|
|
+ h := Left;
|
|
|
+ Left := Right;
|
|
|
+ Right := h;
|
|
|
+ end
|
|
|
+end;
|
|
|
+
|
|
|
+function TFresnelRect.IsEmpty: Boolean;
|
|
|
+begin
|
|
|
+ Result := (Right <= Left) or (Bottom <= Top);
|
|
|
+end;
|
|
|
+
|
|
|
+function TFresnelRect.Contains(const P: TFresnelPoint): Boolean;
|
|
|
+begin
|
|
|
+ Result := (Left <= P.X) and (P.X < Right) and (Top <= P.Y) and (P.Y < Bottom);
|
|
|
+end;
|
|
|
+
|
|
|
+function TFresnelRect.Contains(const R: TFresnelRect): Boolean;
|
|
|
+begin
|
|
|
+ Result := (Left <= R.Left) and (R.Right <= Right) and (Top <= R.Top) and (R.Bottom <= Bottom);
|
|
|
+end;
|
|
|
+
|
|
|
+function TFresnelRect.Contains(const ax, ay: TFresnelLength): Boolean;
|
|
|
+begin
|
|
|
+ Result := (Left <= ax) and (ax < Right) and (Top <= ay) and (ay < Bottom);
|
|
|
+end;
|
|
|
+
|
|
|
+function TFresnelRect.IntersectsWith(const R: TFresnelRect): Boolean;
|
|
|
+begin
|
|
|
+ Result := (Left < R.Right) and (R.Left < Right) and (Top < R.Bottom) and (R.Top < Bottom);
|
|
|
+end;
|
|
|
+
|
|
|
+class function TFresnelRect.Intersect(const R1, R2: TFresnelRect): TFresnelRect;
|
|
|
+begin
|
|
|
+ Result.Left:=Max(R1.Left,R2.Left);
|
|
|
+ Result.Right:=Min(R1.Right,R2.Right);
|
|
|
+ Result.Top:=Max(R1.Top,R2.Top);
|
|
|
+ Result.Bottom:=Min(R1.Bottom,R2.Bottom);
|
|
|
+ if Result.IsEmpty then
|
|
|
+ FillByte(Result,SizeOf(TFresnelRect),0);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFresnelRect.Intersect(const R: TFresnelRect);
|
|
|
+begin
|
|
|
+ if Left<R.Left then Left:=R.Left;
|
|
|
+ if Right>R.Right then Right:=R.Right;
|
|
|
+ if Top<R.Top then Top:=R.Top;
|
|
|
+ if Bottom>R.Bottom then Bottom:=R.Bottom;
|
|
|
+ if IsEmpty then
|
|
|
+ FillByte(Self,SizeOf(TFresnelRect),0);
|
|
|
+end;
|
|
|
+
|
|
|
+class function TFresnelRect.Union(const R1, R2: TFresnelRect): TFresnelRect;
|
|
|
+begin
|
|
|
+ Result.Left:=Min(R1.Left,R2.Left);
|
|
|
+ Result.Right:=Max(R1.Right,R2.Right);
|
|
|
+ Result.Top:=Min(R1.Top,R2.Top);
|
|
|
+ Result.Bottom:=Max(R1.Bottom,R2.Bottom);
|
|
|
+ if Result.IsEmpty then
|
|
|
+ FillByte(Result,SizeOf(TFresnelRect),0);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFresnelRect.Union(const R: TFresnelRect);
|
|
|
+begin
|
|
|
+ if Left>R.Left then Left:=R.Left;
|
|
|
+ if Right<R.Right then Right:=R.Right;
|
|
|
+ if Top>R.Top then Top:=R.Top;
|
|
|
+ if Bottom<R.Bottom then Bottom:=R.Bottom;
|
|
|
+ if IsEmpty then
|
|
|
+ FillByte(Self,SizeOf(TFresnelRect),0);
|
|
|
+end;
|
|
|
+
|
|
|
+class function TFresnelRect.Union(const Points: array of TFresnelPoint
|
|
|
+ ): TFresnelRect;
|
|
|
+var
|
|
|
+ i: Integer;
|
|
|
+begin
|
|
|
+ if Length(Points) > 0 then
|
|
|
+ begin
|
|
|
+ Result.TopLeft := Points[Low(Points)];
|
|
|
+ Result.BottomRight := Points[Low(Points)];
|
|
|
+
|
|
|
+ for i := Low(Points)+1 to High(Points) do
|
|
|
+ begin
|
|
|
+ if Points[i].X < Result.Left then Result.Left := Points[i].X;
|
|
|
+ if Points[i].X > Result.Right then Result.Right := Points[i].X;
|
|
|
+ if Points[i].Y < Result.Top then Result.Top := Points[i].Y;
|
|
|
+ if Points[i].Y > Result.Bottom then Result.Bottom := Points[i].Y;
|
|
|
+ end;
|
|
|
+ end else
|
|
|
+ Result := Empty;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFresnelRect.Offset(const DX, DY: TFresnelLength);
|
|
|
+begin
|
|
|
+ Left:=Left+DX;
|
|
|
+ Top:=Top+DY;
|
|
|
+ Right:=Right+DX;
|
|
|
+ Bottom:=Bottom+DY;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFresnelRect.Offset(const DP: TFresnelPoint);
|
|
|
+begin
|
|
|
+ Left:=Left+DP.X;
|
|
|
+ Top:=Top+DP.Y;
|
|
|
+ Right:=Right+DP.X;
|
|
|
+ Bottom:=Bottom+DP.Y;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFresnelRect.SetLocation(const X, Y: TFresnelLength);
|
|
|
+begin
|
|
|
+ Offset(X-Left, Y-Top);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFresnelRect.SetLocation(const P: TFresnelPoint);
|
|
|
+begin
|
|
|
+ Offset(P.X-Left, P.Y-Top);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFresnelRect.Inflate(const DX, DY: TFresnelLength);
|
|
|
+begin
|
|
|
+ Left:=Left-DX;
|
|
|
+ Top:=Top-DY;
|
|
|
+ Right:=Right+DX;
|
|
|
+ Bottom:=Bottom+DY;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TFresnelRect.Inflate(const DL, DT, DR, DB: TFresnelLength);
|
|
|
+begin
|
|
|
+ Left:=Left-DL;
|
|
|
+ Top:=Top-DT;
|
|
|
+ Right:=Right+DR;
|
|
|
+ Bottom:=Bottom+DB;
|
|
|
+end;
|
|
|
+
|
|
|
+function TFresnelRect.CenterPoint: TFresnelPoint;
|
|
|
+begin
|
|
|
+ Result.X := (Left+Right)/2;
|
|
|
+ Result.Y := (Top+Bottom)/2;
|
|
|
+end;
|
|
|
+
|
|
|
{ TFresnelViewport }
|
|
|
|
|
|
procedure TFresnelViewport.CSSResolverLog(Sender: TObject;
|
|
@@ -1148,28 +1526,23 @@ function TFresnelViewport.GetElementAt(const x, y: TFresnelLength
|
|
|
var
|
|
|
El: TFresnelElement;
|
|
|
i: Integer;
|
|
|
- aLeft, aTop, aPaddingLeft, aPaddingTop: TFresnelLength;
|
|
|
BorderBox: TFresnelRect;
|
|
|
+ aContentOffset: TFresnelPoint;
|
|
|
begin
|
|
|
Result:=nil;
|
|
|
if Node=nil then exit;
|
|
|
El:=Node.Element;
|
|
|
if not El.Rendered then exit;
|
|
|
- BorderBox:=El.RenderedBorderBox;
|
|
|
if Node.NodeCount>0 then begin
|
|
|
- aPaddingLeft:=El.GetRenderedCSSLength(fcaPaddingLeft,false);
|
|
|
- aPaddingTop:=El.GetRenderedCSSLength(fcaPaddingTop,false);
|
|
|
- aLeft:=BorderBox.Left+aPaddingLeft;
|
|
|
- aTop:=BorderBox.Top+aPaddingTop;
|
|
|
-
|
|
|
+ aContentOffset:=El.RenderedContentBox.TopLeft;
|
|
|
for i:=Node.NodeCount-1 downto 0 do
|
|
|
begin
|
|
|
- Result:=Check(Node.Nodes[i],dx+aLeft,dy+aTop);
|
|
|
+ Result:=Check(Node.Nodes[i],dx+aContentOffset.X,dy+aContentOffset.Y);
|
|
|
if Result<>nil then exit;
|
|
|
end;
|
|
|
end;
|
|
|
- if (x>=BorderBox.Left+dx) and (y>=BorderBox.Top+dy)
|
|
|
- and (x<=BorderBox.Right+dx) and (y<=BorderBox.Right+dy) then
|
|
|
+ BorderBox:=El.RenderedBorderBox;
|
|
|
+ if BorderBox.Contains(x-dx,y-dy) then
|
|
|
Result:=El
|
|
|
else
|
|
|
Result:=nil;
|
|
@@ -2613,23 +2986,20 @@ end;
|
|
|
|
|
|
function TFresnelElement.GetBoundingClientRect: TFresnelRect;
|
|
|
var
|
|
|
- Box: TFresnelRect;
|
|
|
- aPaddingLeft, aPaddingTop, aLeft, aTop: TFresnelLength;
|
|
|
+ Node: TFresnelLayoutNode;
|
|
|
begin
|
|
|
- Result:=RenderedBorderBox;
|
|
|
- if Parent<>nil then
|
|
|
+ if (not Rendered) then
|
|
|
begin
|
|
|
- Box:=Parent.GetBoundingClientRect;
|
|
|
- aPaddingLeft:=Parent.GetRenderedCSSLength(fcaPaddingLeft,false);
|
|
|
- aPaddingTop:=Parent.GetRenderedCSSLength(fcaPaddingTop,false);
|
|
|
- debugln(['TFresnelElement.GetBoundingClientRect ',Name,' RenderedBorderBox=',Result.Left,',',Result.Top,',',Result.Right,',',Result.Bottom,' Parent=',Parent.Name,' ',Box.Left,',',Box.Top,' Pad=',aPaddingLeft,',',aPaddingTop]);
|
|
|
- aLeft:=Box.Left+aPaddingLeft;
|
|
|
- aTop:=Box.Top+aPaddingTop;
|
|
|
- Result.Left:=Result.Left+aLeft;
|
|
|
- Result.Top:=Result.Top+aTop;
|
|
|
- Result.Right:=Result.Right+aLeft;
|
|
|
- Result.Bottom:=Result.Bottom+aTop;
|
|
|
+ Result.Clear;
|
|
|
+ exit;
|
|
|
+ end;
|
|
|
+ Result:=RenderedBorderBox;
|
|
|
+ Node:=LayoutNode.Parent;
|
|
|
+ while Node<>nil do begin
|
|
|
+ Result.Offset(Node.Element.RenderedContentBox.TopLeft);
|
|
|
+ Node:=Node.Parent;
|
|
|
end;
|
|
|
+ //debugln(['TFresnelElement.GetBoundingClientRect ',Name,' Result=',Result.Left,',',Result.Top,',',Result.Right,',',Result.Bottom]);
|
|
|
end;
|
|
|
|
|
|
function TFresnelElement.GetRenderedCSSLength(Attr: TFresnelCSSAttribute;
|