Class SvgIcon
- All Implemented Interfaces:
Icon
Icon: keeps the SVG source and lazily rasterizes it
(via the installed SvgRasterizer) to a cached Image per
requested pixel size (a small LRU of 16 sizes). Because it rasterizes at the exact device size it
is drawn at (see Icon.paint(limn.graphics.Canvas, float, float, float, limn.graphics.Color, boolean)), an SVG icon stays crisp on HiDPI and at
any zoom: no blur from up/down-sampling a fixed bitmap. Draw it tinted to
recolor with the theme (SVG icons are single-color masks, so Icon.tintable()
is true); draw it untinted to keep the SVG's own colors.
Each rasterized Image is cached and its identity is the GPU texture
key, so reusing one SvgIcon reuses a single texture per size across the
whole UI. Rasterization needs the backend running (the rasterizer is installed
at startup); call image() during setup to warm the cache if desired.
An instance is confined to the UI thread: the size cache is a plain
LRU map with no lock, and it is written by every miss. image(int) and
image(int, boolean) therefore reject any other thread once a backend is
running. The one way to move the parse and rasterize off that thread is
imageAsync(int), which does the work on the worker pool and folds the
result back in here.
-
Nested Class Summary
Nested classes/interfaces inherited from interface limn.graphics.Icon
Icon.Mirroring -
Method Summary
Modifier and TypeMethodDescriptionstatic SvgIconfromResource(String path) An icon from a classpath resource (e.g.image()Base-resolution bitmap, a convenience for warming the cache or ad-hoc draws.image(int pixelSize) Rasterized bitmap fit intopixelSizepx (cached; stable identity, because that identity is the GPU texture key).image(int pixelSize, boolean dark) Iconentry point: rasterizes at the requested device size (theme brightness is irrelevant; SVG icons recolor by tint, not by variant).imageAsync(int pixelSize) Rasterizes forpixelSizeon theUiworker pool and folds the bitmap into this icon's cache on the UI thread, so the nextimage(int)at that size is a hit and no frame pays for the parse.static voidinstallRasterizer(SvgRasterizer newRasterizer) Installs the backend rasterizer (called by the backend at startup).static booleanWhether SVG icons can be rasterized at all; without one they draw nothing.static SvgIconAn icon from raw SVG source.static voiduninstallRasterizer(SvgRasterizer expected) Removes the rasterizer if it is stillexpected, so a late teardown cannot clear a newer one.
-
Method Details
-
of
An icon from raw SVG source. -
fromResource
An icon from a classpath resource (e.g."/limn/demo/icons/search.svg").Reads the resource on the calling thread and needs no asynchronous form: an icon is a few kilobytes of text, read once from a jar the class loader already has open, and nothing is parsed or rasterized here; the expensive half happens later, in
image(int), which does have one. -
installRasterizer
Installs the backend rasterizer (called by the backend at startup). -
uninstallRasterizer
Removes the rasterizer if it is stillexpected, so a late teardown cannot clear a newer one. -
isRasterizerInstalled
public static boolean isRasterizerInstalled()Whether SVG icons can be rasterized at all; without one they draw nothing. -
image
Rasterized bitmap fit intopixelSizepx (cached; stable identity, because that identity is the GPU texture key).A miss parses and rasterizes the SVG on the calling thread, and the calling thread is normally the UI thread inside
Icon.paint(limn.graphics.Canvas, float, float, float, limn.graphics.Color, boolean), so the first paint at a new content scale, at a new size step, or at each step of a zoom gesture, pays a parse and a rasterize inside that frame.imageAsync(int)is the form that pays it on the worker pool; calling that ahead of the paint (on a scale change, or during setup) is what keeps the frame clean. There is no asynchronous form ofIcon.image(int, boolean)itself, and there should not be: a paint asking for a bitmap has to be answered during that paint.- Parameters:
pixelSize- target extent in device pixels; values below 1 are treated as 1- Throws:
IllegalStateException- if called off the UI thread while a backend is running, or if noSvgRasterizeris installed
-
imageAsync
Rasterizes forpixelSizeon theUiworker pool and folds the bitmap into this icon's cache on the UI thread, so the nextimage(int)at that size is a hit and no frame pays for the parse. Returned unstarted:icon.imageAsync(px) .onSuccess(bitmap -> requestRepaint()) .deliverIf(this::isAttached) .start();The delivered
Imageis the one this icon now has cached for that size, so drawing it and drawingimage(int)share a single texture. A size already cached is delivered without rasterizing anything again, but a size still in flight is not: unlikeImages.loadShared(java.nio.file.Path), two calls for one size before the first lands rasterize twice, and the second bitmap replaces the first in the cache. Warm a size once, or hold theJoband cancel it before asking again.Cancelling stops the delivery, not the work: if the rasterize had already finished, the bitmap is still folded into the cache; it is paid for either way, and the next paint at that size may as well have it. A failure (no installed rasterizer, malformed SVG) reaches
onFailureon the UI thread; nothing is thrown from here.- Parameters:
pixelSize- target extent in device pixels; values below 1 are treated as 1- Throws:
IllegalStateException- if called off the UI thread, or if no backend is running
-
image
Iconentry point: rasterizes at the requested device size (theme brightness is irrelevant; SVG icons recolor by tint, not by variant). UI thread, with the miss cost described onimage(int). -
image
Base-resolution bitmap, a convenience for warming the cache or ad-hoc draws. UI thread.
-