RSCL v2 Release Deep Dive

The RiverSoftAVG SVG Component Library version 2.0 was finally released yesterday (Yea! ūüôā ) ¬†Now that v2.0 is “in the can,” I wanted to investigate and explain exactly what has changed. ¬†The RSCL v2.0 has some great¬†new features, a lot of improvements and refactorizations, and over 60¬†bug fixes. ¬†However, the¬†History.txt for the RSCL v2.0 is over 1100¬†lines long for v2.0 beta¬†releases alone, and includes “fixes” of new features, refactorizations, and regressions (all of which should not be considered bug fixes as far as final counts between v1.x and v2.0). ¬†It can be daunting to understand what has really changed, and what really matters, between v1.x and v2.0.

In this blog post, I attempt to separate out the changes and group them logically into

  • New
  • Improved (including refactorizations)
  • Bug Fixes

The New

This is what most people are interested in, the headliner features.

  • Save SVGs to XML – RSCL v2 can now load an SVG, change its properties in code, and then save out a compliant SVG file.
  • Load and Save SVGs to Delphi Binary – a new file format based on Delphi streaming was added.
    textPath example

    textPath example

    This format provides faster loading and saving of SVGs at the expense of being able to use them with other programs (and usually larger file sizes).

  • New Text Support
    • Text on Path

      Baseline Shift Example

      Baseline Shift Example

    • Baseline Shift (i.e., superscript, subscript, shift)
    • Font Variant Support (i.e., Small Caps)
    • Letter Spacing
    • Word Spacing
    • Kerning
    • Direction (i.e., left to right, or right to left. ¬†no bi-directional support though except with simple text elements)
    • Writing Mode (i.e., left to right top to bottom, right to left top to bottom, top to bottom left to right)
    • Glyph Orientation Horizontal (i.e., rotation of characters when going left to right or right to left)

      Writing Mode, Glyph Orientation Example

      Writing Mode, Glyph Orientation Example

    • Glyph Orientation Vertical¬†(i.e., rotation of characters when going top to bottom)
    • X, Y, DX, DY, and Rotation of individual characters
  • New TRSSVGImageList Components (VCL and FMX XE8+) –¬†manage a list of SVGs in your application using TRSSVGImageList. ¬†It embeds every SVG within the image list (simplifying deployment) and re-renders the SVGs as needed. ¬†Like a traditional TImageList, multiple controls can use the same TImageList, either different items or the same item, and it is all managed automatically for you.
  • Detect and respond to mouse events on SVG elements – call TSVGGraphicElement.ElementAtPos to find the element at a screen point or respond to TRSSVGImage.OnClickElement events

    Detect Mouse Events

    Detect Mouse Events

  • New VCL TRSSVGScreen control provides flicker-reduced TRSSVGImage-like¬†control (note that it is not transparent though so you cannot¬†stack TRSSVGScreen controls on top of each other without obscuring¬†SVGs underneath
  • New TSVGDocument DrawBeforeElement, DrawElement, and DrawAfterElement methods – draw specific portions of the SVG in place so that you can buffer to bitmaps unchanging parts (such as background or foreground) to speed up redraws
  • Created RSCL Evaluation version

The Improved

There were a lot of improvements and refactorizations in v2.0.  The following list highlights the most important:

  • Speed Optimizations
    • Refactored TSVGStyle class to store Style=Value pairs in a
      hash table (reduced time to load SVGs)
    • Improved TRSSVGImage (VCL) painting efficiency by deferring bitmap¬†update until Paint call
    • Optimized TSVGElement.Assign method by wrapping assignment in
      BeginUpdate/EndUpdate

      Improved Linear and Radial Gradients

      Improved Linear and Radial Gradients

    • Slightly optimized TRSPathData.GetNum method (used in parsing paths)
  • Linear Gradients
    • Rotate & Scale – Linear Gradients transform based on referencing element
  • Radial Gradients
    • Added Focal point as well as Center Point
  • Text Support
    • Pen Stroke

      Gradients on Text Fill and Stroke

      Gradients on Text Fill and Stroke

    • Path-Based Text Drawing
    • Text Support of GPU Canvas in FMX – the GPU Canvas has real problems with converting text to path and layouts. ¬†The RSCL cleanly handles any difficiencies in GPU Canvas.
  • Font Support
    • ¬†Implemented choosing generic fonts (serif, sans-serif, and monospace)
  • Path Support
    • Added TRSPathData.FormatStr property to allow formatting the floating¬†point values, generally to make the GetPathString return a smaller¬†string to reduce the size of saved SVG files
  • Refactoring
    • TSVGLength (and descendants) – manages a length in SVG, which includes a raw value and the unit it is enumerated in (e.g., millimeters). ¬†To refactor the SVG from a static SVG viewer to a static SVG editor¬†required some major changes to the TSVGxxxElement classes and their¬†properties, generally to be able to save properties that were read (before¬†the elements would convert the svg values and then discard any extraneous¬†information. For example, to save a length value such as ‘1in’ requires¬†saving the raw value (1) and the unit (in) instead of the converted value¬†(96 pixels).
    • TSVGViewBox –¬†Refactored ViewBox property from TSVGRect (record) to TSVGViewBox *object*
    • The behavior of TSVGDocument.OnChange event has changed. The OnChange¬†event usually does not get called when the structure of the SVG¬†has changed anymore; please use the ¬†SVGDocument.OnAddElement¬†and ¬†SVGDocument.OnRemoveElement property instead. The Sender
      parameter is now set to the element where the change occurs.
      If the Sender is nil, this means that the change event occurred
      because of BeginUpdate/EndUpdate method calls; in this case it
      can mean that the structure of the SVG document has changed.
    • Moved basic SVG shape elements (rect, ellipse, etc) to
      RSSVG.BasicShapes.pas and FMX.RS.SVG.BasicShapes.pas
    • Moved SVG text elements to RSSVG.Text.pas and FMX.RS.SVGText.pas
  • TSVGDocument Improvements
    • Gradients property to track list of Gradients in document
    • Markers property to track list of Markers in document
    • Patterns property to track list of Patterns in document
  • TSVGElement (base class for every element in SVG) Improvements
    • BoundsRect property is¬†writable as well
      as readable
    • Added Enabled property (Disabled elements are drawn
      grayed out and ignored in ElementAtPos method calls by default)
    • ToString method¬†returns XML string of¬†element and its children
    • Added OnAddElement event
    • Added OnRemoveElement event
    • Modified the behavior of OnChange event to set the¬†Sender to the element that changed. If Sender = nil then it means¬†the structure of the SVG has changed
    • Modified OnDrawing event signature to include a DoDraw
      parameter. If this variable is set to false, the current Element
      will NOT be drawn. However, its children may still be.
    • Added mechanism¬†to TSVGElement to track and notify listeners if the
      current element is changed. For example, this allows TSVGUse to be notified when the elements that it uses changes and then to ask to be redrawn
  • TSVGGraphicElement (base class for every visible SVG element) Improvements
    • Modified behavior of Style Properties (e.g.,
      ClipRule, Overflow, ShapeRendering, etc) to automatically
      remove themselves from Inherits property when they are changed
  • TSVGBrush Improvements
    • Added ParentColor property
    • Added ParentOpacity property
    • Added OnIsInherited event
  • TSVGFont Improvements
    • Added IsDecorated method to return if font is decorated (underlined,¬†strike-out or overline)
    • Added ParentFamily property
    • Added ParentFontVariant property
    • Added ParentSize property
    • Added ParentStyle property
    • Added ParentDecorated property
    • Added ParentWeight property
    • Added OnIsInherited event
  • TSVGPen Improvements
    • Added ParentColor property
    • Added ParentOpacity property
    • Added ParentDasharray property
    • Added ParentDashOffset property
    • Added ParentLinecap property
    • Added ParentLineJoin property
    • Added ParentMiterLimit property
    • Added ParentThickness property
    • Added OnIsInherited event
  • New Demo Projects
    • Printer (VCL)
    • Editor (FMX)
    • Anatomy (VCL)
    • Clock World (FMX)
    • Stream (FMX)
    • ImageList (VCL)
    • ImageList (FMX)

The Fixed

The number of bugs fixed is a great case of that there are lies, damn lies, and statistics. ¬†ūüôā ¬†There are at least 66 bug fixes in RSCL v2.0 versus v1.9. ¬†The number is open to interpretation as a lot of ParseXXX functions were fixed with a simple copy and paste of correct function parameters. ¬†Should these be included? ¬†Also, fixing bugs in FMX and VCL can technically be separate bug fixes as both have to be tested. ¬†This became a judgement call and is reflected below.

Without further ado, here is the lists of bugs fixed in RSCL v2.0:

  • Fixed edge case memory leak in TSVGDocument.Clear by freeing styles
    (Styles.Clear does not call OnValueNotify event so styles
    were not being freed)
  • Fixed edge case memory leak in TSVGDocument.Destroy by freeing styles¬†(Styles.Clear does not call OnValueNotify event so styles
    were not being freed)
  • Fixed graphical corruption in pattern by clearing canvas before
    generating pattern in TSVGPattern.GetPattern method
  • Fixed TSVGGraphicElement.GetBoundsRect(TSVGMatrix) method to
    correctly transform the bounds rectangle (including rotation) and return the boundsrect for the transformed boundsrect
  • Fixed font-family style property support (on Windows and Mac)
    to include list of font families and supporting generic (serif,
    sans-serif, and monospace) fonts
    Note: The first font found on the system is used. The RSCL
    does not support detecting a character is not present in the
    current font and selecting the next font in the list for that
    character
  • Fixed TSVGLinearGradient.GetGradient method to account for
    transformations of the gradient
  • Fixed TSVGGraphicElement.GetClipRect method to slightly inflate
    clipping rectangle to be bigger than BoundsRect
  • Fixed value of SVGAlignNames[saNone] to equal ‘none’
  • Fixed bug in TSVGElement.Assign method where Items were SHARED
    instead of copied/cloned
  • Fixed TRSSVGDocument/TRSFmxSVGDocument.LoadSVGFromStrings method to correctly read unicode TStrings
  • Fixed floating point error in TSVGMarker.DrawMidMarker method
  • Fixed floating point error in TSVGMarker.MidMarkerAtPos method
  • Fixed SVGs to be properly clipped when Overflow attribute is hidden
  • Fixed TSVGCustomViewBox.Draw method to correctly modify the matrix
    for the ViewBox (if specified) or BoundsRect INSTEAD of modifying
    the drawing rectangle
  • Fixed markers to be properly clipped when Overflow attribute is hidden
  • Fixed correctly setting FillMode for TRSSVGPath control (VCL)
    in TSVGPolyline.AssignTo method
  • Fixed CleanText function to strip off control characters before
    seeing if any spaces should be appended to left or right
  • Fixed bug in TRSGPBrush.Assign method where TBrush.Color was
    incorrectly converted to alpha color (VCL Only)
  • Fixed bug in TRSGPPen.Assign method where TBrush.Color was
    incorrectly converted to alpha color (VCL Only)
  • Fixed bug in ToMatrix function where result matrix was not
    zeroed out before retrieving the matrix elements (VCL Only)
  • Fixed TSVGCustomViewBox.GetBoundsRect method to return children’s
    combined boundsrect if the Width and Height are not set for the
    viewbox
  • Fixed bug in TSVGGraphicElement.AssignProperties method where
    ClipRect was not being copied correctly
  • Fixed bug in TSVGElement.Assign method where incorrect Owner
    was being assigned if Self was TSVGDocument
  • Fixed TSVGElement.HasAncestor method
  • Fixed bug in TSVGDocument.ReadStyles method where descendant
    selectors were parsed as if they were grouped together (e.g.,
    ‘#alpha * {fill:green}’ would be separated into 2 styles,¬†‘#alpha’ and ‘*’
  • Fixed TSVGImage.DoInternalDraw method to preserve aspect ratio
    when drawing image
  • Fixed bug in TSVGCustomText where BoundsRect would be reported
    incorrectly when a font property would change (overrode
    TSVGCustomText.PropagateObjectPropChange method to force
    recalculation of TextWidth and TextHeight)
  • Fixed ParseRect function to return empty rect if Value does not
    contain 4 numbers
  • Fixed access violation when accessing TRSGPImage Codecs (VCL Only)
  • Fixed bug in installer which would not set the library path correctly
    for iOS64 in XE8+
  • Fixed TSVGGraphicElement.SetCursor method to set inherits for
    cursor to false when changed
  • Fixed TSVGElement.Destroy method so that you can just call
    Element.Free and it will correctly remove itself from its parent
  • Fixed subtle bug where setting TSVGBrush.Kind property would be overwritten¬†if the URI contained a gradient or pattern URI (which would reset¬†the Kind to bkGradient/bkBitmap
  • Fixed subtle bug where setting TSVGPen.Kind property would be overwritten¬†if the URI contained a gradient or pattern URI (which would reset¬†the Kind to bkGradient/bkBitmap
  • Fixed bug in ParseOverflow function where ‘auto’ was not correctly
    interpreted as visible
  • Fixed finding Design-time ‘Help…’ topics by searching for¬†Unit_ClassName, not Unit.ClassName
  • Fixed TSVGRadialGradient.GetGradient method to correctly calculate
    focal point when it is a percentage
  • Fixed TSVGRadialGradient.GetGradient method to correctly calculate
    rotation center when units are csuObjectBoundingBox
  • Fixed FMX to use Shape Caching (accidentally turned off)
  • Fixed bug in TSVGUse.ShouldDraw method where it would display
    a referenced element when the TSVGUse.Visible=False and the
    Reference.Visible=inherit
  • Fixed bug in TSVGImage.Draw method where image would be drawn even¬†if not visible
  • Fixed incorrect calculation for picas in TSVGDocument.CalcUnitFactors
    method
  • Fixed bug in TSVGGraphicElement.AssignTo method where FloatToStr
    was not using USFormatSettings (as required by SVG spec)
  • Fixed TSVGGraphicElement.FillRule default property value to frNonZero
  • Fixed bug in TSVGDocument.SupportsLanguage method to return FALSE
    if input string is empty
  • Fixed TSVGElement.HasExtensions to return FALSE when an empty string
    is supplied
  • Fixed TSVGElement.HasFeatures to return FALSE when an empty string
    is supplied
  • Fixed TSVGElement.HasLanguages to return FALSE when an empty string
    is supplied
  • Fixed bug in TSVGGraphicElement.BeginDraw method where Canvas.Font.Brush¬†was not set in VCL
  • Improved csuObjectBoundingBox handling in TSVGPattern.GetPattern method¬†(still incorrect but better)
  • Fixed bug in TRSFmxSVGDocument destructor where viewers are not
    notified the document is going away
  • Fixed bug in TSVGText.DoLoadFromXML method where multiple
    spaces (and other control codes) between words were not removed
    for the Text property
  • Fixed TSVGText.GetBounds to return an accurate Bounding box
    after the first time the text is drawn (DoInternalDraw caches
    TextWidth and TextHeight for later use)
  • Improved appearance of overline extended style for TSVGText
    (now a rectangle instead of thin line)
  • Fixed bug in TSVGPolyline.GetShape method where 2 ClosePaths
    could be added in a row, causing FMX to black out the entire canvas
    (However, this bug was hidden until fixed bug where FMX was not
    using Shape Caching)
  • Fixed ParseFontFamily function to return a list of font names
  • Fixed GetSVGUnit function to return suPercent if input string
    ends with ‘%’ (before input string had to be exactly equal)
  • Fixed bug in ParsePoints where if number of values was not even,
    NO points would be returned. Now, all the points except the
    missing last one are returned (follows SVG specification)
  • Fixed ParseNumbers function to also use line feeds and carriage returns
    as delimiters
  • Fixed ParseXXX function to also use line feeds and carriage returns
    as delimiters
  • Fixed bug in TRSGPPath.AddText(Pt: TPointF;…) method where
    aRect was not initialized for measuring the text properly
  • Fixed invalid parameter for GDI+ function bug in TRSGPPath.AddPolygon
    method by ensuring at least 3 points are specified
  • Fixed TRSGPFont.GetHeight method to return a value even when
    Owner is nil
  • Fixed access violation in TSVGCustomGradient.ElementNotification method¬†where the method tried to use the Item after it had been freed
    by inherited method
  • Fixed bug in TRSPathData.GetPathString method to use USFormatSettings¬†for FloatToStr calls
  • Fixed bug in TRSPathData.AddArcSvg method where arcs that begin
    and end at same point would not get added (now adds ellipse)

Leave a Reply

Your email address will not be published. Required fields are marked *