Browse Source

skia: background-image simple linear-gradient

mattias 1 year ago
parent
commit
0639042893
4 changed files with 372 additions and 21 deletions
  1. 2 1
      demo/Button/MainUnit.pas
  2. 299 4
      src/base/fresnel.dom.pas
  3. 16 0
      src/base/fresnel.renderer.pas
  4. 55 16
      src/skia/fresnel.skiarenderer.pas

+ 2 - 1
demo/Button/MainUnit.pas

@@ -69,7 +69,8 @@ end;
 procedure TMainForm.MainFormCreate(Sender: TObject);
 procedure TMainForm.MainFormCreate(Sender: TObject);
 begin
 begin
   Stylesheet.Add('div {'
   Stylesheet.Add('div {'
-    +'  background:#44cc66;'
+    //+'  background:#44cc66;'
+    +'  background:linear-gradient(#ededed, #bab1ba);'
     +'  border:7px solid #18ab29;'
     +'  border:7px solid #18ab29;'
     +'  padding:16px 31px;'
     +'  padding:16px 31px;'
     +'  font-size:15px; font-family:Arial; font-weight:bold;'
     +'  font-size:15px; font-family:Arial; font-weight:bold;'

+ 299 - 4
src/base/fresnel.dom.pas

@@ -126,6 +126,8 @@ type
     fcaVisibility,
     fcaVisibility,
     fcaBackground, // shorthand for background-[attachment,clip,color,image,origin,position,repeat,size]
     fcaBackground, // shorthand for background-[attachment,clip,color,image,origin,position,repeat,size]
     fcaBackgroundColor,
     fcaBackgroundColor,
+    fcaBackgroundImage,
+    fcaBackgroundOrigin,
     fcaColor,     // text color
     fcaColor,     // text color
     fcaCursor
     fcaCursor
     );
     );
@@ -212,6 +214,8 @@ const
     'visibility',
     'visibility',
     'background',
     'background',
     'background-color',
     'background-color',
+    'background-image',
+    'background-origin',
     'color',
     'color',
     'cursor'
     'cursor'
     );
     );
@@ -358,6 +362,22 @@ type
     );
     );
   TFresnelLengthChecks = set of TFresnelLengthCheck;
   TFresnelLengthChecks = set of TFresnelLengthCheck;
 
 
+  TFresnelCSSImage = class
+  end;
+
+  TFresnelCSSImageLinearGradient = class(TFresnelCSSImage)
+  public type
+    TColorPercentage = record
+      Color: TFPColor;
+      Percentage: TFresnelLength;
+    end;
+    TColorPercentageArray = array of TColorPercentage;
+  public
+    // angle
+    // side corner
+    Colors: TColorPercentageArray;
+  end;
+
   { TFresnelElement }
   { TFresnelElement }
 
 
   TFresnelElement = class(TFresnelComponent, ICSSNode, IFPObserver, IFresnelRenderable)
   TFresnelElement = class(TFresnelComponent, ICSSNode, IFPObserver, IFresnelRenderable)
@@ -453,9 +473,15 @@ type
     function CheckCSSVisibility(const AValue: string): boolean; virtual;
     function CheckCSSVisibility(const AValue: string): boolean; virtual;
     function CheckOrSetCSSBackground(const AValue: string; Check: boolean): boolean; virtual;
     function CheckOrSetCSSBackground(const AValue: string; Check: boolean): boolean; virtual;
     function CheckCSSBackgroundColor(const AValue: string): boolean; virtual;
     function CheckCSSBackgroundColor(const AValue: string): boolean; virtual;
+    function CheckCSSBackgroundImage(const AValue: string): boolean; virtual;
+    function CheckCSSBackgroundOrigin(const AValue: string): boolean; virtual;
     function CheckCSSColor(const AValue: string): boolean; virtual; // check the "color" attribute, for general check use CheckCSSColorValue
     function CheckCSSColor(const AValue: string): boolean; virtual; // check the "color" attribute, for general check use CheckCSSColorValue
-    function CheckCSSColorValue(AValue: string): boolean; virtual;
     function CheckCSSCursor(const AValue: string): boolean; virtual;
     function CheckCSSCursor(const AValue: string): boolean; virtual;
+    // check domains
+    function CheckCSSColorValue(const AValue: string): boolean; virtual;
+    function CheckCSSImageValue(const AValue: string): boolean; virtual;
+    function CheckCSSGradientValue(const AValue: string): boolean; virtual;
+
     function GetComputedCSSValue(AttrID: TCSSNumericalID): TCSSString; virtual;
     function GetComputedCSSValue(AttrID: TCSSNumericalID): TCSSString; virtual;
     procedure SetComputedCSSValue(AttrID: TCSSNumericalID; const Value: TCSSString); virtual;
     procedure SetComputedCSSValue(AttrID: TCSSNumericalID; const Value: TCSSString); virtual;
     procedure SetCSSClasses(const AValue: TStrings); virtual;
     procedure SetCSSClasses(const AValue: TStrings); virtual;
@@ -472,7 +498,8 @@ type
     procedure InitCSSResolver(aResolver: TCSSResolver); virtual;
     procedure InitCSSResolver(aResolver: TCSSResolver); virtual;
     procedure Notification(AComponent: TComponent; Operation: TOperation);
     procedure Notification(AComponent: TComponent; Operation: TOperation);
       override;
       override;
-    function CSSReadNextValue(const aValue: string; var p: integer): string;
+    function CSSReadNextValue(const aValue: string; var p: integer): string; // read e.g. url("bla")
+    function CSSReadNextToken(const aValue: string; var p: integer): string; // read linear-gradient with out the brackets
     function CheckCSSLength(Attr: TFresnelCSSAttribute; const AValue: string; const Checks: TFresnelLengthChecks = []): boolean; virtual;
     function CheckCSSLength(Attr: TFresnelCSSAttribute; const AValue: string; const Checks: TFresnelLengthChecks = []): boolean; virtual;
     procedure ComputeCSSAttribute(Attr: TFresnelCSSAttribute); virtual;
     procedure ComputeCSSAttribute(Attr: TFresnelCSSAttribute); virtual;
     function GetDPI(IsHorizontal: boolean): TFresnelLength; virtual;
     function GetDPI(IsHorizontal: boolean): TFresnelLength; virtual;
@@ -571,6 +598,8 @@ type
     function GetRenderedCSSBorderWidth(Attr: TFresnelCSSAttribute): TFresnelLength; virtual;
     function GetRenderedCSSBorderWidth(Attr: TFresnelCSSAttribute): TFresnelLength; virtual;
     function GetRenderedCSSBorderRadius(Corner: TFresnelCSSCorner): TFresnelPoint; virtual; // on fail returns 0
     function GetRenderedCSSBorderRadius(Corner: TFresnelCSSCorner): TFresnelPoint; virtual; // on fail returns 0
     function GetRenderedCSSTextShadow(out aOffsetX, aOffsetY, aRadius: TFresnelLength; out aColor: TFPColor): boolean; virtual; // on fail returns 0
     function GetRenderedCSSTextShadow(out aOffsetX, aOffsetY, aRadius: TFresnelLength; out aColor: TFPColor): boolean; virtual; // on fail returns 0
+    function GetRenderedCSSImage(Attr: TFresnelCSSAttribute): TFresnelCSSImage; virtual; // on fail returns nil
+    function GetRenderedCSSLinearGradient(const LGParams: string): TFresnelCSSImageLinearGradient; virtual; // on fail returns nil
     property Rendered: boolean read FRendered write FRendered;
     property Rendered: boolean read FRendered write FRendered;
     property RenderedBorderBox: TFresnelRect read FRenderedBorderBox write FRenderedBorderBox; // relative to layout parent
     property RenderedBorderBox: TFresnelRect read FRenderedBorderBox write FRenderedBorderBox; // relative to layout parent
     property RenderedContentBox: TFresnelRect read FRenderedContentBox write FRenderedContentBox; // relative to layout parent
     property RenderedContentBox: TFresnelRect read FRenderedContentBox write FRenderedContentBox; // relative to layout parent
@@ -2726,6 +2755,9 @@ begin
   begin
   begin
     if not Check then
     if not Check then
       SetCSSElAttribute(fcaBackgroundColor,s);
       SetCSSElAttribute(fcaBackgroundColor,s);
+  end else if CheckCSSImageValue(s) then begin
+    if not Check then
+      SetCSSElAttribute(fcaBackgroundImage,s);
   end else begin
   end else begin
     CSSInvalidValueWarning(20240527102124,fcaBackground,s);
     CSSInvalidValueWarning(20240527102124,fcaBackground,s);
     exit;
     exit;
@@ -2738,12 +2770,33 @@ begin
   Result:=CheckCSSColorValue(AValue);
   Result:=CheckCSSColorValue(AValue);
 end;
 end;
 
 
+function TFresnelElement.CheckCSSBackgroundImage(const AValue: string): boolean;
+begin
+  case AValue of
+  '','none': exit(true);
+  end;
+  Result:=CheckCSSImageValue(AValue);
+end;
+
+function TFresnelElement.CheckCSSBackgroundOrigin(const AValue: string
+  ): boolean;
+begin
+  case AValue of
+  '',
+  'content-box',
+  'padding-box',
+  'border-box': Result:=true;
+  else
+    Result:=false;
+  end;
+end;
+
 function TFresnelElement.CheckCSSColor(const AValue: string): boolean;
 function TFresnelElement.CheckCSSColor(const AValue: string): boolean;
 begin
 begin
   Result:=CheckCSSColorValue(AValue);
   Result:=CheckCSSColorValue(AValue);
 end;
 end;
 
 
-function TFresnelElement.CheckCSSColorValue(AValue: string): boolean;
+function TFresnelElement.CheckCSSColorValue(const AValue: string): boolean;
 var
 var
   aColor: TFPColor;
   aColor: TFPColor;
 begin
 begin
@@ -2754,6 +2807,57 @@ begin
   if aColor.Alpha=alphaOpaque then ;
   if aColor.Alpha=alphaOpaque then ;
 end;
 end;
 
 
+function TFresnelElement.CheckCSSImageValue(const AValue: string): boolean;
+begin
+  Result:=false;
+  if CheckCSSGradientValue(AValue) then exit(true);
+end;
+
+function TFresnelElement.CheckCSSGradientValue(const AValue: string): boolean;
+var
+  s: String;
+  p: Integer;
+begin
+  Result:=false;
+  p:=1;
+  s:=CSSReadNextToken(AValue,p);
+  case s of
+  'linear-gradient':
+    begin
+      s:=CSSReadNextToken(AValue,p);
+      if s<>'(' then exit;
+      repeat
+        s:=CSSReadNextToken(AValue,p);
+        case s of
+        ')':
+          exit(true);
+        // todo 'to'
+        // todo angle
+        // todo percentage, e.g. linear-gradient(red 10%, 30%, blue 90%);
+        else
+          if not CheckCSSColorValue(s) then
+            exit;
+          s:=CSSReadNextToken(AValue,p);
+          case s of
+          ',':
+            continue;
+          // todo percentage and lengths
+          ')':
+            exit(true);
+          else
+            CSSWarning(20240609193614,'invalid linear-gradient "'+AValue+'"');
+            exit;
+          end;
+        end;
+      until false;
+    end;
+  // todo radial-gradient
+  // todo conic-gradient
+  // todo repeating-linear-gradient
+  // todo repeating-radial-gradient
+  end;
+end;
+
 function TFresnelElement.CheckCSSCursor(const AValue: string): boolean;
 function TFresnelElement.CheckCSSCursor(const AValue: string): boolean;
 begin
 begin
   case AValue of
   case AValue of
@@ -2966,14 +3070,110 @@ function TFresnelElement.CSSReadNextValue(const aValue: string; var p: integer
   ): string;
   ): string;
 var
 var
   l: SizeInt;
   l: SizeInt;
+
+  function SkipApostroph: boolean;
+  begin
+    inc(p);
+    while (p<=l) and (aValue[p]<>'"') do inc(p);
+    if p>l then
+      exit(false); // missing apostroph
+    inc(p);
+    Result:=true;
+  end;
+
+  function SkipRoundBrackets: boolean;
+  var
+    Lvl: Integer;
+  begin
+    Result:=false;
+    inc(p);
+    Lvl:=1;
+    while (p<=l) do
+    begin
+      case aValue[p] of
+      '(': inc(Lvl);
+      ')':
+        begin
+          dec(Lvl);
+          if Lvl=0 then exit(true);
+        end;
+      '"':
+        if not SkipApostroph then exit;
+      end;
+      inc(p);
+    end;
+  end;
+
+var
   StartP: Integer;
   StartP: Integer;
 begin
 begin
   Result:='';
   Result:='';
   l:=length(aValue);
   l:=length(aValue);
+  while (p<=l) and (aValue[p] in [' ',#9,#10,#13]) do inc(p);
   if p>l then exit;
   if p>l then exit;
+  StartP:=p;
+  case aValue[p] of
+  ',',';',')','{','}':
+    begin
+      Result:=aValue[p];
+      inc(p);
+      exit;
+    end;
+  '(':
+    if not SkipRoundBrackets then exit;
+  '"':
+    if not SkipApostroph then exit;
+  else
+    while (p<=l) do
+    begin
+      case aValue[p] of
+      ' ',#9,#10,#13,',',';',')','{','}': break;
+      '(':
+        if not SkipRoundBrackets then exit;
+      '"':
+        if not SkipApostroph then exit;
+      end;
+      inc(p);
+    end;
+  end;
+  Result:=copy(aValue,StartP,p-StartP);
+end;
+
+function TFresnelElement.CSSReadNextToken(const aValue: string; var p: integer
+  ): string;
+var
+  l: SizeInt;
+  StartP: Integer;
+begin
+  Result:='';
+  l:=length(aValue);
   while (p<=l) and (aValue[p] in [' ',#9,#10,#13]) do inc(p);
   while (p<=l) and (aValue[p] in [' ',#9,#10,#13]) do inc(p);
+  if p>l then exit;
   StartP:=p;
   StartP:=p;
-  while (p<=l) and not (aValue[p] in [' ',#9,#10,#13]) do inc(p);
+  case aValue[p] of
+  ',',';','(',')','{','}':
+    begin
+      Result:=aValue[p];
+      inc(p);
+      exit;
+    end;
+  '"':
+    begin
+      inc(p);
+      while (p<=l) and (aValue[p]<>'"') do inc(p);
+      if p>l then
+        exit; // missing apostroph
+      inc(p);
+    end;
+  else
+    while (p<=l) do
+    begin
+      case aValue[p] of
+      ' ',#9,#10,#13,',',';','(',')','"','{','}': break;
+      end;
+      inc(p);
+    end;
+  end;
   Result:=copy(aValue,StartP,p-StartP);
   Result:=copy(aValue,StartP,p-StartP);
 end;
 end;
 
 
@@ -3481,6 +3681,99 @@ begin
   Result:=true;
   Result:=true;
 end;
 end;
 
 
+function TFresnelElement.GetRenderedCSSImage(Attr: TFresnelCSSAttribute
+  ): TFresnelCSSImage;
+var
+  p: Integer;
+  s, aValue: String;
+begin
+  Result:=nil;
+  aValue:=GetRenderedCSString(Attr,false);
+  if aValue='' then exit;
+  p:=1;
+  s:=CSSReadNextToken(aValue,p);
+  case s of
+  'linear-gradient':
+    Result:=GetRenderedCSSLinearGradient(copy(aValue,p,length(aValue)));
+  end;
+end;
+
+function TFresnelElement.GetRenderedCSSLinearGradient(const LGParams: string
+  ): TFresnelCSSImageLinearGradient;
+// For example:
+// linear-gradient(red, orange, yellow, green, blue);
+// linear-gradient(red 0%, orange 25%, yellow 50%, green 75%, blue 100%);
+// linear-gradient(red 10%, 30%, blue 90%);
+// linear-gradient(red, orange 10% 30%, yellow 50% 70%, green 90%);
+// linear-gradient(red 0%, orange 10% 30%, yellow 50% 70%, green 90% 100%);
+// linear-gradient(45deg, blue, red)
+// linear-gradient(to left top, blue, red)
+// linear-gradient(in oklab, blue, red)
+var
+  p, ColorCnt, i: Integer;
+  s: String;
+  aColor: TFPColor;
+begin
+  Result:=TFresnelCSSImageLinearGradient.Create;
+  p:=1;
+  s:=CSSReadNextToken(LGParams,p);
+  if s<>'(' then exit;
+  ColorCnt:=0;
+  repeat
+    s:=CSSReadNextToken(LGParams,p);
+    case s of
+    ')':
+      exit;
+    // todo 'to'
+    // todo angle
+    // todo percentage, e.g. linear-gradient(red 10%, 30%, blue 90%);
+    else
+      if not CSSToFPColor(s,aColor) then
+        break;
+      inc(ColorCnt);
+      SetLength(Result.Colors,ColorCnt);
+      Result.Colors[ColorCnt-1].Color:=aColor;
+      if ColorCnt=1 then
+        Result.Colors[ColorCnt-1].Percentage:=0
+      else
+        Result.Colors[ColorCnt-1].Percentage:=-1;
+
+      s:=CSSReadNextToken(LGParams,p);
+      case s of
+      ',':
+        continue;
+      // todo percentages and lengths
+      ')':
+        break;
+      else
+        break;
+      end;
+    end;
+  until false;
+
+  if ColorCnt=0 then
+  begin
+    // missing params
+    FreeAndNil(Result);
+    exit;
+  end;
+
+  if (ColorCnt>1) and (Result.Colors[ColorCnt-1].Percentage<0) then
+    Result.Colors[ColorCnt-1].Percentage:=100;
+
+  for i:=1 to ColorCnt-2 do
+  begin
+    // todo: percentage without color: mix colors from neighbours
+    // todo: check for monoton percentages
+    if Result.Colors[i].Percentage<0 then
+    begin
+      Result.Colors[i].Percentage:=TFresnelLength(i)/(ColorCnt-1);
+    end;
+  end;
+  //for i:=0 to ColorCnt-1 do
+  //  writeln('TFresnelElement.GetRenderedCSSLinearGradient ',GetPath,' ',i,' ',dbgs(Result.Colors[i].Color),' ',Result.Colors[i].Percentage);
+end;
+
 function TFresnelElement.AddEventListener(aID: TEventID; aHandler: TFresnelEventHandler): Integer;
 function TFresnelElement.AddEventListener(aID: TEventID; aHandler: TFresnelEventHandler): Integer;
 begin
 begin
   Result:=EventDispatcher.RegisterHandler(aHandler,aID).ID;
   Result:=EventDispatcher.RegisterHandler(aHandler,aID).ID;
@@ -4217,6 +4510,8 @@ begin
     fcaVisibility: Result:=CheckCSSVisibility(s);
     fcaVisibility: Result:=CheckCSSVisibility(s);
     fcaBackground: Result:=CheckOrSetCSSBackground(s,true);
     fcaBackground: Result:=CheckOrSetCSSBackground(s,true);
     fcaBackgroundColor: Result:=CheckCSSBackgroundColor(s);
     fcaBackgroundColor: Result:=CheckCSSBackgroundColor(s);
+    fcaBackgroundImage: Result:=CheckCSSBackgroundImage(s);
+    fcaBackgroundOrigin: Result:=CheckCSSBackgroundOrigin(s);
     fcaColor: Result:=CheckCSSColor(s);
     fcaColor: Result:=CheckCSSColor(s);
     fcaCursor: Result:=CheckCSSCursor(s);
     fcaCursor: Result:=CheckCSSCursor(s);
     end;
     end;

+ 16 - 0
src/base/fresnel.renderer.pas

@@ -18,13 +18,18 @@ type
     FSubPixel: boolean;
     FSubPixel: boolean;
   protected
   protected
     type
     type
+
+      { TBorderAndBackground }
+
       TBorderAndBackground = class
       TBorderAndBackground = class
       public
       public
         Box: TFresnelRect;
         Box: TFresnelRect;
         Width: array[TFresnelCSSSide] of TFresnelLength;
         Width: array[TFresnelCSSSide] of TFresnelLength;
         BackgroundColorFP: TFPColor;
         BackgroundColorFP: TFPColor;
+        BackgroundImage: TFresnelCSSImage;
         Color: array[TFresnelCSSSide] of TFPColor;
         Color: array[TFresnelCSSSide] of TFPColor;
         Radius: array[TFresnelCSSCorner] of TFresnelPoint;
         Radius: array[TFresnelCSSCorner] of TFresnelPoint;
+        destructor Destroy; override;
       end;
       end;
   protected
   protected
     FOrigin: TFresnelPoint;
     FOrigin: TFresnelPoint;
@@ -180,6 +185,9 @@ begin
         BorderParams.Color[s]:=colTransparent;
         BorderParams.Color[s]:=colTransparent;
     end;
     end;
 
 
+    // border-image
+    BorderParams.BackgroundImage:=El.GetRenderedCSSImage(fcaBackgroundImage);
+
     // border-radius
     // border-radius
     for Corner in TFresnelCSSCorner do
     for Corner in TFresnelCSSCorner do
       BorderParams.Radius[Corner]:=El.GetRenderedCSSBorderRadius(Corner);
       BorderParams.Radius[Corner]:=El.GetRenderedCSSBorderRadius(Corner);
@@ -257,5 +265,13 @@ begin
   DrawChildren(Viewport);
   DrawChildren(Viewport);
 end;
 end;
 
 
+{ TFresnelRenderer.TBorderAndBackground }
+
+destructor TFresnelRenderer.TBorderAndBackground.Destroy;
+begin
+  FreeAndNil(BackgroundImage);
+  inherited Destroy;
+end;
+
 end.
 end.
 
 

+ 55 - 16
src/skia/fresnel.skiarenderer.pas

@@ -113,6 +113,8 @@ type
     FCanvas: ISkCanvas;
     FCanvas: ISkCanvas;
     class constructor InitSkiaRenderer;
     class constructor InitSkiaRenderer;
   protected
   protected
+    procedure DrawElBackground(El: TFresnelElement; Params: TBorderAndBackground;
+      HasRadius: boolean; const Radii: TSkRoundRectRadii); virtual;
     procedure DrawElBorder(El: TFresnelElement; Params: TBorderAndBackground); override;
     procedure DrawElBorder(El: TFresnelElement; Params: TBorderAndBackground); override;
     procedure DrawImage(const aLeft, aTop, aWidth, aHeight: TFresnelLength;
     procedure DrawImage(const aLeft, aTop, aWidth, aHeight: TFresnelLength;
       const aImage: TFPCustomImage); override;
       const aImage: TFPCustomImage); override;
@@ -547,6 +549,57 @@ begin
   ImagesConfig.ImageClass := TFresnelSkiaFPImage;
   ImagesConfig.ImageClass := TFresnelSkiaFPImage;
 end;
 end;
 
 
+procedure TFresnelSkiaRenderer.DrawElBackground(El: TFresnelElement;
+  Params: TBorderAndBackground; HasRadius: boolean;
+  const Radii: TSkRoundRectRadii);
+var
+  r: TRectF;
+  LinGrad: TFresnelCSSImageLinearGradient;
+  StartP, EndP: TPointF;
+  Color1, Color2: TAlphaColor;
+  Shader: ISkShader;
+  SkPaint: ISkPaint;
+  Oval: ISkRoundRect;
+begin
+  if El=nil then ;
+
+  r:=RectF(0,0,Params.Box.Width,Params.Box.Height);
+  r.Offset(Params.Box.Left+Origin.X,Params.Box.Top+Origin.Y);
+
+  if Params.BackgroundImage is TFresnelCSSImageLinearGradient then
+  begin
+    // draw linear gradient background
+    LinGrad:=TFresnelCSSImageLinearGradient(Params.BackgroundImage);
+    StartP:=Pointf(r.Left,r.Top);
+    EndP:=Pointf(r.Left,r.Bottom);
+    Color1:=FPColorToSkia(LinGrad.Colors[0].Color);
+    if length(LinGrad.Colors)=1 then
+      Color2:=Color1
+    else
+      Color2:=FPColorToSkia(LinGrad.Colors[1].Color);
+    SkPaint:=TSkPaint.Create(TSkPaintStyle.Fill);
+    Shader:=TSkShader.MakeGradientLinear(StartP,EndP,Color1,Color2);
+    SkPaint.Shader:=Shader;
+
+  end else if Params.BackgroundColorFP.Alpha>alphaTransparent then
+  begin
+    // draw background color
+    SkPaint:=TSkPaint.Create(TSkPaintStyle.Fill);
+    SkPaint.setColor(FPColorToSkia(Params.BackgroundColorFP));
+    SkPaint.SetAntiAlias(true);
+  end else
+    exit;
+
+  if HasRadius then
+  begin
+    Oval:=TSkRoundRect.Create;
+    Oval.SetRect(r,Radii);
+    Canvas.DrawRoundRect(Oval, SkPaint);
+  end else begin
+    Canvas.DrawRect(r, SkPaint);
+  end;
+end;
+
 procedure TFresnelSkiaRenderer.DrawElBorder(El: TFresnelElement;
 procedure TFresnelSkiaRenderer.DrawElBorder(El: TFresnelElement;
   Params: TBorderAndBackground);
   Params: TBorderAndBackground);
 const
 const
@@ -569,9 +622,9 @@ var
   Corner: TFresnelCSSCorner;
   Corner: TFresnelCSSCorner;
   Radii: TSkRoundRectRadii;
   Radii: TSkRoundRectRadii;
   SkPaint: ISkPaint;
   SkPaint: ISkPaint;
-  Oval: ISkRoundRect;
   SkCorner: TSkRoundRectCorner;
   SkCorner: TSkRoundRectCorner;
   Side: TFresnelCSSSide;
   Side: TFresnelCSSSide;
+  Oval: ISkRoundRect;
 begin
 begin
   if El=nil then ;
   if El=nil then ;
 
 
@@ -624,21 +677,7 @@ begin
   r.Offset(Params.Box.Left+Origin.X,Params.Box.Top+Origin.Y);
   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);
   //writeln('TFresnelSkiaRenderer.DrawElBorder ',El.GetPath,' Box=',Params.Box.ToString,' Origin=',Origin.ToString,' r=',r.Left,',',r.Top,',',r.Right,',',r.Bottom);
 
 
-  // draw background color
-  if Params.BackgroundColorFP.Alpha>alphaTransparent then
-  begin
-    SkPaint:=TSkPaint.Create(TSkPaintStyle.Fill);
-    SkPaint.setColor(FPColorToSkia(Params.BackgroundColorFP));
-    SkPaint.SetAntiAlias(true);
-    if HasRadius then
-    begin
-      Oval:=TSkRoundRect.Create;
-      Oval.SetRect(r,Radii);
-      Canvas.DrawRoundRect(Oval, SkPaint);
-    end else begin
-      Canvas.DrawRect(r, SkPaint);
-    end;
-  end;
+  DrawElBackground(El,Params,HasRadius,Radii);
 
 
   // draw border
   // draw border
   if HasBorder then
   if HasBorder then