Ignore:
Timestamp:
Apr 17, 2019, 12:58:41 AM (5 years ago)
Author:
chronos
Message:
  • Modified: Propagate project build mode options to used packages.
  • Added: Check memory leaks using heaptrc.
  • Modified: Update BGRABitmap package.
Location:
GraphicTest
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • GraphicTest

    • Property svn:ignore
      •  

        old new  
        88GraphicTest.lps
        99GraphicTest.dbg
         10heaptrclog.trc
  • GraphicTest/Packages/bgrabitmap/bgrasvg.pas

    r494 r521  
    77uses
    88  Classes, SysUtils, BGRABitmapTypes, laz2_DOM, BGRAUnits, BGRASVGShapes,
    9   BGRACanvas2D;
     9  BGRACanvas2D, BGRASVGType, FPimage;
     10
     11type
     12  TCSSUnit = BGRAUnits.TCSSUnit;
     13
     14const
     15  cuCustom = BGRAUnits.cuCustom;
     16  cuPixel = BGRAUnits.cuPixel;
     17  cuCentimeter = BGRAUnits.cuCentimeter;
     18  cuMillimeter = BGRAUnits.cuMillimeter;
     19  cuInch = BGRAUnits.cuInch;
     20  cuPica = BGRAUnits.cuPica;
     21  cuPoint = BGRAUnits.cuPoint;
     22  cuFontEmHeight = BGRAUnits.cuFontEmHeight;
     23  cuFontXHeight = BGRAUnits.cuFontXHeight;
     24  cuPercent = BGRAUnits.cuPercent;
    1025
    1126type
     
    2136  TSVGUnits = class(TCSSUnitConverter)
    2237  private
     38    FOnRecompute: TSVGRecomputeEvent;
     39    FViewOffset: TPointF;
    2340    function GetCustomDpi: TPointF;
    2441    procedure Recompute;
     42    procedure SetOnRecompute(AValue: TSVGRecomputeEvent);
    2543  protected
    2644    FSvg: TDOMElement;
    2745    FViewBox: TSVGViewBox;
    28     FViewSize: TSVGSize;
     46    FOriginalViewSize, FProportionalViewSize: TSVGSize;
     47
    2948    FDefaultUnitHeight, FDefaultUnitWidth: TFloatWithCSSUnit;
    3049    FDefaultDpi: PSingle;
    3150    FUseDefaultDPI: boolean;
    3251    FDpiScaleX,FDpiScaleY: single;
     52    FContainerHeight: TFloatWithCSSUnit;
     53    FContainerWidth: TFloatWithCSSUnit;
     54    procedure SetContainerHeight(AValue: TFloatWithCSSUnit);
     55    procedure SetContainerWidth(AValue: TFloatWithCSSUnit);
    3356    function GetDefaultUnitHeight: TFloatWithCSSUnit; override;
    3457    function GetDefaultUnitWidth: TFloatWithCSSUnit; override;
     
    4770    procedure SetDefaultDpiAndOrigin;
    4871    constructor Create(ASvg: TDOMElement; ADefaultDpi: PSingle);
     72    function GetStretchRectF(AViewSize: TRectF; par: TSVGPreserveAspectRatio): TRectF;
    4973    property ViewBox: TSVGViewBox read FViewBox write SetViewBox;
     74    property OriginalViewSize: TSVGSize read FOriginalViewSize;
     75    property ProportionalViewSize: TSVGSize read FProportionalViewSize;
     76    property ViewOffset: TPointF read FViewOffset;
    5077    property CustomOrigin: TPointF read GetCustomOrigin write SetCustomOrigin;
    5178    property CustomDpiX: single read GetCustomDpiX;
    5279    property CustomDpiY: single read GetCustomDpiY;
    5380    property CustomDpi: TPointF read GetCustomDpi write SetCustomDpi;
     81    property ContainerWidth: TFloatWithCSSUnit read FContainerWidth write SetContainerWidth;
     82    property ContainerHeight: TFloatWithCSSUnit read FContainerHeight write SetContainerHeight;
     83    property OnRecompute: TSVGRecomputeEvent read FOnRecompute write SetOnRecompute;
    5484  end;
    5585
     
    5888  TBGRASVG = class
    5989  private
    60     function GetAttribute(AName: string): string;
     90    function GetAttribute(AName: string): string; overload;
     91    function GetAttribute(AName: string; ADefault: string): string; overload;
    6192    function GetCustomDpi: TPointF;
    6293    function GetHeight: TFloatWithCSSUnit;
    6394    function GetHeightAsCm: single;
    6495    function GetHeightAsInch: single;
    65     function GetPreserveAspectRatio: string;
    66     function GetViewBox: TSVGViewBox;
    67     function GetViewBox(AUnit: TCSSUnit): TSVGViewBox;
     96    function GetPreserveAspectRatio: TSVGPreserveAspectRatio;
     97    function GetUTF8String: utf8string;
     98    function GetViewBox: TSVGViewBox; overload;
     99    function GetViewBox(AUnit: TCSSUnit): TSVGViewBox; overload;
    68100    procedure GetViewBoxIndirect(AUnit: TCSSUnit; out AViewBox: TSVGViewBox);
     101    function GetViewMin(AUnit: TCSSUnit): TPointF;
     102    function GetViewSize(AUnit: TCSSUnit): TPointF;
    69103    function GetWidth: TFloatWithCSSUnit;
    70104    function GetWidthAsCm: single;
     
    77111    procedure SetHeightAsCm(AValue: single);
    78112    procedure SetHeightAsInch(AValue: single);
    79     procedure SetPreserveAspectRatio(AValue: string);
     113    procedure SetPreserveAspectRatio(AValue: TSVGPreserveAspectRatio);
     114    procedure SetUTF8String(AValue: utf8string);
    80115    procedure SetViewBox(AValue: TSVGViewBox);
    81116    procedure SetWidth(AValue: TFloatWithCSSUnit);
     
    89124    FDefaultDpi: single;
    90125    FContent: TSVGContent;
     126    FDataLink: TSVGDataLink;
    91127    procedure Init(ACreateEmpty: boolean);
    92128    function GetViewBoxAlignment(AHorizAlign: TAlignment; AVertAlign: TTextLayout): TPointF;
     129    procedure UnitsRecompute(Sender: TObject);
    93130  public
    94131    constructor Create; overload;
     
    97134    constructor Create(AFilenameUTF8: string); overload;
    98135    constructor Create(AStream: TStream); overload;
     136    constructor CreateFromString(AUTF8String: string);
    99137    destructor Destroy; override;
    100138    procedure LoadFromFile(AFilenameUTF8: string);
    101139    procedure LoadFromStream(AStream: TStream);
     140    procedure LoadFromResource(AFilename: string);
    102141    procedure SaveToFile(AFilenameUTF8: string);
    103142    procedure SaveToStream(AStream: TStream);
     
    108147    procedure Draw(ACanvas2d: TBGRACanvas2D; x,y: single; destDpi: single); overload;
    109148    procedure Draw(ACanvas2d: TBGRACanvas2D; x,y: single; destDpi: TPointF); overload;
    110     procedure StretchDraw(ACanvas2d: TBGRACanvas2D; x,y,w,h: single); overload;
     149    procedure StretchDraw(ACanvas2d: TBGRACanvas2D; x,y,w,h: single; useSvgAspectRatio: boolean = false); overload;
     150    procedure StretchDraw(ACanvas2d: TBGRACanvas2D; r: TRectF; useSvgAspectRatio: boolean = false); overload;
    111151    procedure StretchDraw(ACanvas2d: TBGRACanvas2D; AHorizAlign: TAlignment; AVertAlign: TTextLayout; x,y,w,h: single); overload;
     152    function GetStretchRectF(AHorizAlign: TAlignment; AVertAlign: TTextLayout; x,y,w,h: single): TRectF;
     153    property AsUTF8String: utf8string read GetUTF8String write SetUTF8String;
    112154    property Units: TSVGUnits read FUnits;
    113155    property Width: TFloatWithCSSUnit read GetWidth write SetWidth;
     
    120162    property ViewBox: TSVGViewBox read GetViewBox write SetViewBox;
    121163    property ViewBoxInUnit[AUnit: TCSSUnit]: TSVGViewBox read GetViewBox;
     164    property ViewMinInUnit[AUnit: TCSSUnit]: TPointF read GetViewMin;
     165    property ViewSizeInUnit[AUnit: TCSSUnit]: TPointF read GetViewSize;
    122166    property Attribute[AName: string]: string read GetAttribute write SetAttribute;
     167    property AttributeDef[AName: string; ADefault: string]: string read GetAttribute;
    123168    property DefaultDpi: single read FDefaultDpi write SetDefaultDpi; //this is not saved in the SVG file
    124169    property CustomDpi: TPointF read GetCustomDpi write SetCustomDpi;
    125170    property Content: TSVGContent read FContent;
    126     property preserveAspectRatio: string read GetPreserveAspectRatio write SetPreserveAspectRatio;
    127   end;
     171    property DataLink: TSVGDataLink read FDataLink;//(for test or internal info)
     172    property preserveAspectRatio: TSVGPreserveAspectRatio read GetPreserveAspectRatio write SetPreserveAspectRatio;
     173  end;
     174
     175  { TFPReaderSVG }
     176
     177  TFPReaderSVG = class(TBGRAImageReader)
     178    private
     179      FRenderDpi: single;
     180      FWidth,FHeight: integer;
     181      FScale: single;
     182    protected
     183      function InternalCheck(Stream: TStream): boolean; override;
     184      procedure InternalRead(Stream: TStream; Img: TFPCustomImage); override;
     185    public
     186      constructor Create; override;
     187      function GetQuickInfo(AStream: TStream): TQuickImageInfo; override;
     188      function GetBitmapDraft(AStream: TStream; AMaxWidth, AMaxHeight: integer; out AOriginalWidth,AOriginalHeight: integer): TBGRACustomBitmap; override;
     189      property RenderDpi: single read FRenderDpi write FRenderDpi;
     190      property Width: integer read FWidth;
     191      property Height: integer read FHeight;
     192      property Scale: single read FScale write FScale;
     193  end;
     194
     195procedure RegisterSvgFormat;
    128196
    129197implementation
    130198
    131 uses laz2_XMLRead, laz2_XMLWrite, BGRAUTF8;
     199uses laz2_XMLRead, laz2_XMLWrite, BGRAUTF8, math;
    132200
    133201const SvgNamespace = 'http://www.w3.org/2000/svg';
     202
     203{ TFPReaderSVG }
     204
     205function TFPReaderSVG.InternalCheck(Stream: TStream): boolean;
     206var
     207  magic: array[1..6] of char;
     208  prevPos: int64;
     209  count: LongInt;
     210begin
     211  prevPos := Stream.Position;
     212  count := Stream.Read({%H-}magic, sizeof(magic));
     213  Stream.Position:= prevPos;
     214  result:= (count = sizeof(magic)) and (magic = '<?xml ');
     215end;
     216
     217procedure TFPReaderSVG.InternalRead(Stream: TStream; Img: TFPCustomImage);
     218var
     219  svg: TBGRASVG;
     220  vmin,vsize: TPointF;
     221  bgra: TBGRACustomBitmap;
     222  c2d: TBGRACanvas2D;
     223  y, x: Integer;
     224  p: PBGRAPixel;
     225begin
     226  svg := TBGRASVG.Create(Stream);
     227  bgra := nil;
     228  try
     229    svg.DefaultDpi:= RenderDpi;
     230    if Img is TBGRACustomBitmap then
     231      bgra := TBGRACustomBitmap(Img)
     232    else
     233      bgra := BGRABitmapFactory.Create;
     234    vsize := svg.GetViewSize(cuPixel);
     235    bgra.SetSize(ceil(vsize.x*scale),ceil(vsize.y*scale));
     236    bgra.FillTransparent;
     237    vmin := svg.GetViewMin(cuPixel);
     238    c2d := TBGRACanvas2D.Create(bgra);
     239    c2d.scale(Scale);
     240    c2d.translate(-vmin.x,-vmin.y);
     241    svg.Draw(c2d,0,0);
     242    c2d.Free;
     243    if bgra<>Img then
     244    begin
     245      Img.SetSize(bgra.Width,bgra.Height);
     246      for y := 0 to bgra.Height-1 do
     247      begin
     248        p := bgra.ScanLine[y];
     249        for x := 0 to bgra.Width-1 do
     250        begin
     251          Img.Colors[x,y] := BGRAToFPColor(p^);
     252          inc(p);
     253        end;
     254      end;
     255    end;
     256    FWidth:= bgra.Width;
     257    FHeight:= bgra.Height;
     258  finally
     259    if bgra<>Img then bgra.Free;
     260    svg.Free;
     261  end;
     262end;
     263
     264constructor TFPReaderSVG.Create;
     265begin
     266  inherited Create;
     267  FRenderDpi:= 96;
     268  FScale := 1;
     269end;
     270
     271function TFPReaderSVG.GetQuickInfo(AStream: TStream): TQuickImageInfo;
     272var
     273  svg: TBGRASVG;
     274  vsize: TPointF;
     275begin
     276  svg := TBGRASVG.Create(AStream);
     277  svg.DefaultDpi:= RenderDpi;
     278  vsize := svg.GetViewSize(cuPixel);
     279  svg.Free;
     280  result.Width:= ceil(vsize.x);
     281  result.Height:= ceil(vsize.y);
     282  result.AlphaDepth:= 8;
     283  result.ColorDepth:= 24;
     284end;
     285
     286function TFPReaderSVG.GetBitmapDraft(AStream: TStream; AMaxWidth,
     287  AMaxHeight: integer; out AOriginalWidth, AOriginalHeight: integer): TBGRACustomBitmap;
     288var
     289  svg: TBGRASVG;
     290  vmin,vsize: TPointF;
     291  c2d: TBGRACanvas2D;
     292  ratio: Single;
     293begin
     294  svg := TBGRASVG.Create(AStream);
     295  result := nil;
     296  try
     297    svg.DefaultDpi:= RenderDpi;
     298    vsize := svg.GetViewSize(cuPixel);
     299    AOriginalWidth:= ceil(vsize.x);
     300    AOriginalHeight:= ceil(vsize.y);
     301    if (vsize.x = 0) or (vsize.y = 0) then exit;
     302    ratio := min(AMaxWidth/vsize.x, AMaxHeight/vsize.y);
     303    result := BGRABitmapFactory.Create(ceil(vsize.x*ratio),ceil(vsize.y*ratio));
     304    if ratio <> 0 then
     305    begin
     306      vmin := svg.GetViewMin(cuPixel);
     307      c2d := TBGRACanvas2D.Create(result);
     308      c2d.scale(ratio);
     309      c2d.translate(-vmin.x,-vmin.y);
     310      svg.Draw(c2d,0,0);
     311      c2d.Free;
     312    end;
     313  finally
     314    svg.Free;
     315  end;
     316end;
     317
     318var AlreadyRegistered: boolean;
     319
     320procedure RegisterSvgFormat;
     321begin
     322  if AlreadyRegistered then exit;
     323  ImageHandlers.RegisterImageReader ('Scalable Vector Graphic', 'svg', TFPReaderSVG);
     324  AlreadyRegistered:= True;
     325end;
    134326
    135327function TSVGUnits.GetCustomDpiX: single;
    136328var pixSize: single;
    137329begin
    138   pixSize := Convert(FDefaultUnitWidth.value,FDefaultUnitWidth.CSSUnit,cuInch,FDefaultDpi^);
     330  with GetDefaultUnitWidth do
     331    pixSize := Convert(value,CSSUnit,cuInch,FDefaultDpi^);
    139332  if pixSize = 0 then
    140333    result := 0
     
    146339var pixSize: single;
    147340begin
    148   pixSize := Convert(FDefaultUnitHeight.value,FDefaultUnitHeight.CSSUnit,cuInch,FDefaultDpi^);
     341  with GetDefaultUnitHeight do
     342    pixSize := Convert(value,CSSUnit,cuInch,FDefaultDpi^);
    149343  if pixSize = 0 then
    150344    result := 0
     
    194388  FViewBox.size.y := parseNextFloat;
    195389
    196   FViewSize.width := parseValue(FSvg.GetAttribute('width'), FloatWithCSSUnit(FViewBox.size.x, cuPixel));
    197   if FViewSize.width.CSSUnit = cuCustom then FViewSize.width.CSSUnit := cuPixel;
    198   FViewSize.height := parseValue(FSvg.GetAttribute('height'), FloatWithCSSUnit(FViewBox.size.y, cuPixel));
    199   if FViewSize.height.CSSUnit = cuCustom then FViewSize.height.CSSUnit := cuPixel;
     390  FOriginalViewSize.width := parseValue(FSvg.GetAttribute('width'), FloatWithCSSUnit(FViewBox.size.x, cuPixel));
     391  if FOriginalViewSize.width.CSSUnit = cuCustom then FOriginalViewSize.width.CSSUnit := cuPixel;
     392  if FOriginalViewSize.width.CSSUnit = cuPercent then
     393  begin
     394    FOriginalViewSize.width.value := FOriginalViewSize.width.value/100*FContainerWidth.value;
     395    FOriginalViewSize.width.CSSUnit := FContainerWidth.CSSUnit;
     396  end;
     397  FOriginalViewSize.height := parseValue(FSvg.GetAttribute('height'), FloatWithCSSUnit(FViewBox.size.y, cuPixel));
     398  if FOriginalViewSize.height.CSSUnit = cuCustom then FOriginalViewSize.height.CSSUnit := cuPixel;
     399  if FOriginalViewSize.height.CSSUnit = cuPercent then
     400  begin
     401    FOriginalViewSize.height.value := FOriginalViewSize.height.value/100*FContainerHeight.value;
     402    FOriginalViewSize.height.CSSUnit := FContainerHeight.CSSUnit;
     403  end;
     404  if FOriginalViewSize.height.CSSUnit <> FOriginalViewSize.width.CSSUnit then
     405    FOriginalViewSize.height := ConvertHeight(FOriginalViewSize.height, FOriginalViewSize.width.CSSUnit);
     406
     407  FProportionalViewSize := FOriginalViewSize;
     408  with GetStretchRectF(RectF(0,0,FOriginalViewSize.width.value,FOriginalViewSize.height.value), TSVGPreserveAspectRatio.DefaultValue) do
     409  begin
     410    FProportionalViewSize.width.value := Right-Left;
     411    FProportionalViewSize.height.value := Bottom-Top;
     412  end;
    200413
    201414  if (FViewBox.size.x <= 0) and (FViewBox.size.y <= 0) then
     
    209422      FDpiScaleY := 1;
    210423      FViewBox.min := PointF(0,0);
    211       FViewBox.size.x := ConvertWidth(FViewSize.width,cuCustom).value;
    212       FViewBox.size.y := ConvertHeight(FViewSize.height,cuCustom).value;
     424      FViewBox.size.x := ConvertWidth(FProportionalViewSize.width,cuCustom).value;
     425      FViewBox.size.y := ConvertHeight(FProportionalViewSize.height,cuCustom).value;
    213426    end else
    214427    begin
    215       FDefaultUnitWidth.value := FViewSize.width.value/FViewBox.size.x;
    216       FDefaultUnitWidth.CSSUnit := FViewSize.width.CSSUnit;
     428      FDefaultUnitWidth.value := FProportionalViewSize.width.value/FViewBox.size.x;
     429      FDefaultUnitWidth.CSSUnit := FProportionalViewSize.width.CSSUnit;
    217430      if FDefaultUnitWidth.CSSUnit = cuCustom then
    218431        begin
     
    220433          FDefaultUnitWidth.CSSUnit := cuInch;
    221434        end;
    222       FDefaultUnitHeight.value := FViewSize.height.value/FViewBox.size.y;
    223       FDefaultUnitHeight.CSSUnit := FViewSize.height.CSSUnit;
     435      FDefaultUnitHeight.value := FProportionalViewSize.height.value/FViewBox.size.y;
     436      FDefaultUnitHeight.CSSUnit := FProportionalViewSize.height.CSSUnit;
    224437      if FDefaultUnitHeight.CSSUnit = cuCustom then
    225438        begin
     
    231444      FDpiScaleY := CustomDpiY/DpiY;
    232445    end;
     446
     447  if Assigned(FOnRecompute) then FOnRecompute(self);
     448end;
     449
     450procedure TSVGUnits.SetOnRecompute(AValue: TSVGRecomputeEvent);
     451begin
     452  if FOnRecompute=AValue then Exit;
     453  FOnRecompute:=AValue;
     454end;
     455
     456procedure TSVGUnits.SetContainerHeight(AValue: TFloatWithCSSUnit);
     457begin
     458  if CompareMem(@FContainerHeight,@AValue,sizeof(TFloatWithCSSUnit)) then Exit;
     459  FContainerHeight:=AValue;
     460  Recompute;
     461end;
     462
     463procedure TSVGUnits.SetContainerWidth(AValue: TFloatWithCSSUnit);
     464begin
     465  if CompareMem(@FContainerWidth,@AValue,sizeof(TFloatWithCSSUnit)) then Exit;
     466  FContainerWidth:=AValue;
     467  Recompute;
    233468end;
    234469
     
    238473begin
    239474  vb := ViewBox;
    240   vs := FViewSize;
     475  vs := FProportionalViewSize;
    241476  if (vs.width.value > 0) and (vs.height.value > 0) then
    242477    begin
     
    303538  FSvg := ASvg;
    304539  FDefaultDpi := ADefaultDpi;
     540  FContainerWidth := FloatWithCSSUnit(640,cuPixel);
     541  FContainerHeight := FloatWithCSSUnit(480,cuPixel);
    305542  Recompute;
    306543end;
    307544
     545function TSVGUnits.GetStretchRectF(AViewSize: TRectF; par: TSVGPreserveAspectRatio): TRectF;
     546var w0,h0,w,h: single;
     547begin
     548  result := AViewSize;
     549  w0 := AViewSize.Right-AViewSize.Left;
     550  h0 := AViewSize.Bottom-AViewSize.Top;
     551  w := w0;
     552  h := h0;
     553
     554  if par.Preserve and
     555     (FViewBox.size.x > 0) and (FViewBox.size.y > 0) and
     556     (w > 0) and (h > 0) then
     557  begin
     558    //viewBox wider than viewSize
     559    if (FViewBox.size.x/FViewBox.size.y > w/h) xor par.Slice then
     560      h := w * FViewBox.size.y / FViewBox.size.x
     561    else
     562      w := h * FViewBox.size.x / FViewBox.size.y;
     563    case par.HorizAlign of
     564      taCenter: result.Left += (w0-w)/2;
     565      taRightJustify: result.Left += w0-w;
     566    end;
     567    case par.VertAlign of
     568      tlCenter: result.Top += (h0-h)/2;
     569      tlBottom: result.Top += h0-h;
     570    end;
     571  end;
     572  result.Right := result.Left+w;
     573  result.Bottom := result.Top+h;
     574end;
     575
    308576{ TBGRASVG }
    309577
    310578function TBGRASVG.GetAttribute(AName: string): string;
    311579begin
    312   result := FRoot.GetAttribute(AName);
     580  result := Trim(FRoot.GetAttribute(AName));
     581end;
     582
     583function TBGRASVG.GetAttribute(AName: string; ADefault: string): string;
     584begin
     585  result := GetAttribute(AName);
     586  if result = '' then result := ADefault;
    313587end;
    314588
     
    320594function TBGRASVG.GetHeight: TFloatWithCSSUnit;
    321595begin
    322   result := TCSSUnitConverter.parseValue(Attribute['height'],FloatWithCSSUnit(0,cuCustom));
     596  result := TCSSUnitConverter.parseValue(Attribute['height'],FloatWithCSSUnit(FUnits.ViewBox.size.y,cuCustom));
    323597end;
    324598
     
    333607end;
    334608
    335 function TBGRASVG.GetPreserveAspectRatio: string;
    336 begin
    337   result := Attribute['preserveAspectRatio'];
     609function TBGRASVG.GetPreserveAspectRatio: TSVGPreserveAspectRatio;
     610begin
     611  result := TSVGPreserveAspectRatio.Parse(Attribute['preserveAspectRatio','xMidYMid']);
     612end;
     613
     614function TBGRASVG.GetUTF8String: utf8string;
     615var str: TMemoryStream;
     616begin
     617  str := TMemoryStream.Create;
     618  SaveToStream(str);
     619  setlength(result, str.Size);
     620  str.Position := 0;
     621  str.Read(result[1], length(result));
     622  str.Free;
    338623end;
    339624
     
    357642end;
    358643
     644function TBGRASVG.GetViewMin(AUnit: TCSSUnit): TPointF;
     645var
     646  vb: TSVGViewBox;
     647begin
     648  GetViewBoxIndirect(AUnit,vb);
     649  result:= vb.min;
     650end;
     651
     652function TBGRASVG.GetViewSize(AUnit: TCSSUnit): TPointF;
     653var
     654  vb: TSVGViewBox;
     655begin
     656  GetViewBoxIndirect(AUnit,vb);
     657  result:= vb.size;
     658end;
     659
    359660function TBGRASVG.GetWidth: TFloatWithCSSUnit;
    360661begin
    361   result := TCSSUnitConverter.parseValue(Attribute['width'],FloatWithCSSUnit(0,cuCustom));
     662  result := TCSSUnitConverter.parseValue(Attribute['width'],FloatWithCSSUnit(FUnits.ViewBox.size.x,cuCustom));
    362663end;
    363664
     
    374675function TBGRASVG.GetZoomable: boolean;
    375676begin
    376   result := trim(Attribute['zoomAndPan'])<>'disable';
     677  result := AttributeDef['zoomAndPan','magnify']<>'disable';
    377678end;
    378679
     
    392693  FUnits.CustomDpi := AValue;
    393694  if AValue.x <> AValue.y then
    394     preserveAspectRatio := 'none';
     695    preserveAspectRatio := TSVGPreserveAspectRatio.Parse('none');
    395696end;
    396697
     
    417718end;
    418719
    419 procedure TBGRASVG.SetPreserveAspectRatio(AValue: string);
    420 begin
    421   Attribute['preserveAspectRatio'] := AValue;
     720procedure TBGRASVG.SetPreserveAspectRatio(AValue: TSVGPreserveAspectRatio);
     721begin
     722  Attribute['preserveAspectRatio'] := AValue.ToString;
     723  Units.Recompute;
     724end;
     725
     726procedure TBGRASVG.SetUTF8String(AValue: utf8string);
     727var str: TMemoryStream;
     728begin
     729  str:= TMemoryStream.Create;
     730  str.Write(AValue[1],length(AValue));
     731  str.Position:= 0;
     732  LoadFromStream(str);
     733  str.Free;
    422734end;
    423735
     
    460772    FRoot := FXml.CreateElement('svg');
    461773    FUnits := TSVGUnits.Create(FRoot,@FDefaultDpi);
    462     FContent := TSVGContent.Create(FXml,FRoot,FUnits);
     774    FUnits.OnRecompute:= @UnitsRecompute;
     775    FDataLink := TSVGDataLink.Create;
     776    FContent := TSVGContent.Create(FXml,FRoot,FUnits,FDataLink,nil);
    463777    FXml.AppendChild(FRoot);
    464778  end;
     
    487801end;
    488802
     803procedure TBGRASVG.UnitsRecompute(Sender: TObject);
     804begin
     805  FContent.Recompute;
     806end;
     807
    489808constructor TBGRASVG.Create;
    490809begin
     
    523842end;
    524843
     844constructor TBGRASVG.CreateFromString(AUTF8String: string);
     845begin
     846  Init(False);
     847  AsUTF8String:= AUTF8String;
     848end;
     849
    525850destructor TBGRASVG.Destroy;
    526851begin
     852  FreeAndNil(FDataLink);
    527853  FreeAndNil(FContent);
    528854  FreeAndNil(FUnits);
     
    565891    raise exception.Create('Root node not found');
    566892  end;
     893  FreeAndNil(FDataLink);
    567894  FreeAndNil(FContent);
    568895  FreeAndNil(FUnits);
     
    571898  FRoot := root as TDOMElement;
    572899  FUnits := TSVGUnits.Create(FRoot,@FDefaultDpi);
    573   FContent := TSVGContent.Create(FXml,FRoot,FUnits);
     900  FUnits.OnRecompute:= @UnitsRecompute;
     901  FDataLink := TSVGDataLink.Create;
     902  FContent := TSVGContent.Create(FXml,FRoot,FUnits,FDataLink,nil);
     903end;
     904
     905procedure TBGRASVG.LoadFromResource(AFilename: string);
     906var
     907  stream: TStream;
     908begin
     909  stream := BGRAResource.GetResourceStream(AFilename);
     910  try
     911    LoadFromStream(stream);
     912  finally
     913    stream.Free;
     914  end;
    574915end;
    575916
     
    614955  ACanvas2d.translate(x,y);
    615956  ACanvas2d.scale(destDpi.x/Units.DpiX,destDpi.y/Units.DpiY);
    616   ACanvas2d.strokeResetTransform;
    617   ACanvas2d.strokeScale(destDpi.x/Units.DpiX,destDpi.y/Units.DpiY);
    618957  with GetViewBoxAlignment(AHorizAlign,AVertAlign) do ACanvas2d.translate(x,y);
    619958  Draw(ACanvas2d, 0,0, cuPixel);
     
    628967  ACanvas2d.save;
    629968  ACanvas2d.translate(x,y);
     969  ACanvas2d.strokeMatrix := ACanvas2d.matrix;
    630970  Content.Draw(ACanvas2d,AUnit);
    631971  ACanvas2d.restore;
     
    643983  ACanvas2d.translate(x,y);
    644984  ACanvas2d.scale(destDpi.x/Units.DpiX,destDpi.y/Units.DpiY);
    645   ACanvas2d.strokeResetTransform;
    646   ACanvas2d.strokeScale(destDpi.x/Units.DpiX,destDpi.y/Units.DpiY);
    647985  Draw(ACanvas2d, 0,0, cuPixel);
    648986  ACanvas2d.restore;
    649987end;
    650988
    651 procedure TBGRASVG.StretchDraw(ACanvas2d: TBGRACanvas2D; x, y, w, h: single);
     989procedure TBGRASVG.StretchDraw(ACanvas2d: TBGRACanvas2D; x, y, w, h: single; useSvgAspectRatio: boolean);
    652990var vb: TSVGViewBox;
    653991begin
     992  if useSvgAspectRatio then
     993  begin
     994    with preserveAspectRatio do
     995      StretchDraw(ACanvas2d, HorizAlign, VertAlign, x,y,w,h);
     996    exit;
     997  end;
    654998  ACanvas2d.save;
    655999  ACanvas2d.translate(x,y);
     
    6601004    ACanvas2d.translate(-min.x,-min.y);
    6611005    if size.x <> 0 then
    662     begin
    6631006      ACanvas2d.scale(w/size.x,1);
    664       ACanvas2d.strokeScale(w/size.x,1);
    665     end;
    6661007    if size.y <> 0 then
    667     begin
    6681008      ACanvas2d.scale(1,h/size.y);
    669       ACanvas2d.strokeScale(1,h/size.y);
    670     end;
    6711009  end;
    6721010  Draw(ACanvas2d, 0,0);
     
    6741012end;
    6751013
     1014procedure TBGRASVG.StretchDraw(ACanvas2d: TBGRACanvas2D; r: TRectF; useSvgAspectRatio: boolean);
     1015begin
     1016  StretchDraw(ACanvas2d, r.Left,r.Top,r.Right-r.Left,r.Bottom-r.Top, useSvgAspectRatio);
     1017end;
     1018
    6761019procedure TBGRASVG.StretchDraw(ACanvas2d: TBGRACanvas2D;
    6771020  AHorizAlign: TAlignment; AVertAlign: TTextLayout; x, y, w, h: single);
     1021var r: TRectF;
     1022begin
     1023  r := GetStretchRectF(AHorizAlign,AVertAlign, x, y, w, h);
     1024  StretchDraw(ACanvas2d, r.Left,r.Top,r.Right-r.Left,r.Bottom-r.Top);
     1025end;
     1026
     1027function TBGRASVG.GetStretchRectF(AHorizAlign: TAlignment;
     1028  AVertAlign: TTextLayout; x, y, w, h: single): TRectF;
    6781029var ratio,stretchRatio,zoom: single;
    679   vb: TSVGViewBox;
    6801030  sx,sy,sw,sh: single;
    681 begin
    682   GetViewBoxIndirect(cuPixel,vb);
    683   if (h = 0) or (w = 0) or (vb.size.x = 0) or (vb.size.y = 0) then exit;
    684   ratio := vb.size.x/vb.size.y;
     1031  size: TSVGSize;
     1032begin
     1033  //determine global ratio according to viewSize
     1034  size := Units.OriginalViewSize;
     1035  size.width := Units.ConvertWidth(size.Width,cuPixel);
     1036  size.height := Units.ConvertHeight(size.height,cuPixel);
     1037  if (h = 0) or (w = 0) or (size.width.value = 0) or (size.height.value = 0) then
     1038  begin
     1039    result := RectF(x,y,w,h);
     1040    exit;
     1041  end;
     1042  ratio := size.width.value/size.height.value;
    6851043  stretchRatio := w/h;
    6861044  if ratio > stretchRatio then
    687     zoom := w / vb.size.x
     1045    zoom := w / size.width.value
    6881046  else
    689     zoom := h / vb.size.y;
     1047    zoom := h / size.height.value;
    6901048
    6911049  sx := x;
    6921050  sy := y;
    693   sw := vb.size.x*zoom;
    694   sh := vb.size.y*zoom;
     1051  sw := size.width.value*zoom;
     1052  sh := size.height.value*zoom;
    6951053
    6961054  case AHorizAlign of
     
    7021060    tlBottom: sy += h - sh;
    7031061  end;
    704   StretchDraw(ACanvas2d, sx,sy,sw,sh);
    705 end;
     1062
     1063  result := Units.GetStretchRectF(RectF(sx,sy,sx+sw,sy+sh), preserveAspectRatio);
     1064end;
     1065
     1066initialization
     1067
     1068  DefaultBGRAImageReader[ifSvg] := TFPReaderSVG;
    7061069
    7071070end.
Note: See TracChangeset for help on using the changeset viewer.