Skip to content

Commit

Permalink
Merge pull request #303 from SixLabors/js/issue-302
Browse files Browse the repository at this point in the history
Fix out of range exception in typographic utils.
  • Loading branch information
JimBobSquarePants authored Oct 10, 2022
2 parents f42190c + 478574b commit 6d831c6
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 18 deletions.
41 changes: 24 additions & 17 deletions src/SixLabors.Fonts/GlyphMetrics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,32 +190,36 @@ internal FontRectangle GetBoundingBox(Vector2 origin, float scaledPointSize)

internal void RenderDecorationsTo(IGlyphRenderer renderer, Vector2 location, float scaledPPEM)
{
(Vector2 Start, Vector2 End, float Thickness) GetEnds(float thickness, float position)
(Vector2 Start, Vector2 End, float Thickness) GetEnds(float thickness, float positionY)
{
Vector2 scale = new Vector2(scaledPPEM) / this.ScaleFactor * MirrorScale;
Vector2 offset = location + (this.Offset * scale * MirrorScale);

// Calculate the correct advance for the line.
float width = this.AdvanceWidth;
if (width == 0)
{
// For zero advance glyphs we must calculate our advance width from bearing + width;
width = this.LeftSideBearing + this.Width;
return (Vector2.Zero, Vector2.Zero, 0);
}

Vector2 tl = (new Vector2(0, position) * scale) + offset;
Vector2 tr = (new Vector2(width, position) * scale) + offset;
Vector2 bl = (new Vector2(0, position + thickness) * scale) + offset;
Vector2 scale = new Vector2(scaledPPEM) / this.ScaleFactor;
Vector2 offset = location + (this.Offset * scale * MirrorScale) + (new Vector2(0, positionY) * scale * MirrorScale);

Vector2 tl = new(offset.X, offset.Y);
Vector2 tr = new(offset.X + (width * scale.X), offset.Y);
Vector2 bl = new(offset.X, offset.Y + (thickness * scale.Y));

return (tl, tr, tl.Y - bl.Y);
return (tl, tr, bl.Y - tl.Y);
}

void DrawLine(float thickness, float position)
{
renderer.BeginFigure();

(Vector2 start, Vector2 end, float finalThickness) = GetEnds(thickness, position);
var halfHeight = new Vector2(0, -finalThickness * .5F);

if (finalThickness == 0)
{
return;
}

Vector2 halfHeight = new(0, finalThickness * .5F);

Vector2 tl = start - halfHeight;
Vector2 tr = end - halfHeight;
Expand All @@ -229,10 +233,10 @@ void DrawLine(float thickness, float position)
bl.Y = MathF.Floor(bl.Y);

// Do the same for vertical components.
tl.X = MathF.Floor(tl.X);
tr.X = MathF.Floor(tr.X);
br.X = MathF.Floor(br.X);
bl.X = MathF.Floor(bl.X);
tl.X = MathF.Round(tl.X);
tr.X = MathF.Round(tr.X);
br.X = MathF.Round(br.X);
bl.X = MathF.Round(bl.X);

renderer.MoveTo(tl);
renderer.LineTo(bl);
Expand All @@ -245,7 +249,10 @@ void DrawLine(float thickness, float position)
void SetDecoration(TextDecorations decorationType, float thickness, float position)
{
(Vector2 start, Vector2 end, float calcThickness) = GetEnds(thickness, position);
((IGlyphDecorationRenderer)renderer).SetDecoration(decorationType, start, end, calcThickness);
if (calcThickness != 0)
{
((IGlyphDecorationRenderer)renderer).SetDecoration(decorationType, start, end, calcThickness);
}
}

// There's no built in metrics for these values so we will need to infer them from the other metrics.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,11 @@ private static bool Match<T>(
int offset = iterator.Increment(increment);
IGlyphShapingCollection collection = iterator.Collection;

if (offset < 0)
{
return false;
}

int i = 0;
while (i < sequence.Length && i < MaxContextLength && offset < collection.Count)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ internal override void RenderTo(IGlyphRenderer renderer, float pointSize, Vector
// Scale and translate the glyph
Vector2 scale = new Vector2(scaledPPEM) / this.ScaleFactor;
var transform = Matrix3x2.CreateScale(scale);
transform.Translation = this.Offset * scale * MirrorScale;
transform.Translation = this.Offset * scale;
scaledVector = GlyphVector.Transform(this.vector, transform);
this.FontMetrics.ApplyTrueTypeHinting(options.HintingMode, this, ref scaledVector, scale, scaledPPEM);
this.scaledVector[scaledPPEM] = scaledVector;
Expand Down
Binary file not shown.
35 changes: 35 additions & 0 deletions tests/SixLabors.Fonts.Tests/Issues/Issues_298.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.

using System;
using Xunit;

namespace SixLabors.Fonts.Tests.Issues
{
public class Issues_298
{
[Fact]
public void DoesNotThrowOutOfBounds()
{
const string content = "Please enter the text";

FontCollection fontFamilies = new();

FontFamily fontFamily = fontFamilies.Add(TestFonts.Issues.Issue298File);

Font font = fontFamily.CreateFont(16, FontStyle.Regular);

TextOptions renderOptions = new(font)
{
Dpi = 96,
WrappingLength = 0f,
VerticalAlignment = VerticalAlignment.Top,
HorizontalAlignment = HorizontalAlignment.Left,
KerningMode = KerningMode.Auto
};

FontRectangle bounds = TextMeasurer.Measure(content.AsSpan(), renderOptions);
Assert.NotEqual(default, bounds);
}
}
}
23 changes: 23 additions & 0 deletions tests/SixLabors.Fonts.Tests/Issues/Issues_302.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.

using Xunit;

namespace SixLabors.Fonts.Tests.Issues
{
public class Issues_302
{
#if OS_WINDOWS
[Fact]
public void DoesNotThrowOutOfBounds()
{
const string content = "فِيلْمٌ";
FontFamily fontFamily = SystemFonts.Get("Arial");
Font font = fontFamily.CreateFont(16, FontStyle.Regular);
TextOptions renderOptions = new(font);

Assert.True(TextMeasurer.TryMeasureCharacterBounds(content, renderOptions, out GlyphBounds[] _));
}
#endif
}
}
2 changes: 2 additions & 0 deletions tests/SixLabors.Fonts.Tests/TestFonts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ public static class Issues
public static string Issue96File => GetFullPath("Issues/Issue96.fuzz");

public static string Issue97File => GetFullPath("Issues/Issue97.fuzz");

public static string Issue298File => GetFullPath("Issues/StyleScript.ttf");
}

private static Stream OpenStream(string path) =>
Expand Down

0 comments on commit 6d831c6

Please sign in to comment.