From 86efe3daa4df43ebacd15757342ccc8d1f0b2633 Mon Sep 17 00:00:00 2001 From: sekelsenmat Date: Mon, 24 Jul 2017 15:32:51 +0000 Subject: [PATCH] fpvectorial: Starts adding support for aggpas rendering git-svn-id: trunk@55578 - --- .gitattributes | 4 + components/fpvectorial/fpvectorial.pas | 164 +++----------- components/fpvectorial/fpvectorial2aggpas.pas | 184 ++++++++++++++++ .../fpvectorial/fpvectorial2aggpaspkg.lpk | 38 ++++ .../fpvectorial/fpvectorial2aggpaspkg.pas | 21 ++ components/fpvectorial/fpvectorial2canvas.pas | 207 ++++++++++++++++++ components/fpvectorial/fpvectorialpkg.lpk | 6 +- components/fpvectorial/fpvectorialpkg.pas | 2 +- components/fpvectorial/svgvectorialreader.pas | 5 +- 9 files changed, 497 insertions(+), 134 deletions(-) create mode 100644 components/fpvectorial/fpvectorial2aggpas.pas create mode 100644 components/fpvectorial/fpvectorial2aggpaspkg.lpk create mode 100644 components/fpvectorial/fpvectorial2aggpaspkg.pas create mode 100644 components/fpvectorial/fpvectorial2canvas.pas diff --git a/.gitattributes b/.gitattributes index 085406a3d9..249959051b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1511,6 +1511,10 @@ components/fpvectorial/examples/wmfviewer.lpr svneol=native#text/plain components/fpvectorial/fpvectbuildunit.pas svneol=native#text/plain components/fpvectorial/fpvectorial.pas svneol=native#text/plain components/fpvectorial/fpvectorial.xml svneol=native#text/plain +components/fpvectorial/fpvectorial2aggpas.pas svneol=native#text/plain +components/fpvectorial/fpvectorial2aggpaspkg.lpk svneol=native#text/plain +components/fpvectorial/fpvectorial2aggpaspkg.pas svneol=native#text/plain +components/fpvectorial/fpvectorial2canvas.pas svneol=native#text/plain components/fpvectorial/fpvectorialpkg.lpk svneol=native#text/plain components/fpvectorial/fpvectorialpkg.pas svneol=native#text/plain components/fpvectorial/fpvtocanvas.pas svneol=native#text/plain diff --git a/components/fpvectorial/fpvectorial.pas b/components/fpvectorial/fpvectorial.pas index 7985d9d8d9..ee5bcfb5bd 100644 --- a/components/fpvectorial/fpvectorial.pas +++ b/components/fpvectorial/fpvectorial.pas @@ -567,7 +567,7 @@ type TvClipMode = (vcmNonzeroWindingRule, vcmEvenOddRule); TvEntityWithPenAndBrush = class(TvEntityWithPen) - protected + public procedure CalcGradientVector(out AGradientStart, AGradientEnd: T2dPoint; const ARect: TRect; ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0); @@ -629,7 +629,7 @@ type FCurMoveSubPartIndex: Integer; FCurMoveSubPartSegment: TPathSegment; // - protected + public FPolyPoints: TPointsArray; FPolyStarts: TIntegerDynArray; public @@ -1453,6 +1453,7 @@ type { Drawer selection methods } function GetRenderer: TvRenderer; procedure SetRenderer(ARenderer: TvRenderer); + procedure ClearRenderer(); { Debug methods } procedure GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer = nil); { Events } @@ -1689,7 +1690,13 @@ type end; TvRenderer = class + public + procedure BeginRender(var ARenderInfo: TvRenderInfo; ADoDraw: Boolean); virtual; abstract; + procedure EndRender(var ARenderInfo: TvRenderInfo; ADoDraw: Boolean); virtual; abstract; + // TPath + procedure TPath_Render(var ARenderInfo: TvRenderInfo; ADoDraw: Boolean; APath: TPath); virtual; abstract; end; + TvRendererClass = class of TvRenderer; var GvVectorialFormats: array of TvVectorialFormatData; @@ -1707,6 +1714,7 @@ procedure RegisterVectorialWriter( function Make2DPoint(AX, AY: Double): T3DPoint; function Dimension(AValue : Double; AUnits : TvUnits) : TvDimension; function ConvertDimensionToMM(ADimension: TvDimension; ATotalSize: Double): Double; +procedure RegisterDefaultRenderer(ARenderer: TvRendererClass); implementation @@ -1722,6 +1730,9 @@ var AutoFitDebug: TStrings = nil; {$endif} +var + gDefaultRenderer: TvRendererClass = nil; + {@@ Registers a new reader for a format } @@ -1828,6 +1839,11 @@ begin end; end; +procedure RegisterDefaultRenderer(ARenderer: TvRendererClass); +begin + gDefaultRenderer := ARenderer; +end; + { TvStyle } constructor TvStyle.Create; @@ -3664,6 +3680,7 @@ begin ATo.MulY := AFrom.MulY; ATo.Page := AFrom.Page; ATo.Canvas := AFrom.Canvas; + ATo.Renderer := AFrom.Renderer; ATo.AdjustPenColorToBackground := AFrom.AdjustPenColorToBackground; ATo.BackgroundColor := AFrom.BackgroundColor; ATo.Selected := AFrom.Selected; @@ -5053,134 +5070,9 @@ begin end; procedure TPath.Render(var ARenderInfo: TvRenderInfo; ADoDraw: Boolean); -var - ADest: TFPCustomCanvas absolute ARenderInfo.Canvas; - ADestX: Integer absolute ARenderInfo.DestX; - ADestY: Integer absolute ARenderInfo.DestY; - AMulX: Double absolute ARenderInfo.MulX; - AMulY: Double absolute ARenderInfo.MulY; - // - i: Integer; - j, n: Integer; - x1, y1, x2, y2: Integer; - pts: TPointsArray; - ACanvas: TCanvas absolute ARenderInfo.Canvas; - coordX, coordY: Integer; - curSegment: TPathSegment; - cur2DSegment: T2DSegment absolute curSegment; - lRect: TRect; - gv1, gv2: T2DPoint; begin inherited Render(ARenderInfo, ADoDraw); - - ConvertPathToPolygons(self, ADestX, ADestY, AMulX, AMulY, FPolyPoints, FPolyStarts); - x1 := MaxInt; - y1 := maxInt; - x2 := -MaxInt; - y2 := -MaxInt; - for i := 0 to High(FPolyPoints) do - begin - {$ifdef FPVECTORIAL_AUTOFIT_DEBUG} - if AutoFitDebug <> nil then AutoFitDebug.Add(Format('==[%d=%d]', [FPolyPoints[i].X, FPolyPoints[i].Y])); - {$endif} - x1 := min(x1, FPolyPoints[i].X); - y1 := min(y1, FPolyPoints[i].Y); - x2 := max(x2, FPolyPoints[i].X); - y2 := max(y2, FPolyPoints[i].Y); - end; - CalcEntityCanvasMinMaxXY_With2Points(ARenderInfo, x1, y1, x2, y2); - // Boundary rect of shape filled with a gradient - lRect := Rect(x1, y1, x2, y2); - - if ADoDraw then - begin - // (1) draw background only - ADest.Pen.Style := psClear; - if (Length(FPolyPoints) > 2) then - case Brush.Kind of - bkSimpleBrush: - if Brush.Style <> bsClear then - begin - if (Brush.Style = bsSolid) and (Length(FPolyStarts) > 1) then - // Non-contiguous polygon (polygon with "holes") --> use special procedure - // Disadvantage: it can only do solid fills! - DrawPolygon(ARenderInfo, FPolyPoints, FPolyStarts, lRect) - else - {$IFDEF USE_LCL_CANVAS} - for i := 0 to High(FPolyStarts) do - begin - j := FPolyStarts[i]; - if i = High(FPolyStarts) then - n := Length(FPolyPoints) - j - else - n := FPolyStarts[i+1] - FPolyStarts[i]; // + 1; - ACanvas.Polygon(@FPolyPoints[j], n, WindingRule = vcmNonZeroWindingRule); - end; - {$ELSE} - ADest.Polygon(FPolyPoints); - {$ENDIF} - end; - - bkHorizontalGradient, - bkVerticalGradient, - bkOtherLinearGradient: - begin - // calculate gradient vector - CalcGradientVector(gv1, gv2, lRect, ADestX, ADestY, AMulX, AMulY); - // Draw the gradient - DrawPolygonBrushLinearGradient(ARenderInfo, FPolyPoints, FPolyStarts, lRect, gv1, gv2); - end; - - bkRadialGradient: - DrawPolygonBrushRadialGradient(ARenderInfo, FPolyPoints, lRect); - end; // case Brush.Kind of... - - // (2) draw border, take care of the segments with modified pen - ADest.Brush.Style := bsClear; // We will paint no background - ApplyPenToCanvas(ARenderInfo, Pen); // Restore pen - - PrepareForSequentialReading; - for j := 0 to Len - 1 do - begin - curSegment := TPathSegment(Next); - case curSegment.SegmentType of - stMoveTo: - begin - inc(i); - coordX := CoordToCanvasX(cur2DSegment.X, ADestX, AMulX); - coordY := CoordToCanvasY(cur2DSegment.Y, ADestY, AMulY); - ADest.MoveTo(coordX, coordY); - end; - st2DLineWithPen, st2DLine, st3DLine: - begin - coordX := CoordToCanvasX(cur2DSegment.X, ADestX, AMulX); - coordY := CoordToCanvasY(cur2DSegment.Y, ADestY, AMulY); - if curSegment.SegmentType = st2DLineWithPen then - begin - ADest.Pen.FPColor := AdjustColorToBackground(T2DSegmentWithPen(Cur2DSegment).Pen.Color, ARenderInfo); - ADest.Pen.Width := T2DSegmentWithPen(cur2DSegment).Pen.Width; - ADest.Pen.Style := T2DSegmentWithPen(cur2DSegment).Pen.Style; - ADest.LineTo(coordX, coordY); - ApplyPenToCanvas(ARenderInfo, Pen); - end else - ADest.LineTo(coordX, coordY); - end; - st2DBezier, st3DBezier, st2DEllipticalArc: - begin - coordX := CoordToCanvasX(T2DSegment(curSegment.Previous).X, ADestX, AMulX); - coordY := CoordToCanvasY(T2DSegment(curSegment.Previous).Y, ADestY, AMulY); - SetLength(pts, 1); - pts[0] := Point(coordX, coordY); - curSegment.AddToPoints(ADestX, ADestY, AMulX, AMulY, pts); - if Length(pts) > 0 then - begin - ADest.PolyLine(pts); - ADest.MoveTo(pts[High(pts)].X, pts[High(pts)].Y); - end; - end; - end; - end; - end; + ARenderInfo.Renderer.TPath_Render(ARenderInfo, ADoDraw, Self); end; @@ -8962,6 +8854,7 @@ begin TvEntity.InitializeRenderInfo(ARenderInfo, AEntity, True); ARenderInfo.Canvas := ACanvas; ARenderInfo.Page := Self; + ARenderInfo.Renderer := FOwner.FRenderer; end; constructor TvPage.Create(AOwner: TvVectorialDocument); @@ -9866,6 +9759,7 @@ begin InitializeRenderInfo(RenderInfo, ADest, nil); InitializeRenderInfo(rInfo, ADest, nil); TvEntity.CopyAndInitDocumentRenderInfo(rInfo, RenderInfo, False, False); + if Assigned(FOwner.FRenderer) then FOwner.FRenderer.BeginRender(RenderInfo, ADoDraw); for i := 0 to GetEntitiesCount - 1 do begin @@ -9895,6 +9789,7 @@ begin end; end; + if Assigned(FOwner.FRenderer) then FOwner.FRenderer.EndRender(RenderInfo, ADoDraw); TvEntity.CopyAndInitDocumentRenderInfo(RenderInfo, rInfo, True, False); {$ifdef FPVECTORIAL_RENDERINFO_VISUALDEBUG} @@ -10147,6 +10042,8 @@ begin FCurrentPageIndex := -1; FStyles := TFPList.Create; FListStyles := TFPList.Create; + if gDefaultRenderer <> nil then + FRenderer := gDefaultRenderer.Create; end; {@@ @@ -10154,7 +10051,7 @@ end; } destructor TvVectorialDocument.Destroy; begin - Clear; + Clear(); FPages.Free; FPages := nil; @@ -10163,8 +10060,7 @@ begin FListStyles.Free; FListStyles := nil; - if FRenderer <> nil then - FreeAndNil(FRenderer); + ClearRenderer(); inherited Destroy; end; @@ -10816,9 +10712,15 @@ end; procedure TvVectorialDocument.SetRenderer(ARenderer: TvRenderer); begin + ClearRenderer(); FRenderer := ARenderer; end; +procedure TvVectorialDocument.ClearRenderer; +begin + if FRenderer <> nil then FreeAndNil(FRenderer); +end; + procedure TvVectorialDocument.GenerateDebugTree(ADestRoutine: TvDebugAddItemProc; APageItem: Pointer); var i, lTmpInt: integer; diff --git a/components/fpvectorial/fpvectorial2aggpas.pas b/components/fpvectorial/fpvectorial2aggpas.pas new file mode 100644 index 0000000000..b8b617804e --- /dev/null +++ b/components/fpvectorial/fpvectorial2aggpas.pas @@ -0,0 +1,184 @@ +{ +Implements support for drawing to the LCL TCanvas via AggPas + +License: The same modified LGPL as the Free Pascal RTL + See the file COPYING.modifiedLGPL for more details + +AUTHORS: Felipe Monteiro de Carvalho +} +unit fpvectorial2aggpas; + +{$ifdef fpc} + {$mode objfpc}{$h+} +{$endif} + +{$define USE_CANVAS_CLIP_REGION} +{.$define DEBUG_CANVAS_CLIP_REGION} + +{.$define FPVECTORIAL_DEBUG_DIMENSIONS} +{.$define FPVECTORIAL_TOCANVAS_DEBUG} +{.$define FPVECTORIAL_DEBUG_BLOCKS} +{.$define FPVECTORIAL_AUTOFIT_DEBUG} +{.$define FPVECTORIAL_SUPPORT_LAZARUS_1_6} +// visual debugs +{.$define FPVECTORIAL_TOCANVAS_ELLIPSE_VISUALDEBUG} +{.$define FPVECTORIAL_RENDERINFO_VISUALDEBUG} + +interface + +uses + Classes, SysUtils, Math, TypInfo, contnrs, types, + // FCL-Image + fpcanvas, fpimage, fpwritebmp, + // lazutils + laz2_dom, + // LCL + lazutf8, lazregions, + Graphics, LCLIntf, LCLType, intfgraphics, graphtype, interfacebase, + // AggPas + agg_fpimage, Agg_LCL, + // fpvectorial + fpvutils, fpvectorial; + +type + + { TFPVAggPasRenderer } + + TFPVAggPasRenderer = class(TvRenderer) + private + Bitmap: TBitmap; + AggLCLCanvas: TAggLCLCanvas; + public + procedure BeginRender(var ARenderInfo: TvRenderInfo; ADoDraw: Boolean); override; + procedure EndRender(var ARenderInfo: TvRenderInfo; ADoDraw: Boolean); override; + // TPath + procedure TPath_Render(var ARenderInfo: TvRenderInfo; ADoDraw: Boolean; APath: TPath); override; + end; + +implementation + + +{ TFPVAggPasRenderer } + +procedure TFPVAggPasRenderer.BeginRender(var ARenderInfo: TvRenderInfo; ADoDraw: Boolean); +var + HasFont: Boolean; + FontFilename: String; +begin + Bitmap := TBitmap.Create; + AggLCLCanvas:=TAggLCLCanvas.Create; + AggLCLCanvas.Image.PixelFormat:=afpimRGBA32; + AggLCLCanvas.Image.SetSize(2000, 2000); + + {$IFDEF LCLGtk2} + {HasFont:=true; + FontFilename:=SetDirSeparators('../../verdana.ttf'); + if not FileExistsUTF8(FontFilename) then begin + ShowMessage('file not found: '+FontFilename+' CurDir='+GetCurrentDirUTF8); + HasFont:=false; + end; } + // paint to agg canvas + {with AggLCLCanvas do begin + if HasFont then begin + Font.LoadFromFile(FontFilename); + Font.Size:=10; + Font.Color:=clBlack; + end;} + {$ELSE} + //HasFont:=false; + {$ENDIF} + + // solid white background + AggLCLCanvas.Brush.Color:=clWhite; + AggLCLCanvas.FillRect(0, 0, AggLCLCanvas.Width, AggLCLCanvas.Height); +end; + +procedure TFPVAggPasRenderer.EndRender(var ARenderInfo: TvRenderInfo; ADoDraw: Boolean); +begin + // convert to LCL native pixel format + Bitmap.LoadFromIntfImage(AggLCLCanvas.Image.IntfImg); + TCanvas(ARenderInfo.Canvas).Draw(0, 0, Bitmap); + + AggLCLCanvas.Free; + Bitmap.Free; +end; + +procedure TFPVAggPasRenderer.TPath_Render(var ARenderInfo: TvRenderInfo; + ADoDraw: Boolean; APath: TPath); +var + ADest: TFPCustomCanvas absolute ARenderInfo.Canvas; + ADestX: Integer absolute ARenderInfo.DestX; + ADestY: Integer absolute ARenderInfo.DestY; + AMulX: Double absolute ARenderInfo.MulX; + AMulY: Double absolute ARenderInfo.MulY; + // + i, j, curPt: Integer; + coordX, coordY: Integer; + curSegment: TPathSegment; + cur2DSegment: T2DSegment absolute curSegment; + pts: TPointsArray; +begin + if not ADoDraw then Exit; + + AggLCLCanvas.Pen.Style := APath.Pen.Style; + AggLCLCanvas.Pen.Width := APath.Pen.Width; + AggLCLCanvas.Pen.FPColor := APath.Pen.Color; + AggLCLCanvas.Brush.Style := APath.Brush.Style; + AggLCLCanvas.Brush.FPColor := APath.Brush.Color; + AggLCLCanvas.Brush.AggFillEvenOdd := APath.ClipMode = vcmEvenOddRule; + + AggLCLCanvas.AggResetPath; + APath.PrepareForSequentialReading; + for j := 0 to APath.Len - 1 do + begin + curSegment := TPathSegment(APath.Next); + case curSegment.SegmentType of + stMoveTo: + begin + inc(i); + coordX := CoordToCanvasX(cur2DSegment.X, ADestX, AMulX); + coordY := CoordToCanvasY(cur2DSegment.Y, ADestY, AMulY); + AggLCLCanvas.AggMoveTo(coordX, coordY); + end; + st2DLineWithPen, st2DLine, st3DLine: + begin + coordX := CoordToCanvasX(cur2DSegment.X, ADestX, AMulX); + coordY := CoordToCanvasY(cur2DSegment.Y, ADestY, AMulY); + if curSegment.SegmentType = st2DLineWithPen then + begin + AggLCLCanvas.Pen.FPColor := APath.AdjustColorToBackground(T2DSegmentWithPen(Cur2DSegment).Pen.Color, ARenderInfo); + AggLCLCanvas.Pen.Width := T2DSegmentWithPen(cur2DSegment).Pen.Width; + AggLCLCanvas.Pen.Style := T2DSegmentWithPen(cur2DSegment).Pen.Style; + AggLCLCanvas.AggLineTo(coordX, coordY); + AggLCLCanvas.Pen.Style := APath.Pen.Style; + AggLCLCanvas.Pen.Width := APath.Pen.Width; + AggLCLCanvas.Pen.FPColor := APath.Pen.Color; + end + else + AggLCLCanvas.AggLineTo(coordX, coordY); + end; + st2DBezier, st3DBezier, st2DEllipticalArc: + begin + coordX := CoordToCanvasX(T2DSegment(curSegment.Previous).X, ADestX, AMulX); + coordY := CoordToCanvasY(T2DSegment(curSegment.Previous).Y, ADestY, AMulY); + + SetLength(pts, 1); + pts[0] := Point(coordX, coordY); + curSegment.AddToPoints(ADestX, ADestY, AMulX, AMulY, pts); + for curPt := 0 to Length(pts)-1 do + begin + AggLCLCanvas.AggLineTo(pts[curPt].X, pts[curPt].Y); + end; + AggLCLCanvas.AggMoveTo(pts[High(pts)].X, pts[High(pts)].Y); + end; + end; + end; + if APath.Len > 0 then + begin + AggLCLCanvas.AggClosePolygon; + AggLCLCanvas.AggDrawPath(AGG_FillAndStroke, False); + end; +end; + +end. + diff --git a/components/fpvectorial/fpvectorial2aggpaspkg.lpk b/components/fpvectorial/fpvectorial2aggpaspkg.lpk new file mode 100644 index 0000000000..0c28d5af1e --- /dev/null +++ b/components/fpvectorial/fpvectorial2aggpaspkg.lpk @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/fpvectorial/fpvectorial2aggpaspkg.pas b/components/fpvectorial/fpvectorial2aggpaspkg.pas new file mode 100644 index 0000000000..65f1810912 --- /dev/null +++ b/components/fpvectorial/fpvectorial2aggpaspkg.pas @@ -0,0 +1,21 @@ +{ This file was automatically created by Lazarus. Do not edit! + This source is only used to compile and install the package. + } + +unit fpvectorial2aggpaspkg; + +{$warn 5023 off : no warning about unused units} +interface + +uses + fpvectorial2aggpas, LazarusPackageIntf; + +implementation + +procedure Register; +begin +end; + +initialization + RegisterPackage('fpvectorial2aggpaspkg', @Register); +end. diff --git a/components/fpvectorial/fpvectorial2canvas.pas b/components/fpvectorial/fpvectorial2canvas.pas new file mode 100644 index 0000000000..51e2d9b378 --- /dev/null +++ b/components/fpvectorial/fpvectorial2canvas.pas @@ -0,0 +1,207 @@ +{ +Implements support for drawing to the LCL TCanvas + +License: The same modified LGPL as the Free Pascal RTL + See the file COPYING.modifiedLGPL for more details + +AUTHORS: Felipe Monteiro de Carvalho +} +unit fpvectorial2canvas; + +{$ifdef fpc} + {$mode objfpc}{$h+} +{$endif} + +{$define USE_CANVAS_CLIP_REGION} +{.$define DEBUG_CANVAS_CLIP_REGION} +{$define USE_LCL_CANVAS} + +{.$define FPVECTORIAL_DEBUG_DIMENSIONS} +{.$define FPVECTORIAL_TOCANVAS_DEBUG} +{.$define FPVECTORIAL_DEBUG_BLOCKS} +{.$define FPVECTORIAL_AUTOFIT_DEBUG} +{.$define FPVECTORIAL_SUPPORT_LAZARUS_1_6} +// visual debugs +{.$define FPVECTORIAL_TOCANVAS_ELLIPSE_VISUALDEBUG} +{.$define FPVECTORIAL_RENDERINFO_VISUALDEBUG} + +interface + +uses + Classes, SysUtils, Math, TypInfo, contnrs, types, + // FCL-Image + fpcanvas, fpimage, fpwritebmp, + // lazutils + laz2_dom, + // LCL + lazutf8, lazregions, + Graphics, LCLIntf, LCLType, intfgraphics, graphtype, interfacebase, + // fpvectorial + fpvutils, fpvectorial; + +type + + { TFPVCanvasRenderer } + + TFPVCanvasRenderer = class(TvRenderer) + public + procedure BeginRender(var ARenderInfo: TvRenderInfo; ADoDraw: Boolean); override; + procedure EndRender(var ARenderInfo: TvRenderInfo; ADoDraw: Boolean); override; + // TPath + procedure TPath_Render(var ARenderInfo: TvRenderInfo; ADoDraw: Boolean; APath: TPath); override; + end; + +implementation + +{ TFPVCanvasRenderer } + +procedure TFPVCanvasRenderer.BeginRender(var ARenderInfo: TvRenderInfo; + ADoDraw: Boolean); +begin + +end; + +procedure TFPVCanvasRenderer.EndRender(var ARenderInfo: TvRenderInfo; + ADoDraw: Boolean); +begin + +end; + +procedure TFPVCanvasRenderer.TPath_Render(var ARenderInfo: TvRenderInfo; + ADoDraw: Boolean; APath: TPath); +var + ADest: TFPCustomCanvas absolute ARenderInfo.Canvas; + ADestX: Integer absolute ARenderInfo.DestX; + ADestY: Integer absolute ARenderInfo.DestY; + AMulX: Double absolute ARenderInfo.MulX; + AMulY: Double absolute ARenderInfo.MulY; + // + i: Integer; + j, n: Integer; + x1, y1, x2, y2: Integer; + pts: TPointsArray; + ACanvas: TCanvas absolute ARenderInfo.Canvas; + coordX, coordY: Integer; + curSegment: TPathSegment; + cur2DSegment: T2DSegment absolute curSegment; + lRect: TRect; + gv1, gv2: T2DPoint; +begin + with APath do begin + ConvertPathToPolygons(APath, ADestX, ADestY, AMulX, AMulY, FPolyPoints, FPolyStarts); + x1 := MaxInt; + y1 := maxInt; + x2 := -MaxInt; + y2 := -MaxInt; + for i := 0 to High(FPolyPoints) do + begin + {$ifdef FPVECTORIAL_AUTOFIT_DEBUG} + if AutoFitDebug <> nil then AutoFitDebug.Add(Format('==[%d=%d]', [FPolyPoints[i].X, FPolyPoints[i].Y])); + {$endif} + x1 := min(x1, FPolyPoints[i].X); + y1 := min(y1, FPolyPoints[i].Y); + x2 := max(x2, FPolyPoints[i].X); + y2 := max(y2, FPolyPoints[i].Y); + end; + CalcEntityCanvasMinMaxXY_With2Points(ARenderInfo, x1, y1, x2, y2); + // Boundary rect of shape filled with a gradient + lRect := Rect(x1, y1, x2, y2); + + if ADoDraw then + begin + // (1) draw background only + ADest.Pen.Style := psClear; + if (Length(FPolyPoints) > 2) then + case Brush.Kind of + bkSimpleBrush: + if Brush.Style <> bsClear then + begin + if (Brush.Style = bsSolid) and (Length(FPolyStarts) > 1) then + // Non-contiguous polygon (polygon with "holes") --> use special procedure + // Disadvantage: it can only do solid fills! + APath.DrawPolygon(ARenderInfo, FPolyPoints, FPolyStarts, lRect) + else + {$IFDEF USE_LCL_CANVAS} + for i := 0 to High(FPolyStarts) do + begin + j := FPolyStarts[i]; + if i = High(FPolyStarts) then + n := Length(FPolyPoints) - j + else + n := FPolyStarts[i+1] - FPolyStarts[i]; // + 1; + ACanvas.Polygon(@FPolyPoints[j], n, WindingRule = vcmNonZeroWindingRule); + end; + {$ELSE} + ADest.Polygon(FPolyPoints); + {$ENDIF} + end; + + bkHorizontalGradient, + bkVerticalGradient, + bkOtherLinearGradient: + begin + // calculate gradient vector + CalcGradientVector(gv1, gv2, lRect, ADestX, ADestY, AMulX, AMulY); + // Draw the gradient + DrawPolygonBrushLinearGradient(ARenderInfo, FPolyPoints, FPolyStarts, lRect, gv1, gv2); + end; + + bkRadialGradient: + DrawPolygonBrushRadialGradient(ARenderInfo, FPolyPoints, lRect); + end; // case Brush.Kind of... + + // (2) draw border, take care of the segments with modified pen + ADest.Brush.Style := bsClear; // We will paint no background + ApplyPenToCanvas(ARenderInfo, Pen); // Restore pen + + PrepareForSequentialReading; + for j := 0 to Len - 1 do + begin + curSegment := TPathSegment(Next); + case curSegment.SegmentType of + stMoveTo: + begin + inc(i); + coordX := CoordToCanvasX(cur2DSegment.X, ADestX, AMulX); + coordY := CoordToCanvasY(cur2DSegment.Y, ADestY, AMulY); + ADest.MoveTo(coordX, coordY); + end; + st2DLineWithPen, st2DLine, st3DLine: + begin + coordX := CoordToCanvasX(cur2DSegment.X, ADestX, AMulX); + coordY := CoordToCanvasY(cur2DSegment.Y, ADestY, AMulY); + if curSegment.SegmentType = st2DLineWithPen then + begin + ADest.Pen.FPColor := AdjustColorToBackground(T2DSegmentWithPen(Cur2DSegment).Pen.Color, ARenderInfo); + ADest.Pen.Width := T2DSegmentWithPen(cur2DSegment).Pen.Width; + ADest.Pen.Style := T2DSegmentWithPen(cur2DSegment).Pen.Style; + ADest.LineTo(coordX, coordY); + ApplyPenToCanvas(ARenderInfo, Pen); + end else + ADest.LineTo(coordX, coordY); + end; + st2DBezier, st3DBezier, st2DEllipticalArc: + begin + coordX := CoordToCanvasX(T2DSegment(curSegment.Previous).X, ADestX, AMulX); + coordY := CoordToCanvasY(T2DSegment(curSegment.Previous).Y, ADestY, AMulY); + SetLength(pts, 1); + pts[0] := Point(coordX, coordY); + curSegment.AddToPoints(ADestX, ADestY, AMulX, AMulY, pts); + if Length(pts) > 0 then + begin + ADest.PolyLine(pts); + ADest.MoveTo(pts[High(pts)].X, pts[High(pts)].Y); + end; + end; + end; + end; + end; + end; +end; + +initialization + +RegisterDefaultRenderer(TFPVCanvasRenderer); + +end. + diff --git a/components/fpvectorial/fpvectorialpkg.lpk b/components/fpvectorial/fpvectorialpkg.lpk index ce5c0c1d92..3d658b80a2 100644 --- a/components/fpvectorial/fpvectorialpkg.lpk +++ b/components/fpvectorial/fpvectorialpkg.lpk @@ -9,7 +9,7 @@ - + @@ -110,6 +110,10 @@ + + + + diff --git a/components/fpvectorial/fpvectorialpkg.pas b/components/fpvectorial/fpvectorialpkg.pas index 8ce93b27e0..802d403c2e 100644 --- a/components/fpvectorial/fpvectorialpkg.pas +++ b/components/fpvectorial/fpvectorialpkg.pas @@ -15,7 +15,7 @@ uses rawvectorialreadwrite, svgvectorialreader_rsvg, svgvectorialwriter, svgzvectorialreader, odtvectorialwriter, docxvectorialwriter, htmlvectorialreader, svgvectorialreader, fpvWMF, wmfvectorialreader, - wmfvectorialwriter; + wmfvectorialwriter, fpvectorial2canvas; implementation diff --git a/components/fpvectorial/svgvectorialreader.pas b/components/fpvectorial/svgvectorialreader.pas index 45880931eb..7038878ed0 100644 --- a/components/fpvectorial/svgvectorialreader.pas +++ b/components/fpvectorial/svgvectorialreader.pas @@ -48,6 +48,7 @@ unit svgvectorialreader; {$mode objfpc}{$H+} {$define SVG_MERGE_LAYER_STYLES} +{$define FPVECTORIAL_SVG_SPLIT_PATHS} interface @@ -2468,10 +2469,12 @@ begin APaths.LastPathStart.X := 0; APaths.LastPathStart.Y := 0; APaths.Data.AddLineToPath(PathEndX, PathEndY); + {$IFDEF FPVECTORIAL_SVG_SPLIT_PATHS} APaths.LastPathClosed := True; APaths.IsFirstPathMove := True; APaths.Add(AData.EndPath(True)); AData.StartPath(); + {$ENDIF} Inc(APaths.CurTokenIndex, 1); end @@ -3583,7 +3586,7 @@ begin if lStr[Length(lStr)] = '%' then begin lStr := Copy(lStr, 1, Length(lStr)-1); - Result := Round(StrToFloat(lStr) * $FFFF / 100); + Result := Round(StrToFloat(lStr, FPointSeparator) * $FFFF / 100); end else Result := StrToInt(lStr) * $101; end;