5
5
using System ;
6
6
using System . Collections . Generic ;
7
7
using System . Runtime . InteropServices ;
8
- using SharpFont ;
8
+ using FreeTypeAPI ;
9
9
10
10
namespace Microsoft . Xna . Framework . Content . Pipeline . Graphics
11
11
{
12
12
// Uses FreeType to rasterize TrueType fonts into a series of glyph bitmaps.
13
- internal class SharpFontImporter : IFontImporter
13
+ unsafe internal class SharpFontImporter : IFontImporter
14
14
{
15
15
// Properties hold the imported font data.
16
16
public IEnumerable < Glyph > Glyphs { get ; private set ; }
17
17
18
18
public float LineSpacing { get ; private set ; }
19
19
20
- public int YOffsetMin { get ; private set ; }
20
+ public long YOffsetMin { get ; private set ; }
21
21
22
22
// Size of the temp surface used for GDI+ rasterization.
23
23
const int MaxGlyphSize = 1024 ;
24
24
25
- Library lib = null ;
26
-
27
25
public void Import ( FontDescription options , string fontName )
28
26
{
29
- lib = new Library ( ) ;
30
- // Create a bunch of GDI+ objects.
31
- var face = CreateFontFace ( options , fontName ) ;
32
- try
33
- {
34
- // Which characters do we want to include?
35
- var characters = options . Characters ;
27
+ CheckError ( FreeType . FT_Init_FreeType ( out FT_Library * library ) ) ;
36
28
37
- var glyphList = new List < Glyph > ( ) ;
38
- var glyphMaps = new Dictionary < uint , GlyphData > ( ) ;
39
-
40
- // Rasterize each character in turn.
41
- foreach ( char character in characters )
42
- {
43
- uint glyphIndex = face . GetCharIndex ( character ) ;
44
- if ( ! glyphMaps . TryGetValue ( glyphIndex , out GlyphData glyphData ) )
45
- {
46
- glyphData = ImportGlyph ( glyphIndex , face ) ;
47
- glyphMaps . Add ( glyphIndex , glyphData ) ;
48
- }
29
+ // Create a bunch of GDI+ objects.
30
+ var face = CreateFontFace ( library , options , fontName ) ;
49
31
50
- var glyph = new Glyph ( character , glyphData ) ;
51
- glyphList . Add ( glyph ) ;
52
- }
53
- Glyphs = glyphList ;
32
+ // Which characters do we want to include?
33
+ var characters = options . Characters ;
54
34
55
- // Store the font height.
56
- LineSpacing = face . Size . Metrics . Height >> 6 ;
35
+ var glyphList = new List < Glyph > ( ) ;
36
+ var glyphMaps = new Dictionary < uint , GlyphData > ( ) ;
57
37
58
- // The height used to calculate the Y offset for each character.
59
- YOffsetMin = - face . Size . Metrics . Ascender >> 6 ;
60
- }
61
- finally
38
+ // Rasterize each character in turn.
39
+ foreach ( char character in characters )
62
40
{
63
- if ( face != null )
64
- face . Dispose ( ) ;
65
- if ( lib != null )
41
+ uint glyphIndex = FreeType . FT_Get_Char_Index ( face , character ) ;
42
+ if ( ! glyphMaps . TryGetValue ( glyphIndex , out GlyphData glyphData ) )
66
43
{
67
- lib . Dispose ( ) ;
68
- lib = null ;
44
+ glyphData = ImportGlyph ( glyphIndex , face ) ;
45
+ glyphMaps . Add ( glyphIndex , glyphData ) ;
69
46
}
47
+
48
+ var glyph = new Glyph ( character , glyphData ) ;
49
+ glyphList . Add ( glyph ) ;
70
50
}
51
+ Glyphs = glyphList ;
52
+
53
+ // Store the font height.
54
+ LineSpacing = face ->size ->metrics . height >> 6 ;
55
+
56
+ // The height used to calculate the Y offset for each character.
57
+ YOffsetMin = - face ->size ->metrics . ascender >> 6 ;
71
58
}
72
59
60
+ private void CheckError ( int error )
61
+ {
62
+ if ( error == 0 )
63
+ return ;
64
+
65
+ throw new Exception ( "An error occured in freetype." ) ; // TODO: Fill the error
66
+ }
73
67
74
68
// Attempts to instantiate the requested GDI+ font object.
75
- private Face CreateFontFace ( FontDescription options , string fontName )
69
+ private FT_Face * CreateFontFace ( FT_Library * library , FontDescription options , string fontName )
76
70
{
77
- try
78
- {
79
- const uint dpi = 96 ;
80
- var face = lib . NewFace ( fontName , 0 ) ;
81
- var fixedSize = ( ( int ) options . Size ) << 6 ;
82
- face . SetCharSize ( 0 , fixedSize , dpi , dpi ) ;
71
+ const uint dpi = 96 ;
83
72
84
- if ( face . FamilyName == "Microsoft Sans Serif" && options . FontName != "Microsoft Sans Serif" )
85
- throw new PipelineException ( string . Format ( "Font {0} is not installed on this computer." , options . FontName ) ) ;
73
+ CheckError ( FreeType . FT_New_Face ( library , fontName , 0 , out FT_Face * face ) ) ;
86
74
87
- return face ;
75
+ var fixedSize = ( ( int ) options . Size ) << 6 ;
76
+ CheckError ( FreeType . FT_Set_Char_Size ( face , 0 , fixedSize , dpi , dpi ) ) ;
88
77
89
- // A font substitution must have occurred.
90
- //throw new Exception(string.Format("Can't find font '{0}'.", options.FontName));
91
- }
92
- catch
93
- {
94
- throw ;
95
- }
78
+ return face ;
96
79
}
97
80
98
81
// Rasterizes a single character glyph.
99
- private GlyphData ImportGlyph ( uint glyphIndex , Face face )
82
+ private GlyphData ImportGlyph ( uint glyphIndex , FT_Face * face )
100
83
{
101
- face . LoadGlyph ( glyphIndex , LoadFlags . Default , LoadTarget . Normal ) ;
102
- face . Glyph . RenderGlyph ( RenderMode . Normal ) ;
84
+ CheckError ( FreeType . FT_Load_Glyph ( face , glyphIndex ) ) ;
85
+ CheckError ( FreeType . FT_Render_Glyph ( face -> glyph ) ) ;
103
86
104
87
// Render the character.
105
88
BitmapContent glyphBitmap = null ;
106
- if ( face . Glyph . Bitmap . Width > 0 && face . Glyph . Bitmap . Rows > 0 )
89
+ if ( face -> glyph -> bitmap . width > 0 && face -> glyph -> bitmap . rows > 0 )
107
90
{
108
- glyphBitmap = new PixelBitmapContent < byte > ( face . Glyph . Bitmap . Width , face . Glyph . Bitmap . Rows ) ;
109
- byte [ ] gpixelAlphas = new byte [ face . Glyph . Bitmap . Width * face . Glyph . Bitmap . Rows ] ;
91
+ glyphBitmap = new PixelBitmapContent < byte > ( ( int ) face -> glyph -> bitmap . width , ( int ) face -> glyph -> bitmap . rows ) ;
92
+ byte [ ] gpixelAlphas = new byte [ face -> glyph -> bitmap . width * face -> glyph -> bitmap . rows ] ;
110
93
//if the character bitmap has 1bpp we have to expand the buffer data to get the 8bpp pixel data
111
94
//each byte in bitmap.bufferdata contains the value of to 8 pixels in the row
112
95
//if bitmap is of width 10, each row has 2 bytes with 10 valid bits, and the last 6 bits of 2nd byte must be discarded
113
- if ( face . Glyph . Bitmap . PixelMode == PixelMode . Mono )
96
+ if ( ( FT_Pixel_Mode ) face -> glyph -> bitmap . pixel_mode == FT_Pixel_Mode . FT_PIXEL_MODE_MONO )
114
97
{
115
98
//variables needed for the expansion, amount of written data, length of the data to write
116
- int written = 0 , length = face . Glyph . Bitmap . Width * face . Glyph . Bitmap . Rows ;
99
+ int written = 0 , length = ( int ) ( face -> glyph -> bitmap . width * face -> glyph -> bitmap . rows ) ;
117
100
for ( int i = 0 ; written < length ; i ++ )
118
101
{
119
102
//width in pixels of each row
120
- int width = face . Glyph . Bitmap . Width ;
103
+ int width = ( int ) face -> glyph -> bitmap . width ;
121
104
while ( width > 0 )
122
105
{
123
106
//valid data in the current byte
124
107
int stride = MathHelper . Min ( 8 , width ) ;
125
108
//copy the valid bytes to pixeldata
126
109
//System.Array.Copy(ExpandByte(face.Glyph.Bitmap.BufferData[i]), 0, gpixelAlphas, written, stride);
127
- ExpandByteAndCopy ( face . Glyph . Bitmap . BufferData [ i ] , stride , gpixelAlphas , written ) ;
110
+ ExpandByteAndCopy ( face -> glyph -> bitmap . buffer [ i ] , stride , gpixelAlphas , written ) ;
128
111
written += stride ;
129
112
width -= stride ;
130
113
if ( width > 0 )
@@ -133,35 +116,37 @@ private GlyphData ImportGlyph(uint glyphIndex, Face face)
133
116
}
134
117
}
135
118
else
136
- Marshal . Copy ( face . Glyph . Bitmap . Buffer , gpixelAlphas , 0 , gpixelAlphas . Length ) ;
119
+ {
120
+ gpixelAlphas = new Span < byte > ( face ->glyph ->bitmap . buffer , gpixelAlphas . Length ) . ToArray ( ) ;
121
+ }
137
122
glyphBitmap . SetPixelData ( gpixelAlphas ) ;
138
123
}
139
124
140
125
if ( glyphBitmap == null )
141
126
{
142
- var gHA = face . Glyph . Metrics . HorizontalAdvance >> 6 ;
143
- var gVA = face . Size . Metrics . Height >> 6 ;
127
+ var gHA = face -> glyph -> metrics . horiAdvance >> 6 ;
128
+ var gVA = face -> size -> metrics . height >> 6 ;
144
129
145
130
gHA = gHA > 0 ? gHA : gVA ;
146
131
gVA = gVA > 0 ? gVA : gHA ;
147
132
148
- glyphBitmap = new PixelBitmapContent < byte > ( gHA , gVA ) ;
133
+ glyphBitmap = new PixelBitmapContent < byte > ( ( int ) gHA , ( int ) gVA ) ;
149
134
}
150
135
151
136
// not sure about this at all
152
137
var abc = new ABCFloat ( ) ;
153
- abc . A = face . Glyph . Metrics . HorizontalBearingX >> 6 ;
154
- abc . B = face . Glyph . Metrics . Width >> 6 ;
155
- abc . C = ( face . Glyph . Metrics . HorizontalAdvance >> 6 ) - ( abc . A + abc . B ) ;
156
- abc . A -= face . Glyph . BitmapLeft ;
157
- abc . B += face . Glyph . BitmapLeft ;
138
+ abc . A = face -> glyph -> metrics . horiBearingX >> 6 ;
139
+ abc . B = face -> glyph -> metrics . width >> 6 ;
140
+ abc . C = ( face -> glyph -> metrics . horiAdvance >> 6 ) - ( abc . A + abc . B ) ;
141
+ abc . A -= face -> glyph -> bitmap_left ;
142
+ abc . B += face -> glyph -> bitmap_left ;
158
143
159
144
// Construct the output Glyph object.
160
145
return new GlyphData ( glyphIndex , glyphBitmap )
161
146
{
162
- XOffset = - ( face . Glyph . Advance . X >> 6 ) ,
163
- XAdvance = face . Glyph . Metrics . HorizontalAdvance >> 6 ,
164
- YOffset = - ( face . Glyph . Metrics . HorizontalBearingY >> 6 ) ,
147
+ XOffset = - ( face -> glyph -> advance . x >> 6 ) ,
148
+ XAdvance = face -> glyph -> metrics . horiAdvance >> 6 ,
149
+ YOffset = - ( face -> glyph -> metrics . horiBearingY >> 6 ) ,
165
150
CharacterWidths = abc
166
151
} ;
167
152
}
0 commit comments