Skip to content

Commit 2b735f3

Browse files
Use GetOrAdd
1 parent d6b9eb3 commit 2b735f3

File tree

4 files changed

+130
-162
lines changed

4 files changed

+130
-162
lines changed

src/SixLabors.Fonts/Tables/General/Colr/ColrV0GlyphSource.cs

Lines changed: 38 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -30,59 +30,51 @@ public ColrV0GlyphSource(ColrTable colr, CpalTable? cpal, Func<ushort, GlyphVect
3030
/// <inheritdoc/>
3131
public override bool TryGetPaintedGlyph(ushort glyphId, out PaintedGlyph glyph, out PaintedCanvas canvas)
3232
{
33-
if (CachedGlyphs.TryGetValue(glyphId, out (PaintedGlyph Glyph, PaintedCanvas Canvas) cached))
33+
(PaintedGlyph Glyph, PaintedCanvas Canvas) result = CachedGlyphs.GetOrAdd(glyphId, id =>
3434
{
35-
glyph = cached.Glyph;
36-
canvas = cached.Canvas;
37-
return true;
38-
}
39-
40-
glyph = default;
41-
canvas = default;
42-
43-
if (!this.Colr.TryGetColrV0Layers(glyphId, out Span<LayerRecord> resolved))
44-
{
45-
return false;
46-
}
47-
48-
List<PaintedLayer> layers = new(resolved.Length);
49-
50-
for (int i = 0; i < resolved.Length; i++)
51-
{
52-
LayerRecord rl = resolved[i];
53-
54-
GlyphVector? gv = this.GlyphLoader(rl.GlyphId);
55-
if (gv is null || !gv.Value.HasValue())
35+
if (this.Colr.TryGetColrV0Layers(id, out Span<LayerRecord> resolved))
5636
{
57-
continue;
58-
}
37+
List<PaintedLayer> layers = new(resolved.Length);
38+
for (int i = 0; i < resolved.Length; i++)
39+
{
40+
LayerRecord rl = resolved[i];
41+
GlyphVector? gv = this.GlyphLoader(rl.GlyphId);
42+
if (gv is null || !gv.Value.HasValue())
43+
{
44+
continue;
45+
}
5946

60-
// Build geometry once for this layer.
61-
List<PathCommand> path = BuildPath(gv.Value);
47+
// Build geometry once for this layer.
48+
List<PathCommand> path = BuildPath(gv.Value);
6249

63-
// Flatten paint graph: attach composite mode to leaves.
64-
List<Rendering.Paint> leafPaints = [];
65-
PaintSolid paint = new() { PaletteIndex = rl.PaletteIndex, Alpha = 1, Format = 2 };
66-
FlattenPaint(paint, Matrix3x2.Identity, CompositeMode.SrcOver, this.Cpal, leafPaints);
50+
// Flatten paint graph: attach composite mode to leaves.
51+
List<Rendering.Paint> leafPaints = [];
52+
PaintSolid paint = new() { PaletteIndex = rl.PaletteIndex, Alpha = 1, Format = 2 };
53+
FlattenPaint(paint, Matrix3x2.Identity, CompositeMode.SrcOver, this.Cpal, leafPaints);
6754

68-
// Emit one layer per leaf paint.
69-
for (int p = 0; p < leafPaints.Count; p++)
70-
{
71-
// Unlike COLR v1, COLR v0 leaves have no transform so we can reuse the same path.
72-
Rendering.Paint leaf = leafPaints[p];
73-
layers.Add(new PaintedLayer(leaf, FillRule.NonZero, leaf.Transform, null, path));
55+
// Emit one layer per leaf paint.
56+
for (int p = 0; p < leafPaints.Count; p++)
57+
{
58+
// Unlike COLR v1, COLR v0 leaves have no transform so we can reuse the same path.
59+
Rendering.Paint leaf = leafPaints[p];
60+
layers.Add(new PaintedLayer(leaf, FillRule.NonZero, leaf.Transform, null, path));
61+
}
62+
}
63+
64+
if (layers.Count > 0)
65+
{
66+
// Canvas viewBox in Y-up; renderer downstream decides orientation via flag.
67+
PaintedGlyph glyph = new(layers);
68+
PaintedCanvas canvas = new(FontRectangle.Empty, isYDown: false, rootTransform: Matrix3x2.Identity);
69+
return (glyph, canvas);
70+
}
7471
}
75-
}
7672

77-
if (layers.Count == 0)
78-
{
79-
return false;
80-
}
73+
return (default, default);
74+
});
8175

82-
// Canvas viewBox in Y-up; renderer downstream decides orientation via flag.
83-
glyph = new PaintedGlyph(layers);
84-
canvas = new PaintedCanvas(FontRectangle.Empty, isYDown: false, rootTransform: Matrix3x2.Identity);
85-
CachedGlyphs[glyphId] = (glyph, canvas);
86-
return true;
76+
glyph = result.Glyph;
77+
canvas = result.Canvas;
78+
return result.Glyph.Layers.Count > 0;
8779
}
8880
}

src/SixLabors.Fonts/Tables/General/Colr/ColrV1GlyphSource.cs

Lines changed: 47 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -30,70 +30,60 @@ public ColrV1GlyphSource(ColrTable colr, CpalTable? cpal, Func<ushort, GlyphVect
3030
/// <inheritdoc/>
3131
public override bool TryGetPaintedGlyph(ushort glyphId, out PaintedGlyph glyph, out PaintedCanvas canvas)
3232
{
33-
if (CachedGlyphs.TryGetValue(glyphId, out (PaintedGlyph Glyph, PaintedCanvas Canvas) cached))
33+
(PaintedGlyph Glyph, PaintedCanvas Canvas) result = CachedGlyphs.GetOrAdd(glyphId, _ =>
3434
{
35-
glyph = cached.Glyph;
36-
canvas = cached.Canvas;
37-
return true;
38-
}
39-
40-
glyph = default;
41-
canvas = default;
42-
43-
if (!this.Colr.TryGetColrV1Layers(glyphId, out List<ResolvedGlyphLayer>? resolved))
44-
{
45-
return false;
46-
}
47-
48-
List<PaintedLayer> layers = new(resolved.Count);
49-
50-
for (int i = 0; i < resolved.Count; i++)
51-
{
52-
ResolvedGlyphLayer rl = resolved[i];
53-
54-
GlyphVector? gv = this.GlyphLoader(rl.GlyphId);
55-
if (gv is null || !gv.Value.HasValue())
35+
if (this.Colr.TryGetColrV1Layers(glyphId, out List<ResolvedGlyphLayer>? resolved))
5636
{
57-
continue;
58-
}
59-
60-
// Build geometry once for this layer.
61-
List<PathCommand> path = BuildPath(gv.Value);
62-
63-
// Flatten paint graph: accumulate wrapper transforms; attach composite mode to leaves.
64-
List<Rendering.Paint> leafPaints = [];
65-
66-
FlattenPaint(rl.Paint, rl.Transform, rl.CompositeMode, this.Cpal, leafPaints);
67-
68-
// Emit one layer per leaf paint.
69-
Bounds? clip = rl.ClipBox;
70-
for (int p = 0; p < leafPaints.Count; p++)
71-
{
72-
Rendering.Paint leaf = leafPaints[p];
73-
74-
Matrix3x2 xForm = Matrix3x2.Identity;
75-
if (leaf is SolidPaint solid)
37+
List<PaintedLayer> layers = new(resolved.Count);
38+
for (int i = 0; i < resolved.Count; i++)
7639
{
77-
// Move the transform from the paint to the layer.
78-
// We do this so that solid paints are also transformed correctly as
79-
// their location is defined in the local space of the layer.
80-
xForm = solid.Transform;
81-
solid.Transform = Matrix3x2.Identity;
40+
ResolvedGlyphLayer rl = resolved[i];
41+
GlyphVector? gv = this.GlyphLoader(rl.GlyphId);
42+
if (gv is null || !gv.Value.HasValue())
43+
{
44+
continue;
45+
}
46+
47+
// Build geometry once for this layer.
48+
List<PathCommand> path = BuildPath(gv.Value);
49+
50+
// Flatten paint graph: accumulate wrapper transforms; attach composite mode to leaves.
51+
List<Rendering.Paint> leafPaints = [];
52+
FlattenPaint(rl.Paint, rl.Transform, rl.CompositeMode, this.Cpal, leafPaints);
53+
54+
// Emit one layer per leaf paint.
55+
Bounds? clip = rl.ClipBox;
56+
for (int p = 0; p < leafPaints.Count; p++)
57+
{
58+
Rendering.Paint leaf = leafPaints[p];
59+
Matrix3x2 xForm = Matrix3x2.Identity;
60+
if (leaf is SolidPaint solid)
61+
{
62+
// Move the transform from the paint to the layer.
63+
// We do this so that solid paints are also transformed correctly as
64+
// their location is defined in the local space of the layer.
65+
xForm = solid.Transform;
66+
solid.Transform = Matrix3x2.Identity;
67+
}
68+
69+
layers.Add(new PaintedLayer(leaf, FillRule.NonZero, xForm, clip, path));
70+
}
8271
}
8372

84-
layers.Add(new PaintedLayer(leaf, FillRule.NonZero, xForm, clip, path));
73+
if (layers.Count > 0)
74+
{
75+
// Canvas viewBox in Y-up; renderer downstream decides orientation via flag.
76+
PaintedGlyph glyph = new(layers);
77+
PaintedCanvas canvas = new(FontRectangle.Empty, isYDown: false, rootTransform: Matrix3x2.Identity);
78+
return (glyph, canvas);
79+
}
8580
}
86-
}
8781

88-
if (layers.Count == 0)
89-
{
90-
return false;
91-
}
82+
return (default, default);
83+
});
9284

93-
// Canvas viewBox in Y-up; renderer downstream decides orientation via flag.
94-
glyph = new PaintedGlyph(layers);
95-
canvas = new PaintedCanvas(FontRectangle.Empty, isYDown: false, rootTransform: Matrix3x2.Identity);
96-
CachedGlyphs[glyphId] = (glyph, canvas);
97-
return true;
85+
glyph = result.Glyph;
86+
canvas = result.Canvas;
87+
return result.Glyph.Layers.Count > 0;
9888
}
9989
}

src/SixLabors.Fonts/Tables/General/Svg/SvgGlyphSource.cs

Lines changed: 44 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ namespace SixLabors.Fonts.Tables.General.Svg;
2121
internal sealed class SvgGlyphSource : IPaintedGlyphSource
2222
{
2323
private readonly SvgTable svgTable;
24-
private static readonly ConcurrentDictionary<ushort, ParsedDoc> DocCache = [];
24+
private static readonly Dictionary<ushort, ParsedDoc> DocCache = [];
2525
private static readonly ConcurrentDictionary<ushort, (PaintedGlyph Glyph, PaintedCanvas Canvas)> CachedGlyphs = [];
2626

2727
private sealed class ParsedDoc
2828
{
2929
public required XDocument Doc { get; init; }
3030

31-
public required ConcurrentDictionary<string, XElement> IdMap { get; init; }
31+
public required Dictionary<string, XElement> IdMap { get; init; }
3232
}
3333

3434
/// <summary>
@@ -40,58 +40,50 @@ private sealed class ParsedDoc
4040
/// <inheritdoc/>
4141
public bool TryGetPaintedGlyph(ushort glyphId, out PaintedGlyph glyph, out PaintedCanvas canvas)
4242
{
43-
if (CachedGlyphs.TryGetValue(glyphId, out (PaintedGlyph Glyph, PaintedCanvas Canvas) cached))
43+
(PaintedGlyph Glyph, PaintedCanvas Canvas) result = CachedGlyphs.GetOrAdd(glyphId, gid =>
4444
{
45-
glyph = cached.Glyph;
46-
canvas = cached.Canvas;
47-
return true;
48-
}
49-
50-
glyph = default;
51-
canvas = default;
52-
53-
if (!this.TryGetParsedDoc(glyphId, out ParsedDoc? parsed))
54-
{
55-
return false;
56-
}
57-
58-
XElement? root = parsed.Doc.Root;
59-
if (root is null)
60-
{
61-
return false;
62-
}
63-
64-
FontRectangle viewBox = GetViewBox(root);
65-
Matrix3x2 rootTransform = ParseTransform(root.Attribute("transform")?.Value);
66-
67-
// Prefer a dedicated group with id="glyph{gid}", else fall back to the root.
68-
string wantedId = "glyph" + glyphId.ToString(CultureInfo.InvariantCulture);
69-
XElement glyphRoot = parsed.IdMap.TryGetValue(wantedId, out XElement? ge) ? ge : root;
70-
71-
List<PaintedLayer> layers = [];
72-
Walk(
73-
glyphRoot,
74-
rootTransform,
75-
inheritedPaint: null,
76-
outputLayers: layers,
77-
idMap: parsed.IdMap);
45+
if (this.TryGetParsedDoc(gid, out ParsedDoc? parsed))
46+
{
47+
XElement? root = parsed.Doc.Root;
48+
if (root is not null)
49+
{
50+
FontRectangle viewBox = GetViewBox(root);
51+
Matrix3x2 rootTransform = ParseTransform(root.Attribute("transform")?.Value);
52+
53+
// Prefer a dedicated group with id="glyph{gid}", else fall back to the root.
54+
string wantedId = "glyph" + gid.ToString(CultureInfo.InvariantCulture);
55+
XElement glyphRoot = parsed.IdMap.TryGetValue(wantedId, out XElement? ge) ? ge : root;
56+
57+
List<PaintedLayer> layers = [];
58+
Walk(
59+
glyphRoot,
60+
rootTransform,
61+
inheritedPaint: null,
62+
outputLayers: layers,
63+
idMap: parsed.IdMap);
64+
65+
if (layers.Count > 0)
66+
{
67+
PaintedGlyph glyph = new(layers);
68+
PaintedCanvas canvas = new(viewBox, true, rootTransform);
69+
return (glyph, canvas);
70+
}
71+
}
72+
}
7873

79-
if (layers.Count == 0)
80-
{
81-
return false;
82-
}
74+
return (default, default);
75+
});
8376

84-
glyph = new PaintedGlyph(layers);
85-
canvas = new PaintedCanvas(viewBox, true, rootTransform);
86-
CachedGlyphs[glyphId] = (glyph, canvas);
87-
return true;
77+
glyph = result.Glyph;
78+
canvas = result.Canvas;
79+
return result.Glyph.Layers.Count > 0;
8880
}
8981

9082
private bool TryGetParsedDoc(ushort glyphId, [NotNullWhen(true)] out ParsedDoc? parsed)
9183
{
9284
parsed = default;
9385

94-
if (!this.svgTable.TryGetDocumentSpan(glyphId, out int start, out int length))
86+
if (!this.svgTable.TryGetDocumentSpan(glyphId, out int _, out int _))
9587
{
9688
return false;
9789
}
@@ -115,7 +107,7 @@ private bool TryGetParsedDoc(ushort glyphId, [NotNullWhen(true)] out ParsedDoc?
115107
}
116108

117109
// TODO: How large is this likely to get? If large, consider a more memory-efficient structure.
118-
ConcurrentDictionary<string, XElement> idMap = new(Environment.ProcessorCount, capacity: 1024, comparer: StringComparer.Ordinal);
110+
Dictionary<string, XElement> idMap = new(1024, StringComparer.Ordinal);
119111

120112
foreach (XElement e in doc.Root.DescendantsAndSelf())
121113
{
@@ -168,7 +160,7 @@ private static void Walk(
168160
Matrix3x2 parentLocalTransform,
169161
Paint? inheritedPaint,
170162
List<PaintedLayer> outputLayers,
171-
ConcurrentDictionary<string, XElement> idMap)
163+
Dictionary<string, XElement> idMap)
172164
{
173165
Matrix3x2 localTransform = parentLocalTransform * ParseTransform(node.Attribute("transform")?.Value);
174166

@@ -413,7 +405,7 @@ private static FillRule ResolveFillRule(XElement e, FillRule inheritedDefault)
413405
private static Paint? ResolvePaint(
414406
XElement e,
415407
Paint? inherited,
416-
ConcurrentDictionary<string, XElement> idMap,
408+
Dictionary<string, XElement> idMap,
417409
out bool fillNone,
418410
out float opacityMul)
419411
{
@@ -467,7 +459,7 @@ private static FillRule ResolveFillRule(XElement e, FillRule inheritedDefault)
467459
return inherited;
468460
}
469461

470-
private static Paint? ResolvePaintServer(string id, ConcurrentDictionary<string, XElement> idMap)
462+
private static Paint? ResolvePaintServer(string id, Dictionary<string, XElement> idMap)
471463
{
472464
if (!idMap.TryGetValue(id, out XElement? server))
473465
{
@@ -484,7 +476,7 @@ private static FillRule ResolveFillRule(XElement e, FillRule inheritedDefault)
484476
};
485477
}
486478

487-
private static LinearGradientPaint? BuildLinearGradient(XElement grad, ConcurrentDictionary<string, XElement> idMap)
479+
private static LinearGradientPaint? BuildLinearGradient(XElement grad, Dictionary<string, XElement> idMap)
488480
{
489481
GradientUnits units = GradientUnits.ObjectBoundingBox;
490482
SpreadMethod spread = SpreadMethod.Pad;
@@ -583,7 +575,7 @@ private static FillRule ResolveFillRule(XElement e, FillRule inheritedDefault)
583575
};
584576
}
585577

586-
private static RadialGradientPaint? BuildRadialGradient(XElement grad, ConcurrentDictionary<string, XElement> idMap)
578+
private static RadialGradientPaint? BuildRadialGradient(XElement grad, Dictionary<string, XElement> idMap)
587579
{
588580
GradientUnits units = GradientUnits.ObjectBoundingBox;
589581
SpreadMethod spread = SpreadMethod.Pad;
@@ -932,7 +924,7 @@ private static bool TryExtractUrlId(string s, [NotNullWhen(true)] out string? id
932924
return false;
933925
}
934926

935-
private static XElement? LookupById(ConcurrentDictionary<string, XElement> idMap, string href)
927+
private static XElement? LookupById(Dictionary<string, XElement> idMap, string href)
936928
{
937929
if (string.IsNullOrEmpty(href) || href[0] != '#')
938930
{

0 commit comments

Comments
 (0)