|
@@ -14,6 +14,7 @@ Type
|
|
TWasmFresnelRenderer = Class(TFresnelRenderer)
|
|
TWasmFresnelRenderer = Class(TFresnelRenderer)
|
|
private
|
|
private
|
|
FCanvas: TCanvasID;
|
|
FCanvas: TCanvasID;
|
|
|
|
+ FFillReset : Boolean;
|
|
FLastFillColor : TFPColor;
|
|
FLastFillColor : TFPColor;
|
|
FLastStrokeColor : TFPColor;
|
|
FLastStrokeColor : TFPColor;
|
|
FLastFontName : String;
|
|
FLastFontName : String;
|
|
@@ -21,12 +22,19 @@ Type
|
|
function CheckFont(aFont: IFresnelFont): boolean;
|
|
function CheckFont(aFont: IFresnelFont): boolean;
|
|
function CheckStrokeColor(aColor: TFPColor): Boolean;
|
|
function CheckStrokeColor(aColor: TFPColor): Boolean;
|
|
protected
|
|
protected
|
|
|
|
+ procedure DoFillRect(const aColor: TFPColor; const aRect: TFresnelRect; CheckFill: Boolean);
|
|
|
|
+ procedure DoRoundRect(const aColor: TFPColor; const aRect: TFresnelRoundRect; Flags: Integer);
|
|
|
|
+ // renderer methods
|
|
|
|
+ procedure SetGradientFillStyle(aGradient : TFresnelCSSLinearGradient);
|
|
|
|
+ procedure RoundRect(const aColor: TFPColor; const aRect: TFresnelRoundRect; Fill : Boolean); override;
|
|
procedure FillRect(const aColor: TFPColor; const aRect: TFresnelRect); override;
|
|
procedure FillRect(const aColor: TFPColor; const aRect: TFresnelRect); override;
|
|
procedure Line(const aColor: TFPColor; const x1, y1, x2, y2: TFresnelLength); override;
|
|
procedure Line(const aColor: TFPColor; const x1, y1, x2, y2: TFresnelLength); override;
|
|
procedure TextOut(const aLeft, aTop: TFresnelLength;
|
|
procedure TextOut(const aLeft, aTop: TFresnelLength;
|
|
const aFont: IFresnelFont; const aColor: TFPColor;
|
|
const aFont: IFresnelFont; const aColor: TFPColor;
|
|
const aText: string); override;
|
|
const aText: string); override;
|
|
procedure DrawImage(const aLeft, aTop, aWidth, aHeight: TFresnelLength; const aImage: TFPCustomImage); override;
|
|
procedure DrawImage(const aLeft, aTop, aWidth, aHeight: TFresnelLength; const aImage: TFPCustomImage); override;
|
|
|
|
+ procedure DrawElBackground(El: TFresnelElement; Params: TBorderAndBackground); override;
|
|
|
|
+ procedure DrawElBorder(El: TFresnelElement; Params: TBorderAndBackground); override;
|
|
public
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
constructor Create(AOwner: TComponent); override;
|
|
property Canvas: TCanvasID read FCanvas write FCanvas;
|
|
property Canvas: TCanvasID read FCanvas write FCanvas;
|
|
@@ -45,15 +53,18 @@ implementation
|
|
|
|
|
|
{ TWasmFresnelRenderer }
|
|
{ TWasmFresnelRenderer }
|
|
|
|
|
|
-Function FresnelToWasmLength(aLen : TFresnelLength) : Longint;
|
|
|
|
|
|
+Function FresnelToWasmLength(aLen : TFresnelLength; Scaled : boolean = False) : Longint;
|
|
begin
|
|
begin
|
|
- Result:=Round(aLen);
|
|
|
|
|
|
+ if Scaled then
|
|
|
|
+ Result:=Round(aLen*100)
|
|
|
|
+ else
|
|
|
|
+ Result:=Round(aLen);
|
|
end;
|
|
end;
|
|
|
|
|
|
function TWasmFresnelRenderer.CheckFillColor(aColor : TFPColor) : Boolean;
|
|
function TWasmFresnelRenderer.CheckFillColor(aColor : TFPColor) : Boolean;
|
|
|
|
|
|
begin
|
|
begin
|
|
- Result:=not (aColor=FLastFillColor);
|
|
|
|
|
|
+ Result:=not (aColor=FLastFillColor) or FFillReset;
|
|
if Result then
|
|
if Result then
|
|
begin
|
|
begin
|
|
With aColor do
|
|
With aColor do
|
|
@@ -62,6 +73,7 @@ begin
|
|
__fresnel_canvas_set_fillstyle(Canvas,Red,Green,Blue,Alpha);
|
|
__fresnel_canvas_set_fillstyle(Canvas,Red,Green,Blue,Alpha);
|
|
end;
|
|
end;
|
|
FLastFillColor:=aColor;
|
|
FLastFillColor:=aColor;
|
|
|
|
+ FFillReset:=False;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -80,6 +92,86 @@ begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+procedure TWasmFresnelRenderer.SetGradientFillStyle(aGradient: TFresnelCSSLinearGradient);
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ Colors : TGradientColorPoints;
|
|
|
|
+ aX1,aY1,aX2,aY2 : Longint;
|
|
|
|
+ P : TGradientColorPoint;
|
|
|
|
+ Len,I : Integer;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ aX1:=FresnelToWasmLength(aGradient.StartPoint.X);
|
|
|
|
+ aY1:=FresnelToWasmLength(aGradient.StartPoint.Y);
|
|
|
|
+ aX2:=FresnelToWasmLength(aGradient.EndPoint.X);
|
|
|
|
+ aY2:=FresnelToWasmLength(aGradient.EndPoint.Y);
|
|
|
|
+ Len:=Length(aGradient.Colors);
|
|
|
|
+ Colors:=[];
|
|
|
|
+ if Len=1 then
|
|
|
|
+ SetLength(Colors,Len+1)
|
|
|
|
+ else
|
|
|
|
+ SetLength(Colors,Len);
|
|
|
|
+ SetLength(Colors,Len);
|
|
|
|
+ For I:=0 to Length(aGradient.Colors)-1 do
|
|
|
|
+ begin
|
|
|
|
+ P.Percentage:=FresnelToWasmLength(aGradient.Colors[I].Percentage,True);
|
|
|
|
+ P.Red:=aGradient.Colors[I].Color.Red;
|
|
|
|
+ P.Green:=aGradient.Colors[I].Color.Green;
|
|
|
|
+ P.Blue:=aGradient.Colors[I].Color.Blue;
|
|
|
|
+ P.Alpha:=aGradient.Colors[I].Color.Alpha;
|
|
|
|
+ Colors[i]:=P;
|
|
|
|
+ end;
|
|
|
|
+ if Len=1 then
|
|
|
|
+ begin
|
|
|
|
+ P.Percentage:=100;
|
|
|
|
+ Colors[1]:=P;
|
|
|
|
+ end;
|
|
|
|
+ __fresnel_canvas_linear_gradient_fillstyle(Canvas,aX1,aY1,aX2,aY2,Length(Colors),PGradientColorPoints(Colors));
|
|
|
|
+ FFillReset:=True;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TWasmFresnelRenderer.DoRoundRect(const aColor: TFPColor; const aRect: TFresnelRoundRect; Flags: Integer);
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ RR : TCanvasRoundRectData; // Array[0..11] of longint;
|
|
|
|
+ Idx : integer;
|
|
|
|
+ Corner : TFresnelCSSCorner;
|
|
|
|
+
|
|
|
|
+ procedure AddP(apoint : TFresnelPoint; OffSetOrigin : Boolean = False);
|
|
|
|
+ begin
|
|
|
|
+ RR[Idx]:=FresnelToWasmLength(aPoint.X+(Ord(OffSetOrigin)*Origin.X),True);
|
|
|
|
+ Inc(Idx);
|
|
|
|
+ RR[Idx]:=FresnelToWasmLength(aPoint.Y+(Ord(OffSetOrigin)*Origin.Y),True);
|
|
|
|
+ Inc(Idx);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ CheckStrokeColor(aColor);
|
|
|
|
+ FLLog(etDebug,'RoundRect(%d,{%s})',[Canvas,aRect.ToString]);
|
|
|
|
+ Idx:=0;
|
|
|
|
+ AddP(aRect.Box.TopLeft,True);
|
|
|
|
+ AddP(aRect.Box.BottomRight,True);
|
|
|
|
+ For Corner in TFresnelCSSCorner do
|
|
|
|
+ AddP(aRect.Radius[Corner]);
|
|
|
|
+ if __fresnel_canvas_roundrect(Canvas,Flags,@RR)<>ECANVAS_SUCCESS then
|
|
|
|
+ FLLog(etError,'failed to draw round rectangle on canvas %d',[Canvas]);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TWasmFresnelRenderer.RoundRect(const aColor: TFPColor; const aRect: TFresnelRoundRect; Fill: Boolean);
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ Flags : Integer;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ Flags:=0;
|
|
|
|
+ if Fill then
|
|
|
|
+ begin
|
|
|
|
+ CheckFillColor(aColor);
|
|
|
|
+ FLags:=ROUNDRECT_FLAG_FILL;
|
|
|
|
+ end;
|
|
|
|
+ DoRoundRect(aColor,aRect,Flags);
|
|
|
|
+end;
|
|
|
|
+
|
|
function TWasmFresnelRenderer.CheckFont(aFont : IFresnelFont) : boolean;
|
|
function TWasmFresnelRenderer.CheckFont(aFont : IFresnelFont) : boolean;
|
|
|
|
|
|
var
|
|
var
|
|
@@ -96,11 +188,18 @@ begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TWasmFresnelRenderer.FillRect(const aColor: TFPColor; const aRect: TFresnelRect);
|
|
|
|
|
|
+procedure TWasmFresnelRenderer.DoFillRect(const aColor: TFPColor; const aRect: TFresnelRect; CheckFill : Boolean);
|
|
|
|
+
|
|
begin
|
|
begin
|
|
- CheckFillColor(aColor);
|
|
|
|
|
|
+ if CheckFill then
|
|
|
|
+ CheckFillColor(aColor);
|
|
FLLog(etDebug,'__fresnel_canvas_fillrect(%d,%d,%d,%d,%d)',[Canvas,FresnelToWasmLength(aRect.Left+Origin.X),FresnelToWasmLength(aRect.Top+Origin.Y),FresnelToWasmLength(aRect.Width),FresnelToWasmLength(aRect.Height)]);
|
|
FLLog(etDebug,'__fresnel_canvas_fillrect(%d,%d,%d,%d,%d)',[Canvas,FresnelToWasmLength(aRect.Left+Origin.X),FresnelToWasmLength(aRect.Top+Origin.Y),FresnelToWasmLength(aRect.Width),FresnelToWasmLength(aRect.Height)]);
|
|
- __fresnel_canvas_fillrect(Canvas,FresnelToWasmLength(aRect.Left),FresnelToWasmLength(aRect.Top),FresnelToWasmLength(aRect.Width),FresnelToWasmLength(aRect.Height));
|
|
|
|
|
|
+ __fresnel_canvas_fillrect(Canvas,FresnelToWasmLength(aRect.Left+Origin.X),FresnelToWasmLength(aRect.Top+Origin.Y),FresnelToWasmLength(aRect.Width),FresnelToWasmLength(aRect.Height));
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TWasmFresnelRenderer.FillRect(const aColor: TFPColor; const aRect: TFresnelRect);
|
|
|
|
+begin
|
|
|
|
+ DoFillRect(aColor,aRect,True);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TWasmFresnelRenderer.Line(const aColor: TFPColor; const x1, y1, x2, y2: TFresnelLength);
|
|
procedure TWasmFresnelRenderer.Line(const aColor: TFPColor; const x1, y1, x2, y2: TFresnelLength);
|
|
@@ -117,11 +216,34 @@ end;
|
|
procedure TWasmFresnelRenderer.TextOut(const aLeft, aTop: TFresnelLength; const aFont: IFresnelFont; const aColor: TFPColor;
|
|
procedure TWasmFresnelRenderer.TextOut(const aLeft, aTop: TFresnelLength; const aFont: IFresnelFont; const aColor: TFPColor;
|
|
const aText: string);
|
|
const aText: string);
|
|
|
|
|
|
|
|
+var
|
|
|
|
+ I,Count : integer;
|
|
|
|
+ aShadow : PFresnelTextShadow;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
CheckFillColor(aColor);
|
|
CheckFillColor(aColor);
|
|
CheckFont(aFont);
|
|
CheckFont(aFont);
|
|
- if __fresnel_canvas_filltext(Canvas,Round(aLeft+Origin.X),Round(aTop+Origin.Y),PByte(aText),Length(aText))<>ECANVAS_SUCCESS then
|
|
|
|
- FLLog(etError,'failed to draw canvas %d text "%s"',[Canvas,aText]);
|
|
|
|
|
|
+ Count:=TextShadowCount;
|
|
|
|
+ if Count=0 then
|
|
|
|
+ begin
|
|
|
|
+ // X,Y,Radius,r,g,b,a)
|
|
|
|
+ if __fresnel_canvas_set_textshadow_params(Canvas,0,0,0,0,0,0,0)<>ECANVAS_SUCCESS then
|
|
|
|
+ FLLog(etError,'failed to clear shadow params for text "%s"',[Canvas,aText]);
|
|
|
|
+ if __fresnel_canvas_filltext(Canvas,FresnelToWasmLength(aLeft+Origin.X),FresnelToWasmLength(aTop+Origin.Y),PByte(aText),Length(aText))<>ECANVAS_SUCCESS then
|
|
|
|
+ FLLog(etError,'failed to draw canvas %d text "%s"',[Canvas,aText]);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ for I:=0 to TextShadowCount-1 do
|
|
|
|
+ begin
|
|
|
|
+ aShadow:=Self.TextShadow[I];
|
|
|
|
+ With aShadow^ do
|
|
|
|
+ if __fresnel_canvas_set_textshadow_params(Canvas,FresnelToWasmLength(Offset.X),FresnelToWasmLength(Offset.Y),FresnelToWasmLength(Radius,True),Color.Red,Color.Green,Color.Blue,Color.Alpha)<>ECANVAS_SUCCESS then
|
|
|
|
+ FLLog(etError,'failed to set shadow params for text "%s"',[Canvas,aText]);
|
|
|
|
+ if __fresnel_canvas_filltext(Canvas,FresnelToWasmLength(aLeft+Origin.X),FresnelToWasmLength(aTop+Origin.Y),PByte(aText),Length(aText))<>ECANVAS_SUCCESS then
|
|
|
|
+ FLLog(etError,'failed to draw canvas %d text "%s"',[Canvas,aText]);
|
|
|
|
+ if __fresnel_canvas_set_textshadow_params(Canvas,0,0,0,0,0,0,0)<>ECANVAS_SUCCESS then
|
|
|
|
+ FLLog(etError,'failed to clear shadow params for text "%s"',[Canvas,aText]);
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TWasmFresnelRenderer.DrawImage(const aLeft, aTop, aWidth, aHeight: TFresnelLength; const aImage: TFPCustomImage);
|
|
procedure TWasmFresnelRenderer.DrawImage(const aLeft, aTop, aWidth, aHeight: TFresnelLength; const aImage: TFPCustomImage);
|
|
@@ -138,8 +260,8 @@ begin
|
|
if Img<>aImage then
|
|
if Img<>aImage then
|
|
Img.Assign(aImage);
|
|
Img.Assign(aImage);
|
|
__fresnel_canvas_draw_image(Canvas,
|
|
__fresnel_canvas_draw_image(Canvas,
|
|
- FresnelToWasmLength({aLeft+}Origin.X),
|
|
|
|
- FresnelToWasmLength({aTop+}Origin.Y),
|
|
|
|
|
|
+ FresnelToWasmLength(aLeft+Origin.X),
|
|
|
|
+ FresnelToWasmLength(aTop+Origin.Y),
|
|
FresnelToWasmLength(aWidth),
|
|
FresnelToWasmLength(aWidth),
|
|
FresnelToWasmLength(aHeight),
|
|
FresnelToWasmLength(aHeight),
|
|
Img.Width,
|
|
Img.Width,
|
|
@@ -151,6 +273,62 @@ begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+procedure TWasmFresnelRenderer.DrawElBackground(El: TFresnelElement; Params: TBorderAndBackground);
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ if el=nil then;
|
|
|
|
+ if Params.BackgroundImage is TFresnelCSSLinearGradient then
|
|
|
|
+ begin
|
|
|
|
+ SetGradientFillStyle(Params.BackgroundImage as TFresnelCSSLinearGradient);
|
|
|
|
+ if Params.HasRadius then
|
|
|
|
+ DoRoundRect(Params.BackgroundColorFP,Params.BoundingBox,ROUNDRECT_FLAG_FILL)
|
|
|
|
+ else
|
|
|
|
+ DoFillRect(Params.BackgroundColorFP,Params.BoundingBox.Box,False);
|
|
|
|
+ end else if Params.BackgroundColorFP.Alpha>alphaTransparent then
|
|
|
|
+ begin
|
|
|
|
+ //FLLog(etDebug,'TFresnelRenderer.DrawElBorder drawing background %s',[El.GetPath]);
|
|
|
|
+ if Params.HasRadius then
|
|
|
|
+ RoundRect(Params.BackgroundColorFP,Params.BoundingBox,True)
|
|
|
|
+ else
|
|
|
|
+ FillRect(Params.BackgroundColorFP,Params.BoundingBox.Box);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TWasmFresnelRenderer.DrawElBorder(El: TFresnelElement; Params: TBorderAndBackground);
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ BB : TFresnelRoundRect;
|
|
|
|
+ HalfWidth : TFresnelLength;
|
|
|
|
+ C : TFresnelCSSCorner;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ FLLog(etDebug,'TWasmFresnelRenderer.DrawElBorder("%s")',[El.GetPath]);
|
|
|
|
+ if Not Params.HasRadius then
|
|
|
|
+ Inherited DrawElBorder(El,Params)
|
|
|
|
+ else if Params.SameBorderWidth then
|
|
|
|
+ begin
|
|
|
|
+ __fresnel_canvas_set_linewidth(Canvas,FresnelToWasmLength(Params.Width[ffsLeft],True));
|
|
|
|
+ BB:=Params.BoundingBox;
|
|
|
|
+ With Params do
|
|
|
|
+ begin
|
|
|
|
+ HalfWidth:=0; // Width[ffsLeft]/2;
|
|
|
|
+ BB.Box.TopLeft.OffSet(-HalfWidth,-HalfWidth);
|
|
|
|
+ BB.Box.BottomRight.OffSet(HalfWidth,HalfWidth);
|
|
|
|
+ For C in TFresnelCSSCorner do
|
|
|
|
+ begin
|
|
|
|
+ BB.Radius[C].X:=BB.Radius[C].X+HalfWidth;
|
|
|
|
+ BB.Radius[C].Y:=BB.Radius[C].Y+HalfWidth;
|
|
|
|
+ end
|
|
|
|
+ end;
|
|
|
|
+ RoundRect(Params.Color[Low(TFresnelCSSSide)],BB,False);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ // Todo
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
constructor TWasmFresnelRenderer.Create(AOwner: TComponent);
|
|
constructor TWasmFresnelRenderer.Create(AOwner: TComponent);
|
|
begin
|
|
begin
|
|
inherited Create(AOwner);
|
|
inherited Create(AOwner);
|