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
└── TSVGIconItemFMX Components Hierarchy
TComponent
└── TCustomImageList
└── TSVGIconImageList (cross-platform)
TImage
└── TSVGIconImage (cross-platform display)
TCustomSourceItem
└── TSVGIconSourceItem
TMultiResBitmap
└── TSVGIconMultiResBitmap
└── TCustomBitmapItem
└── TSVGIconBitmapItemFactory 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
// 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 ControlsFMX 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 32x32Advantages:
- 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 implementationTImage32SVG: ISVG implementation- Uses
Image32andImg32.SVG.Readerunits
Rendering Process:
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 TBitmapSkia4Delphi 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 implementationTSkiaSVG: ISVG implementation- Uses
Skia,Skia.APIunits
Rendering Process:
1. Parse SVG → Skia SkDOM
2. Create SkSVGDOM
3. Render to SkSurface
4. Apply effects (color, opacity)
5. Convert to VCL TBitmapDirect2D 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 implementationTD2DSVG: ISVG implementation- Uses
Winapi.D2D1,D2DSVGHandlerunits
Rendering Process:
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 TBitmapSVGMagic Engine
Location: SVGMagicFactory.pas
Implementation:
- Uses SVGMagic library
- GDI+ based rendering
- Windows only
- Good compatibility
Key Classes:
TSVGMagicFactory: Factory implementationTSVGMagic: ISVG implementation- Uses
TWSVG,TWSVGGraphic,TWSVGGDIPlusRasterizer
Rendering Process:
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 TBitmapBitmap Caching Strategy
Cache Structure
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 changeCache Lifecycle
1. Icon Requested
↓
2. Check Cache
├─→ Hit: Return cached bitmap
└─→ Miss: ↓
3. Render SVG
↓
4. Store in Cache
↓
5. Return bitmapCache Invalidation
Triggers that clear cache:
- Size change
- Opacity change
- FixedColor change
- GrayScale change
- SVGText change
- RecreateBitmaps() call
DPI Awareness
VCL DPI Handling
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
// 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
// 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:
- Collection sends update message
- TSVGIconImageList receives message
- Invalidates affected bitmaps
- VirtualImageLists receive ImageCollection message
- All linked controls refresh automatically
Memory Management
Object Lifecycle
// 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 inheritedReference Counting
// ISVG uses interface reference counting
type
ISVG = interface
['{...}']
// Methods...
end;
// Implementations
type
TImage32SVG = class(TInterfacedObject, ISVG)
// Automatically freed when reference count reaches 0Thread 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
// 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:
// 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
// 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)
Recommended SVG Optimizations
For best results:
- Remove unnecessary metadata
- Simplify complex paths
- Use viewBox for scalability
- Minimize decimal precision
- Use consistent units
- Avoid external references