Browse Source

CachingGlyphRenderer: use a 1 dictionary instead of 3

af/merge-core
Anton Firszov 8 years ago
parent
commit
bd65fc543c
  1. 71
      src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs

71
src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs

@ -167,19 +167,19 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
private PathBuilder builder;
private Point currentRenderPosition = default;
private GlyphRendererParameters currentRenderingGlyph = default;
private GlyphRendererParameters currentGlyphRenderParams = default;
private int offset = 0;
private PointF currentPoint = default(PointF);
private HashSet<GlyphRendererParameters> renderedGlyphs = new HashSet<GlyphRendererParameters>();
private Dictionary<GlyphRendererParameters, Buffer2D<float>> glyphMap;
private Dictionary<GlyphRendererParameters, Buffer2D<float>> glyphMapPen;
private readonly Dictionary<GlyphRendererParameters, GlyphRenderData> glyphData = new Dictionary<GlyphRendererParameters, GlyphRenderData>();
private bool renderOutline = false;
private bool renderFill = false;
private bool raterizationRequired = false;
public CachingGlyphRenderer(MemoryAllocator memoryManager, int size, IPen pen, bool renderFill)
public CachingGlyphRenderer(MemoryAllocator memoryAllocator, int size, IPen pen, bool renderFill)
{
this.MemoryManager = memoryManager;
this.MemoryAllocator = memoryAllocator;
this.Pen = pen;
this.renderFill = renderFill;
this.renderOutline = pen != null;
@ -187,14 +187,12 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
if (this.renderFill)
{
this.FillOperations = new List<DrawingOperation>(size);
this.glyphMap = new Dictionary<GlyphRendererParameters, Buffer2D<float>>();
}
if (this.renderOutline)
{
this.offset = (int)MathF.Ceiling((pen.StrokeWidth * 2) + 2);
this.OutlineOperations = new List<DrawingOperation>(size);
this.glyphMapPen = new Dictionary<GlyphRendererParameters, Buffer2D<float>>();
}
this.builder = new PathBuilder();
@ -204,7 +202,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
public List<DrawingOperation> OutlineOperations { get; }
public MemoryAllocator MemoryManager { get; internal set; }
public MemoryAllocator MemoryAllocator { get; internal set; }
public IPen Pen { get; internal set; }
@ -221,8 +219,8 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
// we have offset our rendering origion a little bit down to prevent edge cropping, move the draw origin up to compensate
this.currentRenderPosition = new Point(this.currentRenderPosition.X - this.offset, this.currentRenderPosition.Y - this.offset);
this.currentRenderingGlyph = paramters;
if (this.renderedGlyphs.Contains(paramters))
this.currentGlyphRenderParams = paramters;
if (this.glyphData.ContainsKey(paramters))
{
// we have already drawn the glyph vectors skip trying again
this.raterizationRequired = false;
@ -254,21 +252,12 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
public void Dispose()
{
if (this.renderFill)
foreach (KeyValuePair<GlyphRendererParameters, GlyphRenderData> kv in this.glyphData)
{
foreach (KeyValuePair<GlyphRendererParameters, Buffer2D<float>> m in this.glyphMap)
{
m.Value.Dispose();
}
kv.Value.Dispose();
}
if (this.renderOutline)
{
foreach (KeyValuePair<GlyphRendererParameters, Buffer2D<float>> m in this.glyphMapPen)
{
m.Value.Dispose();
}
}
this.glyphData.Clear();
}
public void EndFigure()
@ -278,13 +267,16 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
public void EndGlyph()
{
GlyphRenderData renderData = default;
// has the glyoh been rendedered already????
if (this.raterizationRequired)
{
IPath path = this.builder.Build();
if (this.renderFill)
{
this.glyphMap[this.currentRenderingGlyph] = this.Render(path);
renderData.FillMap = this.Render(path);
}
if (this.renderOutline)
@ -298,10 +290,14 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
path = path.GenerateOutline(this.Pen.StrokeWidth, this.Pen.StrokePattern);
}
this.glyphMapPen[this.currentRenderingGlyph] = this.Render(path);
renderData.OutlineMap = this.Render(path);
}
this.renderedGlyphs.Add(this.currentRenderingGlyph);
this.glyphData[this.currentGlyphRenderParams] = renderData;
}
else
{
renderData = this.glyphData[this.currentGlyphRenderParams];
}
if (this.renderFill)
@ -309,7 +305,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
this.FillOperations.Add(new DrawingOperation
{
Location = this.currentRenderPosition,
Map = this.glyphMap[this.currentRenderingGlyph]
Map = renderData.FillMap
});
}
@ -318,7 +314,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
this.OutlineOperations.Add(new DrawingOperation
{
Location = this.currentRenderPosition,
Map = this.glyphMapPen[this.currentRenderingGlyph]
Map = renderData.OutlineMap
});
}
}
@ -341,10 +337,10 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
}
// take the path inside the path builder, scan thing and generate a Buffer2d representing the glyph and cache it.
Buffer2D<float> fullBuffer = this.MemoryManager.Allocate2D<float>(size.Width + 1, size.Height + 1, true);
Buffer2D<float> fullBuffer = this.MemoryAllocator.Allocate2D<float>(size.Width + 1, size.Height + 1, true);
using (IBuffer<float> bufferBacking = this.MemoryManager.Allocate<float>(path.MaxIntersections))
using (IBuffer<PointF> rowIntersectionBuffer = this.MemoryManager.Allocate<PointF>(size.Width))
using (IBuffer<float> bufferBacking = this.MemoryAllocator.Allocate<float>(path.MaxIntersections))
using (IBuffer<PointF> rowIntersectionBuffer = this.MemoryAllocator.Allocate<PointF>(size.Width))
{
float subpixelFraction = 1f / subpixelCount;
float subpixelFractionPoint = subpixelFraction / subpixelCount;
@ -457,6 +453,19 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors
this.builder.AddBezier(this.currentPoint, secondControlPoint, point);
this.currentPoint = point;
}
private struct GlyphRenderData : IDisposable
{
public Buffer2D<float> FillMap;
public Buffer2D<float> OutlineMap;
public void Dispose()
{
this.FillMap?.Dispose();
this.OutlineMap?.Dispose();
}
}
}
}
}
Loading…
Cancel
Save