Recent

Author Topic: SVG parsing issue  (Read 207 times)

CCRDude

  • Hero Member
  • *****
  • Posts: 502
SVG parsing issue
« on: October 30, 2019, 10:57:22 am »
I've been using BGRABitmap for a few years now. After initial problems with my SVGs, it worked like a charm... until two days ago I updated Lazarus & FPC to the latest trunk, and updated BGRABitmap as well, from 9.9.1 (or .3?) to 10.6.2.0 (from OPM). Now my GUI crashes on calling draw on TBGRASVG objects, ignoring the existing exception handling...

Code: [Select]
Project Test raised exception class 'External: SIGSEGV'.
At address 5B0EC5

Here's the crash callstack:

Code: [Select]
#0 BGRASVGTYPE$_$TSVGELEMENT_$__$$_APPLYSTROKESTYLE$TBGRACANVAS2D$TCSSUNIT at :0
#1 BGRASVGSHAPES$_$TSVGPATH_$__$$_INTERNALDRAW$TBGRACANVAS2D$TCSSUNIT at :0
#2 BGRASVGSHAPES$_$TSVGPATH_$__$$_INTERNALDRAW$TBGRACANVAS2D$TCSSUNIT at :0
#3 BGRASVGTYPE$_$TSVGELEMENT_$__$$_DRAW$TBGRACANVAS2D$TCSSUNIT at :0
#4 ?? at :0

Here's the crashing code example:
Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
var
   w, h: TFloatWithCSSUnit;
   c: TCSSUnitConverter;
   dWidth, dHeight: single;
   ico: TBGRASVG;
   bmp: TBGRABitmap;
begin
   ico := TBGRASVG.Create('c:\qa\bgra-test.svg');
   w := ico.Width;
   h := ico.Height;
   c := TCSSUnitConverter.Create;
   try
      dWidth := c.ConvertWidth(w.Value, w.CSSUnit, cuPixel) * ScreenInfo.PixelsPerInchX / 96;
      dHeight := c.ConvertHeight(h.Value, h.CSSUnit, cuPixel) * ScreenInfo.PixelsPerInchY / 96;
      bmp := TBGRABitmap.Create((Round(dWidth)), (Round(dHeight)), BGRAPixelTransparent);
      try
         ico.Draw(bmp.Canvas2D, 0, 0, cuPixel); // this call crashes
         Image1.Picture.Assign(bmp.Bitmap);
         bmp.SaveToFile(ExtractFilePath(ParamStr(0)) + 'test.png');
      except
         on E: Exception do begin
            {$IFDEF MSWindows}
            // not triggered, program already crashed
            OutputDebugString('Unable to convert resource from SVG to PNG');
            {$ENDIF MSWindows}
         end;
      end;
   finally
      c.Free;
   end;
end;

I've been trying out various things. If I add BGRABitmap by source path (and remove the package code), debug mode will work (as will 64 bit Windows release binary, but not 32 bit Windows release binary).

This looks like some kind of optimization kills functionality in release mode (standard release mode from build mode manager) - both if directly compiled by source path, and by using the package (which is with release mode settings I guess).

Without the package, at least the exception handling gets triggered, with an "Access violation".

CCRDude

  • Hero Member
  • *****
  • Posts: 502
Re: SVG parsing issue
« Reply #1 on: October 30, 2019, 12:47:10 pm »
By enabling debug information in the release build, I could track tit down to the line in TSVGElement.ApplyStrokeStyle in BGASVGType.pas: line 1842:

Code: [Select]
lw := Units.ConvertWidth(strokeWidth,AUnit).value;
By splitting a bit of code and some further debugging, it looks like the problem is here:

Code: [Select]
function TSVGElement.GetStrokeWidth: TFloatWithCSSUnit;
begin
  result := OrthoAttributeOrStyleWithUnit['stroke-width',FloatWithCSSUnit(1,cuCustom)];
end;

The return result of TSVGCustomElement.GetOrthoAttributeOrStyleWithUnit is still correct (9.782999999999, cucustom in my case), but the debugger is no longer able to show the return result of GetStrokeWidth in its last line (cannot access memory at address 0x0).

The difference is in -O1 and -O3.

Lazarus 2.1. FPC 3.3.1. svn rev 62415.

Compiling the package with -O2 instead of -O3 gets rid of the error.

circular

  • Hero Member
  • *****
  • Posts: 3053
    • Personal webpage
Re: SVG parsing issue
« Reply #2 on: October 30, 2019, 02:59:23 pm »
Hmmm could be a problem with the compiler with record types.

I had some strange issues as well with TPointF. Sometimes the problem was fixed by adding compiler directives around to disable optimizations.

Side note:
- you scale the bitmap according to ScreenInfo.PixelsPerInch, though later you call the Draw function of the SVG without supplying the DPI or the rectangle area (StretchDraw). So the size may not match the bitmap.
- you don't need to create your own TCSSUnitConverter, instead you could use the Units property of the TBGRASVG object.
Conscience is the debugger of the mind