Skip to content

Library Architecture

This document provides a detailed overview of the SVGIconImageList library architecture, design patterns, and internal structure.

Overview

SVGIconImageList is designed with a flexible, modular architecture that separates concerns:

  • Storage Layer: Manages SVG icon collections
  • Rendering Layer: Converts SVG to bitmaps using pluggable engines
  • Presentation Layer: VCL/FMX components for displaying icons
  • Factory Pattern: Abstracts rendering engine implementations

Component Architecture

VCL Components Hierarchy

TComponent
├── TDragImageList
│   └── TSVGIconImageListBase (abstract base)
│       ├── TSVGIconImageList (classic all-in-one)
│       └── TSVGIconVirtualImageList (virtual, Delphi 10.3+)

├── TCustomImageCollection (Delphi 10.3+)
│   └── TSVGIconImageCollection (storage only)

└── TGraphicControl
    └── TSVGIconImage (display component)

TGraphic
└── TSVGGraphic (TPicture integration)

TOwnedCollection
└── TSVGIconItems
    └── TCollectionItem
        └── TSVGIconItem

FMX Components Hierarchy

TComponent
└── TCustomImageList
    └── TSVGIconImageList (cross-platform)

TImage
└── TSVGIconImage (cross-platform display)

TCustomSourceItem
└── TSVGIconSourceItem

TMultiResBitmap
└── TSVGIconMultiResBitmap
    └── TCustomBitmapItem
        └── TSVGIconBitmapItem

Factory Pattern

The library uses the Factory Pattern to abstract SVG rendering engines:

Interface Hierarchy

ISVGFactory
├── GetImage32SVGFactory → TImage32SVGFactory
├── GetSkiaSVGFactory → TSkiaSVGFactory
├── GetD2DSVGFactory → TD2DSVGFactory
└── GetSVGMagicFactory → TSVGMagicFactory

ISVG (common interface)
├── TImage32SVG (Image32 implementation)
├── TSkiaSVG (Skia4Delphi implementation)
├── TD2DSVG (Direct2D implementation)
└── TSVGMagic (SVGMagic implementation)

Factory Selection

pascal
// Global factory selection
SetGlobalSvgFactory(GetImage32SVGFactory);  // Default
SetGlobalSvgFactory(GetSkiaSVGFactory);
SetGlobalSvgFactory(GetD2DSVGFactory);
SetGlobalSvgFactory(GetSVGMagicFactory);

// All new ISVG instances use selected factory
var SVG := GlobalSVGFactory.NewSvg;

Rendering Pipeline

VCL Rendering Flow

1. SVG Source (XML text)

2. ISVG Interface (via Factory)

3. Apply Rendering Attributes
   - FixedColor
   - Opacity
   - GrayScale
   - ApplyFixedColorToRootOnly

4. Engine-Specific Rendering
   - Image32: Rasterize using Image32 library
   - Skia: Render using Skia4Delphi
   - D2D: Render using Direct2D
   - SVGMagic: Render using SVGMagic library

5. TBitmap Output

6. VCL ImageList Integration

7. Display in Controls

FMX Rendering Flow

1. SVG Source (XML text)

2. TFmxImageSVG (engine-specific)
   - TFmxImage32SVG
   - TFmxImageSKIASVG

3. Apply Rendering Attributes
   - FixedColor (TAlphaColor)
   - Opacity
   - GrayScale
   - BitmapZoom

4. Multi-Resolution Bitmap Generation
   - 1x scale
   - 1.5x scale
   - 2x scale
   - 3x scale

5. FMX ImageList Integration

6. Display in Controls (cross-platform)

Storage Patterns

Classic Pattern (TSVGIconImageList)

Used in: All Delphi versions (XE6+)

TSVGIconImageList
├── SVGIconItems: TSVGIconItems
│   ├── Item[0]: TSVGIconItem
│   │   ├── IconName: string
│   │   ├── SVG: ISVG
│   │   └── Rendering properties
│   ├── Item[1]: TSVGIconItem
│   └── ...
└── Bitmap Cache (internal)
    ├── Size 16x16
    ├── Size 24x24
    └── Size 32x32

Advantages:

  • Self-contained
  • Simple to use
  • Works with all Delphi versions

Disadvantages:

  • Duplicate storage for multiple sizes
  • Higher memory usage

Virtual Pattern (TSVGIconImageCollection + VirtualImageList)

Used in: Delphi 10.3+

TSVGIconImageCollection (Storage)
├── SVGIconItems: TSVGIconItems
│   ├── Item[0]: TSVGIconItem (SVG source)
│   ├── Item[1]: TSVGIconItem (SVG source)
│   └── ...
    ↓ Referenced by ↓
TSVGIconVirtualImageList (Size 16)
├── Rendered bitmaps at 16x16
└── Reference to Collection

TSVGIconVirtualImageList (Size 32)
├── Rendered bitmaps at 32x32
└── Reference to Collection (same icons!)

Advantages:

  • Shared storage (memory efficient)
  • Centralized management
  • Multiple sizes from one source

Disadvantages:

  • Requires Delphi 10.3+
  • Slightly more complex setup

SVG Engine Implementations

Image32 Engine

Location: Image32SVGFactory.pas

Implementation:

  • Uses Image32 library by Angus Johnson
  • Pure Pascal implementation
  • No external dependencies
  • Good SVG 1.1 compliance
  • Rasterizes to 32-bit bitmaps

Key Classes:

  • TImage32SVGFactory: Factory implementation
  • TImage32SVG: ISVG implementation
  • Uses Image32 and Img32.SVG.Reader units

Rendering Process:

pascal
1. Parse SVG XML → Image32 SVG object tree
2. Apply transformations and styles
3. Rasterize to Image32 TImage
4. Apply FixedColor/GrayScale/Opacity
5. Convert to VCL TBitmap

Skia4Delphi Engine

Location: SkiaSVGFactory.pas

Implementation:

  • Uses Skia4Delphi wrapper by Vinícius Barbosa
  • Wraps Google's Skia graphics library
  • Excellent rendering quality
  • Hardware acceleration support
  • Strong SVG 1.1 compliance

Key Classes:

  • TSkiaSVGFactory: Factory implementation
  • TSkiaSVG: ISVG implementation
  • Uses Skia, Skia.API units

Rendering Process:

pascal
1. Parse SVG → Skia SkDOM
2. Create SkSVGDOM
3. Render to SkSurface
4. Apply effects (color, opacity)
5. Convert to VCL TBitmap

Direct2D Engine

Location: D2DSVGFactory.pas

Implementation:

  • Uses Windows Direct2D API
  • Native Windows rendering
  • GPU acceleration
  • Requires Windows 7+
  • Good performance on modern Windows

Key Classes:

  • TD2DSVGFactory: Factory implementation
  • TD2DSVG: ISVG implementation
  • Uses Winapi.D2D1, D2DSVGHandler units

Rendering Process:

pascal
1. Parse SVG XML → D2D geometry
2. Create D2D render target
3. Draw geometries with D2D
4. Apply transforms and effects
5. Convert to VCL TBitmap

SVGMagic Engine

Location: SVGMagicFactory.pas

Implementation:

  • Uses SVGMagic library
  • GDI+ based rendering
  • Windows only
  • Good compatibility

Key Classes:

  • TSVGMagicFactory: Factory implementation
  • TSVGMagic: ISVG implementation
  • Uses TWSVG, TWSVGGraphic, TWSVGGDIPlusRasterizer

Rendering Process:

pascal
1. Parse SVG → TWSVG object
2. Create TWSVGGDIPlusRasterizer
3. Render to TWSVGGraphic (bitmap)
4. Apply FixedColor/GrayScale (post-processing)
5. Apply Opacity (AlphaBlend)
6. Return as TBitmap

Bitmap Caching Strategy

Cache Structure

pascal
type
  TBitmapCache = record
    Size: TSize;           // Width x Height
    FixedColor: TColor;
    GrayScale: Boolean;
    Opacity: Byte;
    Bitmap: TBitmap;
    LastAccess: TDateTime;
  end;

// Cached internally per icon per size
// Invalidated when properties change

Cache Lifecycle

1. Icon Requested

2. Check Cache
   ├─→ Hit: Return cached bitmap
   └─→ Miss: ↓
3. Render SVG

4. Store in Cache

5. Return bitmap

Cache Invalidation

Triggers that clear cache:

  • Size change
  • Opacity change
  • FixedColor change
  • GrayScale change
  • SVGText change
  • RecreateBitmaps() call

DPI Awareness

VCL DPI Handling

pascal
procedure TSVGIconImageListBase.DPIChanged(Sender: TObject; const OldDPI, NewDPI: Integer);
begin
  if Scaled then
  begin
    // Calculate new size
    FWidth := MulDiv(FWidth, NewDPI, OldDPI);
    FHeight := MulDiv(FHeight, NewDPI, OldDPI);

    // Recreate bitmaps at new size
    RecreateBitmaps;
  end;
end;

FMX Multi-Scale Handling

pascal
// Automatically generates bitmaps for standard scales
procedure TSVGIconMultiResBitmap.UpdateImageSize(const AWidth, AHeight, AZoom: Integer);
const
  SCALES: array[0..3] of Single = (1.0, 1.5, 2.0, 3.0);
var
  Scale: Single;
begin
  for Scale in SCALES do
  begin
    // Generate bitmap for each scale
    CreateBitmapItem(Round(AWidth * Scale), Round(AHeight * Scale), Scale);
  end;
end;

Message Broadcasting

Update Notification System

pascal
// VCL: Uses messaging system for updates
procedure TSVGIconItems.Update(Item: TCollectionItem);
begin
  inherited;
  TMessageManager.DefaultManager.SendMessage(Self,
    TSVGItemsUpdateMessage.Create);

  // Notify VirtualImageLists (Delphi 10.3+)
  if Owner is TSVGIconImageCollection then
    TMessageManager.DefaultManager.SendMessage(nil,
      TImageCollectionChangedMessage.Create(...));
end;

Automatic Updates

When SVGIconItems change:

  1. Collection sends update message
  2. TSVGIconImageList receives message
  3. Invalidates affected bitmaps
  4. VirtualImageLists receive ImageCollection message
  5. All linked controls refresh automatically

Memory Management

Object Lifecycle

pascal
// Component creation
TSVGIconImageList.Create
  ├─→ Create SVGIconItems collection
  │   └─→ Each item creates ISVG interface
  ├─→ Initialize bitmap cache
  └─→ Subscribe to DPI change messages

// Icon loading
LoadFromFile
  ├─→ Create ISVG via GlobalSVGFactory
  ├─→ Load SVG source
  └─→ Add to collection

// Rendering
GetBitmap(Index, Width, Height)
  ├─→ Check cache
  ├─→ If miss: Render via ISVG.PaintTo
  ├─→ Store in cache
  └─→ Return bitmap

// Component destruction
TSVGIconImageList.Destroy
  ├─→ Free all cached bitmaps
  ├─→ Free SVGIconItems collection
  │   └─→ Each item releases ISVG interface
  └─→ Call inherited

Reference Counting

pascal
// ISVG uses interface reference counting
type
  ISVG = interface
    ['{...}']
    // Methods...
  end;

// Implementations
type
  TImage32SVG = class(TInterfacedObject, ISVG)
  // Automatically freed when reference count reaches 0

Thread Safety

Current Implementation

Not thread-safe by default:

  • Bitmap cache is not synchronized
  • SVG rendering is not thread-safe
  • Collections are not protected by locks

Safe usage:

  • Load all icons on main thread
  • Access from main thread only
  • Use TThread.Synchronize for updates

Thread-Safe Patterns

pascal
// Safe: Load in background, add on main thread
TTask.Run(
  procedure
  var
    SVG: ISVG;
  begin
    SVG := GlobalSVGFactory.NewSvg;
    SVG.LoadFromFile('icon.svg');  // OK: Creates separate ISVG instance

    TThread.Synchronize(nil,
      procedure
      begin
        SVGIconImageList1.Add(SVG, 'icon');  // Must be on main thread
      end
    );
  end
);

Extensibility Points

Custom Rendering Engine

To add a new SVG rendering engine:

pascal
// 1. Implement ISVG interface
type
  TMyCustomSVG = class(TInterfacedObject, ISVG)
  private
    // Your rendering engine integration
  public
    // Implement all ISVG methods
    function IsEmpty: Boolean;
    procedure LoadFromFile(const FileName: string);
    procedure PaintTo(DC: HDC; R: TRectF; KeepAspectRatio: Boolean = True);
    // ... etc
  end;

// 2. Implement ISVGFactory
type
  TMyCustomSVGFactory = class(TInterfacedObject, ISVGFactory)
  public
    function NewSvg: ISVG;
  end;

// 3. Provide factory getter
function GetMyCustomSVGFactory: ISVGFactory;
begin
  if FMyCustomSVGFactory = nil then
    FMyCustomSVGFactory := TMyCustomSVGFactory.Create;
  Result := FMyCustomSVGFactory;
end;

// 4. Use your factory
SetGlobalSvgFactory(GetMyCustomSVGFactory);

Custom Icon Item

pascal
// Extend TSVGIconItem for custom behavior
type
  TMyCustomIconItem = class(TSVGIconItem)
  published
    property CustomProperty: string;
  end;

// Use with custom collection
type
  TMyCustomIconItems = class(TSVGIconItems)
  public
    constructor Create(AOwner: TComponent); override;
  end;

constructor TMyCustomIconItems.Create(AOwner: TComponent);
begin
  inherited Create(AOwner, TMyCustomIconItem);  // Use custom item class
end;

File Format Support

SVG Compliance

Supported SVG 1.1 features:

  • Basic shapes (rect, circle, ellipse, line, polyline, polygon)
  • Paths with all commands
  • Text elements (basic support)
  • Groups and transformations
  • Fill and stroke attributes
  • Gradients (linear, radial)
  • Opacity and colors
  • ViewBox and preserveAspectRatio

Limited support:

  • Filters (depends on engine)
  • Animations (static rendering only)
  • Embedded images (depends on engine)
  • External references

Not supported:

  • JavaScript/ECMA scripts
  • Interactive features
  • SMIL animations (runtime)

For best results:

  1. Remove unnecessary metadata
  2. Simplify complex paths
  3. Use viewBox for scalability
  4. Minimize decimal precision
  5. Use consistent units
  6. Avoid external references

See Also

Released under Apache License, Version 2.0.