Ignore:
Timestamp:
Apr 9, 2015, 9:58:36 PM (9 years ago)
Author:
chronos
Message:
  • Fixed: Use csOpaque control style also to Image, PaintBox and OpenGLControl.
  • Modified: Change size of test frame with SpinEdits as delayed using timer.
  • Updated: BRGABitmap package to version 8.1.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • GraphicTest/Packages/bgrabitmap/bgracanvas2d.pas

    r452 r472  
    33{ To do :
    44
     5  draw text with a different precision if the matrix is scaled
     6  drawImage(in image, in double sx, in double sy, in double sw, in double sh, in double dx, in double dy, in double dw, in double dh)
     7  -> using FillPoly with texture coordinates
    58  linear gradient any transformation
    69  clearPath clipping
    710  createRadialGradient
    8   text functions
    911  globalCompositeOperation
    10   drawImage(in image, in double sx, in double sy, in double sw, in double sh, in double dx, in double dy, in double dw, in double dh)
    1112  image data functions
    1213}
     
    1718
    1819uses
    19   Classes, SysUtils, Graphics, BGRABitmapTypes, BGRATransform, BGRAGradientScanner;
     20  Classes, SysUtils, Graphics, BGRABitmapTypes, BGRATransform, BGRAGradientScanner, BGRAPath;
    2021
    2122type
     
    4748    globalAlpha: byte;
    4849
     50    fontName: string;
     51    fontStyle: TFontStyles;
     52    fontEmHeight: single;
     53    textAlign: TAlignment;
     54    textBaseline: string;
     55
    4956    lineWidth: single;
    5057    lineCap: TPenEndCap;
     
    5562    shadowOffsetX,shadowOffsetY,shadowBlur: single;
    5663    shadowColor: TBGRAPixel;
     64    shadowFastest: boolean;
    5765
    5866    matrix: TAffineMatrix;
     
    6371  end;
    6472
     73  TCanvas2dTextSize = record
     74    width,height: single;
     75  end;
     76
    6577  { TBGRACanvas2D }
    6678
    67   TBGRACanvas2D = class
     79  TBGRACanvas2D = class(IBGRAPath)
    6880  private
    6981    FSurface: TBGRACustomBitmap;
     
    7486    FPathPoints: array of TPointF;
    7587    FPathPointCount: integer;
     88    FFontRenderer: TBGRACustomFontRenderer;
     89    FLastCoord, FStartCoord: TPointF;
     90    function GetCurrentPath: ArrayOfTPointF;
     91    function GetFontName: string;
     92    function GetFontRenderer: TBGRACustomFontRenderer;
     93    function GetFontEmHeight: single;
     94    function GetFontString: string;
     95    function GetFontStyle: TFontStyles;
    7696    function GetGlobalAlpha: single;
    7797    function GetHasShadow: boolean;
    7898    function GetHeight: Integer;
    7999    function GetLineCap: string;
     100    function GetLineCapLCL: TPenEndCap;
    80101    function GetlineJoin: string;
     102    function GetlineJoinLCL: TPenJoinStyle;
    81103    function GetLineWidth: single;
     104    function GetMatrix: TAffineMatrix;
    82105    function GetMiterLimit: single;
    83106    function GetPixelCenteredCoordinates: boolean;
    84107    function GetShadowBlur: single;
     108    function GetShadowFastest: boolean;
    85109    function GetShadowOffset: TPointF;
    86110    function GetShadowOffsetX: single;
    87111    function GetShadowOffsetY: single;
     112    function GetTextAlign: string;
     113    function GetTextAlignLCL: TAlignment;
     114    function GetTextBaseline: string;
    88115    function GetWidth: Integer;
     116    procedure SetFontName(AValue: string);
     117    procedure SetFontRenderer(AValue: TBGRACustomFontRenderer);
     118    procedure SetFontEmHeight(AValue: single);
     119    procedure SetFontString(AValue: string);
     120    procedure SetFontStyle(AValue: TFontStyles);
    89121    procedure SetGlobalAlpha(const AValue: single);
    90122    procedure SetLineCap(const AValue: string);
     123    procedure SetLineCapLCL(AValue: TPenEndCap);
    91124    procedure SetLineJoin(const AValue: string);
    92125    procedure FillPoly(const points: array of TPointF);
    93126    procedure FillStrokePoly(const points: array of TPointF; fillOver: boolean);
     127    procedure SetLineJoinLCL(AValue: TPenJoinStyle);
    94128    procedure SetLineWidth(const AValue: single);
     129    procedure SetMatrix(AValue: TAffineMatrix);
    95130    procedure SetMiterLimit(const AValue: single);
    96131    procedure SetPixelCenteredCoordinates(const AValue: boolean);
    97132    procedure SetShadowBlur(const AValue: single);
     133    procedure SetShadowFastest(AValue: boolean);
    98134    procedure SetShadowOffset(const AValue: TPointF);
    99135    procedure SetShadowOffsetX(const AValue: single);
    100136    procedure SetShadowOffsetY(const AValue: single);
     137    procedure SetTextAlign(AValue: string);
     138    procedure SetTextAlignLCL(AValue: TAlignment);
     139    procedure SetTextBaseine(AValue: string);
    101140    procedure StrokePoly(const points: array of TPointF);
    102141    procedure DrawShadow(const points, points2: array of TPointF);
     
    105144    function ApplyTransform(const points: array of TPointF): ArrayOfTPointF; overload;
    106145    function ApplyTransform(point: TPointF): TPointF; overload;
    107     function GetPenPos: TPointF;
     146    function GetPenPos(defaultX, defaultY: single): TPointF;
     147    function GetPenPos(defaultPt: TPointF): TPointF;
    108148    procedure AddPoint(point: TPointF);
    109149    procedure AddPoints(const points: array of TPointF);
    110150    procedure AddPointsRev(const points: array of TPointF);
    111151    function ApplyGlobalAlpha(color: TBGRAPixel): TBGRAPixel;
     152    function GetDrawMode: TDrawMode;
     153    procedure copyTo({%H-}dest: IBGRAPath); //IBGRAPath
    112154  public
     155    antialiasing, linearBlend: boolean;
    113156    constructor Create(ASurface: TBGRACustomBitmap);
    114157    destructor Destroy; override;
     
    118161    procedure save;
    119162    procedure restore;
    120     procedure scale(x,y: single);
    121     procedure rotate(angleRad: single);
     163    procedure scale(x,y: single); overload;
     164    procedure scale(factor: single); overload;
     165    procedure rotate(angleRadCW: single);
    122166    procedure translate(x,y: single);
    123     procedure transform(a,b,c,d,e,f: single);
     167    procedure transform(a,b,c,d,e,f: single); overload;
     168    procedure transform(AMatrix: TAffineMatrix); overload;
    124169    procedure setTransform(a,b,c,d,e,f: single);
    125170    procedure resetTransform;
     
    137182    procedure shadowColor(color: TColor); overload;
    138183    procedure shadowColor(color: string); overload;
     184    procedure shadowNone;
    139185    function getShadowColor: TBGRAPixel;
    140186    function createLinearGradient(x0,y0,x1,y1: single): IBGRACanvasGradient2D; overload;
     
    149195    procedure clearRect(x,y,w,h: single);
    150196
     197    procedure addPath(APath: IBGRAPath); overload;
     198    procedure addPath(ASvgPath: string); overload;
     199    procedure path(APath: IBGRAPath); overload;
     200    procedure path(ASvgPath: string); overload;
    151201    procedure beginPath;
    152202    procedure closePath;
     
    154204    procedure moveTo(x,y: single); overload;
    155205    procedure lineTo(x,y: single); overload;
    156     procedure moveTo(pt: TPointF); overload;
    157     procedure lineTo(pt: TPointF); overload;
     206    procedure moveTo(const pt: TPointF); overload;
     207    procedure lineTo(const pt: TPointF); overload;
    158208    procedure polylineTo(const pts: array of TPointF);
    159209    procedure quadraticCurveTo(cpx,cpy,x,y: single); overload;
    160     procedure quadraticCurveTo(cp,pt: TPointF); overload;
     210    procedure quadraticCurveTo(const cp,pt: TPointF); overload;
    161211    procedure bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y: single); overload;
    162     procedure bezierCurveTo(cp1,cp2,pt: TPointF); overload;
     212    procedure bezierCurveTo(const cp1,cp2,pt: TPointF); overload;
    163213    procedure rect(x,y,w,h: single);
    164     procedure roundRect(x,y,w,h,radius: single);
     214    procedure roundRect(x,y,w,h,radius: single); overload;
     215    procedure roundRect(x,y,w,h,rx,ry: single); overload;
    165216    procedure spline(const pts: array of TPointF; style: TSplineStyle= ssOutside);
    166217    procedure splineTo(const pts: array of TPointF; style: TSplineStyle= ssOutside);
    167     procedure arc(x, y, radius, startAngle, endAngle: single; anticlockwise: boolean); overload;
    168     procedure arc(x, y, radius, startAngle, endAngle: single); overload;
     218    procedure arc(x, y, radius, startAngleRadCW, endAngleRadCW: single; anticlockwise: boolean); overload;
     219    procedure arc(x, y, radius, startAngleRadCW, endAngleRadCW: single); overload;
     220    procedure arc(cx, cy, rx,ry, xAngleRadCW, startAngleRadCW, endAngleRadCW: single; anticlockwise: boolean); overload;
     221    procedure arc(cx, cy, rx,ry, xAngleRadCW, startAngleRadCW, endAngleRadCW: single); overload;
     222    procedure arc(const arcDef: TArcDef); overload;
    169223    procedure arcTo(x1, y1, x2, y2, radius: single); overload;
    170224    procedure arcTo(p1,p2: TPointF; radius: single); overload;
     225    procedure arcTo(rx, ry, xAngleRadCW: single; largeArc,anticlockwise: boolean; x, y: single);
     226    procedure circle(x,y,r: single);
     227    procedure ellipse(x,y,rx,ry: single);
     228    procedure text(AText: string; x,y: single);
     229    procedure fillText(AText: string; x,y: single);
     230    procedure strokeText(AText: string; x,y: single);
     231    function measureText(AText: string): TCanvas2dTextSize;
     232
    171233    procedure fill;
    172234    procedure stroke;
     
    183245
    184246    function getLineStyle: TBGRAPenStyle;
    185     procedure lineStyle(const AValue: array of single);
     247    procedure lineStyle(const AValue: array of single); overload;
     248    procedure lineStyle(AStyle: TPenStyle); overload;
    186249
    187250    property surface: TBGRACustomBitmap read FSurface;
     
    190253    property pixelCenteredCoordinates: boolean read GetPixelCenteredCoordinates write SetPixelCenteredCoordinates;
    191254    property globalAlpha: single read GetGlobalAlpha write SetGlobalAlpha;
     255    property matrix: TAffineMatrix read GetMatrix write SetMatrix;
    192256
    193257    property lineWidth: single read GetLineWidth write SetLineWidth;
    194258    property lineCap: string read GetLineCap write SetLineCap;
     259    property lineCapLCL: TPenEndCap read GetLineCapLCL write SetLineCapLCL;
    195260    property lineJoin: string read GetlineJoin write SetLineJoin;
     261    property lineJoinLCL: TPenJoinStyle read GetlineJoinLCL write SetLineJoinLCL;
    196262    property miterLimit: single read GetMiterLimit write SetMiterLimit;
    197263
     
    200266    property shadowOffset: TPointF read GetShadowOffset write SetShadowOffset;
    201267    property shadowBlur: single read GetShadowBlur write SetShadowBlur;
     268    property shadowFastest: boolean read GetShadowFastest write SetShadowFastest;
    202269    property hasShadow: boolean read GetHasShadow;
     270
     271    property fontName: string read GetFontName write SetFontName;
     272    property fontEmHeight: single read GetFontEmHeight write SetFontEmHeight;
     273    property fontStyle: TFontStyles read GetFontStyle write SetFontStyle;
     274    property font: string read GetFontString write SetFontString;
     275    property textAlignLCL: TAlignment read GetTextAlignLCL write SetTextAlignLCL;
     276    property textAlign: string read GetTextAlign write SetTextAlign;
     277    property textBaseline: string read GetTextBaseline write SetTextBaseine;
     278
     279    property currentPath: ArrayOfTPointF read GetCurrentPath;
     280    property fontRenderer: TBGRACustomFontRenderer read GetFontRenderer write SetFontRenderer;
     281
     282  protected
     283    function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} IID: TGUID; out Obj): HResult; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND};
     284    function _AddRef: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND};
     285    function _Release: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND};
    203286  end;
    204287
    205288implementation
    206289
    207 uses Math, BGRAPen, BGRAFillInfo, BGRAPolygon, BGRABlend, FPWriteJPEG, FPWriteBMP, base64;
     290uses Types, Math, BGRAPen, BGRAFillInfo, BGRAPolygon, BGRABlend, FPWriteJPEG, FPWriteBMP, base64;
    208291
    209292type
     
    446529  globalAlpha := 255;
    447530
     531  fontName := 'Arial';
     532  fontEmHeight := 10;
     533  fontStyle := [];
     534  textAlign:= taLeftJustify;
     535  textBaseline := 'alphabetic';
     536
    448537  lineWidth := 1;
    449538  lineCap := pecFlat;
     
    456545  shadowBlur := 0;
    457546  shadowColor := BGRAPixelTransparent;
     547  shadowFastest:= false;
    458548
    459549  matrix := AMatrix;
     
    473563  result.globalAlpha := globalAlpha;
    474564
     565  result.fontName:= fontName;
     566  result.fontEmHeight := fontEmHeight;
     567  result.fontStyle := fontStyle;
     568
    475569  result.lineWidth := lineWidth;
    476570  result.lineCap := lineCap;
     
    483577  result.shadowBlur := shadowBlur;
    484578  result.shadowColor := shadowColor;
     579  result.shadowFastest := shadowFastest;
    485580end;
    486581
     
    495590function TBGRACanvas2D.GetHeight: Integer;
    496591begin
    497   result := Surface.Height;
     592  if Assigned(surface) then
     593    result := Surface.Height
     594  else
     595    result := 0;
    498596end;
    499597
     
    507605end;
    508606
     607function TBGRACanvas2D.GetLineCapLCL: TPenEndCap;
     608begin
     609  result := currentState.lineCap;
     610end;
     611
    509612function TBGRACanvas2D.GetlineJoin: string;
    510613begin
     
    516619end;
    517620
     621function TBGRACanvas2D.GetlineJoinLCL: TPenJoinStyle;
     622begin
     623  result := currentState.lineJoin;
     624end;
     625
    518626function TBGRACanvas2D.getLineStyle: TBGRAPenStyle;
    519627begin
     
    526634end;
    527635
     636function TBGRACanvas2D.GetMatrix: TAffineMatrix;
     637begin
     638  result := currentState.matrix;
     639end;
     640
    528641function TBGRACanvas2D.GetMiterLimit: single;
    529642begin
     
    541654end;
    542655
     656function TBGRACanvas2D.GetShadowFastest: boolean;
     657begin
     658  result := currentState.shadowFastest;
     659end;
     660
    543661function TBGRACanvas2D.GetShadowOffset: TPointF;
    544662begin
     
    556674end;
    557675
     676function TBGRACanvas2D.GetTextAlign: string;
     677begin
     678  case currentState.textAlign of
     679    taRightJustify: result := 'right';
     680    taCenter: result := 'center';
     681  else
     682    result := 'left';
     683  end;
     684end;
     685
     686function TBGRACanvas2D.GetTextAlignLCL: TAlignment;
     687begin
     688  result := currentState.textAlign;
     689end;
     690
     691function TBGRACanvas2D.GetTextBaseline: string;
     692begin
     693  result := currentState.textBaseline;
     694end;
     695
    558696function TBGRACanvas2D.GetGlobalAlpha: single;
    559697begin
    560698  result := currentState.globalAlpha/255;
     699end;
     700
     701function TBGRACanvas2D.GetCurrentPath: ArrayOfTPointF;
     702var i: integer;
     703begin
     704  setlength(result, FPathPointCount);
     705  for i := 0 to high(result) do
     706    result[i] := FPathPoints[i];
     707end;
     708
     709function TBGRACanvas2D.GetFontName: string;
     710begin
     711  result := currentState.fontName;
     712end;
     713
     714function TBGRACanvas2D.GetFontRenderer: TBGRACustomFontRenderer;
     715var zoom1,zoom2,zoom: single;
     716begin
     717  if FFontRenderer = nil then
     718  begin
     719    if FSurface <> nil then
     720      result := FSurface.FontRenderer
     721    else
     722      result := nil;
     723  end else
     724    result := FFontRenderer;
     725  if Assigned(result) then
     726  begin
     727    result.FontName := currentState.fontName;
     728    result.FontStyle := currentState.fontStyle;
     729    if antialiasing then
     730      result.FontQuality:= fqFineAntialiasing
     731    else
     732      result.FontQuality := fqSystem;
     733    result.FontOrientation := 0;
     734    zoom1 := VectLen(currentState.matrix[1,1],currentState.matrix[2,1]);
     735    zoom2 := VectLen(currentState.matrix[1,2],currentState.matrix[2,2]);
     736    if zoom1>zoom2 then zoom := zoom1 else zoom := zoom2;
     737    result.FontEmHeight := round(currentState.fontEmHeight*zoom);
     738  end;
     739end;
     740
     741function TBGRACanvas2D.GetFontEmHeight: single;
     742begin
     743  result := currentState.fontEmHeight;
     744end;
     745
     746function TBGRACanvas2D.GetFontString: string;
     747var formats: TFormatSettings;
     748begin
     749  formats := DefaultFormatSettings;
     750  formats.DecimalSeparator := '.';
     751
     752  result := '';
     753  if fsItalic in currentState.fontStyle then
     754    result := result+'italic ';
     755  if fsBold in currentState.fontStyle then
     756    result += 'bold ';
     757  result += FloatToStrF(currentState.fontEmHeight,ffGeneral,6,0,formats)+'px ';
     758  result += currentState.fontName;
     759  result := trim(result);
     760end;
     761
     762function TBGRACanvas2D.GetFontStyle: TFontStyles;
     763begin
     764  result := currentState.fontStyle;
    561765end;
    562766
     
    570774function TBGRACanvas2D.GetWidth: Integer;
    571775begin
    572   result := Surface.Width;
     776  if Assigned(Surface) then
     777    result := Surface.Width
     778  else
     779    result := 0;
     780end;
     781
     782procedure TBGRACanvas2D.SetFontName(AValue: string);
     783begin
     784  currentState.fontName := AValue;
     785end;
     786
     787procedure TBGRACanvas2D.SetFontRenderer(AValue: TBGRACustomFontRenderer);
     788begin
     789  if AValue = FFontRenderer then exit;
     790  FreeAndNil(FFontRenderer);
     791  FFontRenderer := AValue;
     792end;
     793
     794procedure TBGRACanvas2D.SetFontEmHeight(AValue: single);
     795begin
     796  currentState.fontEmHeight := AValue;
     797end;
     798
     799procedure TBGRACanvas2D.SetFontString(AValue: string);
     800var idxSpace,errPos: integer;
     801  attrib,u: string;
     802  value: single;
     803begin
     804  currentState.fontStyle := [];
     805  currentState.fontEmHeight := 10;
     806  currentState.fontName := 'Arial';
     807  AValue := trim(AValue);
     808  while AValue <> '' do
     809  begin
     810    while (AValue <> '') and (AValue[1]in [#0..#32]) do delete(AValue,1,1);
     811    idxSpace := pos(' ',AValue);
     812    if idxSpace = 0 then
     813      attrib := AValue
     814    else
     815      attrib := copy(AValue,1,idxSpace-1);
     816    attrib := lowerCase(attrib);
     817    if attrib = '' then break;
     818    if (attrib = 'normal') or (attrib = 'small-caps') or (attrib = 'lighter') then
     819    begin
     820      //nothing
     821    end else
     822    if (attrib = 'italic') or (attrib = 'oblique') then
     823    begin
     824      currentState.fontStyle += [fsItalic];
     825    end else
     826    if (attrib = 'bold') or (attrib = 'bolder') then
     827    begin
     828      currentState.fontStyle += [fsBold];
     829    end else
     830    if (attrib[1] in ['.','0'..'9']) then
     831    begin
     832      u := '';
     833      while (length(attrib)>0) and (attrib[length(attrib)] in['a'..'z']) do
     834      begin
     835        u := attrib[length(attrib)]+u;
     836        delete(attrib,length(attrib),1);
     837      end;
     838      val(attrib,value,errPos);
     839      if errPos = 0 then
     840      begin
     841        if u = '' then //weight
     842        begin
     843          if value >= 600 then currentState.fontStyle += [fsBold];
     844        end else
     845        if u = 'px' then currentState.fontEmHeight := value else
     846        if u = 'pt' then currentState.fontEmHeight:= value/72*96 else
     847        if u = 'in' then currentState.fontEmHeight:= value*96 else
     848        if u = 'mm' then currentState.fontEmHeight:= value/25.4*96 else
     849        if u = 'cm' then currentState.fontEmHeight:= value/2.54*96;
     850      end;
     851    end else
     852      break;
     853    delete(AValue,1,length(attrib)+1);
     854  end;
     855  AValue := trim(AValue);
     856  if AValue <> '' then currentState.fontName := AValue;
     857end;
     858
     859procedure TBGRACanvas2D.SetFontStyle(AValue: TFontStyles);
     860begin
     861  currentState.fontStyle:= AValue;
    573862end;
    574863
     
    590879end;
    591880
     881procedure TBGRACanvas2D.SetLineCapLCL(AValue: TPenEndCap);
     882begin
     883  currentState.lineCap := AValue;
     884end;
     885
    592886procedure TBGRACanvas2D.SetLineJoin(const AValue: string);
    593887begin
     
    604898  tempScan: TBGRACustomScanner;
    605899begin
    606   if length(points) = 0 then exit;
     900  if (length(points) = 0) or (surface = nil) then exit;
    607901  If hasShadow then DrawShadow(points,[]);
    608902  if currentState.clipMask <> nil then
     
    612906    else
    613907      tempScan := TBGRASolidColorMaskScanner.Create(currentState.clipMask,Point(0,0),ApplyGlobalAlpha(currentState.fillColor));
    614     BGRAPolygon.FillPolyAntialiasWithTexture(surface, points, tempScan, true);
     908    if self.antialiasing then
     909      BGRAPolygon.FillPolyAntialiasWithTexture(surface, points, tempScan, true, linearBlend)
     910    else
     911      BGRAPolygon.FillPolyAliasedWithTexture(surface, points, tempScan, true, GetDrawMode);
    615912    tempScan.free;
    616913  end else
     
    621918      begin
    622919        tempScan := TBGRAOpacityScanner.Create(currentState.fillTextureProvider.texture, currentState.globalAlpha);
    623         BGRAPolygon.FillPolyAntialiasWithTexture(surface, points, tempScan, true);
     920        if self.antialiasing then
     921          BGRAPolygon.FillPolyAntialiasWithTexture(surface, points, tempScan, true, linearBlend)
     922        else
     923          BGRAPolygon.FillPolyAliasedWithTexture(surface, points, tempScan, true, GetDrawMode);
    624924        tempScan.Free;
    625925      end else
    626         BGRAPolygon.FillPolyAntialiasWithTexture(surface, points, currentState.fillTextureProvider.texture, true)
     926      begin
     927        if self.antialiasing then
     928          BGRAPolygon.FillPolyAntialiasWithTexture(surface, points, currentState.fillTextureProvider.texture, true, linearBlend)
     929        else
     930          BGRAPolygon.FillPolyAliasedWithTexture(surface, points, currentState.fillTextureProvider.texture, true, GetDrawMode);
     931      end
    627932    end
    628933    else
    629       BGRAPolygon.FillPolyAntialias(surface, points, ApplyGlobalAlpha(currentState.fillColor), false, true);
     934    begin
     935      if self.antialiasing then
     936        BGRAPolygon.FillPolyAntialias(surface, points, ApplyGlobalAlpha(currentState.fillColor), false, true, linearBlend)
     937      else
     938        BGRAPolygon.FillPolyAliased(surface, points, ApplyGlobalAlpha(currentState.fillColor), false, true, GetDrawMode)
     939    end
    630940  end;
    631941end;
     
    639949  texture: IBGRAScanner;
    640950begin
    641   if length(points) = 0 then exit;
     951  if (length(points) = 0) or (surface = nil) then exit;
    642952  tempScan := nil;
    643953  tempScan2 := nil;
     
    6931003
    6941004  if fillOver then multi.PolygonOrder := poFirstOnTop else multi.PolygonOrder:= poLastOnTop;
     1005  multi.Antialiasing := self.antialiasing;
    6951006  multi.Draw(surface);
    6961007  tempScan.free;
     
    6991010end;
    7001011
     1012procedure TBGRACanvas2D.SetLineJoinLCL(AValue: TPenJoinStyle);
     1013begin
     1014  currentState.lineJoin := AValue;
     1015end;
     1016
    7011017procedure TBGRACanvas2D.lineStyle(const AValue: array of single);
    7021018begin
     
    7041020end;
    7051021
     1022procedure TBGRACanvas2D.lineStyle(AStyle: TPenStyle);
     1023begin
     1024  case AStyle of
     1025    psSolid: lineStyle(SolidPenStyle);
     1026    psDash: lineStyle(DashPenStyle);
     1027    psDot: lineStyle(DotPenStyle);
     1028    psDashDot: lineStyle(DashDotPenStyle);
     1029    psDashDotDot: lineStyle(DashDotDotPenStyle);
     1030    psClear: lineStyle(ClearPenStyle);
     1031  end;
     1032end;
     1033
     1034function TBGRACanvas2D.QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} IID: TGUID; out Obj): HResult; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND};
     1035begin
     1036  if GetInterface(iid, obj) then
     1037    Result := S_OK
     1038  else
     1039    Result := longint(E_NOINTERFACE);
     1040end;
     1041
     1042{ There is no automatic reference counting, but it is compulsory to define these functions }
     1043function TBGRACanvas2D._AddRef: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND};
     1044begin
     1045  result := 0;
     1046end;
     1047
     1048function TBGRACanvas2D._Release: Integer; {$IF (not defined(WINDOWS)) AND (FPC_FULLVERSION>=20501)}cdecl{$ELSE}stdcall{$IFEND};
     1049begin
     1050  result := 0;
     1051end;
     1052
    7061053procedure TBGRACanvas2D.SetLineWidth(const AValue: single);
    7071054begin
    7081055  currentState.lineWidth := AValue;
     1056end;
     1057
     1058procedure TBGRACanvas2D.SetMatrix(AValue: TAffineMatrix);
     1059begin
     1060  currentState.matrix := AValue;
    7091061end;
    7101062
     
    7281080end;
    7291081
     1082procedure TBGRACanvas2D.SetShadowFastest(AValue: boolean);
     1083begin
     1084  currentState.shadowFastest := AValue;
     1085end;
     1086
    7301087procedure TBGRACanvas2D.SetShadowOffset(const AValue: TPointF);
    7311088begin
     
    7421099begin
    7431100  currentState.shadowOffsetY := AValue;
     1101end;
     1102
     1103procedure TBGRACanvas2D.SetTextAlign(AValue: string);
     1104begin
     1105  AValue := trim(LowerCase(AValue));
     1106  if (AValue = 'left') or (AValue = 'start') then
     1107    textAlignLCL := taLeftJustify else
     1108  if (AValue = 'right') or (AValue = 'end') then
     1109    textAlignLCL := taRightJustify else
     1110  if AValue = 'center' then
     1111    textAlignLCL := taCenter;
     1112end;
     1113
     1114procedure TBGRACanvas2D.SetTextAlignLCL(AValue: TAlignment);
     1115begin
     1116  currentState.textAlign := AValue;
     1117end;
     1118
     1119procedure TBGRACanvas2D.SetTextBaseine(AValue: string);
     1120begin
     1121  currentState.textBaseline := trim(lowercase(AValue));
    7441122end;
    7451123
     
    7501128  contour: array of TPointF;
    7511129begin
    752   if (length(points)= 0) or (currentState.lineWidth = 0) then exit;
     1130  if (length(points)= 0) or (currentState.lineWidth = 0) or (surface = nil) then exit;
    7531131  contour := ComputeWidePolylinePoints(points,currentState.lineWidth,BGRAPixelTransparent,
    7541132      currentState.lineCap,currentState.lineJoin,currentState.lineStyle,[plAutoCycle],miterLimit);
     
    7611139    else
    7621140      tempScan := TBGRASolidColorMaskScanner.Create(currentState.clipMask,Point(0,0),ApplyGlobalAlpha(currentState.strokeColor));
    763     BGRAPolygon.FillPolyAntialiasWithTexture(Surface,contour,tempScan,True);
     1141    if self.antialiasing then
     1142      BGRAPolygon.FillPolyAntialiasWithTexture(Surface,contour,tempScan,True, linearBlend)
     1143    else
     1144      BGRAPolygon.FillPolyAliasedWithTexture(Surface,contour,tempScan,True,GetDrawMode);
    7641145    tempScan.free;
    7651146  end else
     
    7691150      texture := nil;
    7701151    if texture = nil then
    771       BGRAPolygon.FillPolyAntialias(Surface,contour,ApplyGlobalAlpha(currentState.strokeColor),false,True)
     1152    begin
     1153      if self.antialiasing then
     1154        BGRAPolygon.FillPolyAntialias(Surface,contour,ApplyGlobalAlpha(currentState.strokeColor),false,True, linearBlend)
     1155      else
     1156        BGRAPolygon.FillPolyAliased(Surface,contour,ApplyGlobalAlpha(currentState.strokeColor),false,True,GetDrawMode)
     1157    end
    7721158    else
    773       BGRAPolygon.FillPolyAntialiasWithTexture(Surface,contour,texture,True);
     1159    begin
     1160      if self.antialiasing then
     1161        BGRAPolygon.FillPolyAntialiasWithTexture(Surface,contour,texture,True, linearBlend)
     1162      else
     1163        BGRAPolygon.FillPolyAliasedWithTexture(Surface,contour,texture,True,GetDrawMode)
     1164    end;
    7741165  end;
    7751166end;
    7761167
    7771168procedure TBGRACanvas2D.DrawShadow(const points, points2: array of TPointF);
     1169const invSqrt2 = 1/sqrt(2);
    7781170var ofsPts,ofsPts2: array of TPointF;
    7791171    offset: TPointF;
    7801172    i: Integer;
    7811173    tempBmp,blurred: TBGRACustomBitmap;
    782 begin
    783   if not hasShadow then exit;
     1174    maxRect: TRect;
     1175    foundRect: TRect;
     1176    firstFound: boolean;
     1177
     1178    procedure AddPt(const coord: TPointF);
     1179    var pixRect: TRect;
     1180    begin
     1181      if isEmptyPointF(coord) then exit;
     1182      pixRect := Types.Rect(round(floor(coord.x)),round(floor(coord.y)),round(ceil(coord.x+0.999))+1,round(ceil(coord.y+0.999))+1);
     1183      if firstFound then
     1184      begin
     1185        foundRect := pixRect;
     1186        firstFound := false
     1187      end
     1188      else
     1189      begin
     1190        if pixRect.left < foundRect.left then foundRect.left := pixRect.Left;
     1191        if pixRect.top < foundRect.top then foundRect.top := pixRect.top;
     1192        if pixRect.right > foundRect.right then foundRect.right := pixRect.right;
     1193        if pixRect.bottom > foundRect.bottom then foundRect.bottom := pixRect.bottom;
     1194      end;
     1195    end;
     1196
     1197begin
     1198  if not hasShadow or (surface = nil) then exit;
    7841199  offset := PointF(shadowOffsetX,shadowOffsetY);
    7851200  setlength(ofsPts, length(points));
     
    7891204  for i := 0 to high(ofsPts2) do
    7901205    ofsPts2[i] := points2[i]+offset;
    791   tempBmp := surface.NewBitmap(width,height,BGRAPixelTransparent);
     1206
     1207  maxRect := Types.Rect(0,0,width,height);
     1208  if currentState.clipMask <> nil then
     1209    foundRect := maxRect
     1210  else
     1211  begin
     1212    firstFound := true;
     1213    for i := 0 to high(ofsPts) do
     1214      AddPt(ofsPts[i]);
     1215    for i := 0 to high(ofsPts2) do
     1216      AddPt(ofsPts2[i]);
     1217    if firstFound then exit;
     1218    InflateRect(foundRect, ceil(shadowBlur),ceil(shadowBlur));
     1219    if not IntersectRect(foundRect, foundRect,maxRect) then exit;
     1220    offset := PointF(-foundRect.Left,-foundRect.Top);
     1221    for i := 0 to high(ofsPts) do
     1222      ofsPts[i] += offset;
     1223    for i := 0 to high(ofsPts2) do
     1224      ofsPts2[i] += offset;
     1225  end;
     1226
     1227  tempBmp := surface.NewBitmap(foundRect.Right-foundRect.Left,foundRect.Bottom-foundRect.Top,BGRAPixelTransparent);
    7921228  tempBmp.FillMode := fmWinding;
    7931229  tempBmp.FillPolyAntialias(ofsPts, getShadowColor);
     
    7951231  if shadowBlur > 0 then
    7961232  begin
    797     if (shadowBlur < 5) and (abs(shadowBlur-round(shadowBlur)) > 1e-6) then
    798       blurred := tempBmp.FilterBlurRadial(round(shadowBlur*10),rbPrecise)
     1233    if shadowFastest then
     1234    begin
     1235      if shadowBlur*invSqrt2 >= 0.5 then
     1236      begin
     1237        blurred := tempBmp.FilterBlurRadial(round(shadowBlur*invSqrt2),rbBox);
     1238        tempBmp.Free;
     1239        tempBmp := blurred;
     1240      end;
     1241    end
    7991242    else
    800       blurred := tempBmp.FilterBlurRadial(round(shadowBlur),rbFast);
    801     tempBmp.Free;
    802     tempBmp := blurred;
     1243    begin
     1244      if (shadowBlur < 5) and (abs(shadowBlur-round(shadowBlur)) > 1e-6) then
     1245        blurred := tempBmp.FilterBlurRadial(round(shadowBlur*10),rbPrecise)
     1246      else
     1247        blurred := tempBmp.FilterBlurRadial(round(shadowBlur),rbFast);
     1248      tempBmp.Free;
     1249      tempBmp := blurred;
     1250    end;
    8031251  end;
    8041252  if currentState.clipMask <> nil then
    8051253    tempBmp.ApplyMask(currentState.clipMask);
    806   surface.PutImage(0,0,tempBmp,dmDrawWithTransparency,currentState.globalAlpha);
     1254  surface.PutImage(foundRect.Left,foundRect.Top,tempBmp,GetDrawMode,currentState.globalAlpha);
    8071255  tempBmp.Free;
    8081256end;
     
    8101258procedure TBGRACanvas2D.ClearPoly(const points: array of TPointF);
    8111259begin
    812   BGRAPolygon.FillPolyAntialias(surface, points, BGRA(0,0,0,255), true, true)
     1260  if surface = nil then exit;
     1261  if self.antialiasing then
     1262    BGRAPolygon.FillPolyAntialias(surface, points, BGRA(0,0,0,255), true, true, linearBlend)
     1263  else
     1264    BGRAPolygon.FillPolyAliased(surface, points, BGRA(0,0,0,255), true, true, dmSet);
    8131265end;
    8141266
     
    8441296end;
    8451297
    846 function TBGRACanvas2D.GetPenPos: TPointF;
    847 begin
    848   if FPathPointCount = 0 then
    849     result := PointF(0,0)
     1298function TBGRACanvas2D.GetPenPos(defaultX,defaultY: single): TPointF;
     1299begin
     1300  if isEmptyPointF(FLastCoord) then
     1301    result := PointF(defaultX,defaultY)
    8501302  else
    851     result := FPathPoints[FPathPointCount-1];
     1303    result := FLastCoord;
     1304end;
     1305
     1306function TBGRACanvas2D.GetPenPos(defaultPt: TPointF): TPointF;
     1307begin
     1308  result := GetPenPos(defaultPt.x,defaultPt.y);
    8521309end;
    8531310
     
    8891346end;
    8901347
     1348function TBGRACanvas2D.GetDrawMode: TDrawMode;
     1349begin
     1350  if linearBlend then result := dmLinearBlend else result := dmDrawWithTransparency;
     1351end;
     1352
     1353procedure TBGRACanvas2D.copyTo(dest: IBGRAPath);
     1354begin
     1355  //nothing
     1356end;
     1357
    8911358constructor TBGRACanvas2D.Create(ASurface: TBGRACustomBitmap);
    8921359begin
     
    8941361  StateStack := TList.Create;
    8951362  FPathPointCount := 0;
     1363  FLastCoord := EmptyPointF;
     1364  FStartCoord := EmptyPointF;
    8961365  currentState := TBGRACanvasState2D.Create(AffineMatrixIdentity,nil);
    8971366  pixelCenteredCoordinates := false;
     1367  antialiasing := true;
    8981368end;
    8991369
     
    9061376  StateStack.Free;
    9071377  currentState.Free;
     1378  FreeAndNil(FFontRenderer);
    9081379  inherited Destroy;
    9091380end;
     
    9171388  encode64: TBase64EncodingStream;
    9181389begin
     1390  if surface = nil then exit;
    9191391  stream := TMemoryStream.Create;
    9201392  if mimeType='image/jpeg' then
     
    9671439end;
    9681440
    969 procedure TBGRACanvas2D.rotate(angleRad: single);
    970 begin
    971   currentState.matrix *= AffineMatrixRotationRad(-angleRad);
     1441procedure TBGRACanvas2D.scale(factor: single);
     1442begin
     1443  currentState.matrix *= AffineMatrixScale(factor,factor);
     1444end;
     1445
     1446procedure TBGRACanvas2D.rotate(angleRadCW: single);
     1447begin
     1448  currentState.matrix *= AffineMatrixRotationRad(-angleRadCW);
    9721449end;
    9731450
     
    9801457begin
    9811458  currentState.matrix *= AffineMatrix(a,c,e,b,d,f);
     1459end;
     1460
     1461procedure TBGRACanvas2D.transform(AMatrix: TAffineMatrix);
     1462begin
     1463  currentState.matrix *= AMatrix;
    9821464end;
    9831465
     
    10631545begin
    10641546  shadowColor(StrToBGRA(color));
     1547end;
     1548
     1549procedure TBGRACanvas2D.shadowNone;
     1550begin
     1551  shadowColor(BGRAPixelTransparent);
    10651552end;
    10661553
     
    11451632end;
    11461633
     1634procedure TBGRACanvas2D.addPath(APath: IBGRAPath);
     1635begin
     1636  if (FPathPointCount <> 0) and not isEmptyPointF(FPathPoints[FPathPointCount-1]) then
     1637  begin
     1638    AddPoint(EmptyPointF);
     1639    FLastCoord := EmptyPointF;
     1640    FStartCoord := EmptyPointF;
     1641  end;
     1642  APath.copyTo(self);
     1643end;
     1644
     1645procedure TBGRACanvas2D.addPath(ASvgPath: string);
     1646var p: TBGRAPath;
     1647begin
     1648  p := TBGRAPath.Create(ASvgPath);
     1649  addPath(p);
     1650  p.Free;
     1651end;
     1652
     1653procedure TBGRACanvas2D.path(APath: IBGRAPath);
     1654begin
     1655  beginPath;
     1656  addPath(APath);
     1657end;
     1658
     1659procedure TBGRACanvas2D.path(ASvgPath: string);
     1660begin
     1661  beginPath;
     1662  addPath(ASvgPath);
     1663end;
     1664
    11471665procedure TBGRACanvas2D.beginPath;
    11481666begin
    11491667  FPathPointCount := 0;
     1668  FLastCoord := EmptyPointF;
     1669  FStartCoord := EmptyPointF;
    11501670end;
    11511671
     
    11581678    while (i > 0) and not isEmptyPointF(FPathPoints[i-1]) do dec(i);
    11591679    AddPoint(FPathPoints[i]);
     1680    FLastCoord := FStartCoord;
    11601681  end;
    11611682end;
     
    11751696      pts[j] := FPathPoints[i+j];
    11761697    if closed then
    1177       splinePts := surface.ComputeClosedSpline(pts,style)
     1698      splinePts := BGRAPath.ComputeClosedSpline(pts,style)
    11781699    else
    1179       splinePts := surface.ComputeOpenedSpline(pts,style);
     1700      splinePts := BGRAPath.ComputeOpenedSpline(pts,style);
    11801701    dec(FPathPointCount,nb);
    11811702    AddPoints(splinePts);
     
    11931714end;
    11941715
    1195 procedure TBGRACanvas2D.moveTo(pt: TPointF);
    1196 begin
    1197   if FPathPointCount <> 0 then
     1716procedure TBGRACanvas2D.moveTo(const pt: TPointF);
     1717begin
     1718  if (FPathPointCount <> 0) and not isEmptyPointF(FPathPoints[FPathPointCount-1]) then
    11981719    AddPoint(EmptyPointF);
    11991720  AddPoint(ApplyTransform(pt));
    1200 end;
    1201 
    1202 procedure TBGRACanvas2D.lineTo(pt: TPointF);
     1721  FStartCoord := pt;
     1722  FLastCoord := pt;
     1723end;
     1724
     1725procedure TBGRACanvas2D.lineTo(const pt: TPointF);
    12031726begin
    12041727  AddPoint(ApplyTransform(pt));
     1728  FLastCoord := pt;
    12051729end;
    12061730
    12071731procedure TBGRACanvas2D.polylineTo(const pts: array of TPointF);
    12081732begin
    1209   AddPoints(ApplyTransform(pts));
     1733  if length(pts)> 0 then
     1734  begin
     1735    AddPoints(ApplyTransform(pts));
     1736    FLastCoord := pts[high(pts)];
     1737  end;
    12101738end;
    12111739
     
    12151743  pts : array of TPointF;
    12161744begin
    1217   curve := BezierCurve(GetPenPos,ApplyTransform(PointF(cpx,cpy)),ApplyTransform(PointF(x,y)));
    1218   pts := Surface.ComputeBezierCurve(curve);
     1745  curve := BezierCurve(ApplyTransform(GetPenPos(cpx,cpy)),ApplyTransform(PointF(cpx,cpy)),ApplyTransform(PointF(x,y)));
     1746  pts := BGRAPath.ComputeBezierCurve(curve);
    12191747  AddPoints(pts);
    1220 end;
    1221 
    1222 procedure TBGRACanvas2D.quadraticCurveTo(cp, pt: TPointF);
     1748  FLastCoord := PointF(x,y);
     1749end;
     1750
     1751procedure TBGRACanvas2D.quadraticCurveTo(const cp, pt: TPointF);
    12231752begin
    12241753  quadraticCurveTo(cp.x,cp.y,pt.x,pt.y);
     
    12301759  pts : array of TPointF;
    12311760begin
    1232   curve := BezierCurve(GetPenPos,ApplyTransform(PointF(cp1x,cp1y)),
     1761  curve := BezierCurve(ApplyTransform(GetPenPos(cp1x,cp1y)),ApplyTransform(PointF(cp1x,cp1y)),
    12331762    ApplyTransform(PointF(cp2x,cp2y)),ApplyTransform(PointF(x,y)));
    1234   pts := Surface.ComputeBezierCurve(curve);
     1763  pts := BGRAPath.ComputeBezierCurve(curve);
    12351764  AddPoints(pts);
    1236 end;
    1237 
    1238 procedure TBGRACanvas2D.bezierCurveTo(cp1, cp2, pt: TPointF);
     1765  FLastCoord := PointF(x,y);
     1766end;
     1767
     1768procedure TBGRACanvas2D.bezierCurveTo(const cp1, cp2, pt: TPointF);
    12391769begin
    12401770  bezierCurveTo(cp1.x,cp1.y,cp2.x,cp2.y,pt.x,pt.y);
     
    12471777  LineTo(x+w,y+h);
    12481778  LineTo(x,y+h);
    1249   LineTo(x,y);
     1779  closePath;
    12501780end;
    12511781
     
    12651795  arcTo(PointF(x,y+h),PointF(x,y), radius);
    12661796  arcTo(PointF(x,y),PointF(x+w,y), radius);
     1797  closePath;
     1798end;
     1799
     1800procedure TBGRACanvas2D.roundRect(x, y, w, h, rx, ry: single);
     1801begin
     1802  if (w <= 0) or (h <= 0) then exit;
     1803  if rx < 0 then rx := 0;
     1804  if ry < 0 then ry := 0;
     1805  if (rx = 0) and (ry = 0) then
     1806  begin
     1807    rect(x,y,w,h);
     1808    exit;
     1809  end;
     1810  if rx*2 > w then rx := w/2;
     1811  if ry*2 > h then ry := h/2;
     1812  moveTo(x+rx,y);
     1813  lineTo(x+w-rx,y);
     1814  arcTo(rx,ry,0,false,false,x+w,y+ry);
     1815  lineTo(x+w,y+h-ry);
     1816  arcTo(rx,ry,0,false,false,x+w-rx,y+h);
     1817  lineTo(x+rx,y+h);
     1818  arcTo(rx,ry,0,false,false,x,y+h-ry);
     1819  lineTo(x,y+ry);
     1820  arcTo(rx,ry,0,false,false,x+rx,y);
     1821  closePath;
    12671822end;
    12681823
     
    12731828  transf := ApplyTransform(pts);
    12741829  if (pts[0] = pts[high(pts)]) and (length(pts) > 1) then
    1275     transf := surface.ComputeClosedSpline(slice(transf, length(transf)-1),style)
     1830    transf := BGRAPath.ComputeClosedSpline(slice(transf, length(transf)-1),style)
    12761831  else
    1277     transf := surface.ComputeOpenedSpline(transf,style);
     1832    transf := BGRAPath.ComputeOpenedSpline(transf,style);
    12781833  AddPoints(transf);
     1834  FLastCoord := pts[high(pts)];
    12791835end;
    12801836
     
    12841840  i: Integer;
    12851841begin
     1842  if length(pts) = 0 then exit;
    12861843  transf := ApplyTransform(pts);
    12871844  if FPathPointCount <> 0 then
     
    12901847    for i := high(transf) downto 1 do
    12911848      transf[i]:= transf[i-1];
    1292     transf[0] := GetPenPos;
    1293   end;
    1294   transf := surface.ComputeOpenedSpline(transf,style);
     1849    transf[0] := ApplyTransform(GetPenPos(pts[0].x,pts[0].y));
     1850  end;
     1851  transf := BGRAPath.ComputeOpenedSpline(transf,style);
    12951852  AddPoints(transf);
    1296 end;
    1297 
    1298 procedure TBGRACanvas2D.arc(x, y, radius, startAngle, endAngle: single;
     1853  FLastCoord := pts[high(pts)];
     1854end;
     1855
     1856procedure TBGRACanvas2D.arc(x, y, radius, startAngleRadCW, endAngleRadCW: single;
    12991857  anticlockwise: boolean);
    13001858var pts: array of TPointF;
     
    13051863  unitAffine: TAffineMatrix;
    13061864  v1orig,v2orig,v1ortho,v2ortho: TPointF;
     1865  startRadCCW,endRadCCW: single;
    13071866begin
    13081867  v1orig := PointF(currentState.matrix[1,1],currentState.matrix[2,1]);
     
    13171876  unitAffine := AffineMatrix(v1ortho.x, v2ortho.x, pt.x,
    13181877                             v1ortho.y, v2ortho.y, pt.y);
    1319   startAngle := -startAngle;
    1320   endAngle := -endAngle;
     1878  startRadCCW := -startAngleRadCW;
     1879  endRadCCW := -endAngleRadCW;
    13211880  if not anticlockwise then
    13221881  begin
    1323     temp := startAngle;
    1324     startAngle := endAngle;
    1325     endAngle := temp;
    1326     pts := surface.ComputeArcRad(0,0,rx,ry,startAngle,endAngle);
     1882    temp := startRadCCW;
     1883    startRadCCW := endRadCCW;
     1884    endRadCCW:= temp;
     1885    pts := BGRAPath.ComputeArcRad(0,0,rx,ry,startRadCCW,endRadCCW);
    13271886    pts := ApplyTransform(pts,unitAffine);
    13281887    AddPointsRev(pts);
    13291888  end else
    13301889  begin
    1331     pts := surface.ComputeArcRad(0,0,rx,ry,startAngle,endAngle);
     1890    pts := BGRAPath.ComputeArcRad(0,0,rx,ry,startRadCCW,endRadCCW);
    13321891    pts := ApplyTransform(pts,unitAffine);
    13331892    AddPoints(pts);
    13341893  end;
    1335 end;
    1336 
    1337 procedure TBGRACanvas2D.arc(x, y, radius, startAngle, endAngle: single);
    1338 begin
    1339   arc(x,y,radius,startAngle,endAngle,false);
     1894  FLastCoord := ArcEndPoint(ArcDef(x,y,radius,radius,0,startAngleRadCW,endAngleRadCW,anticlockwise));
     1895end;
     1896
     1897procedure TBGRACanvas2D.arc(x, y, radius, startAngleRadCW, endAngleRadCW: single);
     1898begin
     1899  arc(x,y,radius,startAngleRadCW,endAngleRadCW,false);
     1900end;
     1901
     1902procedure TBGRACanvas2D.arc(cx, cy, rx, ry, xAngleRadCW, startAngleRadCW, endAngleRadCW: single;
     1903  anticlockwise: boolean);
     1904begin
     1905  arc(ArcDef(cx,cy,rx,ry,xAngleRadCW,startAngleRadCW,endAngleRadCW,anticlockwise))
     1906end;
     1907
     1908procedure TBGRACanvas2D.arc(cx, cy, rx, ry, xAngleRadCW, startAngleRadCW, endAngleRadCW: single);
     1909begin
     1910  arc(ArcDef(cx,cy,rx,ry,xAngleRadCW,startAngleRadCW,endAngleRadCW,false))
     1911end;
     1912
     1913procedure TBGRACanvas2D.arc(const arcDef: TArcDef);
     1914var previousMatrix: TAffineMatrix;
     1915begin
     1916  if (arcDef.radius.x = 0) and (arcDef.radius.y = 0) then
     1917    lineTo(arcDef.center) else
     1918  begin
     1919    previousMatrix := currentState.matrix;
     1920    translate(arcDef.center.x,arcDef.center.y);
     1921    rotate(arcDef.xAngleRadCW);
     1922    scale(arcDef.radius.x,arcDef.radius.y);
     1923    arc(0,0,1,arcDef.startAngleRadCW,arcDef.endAngleRadCW,arcDef.anticlockwise);
     1924    currentState.matrix := previousMatrix;
     1925    FLastCoord := ArcEndPoint(arcDef);
     1926  end;
    13401927end;
    13411928
    13421929procedure TBGRACanvas2D.arcTo(x1, y1, x2, y2, radius: single);
    1343 var p0,p1,p2,p3,p4,an,bn,cn,c: TPointF;
    1344     dir, a2, b2, c2, cosx, sinx, d,
    1345     angle0, angle1: single;
    1346     anticlockwise: boolean;
    1347 begin
    1348   if FPathPointCount = 0 then
    1349     moveTo(x1,y1);
    1350   radius := abs(radius);
    1351   p0 := GetPenPos;
    1352   p1 := PointF(x1,y1);
    1353   p2 := PointF(x2,y2);
    1354 
    1355   if (p0 = p1) or (p1 = p2) or (radius = 0) then
    1356   begin
    1357     lineto(x1,y1);
    1358     exit;
    1359   end;
    1360 
    1361   dir := (x2-x1)*(p0.y-y1) + (y2-y1)*(x1-p0.x);
    1362   if dir = 0 then
    1363   begin
    1364     lineto(x1,y1);
    1365     exit;
    1366   end;
    1367 
    1368   a2 := (p0.x-x1)*(p0.x-x1) + (p0.y-y1)*(p0.y-y1);
    1369   b2 := (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
    1370   c2 := (p0.x-x2)*(p0.x-x2) + (p0.y-y2)*(p0.y-y2);
    1371   cosx := (a2+b2-c2)/(2*sqrt(a2*b2));
    1372 
    1373   sinx := sqrt(1 - cosx*cosx);
    1374   if (sinx = 0) or (cosx = 1) then
    1375   begin
    1376     lineto(x1,y1);
    1377     exit;
    1378   end;
    1379   d := radius / ((1 - cosx) / sinx);
    1380 
    1381   an := (p1-p0)*(1/sqrt(a2));
    1382   bn := (p1-p2)*(1/sqrt(b2));
    1383   p3 := p1 - an*d;
    1384   p4 := p1 - bn*d;
    1385   anticlockwise := (dir < 0);
    1386 
    1387   cn := PointF(an.y,-an.x)*radius;
    1388   if not anticlockwise then cn := -cn;
    1389   c := p3 + cn;
    1390   angle0 := arctan2((p3.y-c.y), (p3.x-c.x));
    1391   angle1 := arctan2((p4.y-c.y), (p4.x-c.x));
    1392 
    1393   lineTo(p3.x,p3.y);
    1394   arc(c.x,c.y, radius, angle0, angle1, anticlockwise);
     1930var p0: TPointF;
     1931begin
     1932  p0 := GetPenPos(x1,y1);
     1933  arc(Html5ArcTo(p0,PointF(x1,y1),PointF(x2,y2),radius));
    13951934end;
    13961935
     
    13981937begin
    13991938  arcTo(p1.x,p1.y,p2.x,p2.y,radius);
     1939end;
     1940
     1941procedure TBGRACanvas2D.arcTo(rx, ry, xAngleRadCW: single; largeArc,
     1942  anticlockwise: boolean; x, y: single);
     1943begin
     1944  arc(SvgArcTo(GetPenPos(x,y), rx,ry, xAngleRadCW, largeArc, anticlockwise, PointF(x,y)));
     1945  FLastCoord := PointF(x,y);
     1946end;
     1947
     1948procedure TBGRACanvas2D.circle(x, y, r: single);
     1949begin
     1950  arc(x,y,r,0,0);
     1951end;
     1952
     1953procedure TBGRACanvas2D.ellipse(x, y, rx, ry: single);
     1954begin
     1955  arc(x,y,rx,ry,0,0,0);
     1956end;
     1957
     1958procedure TBGRACanvas2D.text(AText: string; x, y: single);
     1959var renderer : TBGRACustomFontRenderer;
     1960  previousMatrix: TAffineMatrix;
     1961begin
     1962  renderer := fontRenderer;
     1963  if renderer.FontEmHeight <= 0 then exit;
     1964  previousMatrix := currentState.matrix;
     1965
     1966  scale(currentState.fontEmHeight/renderer.FontEmHeight);
     1967  if (currentState.textBaseline <> 'top') and
     1968    (currentState.textBaseline <> 'hanging') then
     1969  with renderer.GetFontPixelMetric do
     1970  begin
     1971    if currentState.textBaseline = 'bottom' then
     1972       translate(0,-Lineheight)
     1973    else if currentState.textBaseline = 'middle' then
     1974       translate(0,-Lineheight/2)
     1975    else if currentState.textBaseline = 'alphabetic' then
     1976       translate(0,-baseline);
     1977  end;
     1978
     1979  if renderer <> nil then
     1980    renderer.CopyTextPathTo(self, x,y, AText, taLeftJustify);
     1981
     1982  currentState.matrix := previousMatrix;
     1983  FLastCoord := EmptyPointF;
     1984  FStartCoord := EmptyPointF;
     1985end;
     1986
     1987procedure TBGRACanvas2D.fillText(AText: string; x, y: single);
     1988begin
     1989  beginPath;
     1990  text(AText,x,y);
     1991  fill;
     1992  beginPath;
     1993end;
     1994
     1995procedure TBGRACanvas2D.strokeText(AText: string; x, y: single);
     1996begin
     1997  beginPath;
     1998  text(AText,x,y);
     1999  stroke;
     2000  beginPath;
     2001end;
     2002
     2003function TBGRACanvas2D.measureText(AText: string): TCanvas2dTextSize;
     2004var renderer: TBGRACustomFontRenderer;
     2005begin
     2006  renderer := fontRenderer;
     2007  if renderer <> nil then
     2008  begin
     2009    with renderer.TextSize(AText) do
     2010    begin
     2011      result.width := cx;
     2012      result.height:= cy;
     2013    end;
     2014  end
     2015  else
     2016  begin
     2017    result.width := 0;
     2018    result.height := 0;
     2019  end;
    14002020end;
    14012021
     
    14422062    currentState.clipMask := surface.NewBitmap(width,height,BGRAWhite);
    14432063  tempBmp := surface.NewBitmap(width,height,BGRABlack);
    1444   tempBmp.FillPolyAntialias(slice(FPathPoints,FPathPointCount),BGRAWhite);
     2064  if antialiasing then
     2065    tempBmp.FillPolyAntialias(slice(FPathPoints,FPathPointCount),BGRAWhite)
     2066  else
     2067    tempBmp.FillPoly(slice(FPathPoints,FPathPointCount),BGRAWhite,dmSet);
    14452068  currentState.clipMask.BlendImage(0,0,tempBmp,boDarken);
    14462069  tempBmp.Free;
     
    14512074  if FPathPointCount = 0 then exit;
    14522075  if currentState.clipMask = nil then exit;
    1453   currentState.clipMask.FillPolyAntialias(slice(FPathPoints,FPathPointCount),BGRAWhite);
     2076  if antialiasing then
     2077    currentState.clipMask.FillPolyAntialias(slice(FPathPoints,FPathPointCount),BGRAWhite)
     2078  else
     2079    currentState.clipMask.FillPoly(slice(FPathPoints,FPathPointCount),BGRAWhite,dmSet);
    14542080  if currentState.clipMask.Equals(BGRAWhite) then
    14552081    FreeAndNil(currentState.clipMask);
Note: See TracChangeset for help on using the changeset viewer.