Browse Source

* Refactoring of border & background

Michaël Van Canneyt 1 year ago
parent
commit
d25ddfc74a

+ 41 - 0
src/base/fresnel.classes.pas

@@ -24,6 +24,9 @@ type
   TFresnelLength = double;
   TArray4FresnelLength =  array[0..3] of TFresnelLength;
 
+  TCalcBoolean = (cbCalc,cbFalse,cbTrue);
+
+
 const
   MaxFresnelLength = TFresnelLength(high(longint));
 
@@ -134,6 +137,14 @@ Procedure FLLog(aType: TEventType; const args : Array of string);
 function DbgSName(const p: TObject): string; overload;
 function DbgSName(const p: TClass): string; overload;
 
+Var
+  MinStrokeWidth : TFresnelLength = 0.09;
+
+operator := (a : boolean) b : TCalcBoolean;
+operator := (a : TCalcBoolean) b : Boolean;
+
+procedure NormStroke(var s: TFresnelLength; NoNegative: boolean);
+function  NormalizeStroke(s: TFresnelLength; NoNegative: boolean) : TFresnelLength; inline;
 
 implementation
 
@@ -611,5 +622,35 @@ begin
   Result:=Name+':'+ClassName;
 end;
 
+operator := (a : boolean) b : TCalcBoolean;
+const
+  bools : Array[Boolean] of TCalcBoolean = (cbFalse,cbTrue);
+
+begin
+  b:=Bools[a];
+end;
+
+operator := (a : TCalcBoolean) b : Boolean;
+
+begin
+  b:=(a=cbTrue);
+end;
+
+function NormalizeStroke(s: TFresnelLength; NoNegative: boolean): TFresnelLength;
+
+begin
+  if NoNegative and (s<0) then
+    Exit(0);
+  if SameValue(s,0,MinStrokeWidth) then
+    Exit(0);
+  Result:=S;
+end;
+
+procedure NormStroke(var s: TFresnelLength; NoNegative: boolean);
+begin
+  S:=NormalizeStroke(S,NoNegative);
+end;
+
+
 end.
 

+ 3 - 0
src/base/fresnel.dom.pas

@@ -341,6 +341,9 @@ type
     procedure TextOut(const aLeft, aTop: TFresnelLength; const aFont: IFresnelFont; const aColor: TFPColor; const aText: string);
     procedure TextShadow(const aLeft, aTop: TFresnelLength; const aFont: IFresnelFont; const aColor: TFPColor; const aRadius: TFresnelLength; const aText: string);
     procedure DrawImage(const aLeft, aTop, aWidth, aHeight: TFresnelLength; const aImage: TFPCustomImage);
+    function GetOrigin : TFresnelPoint;
+    procedure SetOrigin (const aValue : TFresnelPoint);
+    property Origin : TFresnelPoint Read GetOrigin Write SetOrigin;
   end;
 
   IFresnelRenderable = Interface ['{1364DA87-CA22-48A4-B1B2-A8A2C3047FD8}']

+ 151 - 13
src/base/fresnel.renderer.pas

@@ -16,23 +16,39 @@ type
   TFresnelRenderer = class(TComponent,IFresnelRenderer)
   private
     FSubPixel: boolean;
+    FOrigin: TFresnelPoint;
   protected
     type
-
       { TBorderAndBackground }
 
       TBorderAndBackground = class
+      Private
+        FHasBorder : TCalcBoolean;
+        FHasRadius : TCalcBoolean;
+        FSameBorderWidth : TCalcBoolean;
+        FRenderer : TFresnelRenderer;
       public
         Box: TFresnelRect;
         Width: array[TFresnelCSSSide] of TFresnelLength;
+        Color: array[TFresnelCSSSide] of TFPColor;
         BackgroundColorFP: TFPColor;
         BackgroundImage: TFresnelCSSImage;
-        Color: array[TFresnelCSSSide] of TFPColor;
         Radius: array[TFresnelCSSCorner] of TFresnelPoint;
+        Constructor Create(aRenderer : TFresnelRenderer);
         destructor Destroy; override;
+        procedure NormStroke(var aNorm: TFresnelLength; NoNegative: Boolean); inline;
+        procedure Normalize;
+        function HasBorder : Boolean;
+        function SameBorderWidth : Boolean;
+        function HasRadius : Boolean;
+        property Renderer : TFresnelRenderer read FRenderer;
       end;
   protected
-    FOrigin: TFresnelPoint;
+    // Create backend-specific TBorderAndBackground if needed
+    function CreateBorderAndBackground : TBorderAndBackground; virtual;
+    // Prepare background and border drawing. Return false if no background/border needed.
+    function PrepareBackgroundBorder(El: TFresnelElement; Params: TBorderAndBackground) : Boolean; virtual;
+    procedure DrawElBackground(El: TFresnelElement; Params: TBorderAndBackground); virtual;
     procedure FillRect(const aColor: TFPColor; const aRect: TFresnelRect); virtual; abstract;
     procedure Line(const aColor: TFPColor; const x1, y1, x2, y2: TFresnelLength); virtual; abstract;
     procedure TextOut(const aLeft, aTop: TFresnelLength; const aFont: IFresnelFont; const aColor: TFPColor; const aText: string); virtual; abstract;
@@ -44,10 +60,13 @@ type
     procedure DrawChildren(El: TFresnelElement); virtual;
     procedure UpdateRenderedAttributes(El: TFresnelElement); virtual;
     procedure SetOrigin(const AValue: TFresnelPoint); virtual;
+    function GetOrigin : TFresnelPoint; virtual;
+    class function GetMinStrokeWidth : TFresnelLength;
+    class function NormalizeLength(s: TFresnelLength; NoNegative: boolean) : TFresnelLength;
   public
     procedure Draw(Viewport: TFresnelViewport); virtual;
     property SubPixel: boolean read FSubPixel write FSubPixel;
-    property Origin: TFresnelPoint read FOrigin write SetOrigin;
+    property Origin: TFresnelPoint read GetOrigin write SetOrigin;
   end;
   TFresnelRendererClass = class of TFresnelRenderer;
 
@@ -61,6 +80,45 @@ begin
   FOrigin:=AValue;
 end;
 
+function TFresnelRenderer.GetOrigin: TFresnelPoint;
+begin
+  Result:=Forigin;
+end;
+
+class function TFresnelRenderer.GetMinStrokeWidth: TFresnelLength;
+begin
+  Result:=0.09;
+end;
+
+class function TFresnelRenderer.NormalizeLength(s: TFresnelLength; NoNegative: boolean): TFresnelLength;
+begin
+  if NoNegative and (s<0) then
+    Exit(0);
+  if SameValue(s,0,MinStrokeWidth) then
+    Exit(0);
+  Result:=S;
+end;
+
+function TFresnelRenderer.CreateBorderAndBackground: TBorderAndBackground;
+begin
+  Result:=TBorderAndBackground.Create(Self);
+end;
+
+function TFresnelRenderer.PrepareBackgroundBorder(El: TFresnelElement; Params: TBorderAndBackground): Boolean;
+begin
+  Params.Normalize;
+  Result:=True;
+end;
+
+procedure TFresnelRenderer.DrawElBackground(El: TFresnelElement; Params: TBorderAndBackground);
+begin
+  if Params.BackgroundColorFP.Alpha>alphaTransparent then
+  begin
+    //FLLog(etDebug,'TFresnelRenderer.DrawElBorder drawing background %s',[El.GetPath]);
+    FillRect(Params.BackgroundColorFP,Params.Box);
+  end;
+end;
+
 procedure TFresnelRenderer.TextShadow(const aLeft, aTop: TFresnelLength;
   const aFont: IFresnelFont; const aColor: TFPColor;
   const aRadius: TFresnelLength; const aText: string);
@@ -85,11 +143,6 @@ var
   c: TFPColor;
 begin
   if El=nil then ;
-  if Params.BackgroundColorFP.Alpha>alphaTransparent then
-  begin
-    //FLLog(etDebug,'TFresnelRenderer.DrawElBorder drawing background %s',[El.GetPath]);
-    FillRect(Params.BackgroundColorFP,Params.Box);
-  end;
   //FLLog(etDebug,'TFresnelRenderer.DrawElBorder drawing border %s',[El.GetPath]);
   for s in TFresnelCSSSide do
   begin
@@ -120,7 +173,7 @@ var
   Corner: TFresnelCSSCorner;
 
 begin
-  //FLLog(etDebug,'TFresnelRenderer.DrawElement %s Origin=%s',[El.GetPath,Origin.ToString]);
+  FLLog(etDebug,'TFresnelRenderer.DrawElement %s Origin=%s',[El.GetPath,Origin.ToString]);
   LNode:=TSimpleFresnelLayoutNode(El.LayoutNode);
   if LNode.SkipRendering then exit;
   aRenderable:=El as IFresnelRenderable;
@@ -130,6 +183,7 @@ begin
   aTop:=El.GetRenderedCSSLength(fcaTop,false);
   aRight:=El.GetRenderedCSSLength(fcaRight,false);
   aBottom:=El.GetRenderedCSSLength(fcaBottom,false);
+  FLLog(etDebug,'TFresnelRenderer.DrawElement %s [(%gx%g),(%gx%g)]',[El.GetPath,aLeft,aTop,aright,aBottom]);
 
   aMarginLeft:=El.GetRenderedCSSLength(fcaMarginLeft,false);
   aMarginRight:=El.GetRenderedCSSLength(fcaMarginRight,false);
@@ -160,7 +214,7 @@ begin
 
   //writeln('TFresnelRenderer.DrawElement ',El.Name,' BorderBox=',El.RenderedBorderBox.ToString,' ContentBox=',El.RenderedContentBox.ToString);
 
-  BorderParams:=TBorderAndBackground.Create;
+  BorderParams:=CreateBorderAndBackground;
   try
     BorderParams.Box:=El.RenderedBorderBox;
     if not SubPixel then
@@ -191,8 +245,14 @@ begin
     // border-radius
     for Corner in TFresnelCSSCorner do
       BorderParams.Radius[Corner]:=El.GetRenderedCSSBorderRadius(Corner);
-
-    DrawElBorder(El,BorderParams);
+    // Normalize
+    if PrepareBackgroundBorder(El,BorderParams) then
+      begin
+      // Background
+      DrawElBackground(El,BorderParams);
+      // Border
+      DrawElBorder(El,BorderParams);
+      end;
   finally
     BorderParams.Free;
   end;
@@ -267,11 +327,89 @@ end;
 
 { TFresnelRenderer.TBorderAndBackground }
 
+
+constructor TFresnelRenderer.TBorderAndBackground.Create(aRenderer: TFresnelRenderer);
+begin
+  FRenderer:=aRenderer;
+end;
+
 destructor TFresnelRenderer.TBorderAndBackground.Destroy;
 begin
   FreeAndNil(BackgroundImage);
   inherited Destroy;
 end;
 
+procedure TFresnelRenderer.TBorderAndBackground.NormStroke(var aNorm: TFresnelLength; NoNegative : Boolean);
+
+begin
+  aNorm:=Renderer.NormalizeLength(aNorm,NoNegative);
+end;
+
+procedure TFresnelRenderer.TBorderAndBackground.Normalize;
+
+var
+  Side : TFresnelCSSSide;
+  Corner : TFresnelCSSCorner;
+begin
+  for Side in TFresnelCSSSide do
+    NormStroke(Width[Side],True);
+  for Corner in TFresnelCSSCorner do
+    begin
+    NormStroke(Radius[Corner].X,True);
+    NormStroke(Radius[Corner].Y,True);
+    end;
+end;
+
+function TFresnelRenderer.TBorderAndBackground.HasBorder: Boolean;
+begin
+  if FHasBorder=cbCalc then
+    FHasBorder:=(Width[ffsLeft]>0)
+                or (Width[ffsRight]>0)
+                or (Width[ffsTop]>0)
+                or (Width[ffsBottom]>0);
+  Result:=FHasBorder;
+end;
+
+function TFresnelRenderer.TBorderAndBackground.SameBorderWidth: Boolean;
+
+var
+  Side : TFresnelCSSSide;
+  Ref : TFresnelLength;
+
+begin
+  if FSameBorderWidth=cbcalc then
+    begin
+    FSameBorderWidth:=cbtrue;
+    Ref:=NormalizeStroke(Width[Low(Side)],True);
+    for Side:=Succ(Low(TFresnelCSSSide)) to High(TFresnelCSSSide) do
+      begin
+      if (not SameValue(NormalizeStroke(Width[Side],True),Ref)) then
+        FSameBorderWidth:=cbfalse;
+      end;
+    end;
+  Result:=FSameBorderWidth;
+end;
+
+function TFresnelRenderer.TBorderAndBackground.HasRadius: Boolean;
+
+var
+  Corner : TFresnelCSSCorner;
+begin
+  if (FHasRadius=cbCalc) then
+    begin
+    FHasRadius:=cbFalse;
+    for Corner in TFresnelCSSCorner do
+    begin
+      if (NormalizeStroke(Radius[Corner].X,True)>0)
+          and (NormalizeStroke(Radius[Corner].Y,True)>0) then
+      begin
+        FHasRadius:=cbtrue;
+        break;
+      end;
+    end;
+    end;
+  Result:=FHasRadius;
+end;
+
 end.
 

+ 6 - 6
src/lcl/fresnel.lcl.pas

@@ -217,8 +217,8 @@ procedure TFresnelLCLRenderer.FillRect(const aColor: TFPColor;
 begin
   Canvas.Brush.FPColor:=aColor;
   Canvas.Brush.Style:=bsSolid;
-  Canvas.FillRect(Rect(floor(FOrigin.X+aRect.Left),floor(FOrigin.Y+aRect.Top),
-                       ceil(FOrigin.X+aRect.Right),ceil(FOrigin.Y+aRect.Bottom)));
+  Canvas.FillRect(Rect(floor(Origin.X+aRect.Left),floor(Origin.Y+aRect.Top),
+                       ceil(Origin.X+aRect.Right),ceil(Origin.Y+aRect.Bottom)));
 end;
 
 procedure TFresnelLCLRenderer.Line(const aColor: TFPColor; const x1, y1, x2,
@@ -226,7 +226,7 @@ procedure TFresnelLCLRenderer.Line(const aColor: TFPColor; const x1, y1, x2,
 begin
   Canvas.Pen.FPColor:=aColor;
   Canvas.Pen.Style:=psSolid;
-  Canvas.Line(round(FOrigin.X+x1),round(FOrigin.Y+y1),round(FOrigin.X+x2),round(FOrigin.Y+y2));
+  Canvas.Line(round(Origin.X+x1),round(Origin.Y+y1),round(Origin.X+x2),round(Origin.Y+y2));
 end;
 
 procedure TFresnelLCLRenderer.TextOut(const aLeft, aTop: TFresnelLength;
@@ -242,7 +242,7 @@ begin
   ts:=Canvas.TextStyle;
   ts.Opaque:=false;
   Canvas.TextStyle:=ts;
-  Canvas.TextOut(round(FOrigin.X+aLeft),round(FOrigin.Y+aTop),aText);
+  Canvas.TextOut(round(Origin.X+aLeft),round(Origin.Y+aTop),aText);
 end;
 
 procedure TFresnelLCLRenderer.DrawImage(const aLeft, aTop, aWidth, aHeight: TFresnelLength; const aImage: TFPCustomImage);
@@ -252,8 +252,8 @@ var
   R : TRect;
 
 begin
-  R.Left:=Round(FOrigin.X+aLeft);
-  R.Top:=Round(FOrigin.Y+aTop);
+  R.Left:=Round(Origin.X+aLeft);
+  R.Top:=Round(Origin.Y+aTop);
   R.Width:=Round(aWidth);
   R.Height:=Round(aHeight);
   if R.IsEmpty then exit;

+ 13 - 6
src/pas2js/fresnel.pas2js.wasmapi.pp

@@ -5,8 +5,8 @@
 unit fresnel.pas2js.wasmapi;
 
 interface
-// Define this to disable API Logging alltogether
-{$DEFINE NOLOGAPICALLS}
+// Define this to disable API Logging altogether
+{ $DEFINE NOLOGAPICALLS}
 
 uses classes, js, web, webassembly, wasienv, fresnel.wasm.shared;
 
@@ -476,7 +476,7 @@ var
   S : String;
 
 begin
-  Writeln('SFS : ',aID,',',aRed,',',aGreen,',',aBlue,',',aAlpha);
+  // Writeln('SFS : ',aID,',',aRed,',',aGreen,',',aBlue,',',aAlpha);
   {$IFNDEF NOLOGAPICALLS}
   If LogAPICalls then
     begin
@@ -487,7 +487,7 @@ begin
   if Not Assigned(Canv) then
     Exit(ECANVAS_NOCANVAS);
   S:=TFresnelHelper.FresnelColorToHTMLColor(aRed,aGreen,aBlue,aAlpha);
-  Writeln('Fill: ',S);
+//  Writeln('Fill: ',S);
   Canv.fillStyle:=S;
   Exit(ECANVAS_SUCCESS);
 end;
@@ -555,7 +555,7 @@ begin
   {$IFNDEF NOLOGAPICALLS}
   If LogAPICalls then
     begin
-    LogCall('Canvas.SetFont(%d,%s)',[aID,S]);
+    LogCall('Canvas.SetFont(%d,"%s")',[aID,S]);
     end;
   {$ENDIF}
   Canv:=GetCanvas(aID);
@@ -589,7 +589,7 @@ begin
   {$IFNDEF NOLOGAPICALLS}
   If LogAPICalls then
     begin
-    LogCall('Canvas.MeasureText(%d,%s)',[aID,S]);
+    LogCall('Canvas.MeasureText(%d,"%s")',[aID,S]);
     end;
   {$ENDIF}
   Canv:=GetCanvas(aID);
@@ -599,6 +599,13 @@ begin
   W:=M.width;
   H:=M.actualBoundingBoxAscent +M.actualBoundingBoxDescent;
   V:=getModuleMemoryDataView;
+  {$IFNDEF NOLOGAPICALLS}
+  If LogAPICalls then
+    begin
+    LogCall('Canvas.MeasureText(%d,"%s") : [%g,%g]',[aID,S,W,H]);
+    end;
+  {$ENDIF}
+ 
   v.setint32(aWidth,Round(W),env.IsLittleEndian);
   v.setint32(aHeight,Round(H),env.IsLittleEndian);
   Result:=ECANVAS_SUCCESS;

+ 72 - 72
src/skia/fresnel.skiarenderer.pas

@@ -113,8 +113,15 @@ type
     FCanvas: ISkCanvas;
     class constructor InitSkiaRenderer;
   protected
-    procedure DrawElBackground(El: TFresnelElement; Params: TBorderAndBackground;
-      HasRadius: boolean; const Radii: TSkRoundRectRadii); virtual;
+    Type
+      TSkiaBorderAndBackground = class (TBorderAndBackground)
+        Radii : TSkRoundRectRadii;
+        procedure CalcRadii;
+      end;
+  protected
+    function PrepareBackgroundBorder(El: TFresnelElement; Params: TBorderAndBackground): Boolean; override;
+    function CreateBorderAndBackGround : TBorderAndBackground; override;
+    procedure DrawElBackground(El: TFresnelElement; Params: TBorderAndBackground); override;
     procedure DrawElBorder(El: TFresnelElement; Params: TBorderAndBackground); override;
     procedure DrawImage(const aLeft, aTop, aWidth, aHeight: TFresnelLength;
       const aImage: TFPCustomImage); override;
@@ -554,9 +561,29 @@ begin
   ImagesConfig.ImageClass := TFresnelSkiaFPImage;
 end;
 
-procedure TFresnelSkiaRenderer.DrawElBackground(El: TFresnelElement;
-  Params: TBorderAndBackground; HasRadius: boolean;
-  const Radii: TSkRoundRectRadii);
+function TFresnelSkiaRenderer.PrepareBackgroundBorder(El: TFresnelElement; Params: TBorderAndBackground): Boolean;
+
+var
+  Minwidth : TFresnelLength;
+
+begin
+  Result:=inherited PrepareBackgroundBorder(El, Params);
+  if not Result then
+    exit;
+  MinWidth:=GetMinStrokeWidth;
+  Result:=(Params.Box.Width>MinWidth) and (Params.Box.Height>MinWidth);
+  if Result then
+    if Params.HasRadius then
+      (Params as TSkiaBorderAndBackground).CalcRadii;
+end;
+
+function TFresnelSkiaRenderer.CreateBorderAndBackGround: TBorderAndBackground;
+begin
+  Result:=TSkiaBorderAndBackground.Create(Self);
+end;
+
+
+procedure TFresnelSkiaRenderer.DrawElBackground(El: TFresnelElement; Params: TBorderAndBackground);
 var
   r: TRectF;
   LinGrad: TFresnelCSSImageLinearGradient;
@@ -565,6 +592,8 @@ var
   Shader: ISkShader;
   SkPaint: ISkPaint;
   Oval: ISkRoundRect;
+  SkiaParams : TSkiaBorderAndBackground Absolute Params;
+
 begin
   if El=nil then ;
 
@@ -595,80 +624,32 @@ begin
   end else
     exit;
 
-  if HasRadius then
+  if Params.HasRadius then
   begin
     Oval:=TSkRoundRect.Create;
-    Oval.SetRect(r,Radii);
+    Oval.SetRect(r,SkiaParams.Radii);
     Canvas.DrawRoundRect(Oval, SkPaint);
   end else begin
     Canvas.DrawRect(r, SkPaint);
   end;
 end;
 
-procedure TFresnelSkiaRenderer.DrawElBorder(El: TFresnelElement;
-  Params: TBorderAndBackground);
-const
-  MinStrokeWidth=0.09;
-
-  procedure NormStroke(var s: TFresnelLength; NoNegative: boolean);
-  begin
-    if NoNegative and (s<0) then
-    begin
-      s:=0;
-      exit;
-    end;
-    if SameValue(s,0,MinStrokeWidth) then
-      s:=0;
-  end;
+procedure TFresnelSkiaRenderer.DrawElBorder(El: TFresnelElement; Params: TBorderAndBackground);
 
 var
   HasBorder, HasRadius, SameBorderWidth: Boolean;
   r: TRectF;
-  Corner: TFresnelCSSCorner;
-  Radii: TSkRoundRectRadii;
   SkPaint: ISkPaint;
-  SkCorner: TSkRoundRectCorner;
-  Side: TFresnelCSSSide;
   Oval: ISkRoundRect;
+  SkiaParams : TSkiaBorderAndBackground Absolute Params;
+
 begin
   if El=nil then ;
+  // Radii are calculated in prepare step.
 
-  if (Params.Box.Width<=MinStrokeWidth)
-      or (Params.Box.Height<=MinStrokeWidth) then
-  begin
-    //writeln('TFresnelSkiaRenderer.DrawElBorder ',El.GetPath,' Params.Box=',Params.Box.ToString);
-    exit;
-  end;
-
-  SameBorderWidth:=true;
-  for Side in TFresnelCSSSide do
-  begin
-    NormStroke(Params.Width[Side],true);
-    if (Side>Low(Side)) and (not SameValue(Params.Width[Side],Params.Width[Low(Side)])) then
-      SameBorderWidth:=false;
-  end;
-
-  HasBorder:=(Params.Width[ffsLeft]>0)
-         or (Params.Width[ffsRight]>0)
-         or (Params.Width[ffsTop]>0)
-         or (Params.Width[ffsBottom]>0);
-  HasRadius:=false;
-  for Corner in TFresnelCSSCorner do
-  begin
-    SkCorner:=CSSToSkRoundRectCorner[Corner];
-    NormStroke(Params.Radius[Corner].X,true);
-    NormStroke(Params.Radius[Corner].Y,true);
-    if (Params.Radius[Corner].X>0) and (Params.Radius[Corner].Y>0) then
-    begin
-      Radii[SkCorner].x:=Params.Radius[Corner].X;
-      Radii[SkCorner].y:=Params.Radius[Corner].Y;
-      HasRadius:=true;
-    end else begin
-      Radii[SkCorner].x:=0;
-      Radii[SkCorner].y:=0;
-    end;
-  end;
-
+  SameBorderWidth:=Params.SameBorderWidth;
+  HasBorder:=Params.HasBorder;
+  HasRadius:=Params.HasRadius;
   if HasBorder then begin
     // with border
     r:=RectF(Params.Width[ffsLeft]/2,
@@ -682,8 +663,6 @@ begin
   r.Offset(Params.Box.Left+Origin.X,Params.Box.Top+Origin.Y);
   //writeln('TFresnelSkiaRenderer.DrawElBorder ',El.GetPath,' Box=',Params.Box.ToString,' Origin=',Origin.ToString,' r=',r.Left,',',r.Top,',',r.Right,',',r.Bottom);
 
-  DrawElBackground(El,Params,HasRadius,Radii);
-
   // draw border
   if HasBorder then
   begin
@@ -695,7 +674,7 @@ begin
     if HasRadius then
     begin
       Oval:=TSkRoundRect.Create;
-      Oval.SetRect(r,Radii);
+      Oval.SetRect(r,SkiaParams.Radii);
       Canvas.DrawRoundRect(Oval, SkPaint);
     end else begin
       Canvas.DrawRect(r, SkPaint);
@@ -721,7 +700,7 @@ begin
   if SkImage=nil then exit;
 
   r:=RectF(aLeft,aTop,aLeft+aWidth,aTop+aHeight);
-  r.Offset(FOrigin.X,FOrigin.Y);
+  r.Offset(Origin.X,Origin.Y);
   Canvas.DrawImageRect(SkImage,r);
 end;
 
@@ -735,7 +714,7 @@ begin
   SkPaint:=TSkPaint.Create(TSkPaintStyle.Fill);
   SkPaint.setColor(FPColorToSkia(aColor));
   r:=aRect.GetRectF;
-  r.Offset(FOrigin.X,FOrigin.Y);
+  r.Offset(Origin.X,Origin.Y);
   Canvas.DrawRect(r, SkPaint);
 end;
 
@@ -746,7 +725,7 @@ var
 begin
   SkPaint:=TSkPaint.Create(TSkPaintStyle.Stroke);
   SkPaint.setColor(FPColorToSkia(aColor));
-  Canvas.DrawLine(FOrigin.X+x1,FOrigin.Y+y1,FOrigin.X+x2,FOrigin.Y+y2, SkPaint);
+  Canvas.DrawLine(Origin.X+x1,Origin.Y+y1,Origin.X+x2,Origin.Y+y2, SkPaint);
 end;
 
 procedure TFresnelSkiaRenderer.TextOut(const aLeft, aTop: TFresnelLength;
@@ -762,8 +741,8 @@ begin
   SkPaint:=TSkPaint.Create;
   SkPaint.setColor(FPColorToSkia(aColor));
   aTextBlob:=TSkTextBlob.MakeFromText(UnicodeString(aText),FreSkiaFont.SKFont);
-  X:=FOrigin.X+aLeft;
-  Y:=FOrigin.Y+aTop - FreSkiaFont.SKMetrics.Ascent;
+  X:=Origin.X+aLeft;
+  Y:=Origin.Y+aTop - FreSkiaFont.SKMetrics.Ascent;
   Canvas.DrawTextBlob(aTextBlob, X, Y, SkPaint);
 end;
 
@@ -783,8 +762,8 @@ begin
   aTextBlob:=TSkTextBlob.MakeFromText(UnicodeString(aText),FreSkiaFont.SKFont);
   //SkPaint.MaskFilter:=TSkMaskFilter.MakeBlur(TSkBlurStyle.Normal,);
   SkPaint.ImageFilter:=TSkImageFilter.MakeBlur(aRadius,aRadius);
-  X:=FOrigin.X+aLeft;
-  Y:=FOrigin.Y+aTop - FreSkiaFont.SKMetrics.Ascent;
+  X:=Origin.X+aLeft;
+  Y:=Origin.Y+aTop - FreSkiaFont.SKMetrics.Ascent;
   Canvas.DrawTextBlob(aTextBlob, X, Y, SkPaint);
 end;
 
@@ -794,5 +773,26 @@ begin
   SubPixel:=true;
 end;
 
+{ TFresnelSkiaRenderer.TSkiaBorderAndBackground }
+
+procedure TFresnelSkiaRenderer.TSkiaBorderAndBackground.CalcRadii;
+
+var
+  Corner : TFresnelCSSCorner;
+  SkCorner : TSkRoundRectCorner;
+
+begin
+  Radii:=Default(TSkRoundRectRadii);
+  for Corner in TFresnelCSSCorner do
+    begin
+    SkCorner:=CSSToSkRoundRectCorner[Corner];
+    if (Radius[Corner].X>0) and (Radius[Corner].Y>0) then
+    begin
+      Radii[SkCorner].x:=Radius[Corner].X;
+      Radii[SkCorner].y:=Radius[Corner].Y;
+    end;
+    end;
+end;
+
 end.
 

+ 1 - 7
src/wasm/fresnel.wasm.app.pp

@@ -77,7 +77,6 @@ Type
     FPrevTick: Int64;
     procedure CheckMessages;
   protected
-    procedure DoFresnelLog(aType: TEventType; const Msg: UTF8String);
     procedure DoTick(aCurrent, aPrevious: Double); virtual;
     Procedure DoLog(EventType : TEventType; const Msg : String);  override;
     procedure CreateWidgetSet; virtual;
@@ -444,11 +443,6 @@ begin
 end;
 
 
-procedure TFresnelWasmApplication.DoFresnelLog(aType: TEventType; const Msg: UTF8String);
-begin
-  DoLog(aType,Msg);
-end;
-
 procedure TFresnelWasmApplication.DoLog(EventType: TEventType; const Msg: String);
 begin
   Writeln('Wasm log[',EventType,'] ',Msg);
@@ -470,7 +464,7 @@ end;
 procedure TFresnelWasmApplication.DoTick(aCurrent, aPrevious: Double);
 
 begin
-  // FLLog(etDebug,'Tick');
+//  FLLog(etDebug,'Tick');
   FLastTick:=Round(aCurrent);
   FPrevTick:=Round(aPrevious);
   try

+ 24 - 17
src/wasm/fresnel.wasm.font.pp

@@ -18,16 +18,16 @@ Type
     Engine: TFresnelWasmFontEngine;
     Family: string;
     Kerning: string;
-    Size: string;
+    Size: double;
     Style: string;
     Variant_: string;
-    Weight: string;
+    Weight: double;
     function GetFamily: string;
     function GetKerning: string;
-    function GetSize: string;
+    function GetSize: TFresnelLength;
     function GetStyle: string;
     function GetVariant: string;
-    function GetWeight: string;
+    function GetWeight: TFresnelLength;
     function TextSize(const aText: string): TFresnelPoint; virtual;
     function TextSizeMaxWidth(const aText: string; MaxWidth: TFresnelLength): TFresnelPoint; virtual;
     function GetTool: TObject;
@@ -62,11 +62,11 @@ var
 begin
   Result:=CompareText(Font1.Family,Font2.Family);
   if Result<>0 then exit;
-  Result:=CompareText(Font1.Size,Font2.Size);
+  Result:=CompareValue(Font1.Size,Font2.Size);
   if Result<>0 then exit;
   Result:=CompareText(Font1.Style,Font2.Style);
   if Result<>0 then exit;
-  Result:=CompareText(Font1.Weight,Font2.Weight);
+  Result:=CompareValue(Font1.Weight,Font2.Weight);
   if Result<>0 then exit;
   Result:=CompareText(Font1.Variant_,Font2.Variant_);
   if Result<>0 then exit;
@@ -74,17 +74,21 @@ begin
 end;
 
 function CompareFresnelFontDescWithWasmFont(Key, Item: Pointer): integer;
+
+Const
+  Delta = 0.1;
+
 var
   Desc: PFresnelFontDesc absolute Key;
   aFont: TFresnelWasmFont absolute Item;
 begin
   Result:=CompareText(Desc^.Family,aFont.Family);
   if Result<>0 then exit;
-  Result:=CompareText(Desc^.Size,aFont.Size);
+  Result:=Ord(Abs(Desc^.Size-aFont.Size)<Delta);
   if Result<>0 then exit;
   Result:=CompareText(Desc^.Style,aFont.Style);
   if Result<>0 then exit;
-  Result:=CompareText(Desc^.Weight,aFont.Weight);
+  Result:=Ord(Abs(Desc^.Weight-aFont.Weight)<Delta);
   if Result<>0 then exit;
   Result:=CompareText(Desc^.Variant_,aFont.Variant_);
   if Result<>0 then exit;
@@ -105,7 +109,7 @@ begin
   Result:=Kerning;
 end;
 
-function TFresnelWasmFont.GetSize: string;
+function TFresnelWasmFont.GetSize: TFresnelLength;
 begin
   Result:=Size;
 end;
@@ -120,7 +124,7 @@ begin
   Result:=Variant_;
 end;
 
-function TFresnelWasmFont.GetWeight: string;
+function TFresnelWasmFont.GetWeight: TFresnelLength;
 begin
   Result:=Weight;
 end;
@@ -132,6 +136,7 @@ begin
   p:=Engine.TextSize(Self,aText);
   Result.X:=p.X;
   Result.Y:=p.Y;
+  Writeln('Textsize : ',Result.ToString);
 end;
 
 function TFresnelWasmFont.TextSizeMaxWidth(const aText: string;
@@ -142,6 +147,7 @@ begin
   p:=Engine.TextSizeMaxWidth(Self,aText,Trunc(Max(1,MaxWidth)));
   Result.X:=p.X;
   Result.Y:=p.Y;
+  Writeln('TextsizeMaxWidth : ',Result.ToString);
 end;
 
 function TFresnelWasmFont.GetTool: TObject;
@@ -221,16 +227,16 @@ begin
   aFontName:=FontToHTML(aFont);
   Result:=aFontName<>FLastFontName;
   if Result then
-    if __fresnel_canvas_set_font(CanvasID,PByte(aFontName),Length(aFontName))=ECANVAS_SUCCESS then
+    if __fresnel_canvas_set_font(CanvasID,PByte(aFontName),Length(aFontName))<>ECANVAS_SUCCESS then
       FLLog(etError,'Failed to set font name to '+aFontName);
 end;
 
 function TFresnelWasmFontEngine.TextSize(aFont: TFresnelWasmFont; const aText: string): TPoint;
 var
-  aSize: TSize;
   aWidth,aHeight : Longint;
 
 begin
+  Writeln('Enter TFresnelWasmFontEngine.TextSize');
   MaybeSetFont(aFont);
   if __fresnel_canvas_measure_text(CanvasID,PByte(aText),Length(aText),@aWidth,@aHeight)<>ECANVAS_SUCCESS then
     begin
@@ -238,6 +244,7 @@ begin
     aHeight:=12;
     end;
   Result:=TPoint.Create(aWidth,aHeight);
+  Writeln(Format('Exit TFresnelWasmFontEngine.TextSize: (%d,%d)',[Result.X,Result.Y]));
 end;
 
 function TFresnelWasmFontEngine.TextSizeMaxWidth(aFont: TFresnelWasmFont;
@@ -245,6 +252,7 @@ function TFresnelWasmFontEngine.TextSizeMaxWidth(aFont: TFresnelWasmFont;
 var
   aSize: TSize;
 begin
+  Writeln('Enter TFresnelWasmFontEngine.TextSizeMaxWidth');
   MaybeSetFont(aFont);
   Result:=TextSize(aFont,aText);
   if Result.X>MaxWidth then
@@ -252,6 +260,7 @@ begin
     Result.X:=0;
     Result.Y:=0;
     end;
+  Writeln(Format('Exit TFresnelWasmFontEngine.TextSizeMaxWidth:  (%d,%d)',[Result.X,Result.Y]));
 end;
 
 function TFresnelWasmFontEngine.FontToHTML(aFont: TFresnelWasmFont): String;
@@ -269,15 +278,13 @@ var
 
 begin
   Result:=aFont.Style;
-  Result:=AddTo(Result,aFont.Weight);
-  if TryStrToInt(aFont.Size,v) then
-    Result:=AddTo(Result,aFont.Size+'pt')
-  else
-   Result:=AddTo(Result,aFont.Size);
+  Result:=AddTo(Result,FormatFloat('##00',aFont.Weight));
+  Result:=AddTo(Result,FormatFloat('##00',aFont.Size)+'px');
   if aFont.Family='' then
     Result:=AddTo(Result,'caption')
   else
     Result:=AddTo(Result,aFont.Family);
+  // Writeln('Font to html: ',Result);
 end;
 
 

+ 6 - 6
src/wasm/fresnel.wasm.render.pp

@@ -99,7 +99,7 @@ end;
 procedure TWasmFresnelRenderer.FillRect(const aColor: TFPColor; const aRect: TFresnelRect);
 begin
   CheckFillColor(aColor);
-  FLLog(etDebug,'__fresnel_canvas_fillrect(%d,%d,%d,%d,%d)',[Canvas,FresnelToWasmLength(aRect.Left),FresnelToWasmLength(aRect.Top),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));
 end;
 
@@ -109,8 +109,8 @@ begin
   CheckStrokeColor(aColor);
   __fresnel_canvas_set_linewidth(Canvas,200);
   __fresnel_canvas_beginpath(Canvas);
-  __fresnel_canvas_moveto(Canvas,FresnelToWasmLength(x1),FresnelToWasmLength(y1));
-  __fresnel_canvas_lineto(Canvas,FresnelToWasmLength(x2),FresnelToWasmLength(y2));
+  __fresnel_canvas_moveto(Canvas,FresnelToWasmLength(x1+Origin.X),FresnelToWasmLength(y1+Origin.y));
+  __fresnel_canvas_lineto(Canvas,FresnelToWasmLength(x2+Origin.X),FresnelToWasmLength(y2+Origin.Y));
   __fresnel_canvas_stroke(Canvas);
 end;
 
@@ -120,7 +120,7 @@ procedure TWasmFresnelRenderer.TextOut(const aLeft, aTop: TFresnelLength; const
 begin
   CheckFillColor(aColor);
   CheckFont(aFont);
-  if __fresnel_canvas_filltext(Canvas,Round(aLeft),Round(aTop),PByte(aText),Length(aText))<>ECANVAS_SUCCESS then
+  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]);
 end;
 
@@ -138,8 +138,8 @@ begin
     if Img<>aImage then
       Img.Assign(aImage);
     __fresnel_canvas_draw_image(Canvas,
-                                FresnelToWasmLength(aLeft),
-                                FresnelToWasmLength(aTop),
+                                FresnelToWasmLength({aLeft+}Origin.X),
+                                FresnelToWasmLength({aTop+}Origin.Y),
                                 FresnelToWasmLength(aWidth),
                                 FresnelToWasmLength(aHeight),
                                 Img.Width,