mattias 1 год назад
Родитель
Сommit
bdb0a7301e
3 измененных файлов с 151 добавлено и 5 удалено
  1. 0 1
      src/base/fresnel.controls.pas
  2. 7 1
      src/base/fresnel.renderer.pas
  3. 144 3
      src/skia/fresnel.skiarenderer.pas

+ 0 - 1
src/base/fresnel.controls.pas

@@ -160,7 +160,6 @@ type
     procedure DoRender(aRenderer: IFresnelRenderer); override;
   Public
     constructor Create(AOwner: TComponent); override;
-
     destructor Destroy; override;
     function GetCSSInitialAttribute(const AttrID: TCSSNumericalID): TCSSString; override;
     Property Image : TImageData Read FImage Write SetImage;

+ 7 - 1
src/base/fresnel.renderer.pas

@@ -160,15 +160,19 @@ begin
     BorderParams.Box:=El.RenderedBorderBox;
     if not SubPixel then
       MathRoundRect(BorderParams.Box);
+
+    // border-width
     BorderParams.Width[ffsLeft]:=aBorderLeft;
     BorderParams.Width[ffsTop]:=aBorderTop;
     BorderParams.Width[ffsRight]:=aBorderRight;
     BorderParams.Width[ffsBottom]:=aBorderBottom;
 
+    // background-color
     aBackgroundColor:=El.CSSRenderedAttribute[fcaBackgroundColor];
     if not CSSToFPColor(aBackgroundColor,BorderParams.BackgroundColorFP) then
       BorderParams.BackgroundColorFP:=colTransparent;
 
+    // border-color
     for s in TFresnelCSSSide do
     begin
       aBorderColor:=El.CSSRenderedAttribute[TFresnelCSSAttribute(ord(fcaBorderLeftColor)+ord(s))];
@@ -176,6 +180,7 @@ begin
         BorderParams.Color[s]:=colTransparent;
     end;
 
+    // border-radius
     for Corner in TFresnelCSSCorner do
       BorderParams.Radius[Corner]:=El.GetRenderedCSSBorderRadius(Corner);
 
@@ -183,12 +188,13 @@ begin
   finally
     BorderParams.Free;
   end;
+
   // Give element a chance to draw itself.
   aRenderable.Render(Self as IFresnelRenderer);
 
   DrawChildren(El);
 
-  aRenderable.BeforeRender;
+  aRenderable.AfterRender;
 end;
 
 procedure TFresnelRenderer.DrawChildren(El: TFresnelElement);

+ 144 - 3
src/skia/fresnel.skiarenderer.pas

@@ -10,7 +10,7 @@ uses
   dynlibs,
   {$ENDIF}
   AVL_Tree, FpImage, System.UITypes,
-  System.Skia, Fresnel.Classes, Fresnel.DOM, Fresnel.Renderer;
+  System.Skia, Fresnel.Classes, Fresnel.DOM, Fresnel.Renderer, Fresnel.Images;
 
 const
   CSSToSkRoundRectCorner: array[TFresnelCSSCorner] of TSkRoundRectCorner = (
@@ -86,11 +86,32 @@ type
     class function GetFont(const FontIntf: IFresnelFont; out FreSkiaFont: TFresnelSkiaFont): boolean; virtual;
   end;
 
+  { TFresnelSkiaFPImage }
+
+  TFresnelSkiaFPImage = class(TFPCustomImage)
+  protected
+    FBytesPerLine: PtrUInt;
+    FData: PByte;
+    FDataSize: PtrUInt;
+    FSkImage: ISkImage;
+    function GetInternalColor(x, y: integer): TFPColor; override;
+    procedure SetInternalColor(x, y: integer; const Value: TFPColor); override;
+    function GetInternalPixel(x, y: integer): integer; override;
+    procedure SetInternalPixel(x, y: integer; Value: integer); override;
+    function GetSkImage: ISkImage; virtual;
+  public
+    constructor Create(AWidth, AHeight: integer); override;
+    destructor Destroy; override;
+    procedure SetSize(AWidth, AHeight: integer); override;
+    property SkImage: ISkImage read GetSkImage;
+  end;
+
   { TFresnelSkiaRenderer - one instance per viewport }
 
   TFresnelSkiaRenderer = class(TFresnelRenderer)
   private
     FCanvas: ISkCanvas;
+    class constructor InitSkiaRenderer;
   protected
     procedure DrawElBorder(El: TFresnelElement; Params: TBorderAndBackground); override;
     procedure DrawImage(const aLeft, aTop, aWidth, aHeight: TFresnelLength;
@@ -417,8 +438,113 @@ begin
   end;
 end;
 
+{ TFresnelSkiaFPImage }
+
+function TFresnelSkiaFPImage.GetSkImage: ISkImage;
+begin
+  if (FSkImage=nil) and (FData<>nil) then
+    FSkImage:=TSkImage.MakeFromRaster(TSkImageInfo.Create(Width, Height),FData,FBytesPerLine);
+  Result:=FSkImage;
+end;
+
+function TFresnelSkiaFPImage.GetInternalColor(x, y: integer): TFPColor;
+var
+  p: PByte;
+  v: DWORD;
+  c: word;
+begin
+  if (x>=0) and (y>=0) and (x<Width) and (y<Height) then
+  begin
+    p:=FData+FBytesPerLine*y+x*4;
+    v:=PDWord(p)^; // reading a DWord solves the big/little endianess
+    c:=v and $ff;
+    Result.Blue:=c or (c shl 8);
+    v:=v shr 8;
+    c:=v and $ff;
+    Result.Green:=c or (c shl 8);
+    v:=v shr 8;
+    c:=v and $ff;
+    Result.Red:=c or (c shl 8);
+    v:=v shr 8;
+    Result.Alpha:=c or (c shl 8);
+  end else begin
+    Result:=colBlack;
+  end;
+end;
+
+procedure TFresnelSkiaFPImage.SetInternalColor(x, y: integer;
+  const Value: TFPColor);
+var
+  p: PByte;
+  v: DWord;
+begin
+  if (x>=0) and (y>=0) and (x<Width) and (y<Height) then
+  begin
+    v:=Value.Alpha shr 8;
+    v:=v shl 8;
+    v:=v or Value.Red shr 8;
+    v:=v shl 8;
+    v:=v or Value.Green shr 8;
+    v:=v shl 8;
+    v:=v or Value.Blue shr 8;
+    p:=FData+FBytesPerLine*y+x*4;
+    PDWord(p)^:=v; // writing a DWord solves the big/little endianess
+  end;
+end;
+
+function TFresnelSkiaFPImage.GetInternalPixel(x, y: integer): integer;
+begin
+  if x=0 then exit;
+  if y=0 then exit;
+  Result:=0;
+end;
+
+procedure TFresnelSkiaFPImage.SetInternalPixel(x, y: integer; Value: integer);
+begin
+  if x=0 then exit;
+  if y=0 then exit;
+  if Value=0 then exit;
+end;
+
+constructor TFresnelSkiaFPImage.Create(AWidth, AHeight: integer);
+begin
+  inherited Create(AWidth,AHeight);
+end;
+
+destructor TFresnelSkiaFPImage.Destroy;
+begin
+  inherited Destroy;
+end;
+
+procedure TFresnelSkiaFPImage.SetSize(AWidth, AHeight: integer);
+begin
+  AWidth:=Max(0,AWidth);
+  AHeight:=Max(0,AHeight);
+  if (Width=AWidth) and (Height=AHeight) then exit;
+
+  case SkNative32ColorType of
+  TSkColorType.BGRA8888: ;
+  TSkColorType.RGBA8888: ;
+  else
+    raise EFresnel.Create('TFresnelSkiaFPImage.Resize SkNative32ColorType not supported: '+IntToStr(ord(SkNative32ColorType)));
+  end;
+
+  FSkImage:=nil;
+
+  inherited SetSize(AWidth, AHeight);
+
+  FBytesPerLine:=AWidth*4;
+  FDataSize:=FBytesPerLine*AHeight;
+  ReAllocMem(FData,FDataSize);
+end;
+
 { TFresnelSkiaRenderer }
 
+class constructor TFresnelSkiaRenderer.InitSkiaRenderer;
+begin
+  ImagesConfig.ImageClass := TFresnelSkiaFPImage;
+end;
+
 procedure TFresnelSkiaRenderer.DrawElBorder(El: TFresnelElement;
   Params: TBorderAndBackground);
 const
@@ -515,7 +641,7 @@ begin
   // draw border
   if HasBorder then
   begin
-    // todo border-right
+    if not SameBorderWidth then ; // todo
     SkPaint:=TSkPaint.Create(TSkPaintStyle.Stroke);
     SkPaint.setColor(FPColorToSkia(Params.Color[ffsLeft]));
     SkPaint.SetStrokeWidth(Params.Width[ffsLeft]);
@@ -533,8 +659,23 @@ end;
 
 procedure TFresnelSkiaRenderer.DrawImage(const aLeft, aTop, aWidth,
   aHeight: TFresnelLength; const aImage: TFPCustomImage);
+var
+  SkiaImg: TFresnelSkiaFPImage;
+  SkImage: ISkImage;
+  r: TRectF;
 begin
-  writeln('ToDo: TFresnelSkiaRenderer.DrawImage ',aLeft,' ',aTop,' ',aWidth,' ',aHeight,' ',aImage<>nil);
+  if not (aImage is TFresnelSkiaFPImage) then
+  begin
+    if aImage=nil then exit;;
+    raise EFresnel.Create('TFresnelSkiaRenderer.DrawImage not supported: '+aImage.ClassName);
+  end;
+  //writeln('TFresnelSkiaRenderer.DrawImage ',FloatToStr(aLeft),' ',FloatToStr(aTop),' ',FloatToStr(aWidth),' ',FloatToStr(aHeight));
+  SkiaImg:=TFresnelSkiaFPImage(aImage);
+  SkImage:=SkiaImg.SkImage;
+  if SkImage=nil then exit;
+
+  r:=RectF(aLeft,aTop,aLeft+aWidth,aTop+aHeight);
+  Canvas.DrawImageRect(SkImage,r);
 end;
 
 procedure TFresnelSkiaRenderer.FillRect(const aColor: TFPColor;