6
votes

I am mucking about with WPF glyphs and documents and have run into a null reference exception in the .Net 4 framework.

I extract and save true-type fonts to disk as .ttf files, then try to create Glyphs based on the fonts. The first time I save a font to disk and instantiate a GlyphTypeface based on the font after creating a GlyphTypeface from another font in the same folder I get a null reference exception.

Say I have fonts A and B. B has not been saved to disk (A may or may not have been saved to disk; that doesn't seem to matter):

1) save B to disk in the same folder as A,
2) create GlyphTypeface using font A,
3) create GlyphTypeface using font B = exception.

Null reference exception at:  
at MS.Internal.FontCache.FontFaceLayoutInfo.IntMap.TryGetValue(Int32 key, UInt16& value)  
at MS.Internal.FontCache.FontFaceLayoutInfo..ctor(Font font)  
at System.Windows.Media.GlyphTypeface.Initialize(Uri typefaceSource, StyleSimulations styleSimulations)  
at System.Windows.Media.GlyphTypeface..ctor(Uri typefaceSource)

If I restart my app and run it again (with font B already on disk), step 3 doesn't throw an exception.

The code to save a font to disk is simply writing a section from a binary stream and letting go of the file:

if (!File.Exists(filename))
{
    using (FileStream fs = File.Create(filename, length))
    {
        fs.Write(m_data, m_index, length);
        fs.Close();
    }
}

Any ideas? I don't want to have to put every font in its own folder...

Thanks for your time.

5

5 Answers

2
votes

I ended up using the workaround of saving each font to its own folder (using the font name for the folder name). The exception went away, so I guess we can chalk this up to a bug in .Net.

2
votes

This bug has been driving me nuts but I think I have a better understanding of what is going on now.

For testing I used the following XAML:

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Glyphs
    FontUri="C:\Users\Public\Desktop\A.ttf"
    FontRenderingEmSize="100"
    Fill="Black"
    UnicodeString="Test"/>
</Page>

Using the XamlPadX application which runs on the .NET 2 runtime I could reliably render the XAML no matter where I placed the font.

Using the Kaxaml application which runs on the .NET 4 runtime the XAML would often fail to render depending on where I placed the font in the file system. By moving the font file around and renaming I tried to discover a pattern in what was allowed. However, it was very hard to see a pattern.

For instance storing the font in the path below would render the glyphs:

C:\Users\Public\Desktop\A.ttf - OK

Renaming it from A.ttf to B.ttf would throw the exception:

C:\Users\Public\Desktop\B.ttf - throws exception

Changing the extension would also throw the exception:

C:\Users\Public\Desktop\A.odttf - throws exception

Renaming parts of the path would sometimes wreak havoc but I was unable to see any pattern. Initially I used the temp path and getting exceptions lead me to this question and the answer about not using that path. However, later I have actually been able to use that path as long as the name of the file is A.ttf and not B.ttf so avoiding the temp path is not a sure fix.

At some point during my tests using my own WPF application the B.ttf file name suddenly started working. However, I had to restart the Kaxaml application before it would accept the B.ttf file name. Also, at that point the A.odttf file name was still throwing exceptions.

My suggestion is to use an application like Kaxaml or to create a small WPF application to test which font file names are acceptable and then use them. However, I fear that the nature of this bug is such that a "good" font file name may turn "bad" at a later point in time. Only time will show.

1
votes

I (and a co-worker) finally found what our particular problem was: do not save the font files to %TEMP%. For some reason, having the fonts saved to some other folder makes it work (for us), and saving it to anywhere inside %TEMP% makes it break.

1
votes

According to XamlToys Doesn't work on framework 4.0???, the problem is in the extension of the file for partial fonts.

When I renamed the .ofttf files I save to .ttf, it all works again. Haven't got the foggiest idea of why that is though. Seems to be new in .NET 4.0.

0
votes

My workaround was to simply replace the < Glyphs > with equavalent < TextBlock >s. The couple of pixels difference in layout was not a problem in my case.

Like you noted was the case for you, in my case also it was not a problem in .Net 3.5, but appeared in .Net 4.0.