Skip to content

Commit f82f94a

Browse files
xqxq
authored andcommitted
This PR adds the ability to provide custom vertical font metrics when layouting text.
The background here is that Skia report different font metrics depending on platform. Windows uses usWinAscent, usWinDescent, and this lovely formula for calculating leading: MAX(0, (hhea.ascender - hhea.descender + hhea.lineGap) - (usWinAscent + usWinDescent)). If I remember correctly Linux uses the sTypo* metrics. For cross-platform .NET applications that want to have similar rendering on both Windows and Linux (in particular vertical positioning) there needs to be a way to override the metrics reported by Skia. toptensoftware#67
1 parent 5bda2df commit f82f94a

2 files changed

Lines changed: 81 additions & 7 deletions

File tree

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// RichTextKit
2+
// Copyright © 2019-2020 Topten Software. All Rights Reserved.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License"); you may
5+
// not use this product except in compliance with the License. You may obtain
6+
// a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
// License for the specific language governing permissions and limitations
14+
// under the License.
15+
16+
using SkiaSharp;
17+
18+
namespace Topten.RichTextKit
19+
{
20+
public class VerticalFontMetrics
21+
{
22+
public float Ascent { get; }
23+
public float Descent { get; }
24+
public float Leading { get; }
25+
26+
public VerticalFontMetrics(float ascent, float descent, float leading)
27+
{
28+
Ascent = ascent;
29+
Descent = descent;
30+
Leading = leading;
31+
}
32+
}
33+
34+
/// <summary>
35+
/// The FontMetricsMapper class is responsible for mapping a font to a set of metrics
36+
/// which affect its layouting. The default instance can be replaced in cases where different
37+
/// layouting is desired.
38+
/// </summary>
39+
public class FontMetricsMapper
40+
{
41+
/// <summary>
42+
/// The default metrics mapper instance.
43+
/// </summary>
44+
public static FontMetricsMapper Default = new FontMetricsMapper();
45+
46+
/// <summary>
47+
/// Maps a given typeface and font size to its vertical metrics.
48+
/// </summary>
49+
/// <param name="typeface">The typeface.</param>
50+
/// <param name="fontSize">The font size in pixels.</param>
51+
/// <returns>The vertical font metrics.</returns>
52+
public virtual VerticalFontMetrics GetVerticalMetrics(SKTypeface typeface, float fontSize)
53+
{
54+
var fontMetrics = typeface.ToFont(fontSize).Metrics;
55+
return new VerticalFontMetrics(fontMetrics.Ascent, fontMetrics.Descent, fontMetrics.Descent);
56+
}
57+
}
58+
}

Topten.RichTextKit/TextShaping/TextShaper.cs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ private TextShaper(SKTypeface typeface)
7979
{
8080
font.Typeface = typeface;
8181
font.Size = overScale;
82-
_fontMetrics = font.Metrics;
82+
//_fontMetrics = font.Metrics;
83+
_fontXMin = font.Metrics.XMin;
84+
_verticalMetrics = FontMetricsMapper.Default.GetVerticalMetrics(typeface, overScale);
8385

8486
// This is a temporary hack until SkiaSharp exposes
8587
// a way to check if a font is fixed pitch. For now
@@ -114,10 +116,20 @@ public void Dispose()
114116
/// </summary>
115117
SKTypeface _typeface;
116118

119+
///// <summary>
120+
///// Font metrics for the font
121+
///// </summary>
122+
//SKFontMetrics _fontMetrics;
123+
124+
/// <summary>
125+
/// The minimum bounding box x value for the font.
126+
/// </summary>
127+
float _fontXMin;
128+
117129
/// <summary>
118-
/// Font metrics for the font
130+
/// The vertical font metrics as provided by the metrics mapper.
119131
/// </summary>
120-
SKFontMetrics _fontMetrics;
132+
readonly VerticalFontMetrics _verticalMetrics;
121133

122134
/// <summary>
123135
/// True if this font face is fixed pitch
@@ -478,10 +490,14 @@ public Result Shape(ResultBufferSet bufferSet, Slice<int> codePoints, IStyle sty
478490
private void ApplyFontMetrics(ref Result result, float fontSize)
479491
{
480492
// And some other useful metrics
481-
result.Ascent = _fontMetrics.Ascent * fontSize / overScale;
482-
result.Descent = _fontMetrics.Descent * fontSize / overScale;
483-
result.Leading = _fontMetrics.Leading * fontSize / overScale;
484-
result.XMin = _fontMetrics.XMin * fontSize / overScale;
493+
//result.Ascent = _fontMetrics.Ascent * fontSize / overScale;
494+
//result.Descent = _fontMetrics.Descent * fontSize / overScale;
495+
//result.Leading = _fontMetrics.Leading * fontSize / overScale;
496+
//result.XMin = _fontMetrics.XMin * fontSize / overScale;
497+
result.Ascent = _verticalMetrics.Ascent * fontSize / overScale;
498+
result.Descent = _verticalMetrics.Descent * fontSize / overScale;
499+
result.Leading = _verticalMetrics.Leading * fontSize / overScale;
500+
result.XMin = _fontXMin * fontSize / overScale;
485501
}
486502

487503
private static Blob GetHarfBuzzBlob(SKStreamAsset asset)

0 commit comments

Comments
 (0)