.NET DBG] OTF Font does not display in FontDialog Class MS] C# & VB .NET

Visual Studio 2008 C# FontDialog Class 를 보면, Windows 에 설치되어 있는 모든 Font 가 보이지 않습니다. MSDN 에 보면 다음과 같은 내용이 있습니다.

"Windows Forms 응용 프로그램에서는 트루타입 글꼴을 지원하고 오픈타입 글꼴은 제한적으로 지원합니다. 지원되지 않는 글꼴을 사용하려 하거나 응용 프로그램을 실행하는 컴퓨터에 해당 글꼴이 설치되어 있지 않은 경우 Microsoft Sans Serif가 대신 사용됩니다."

http://msdn.microsoft.com/ko-kr/library/system.drawing.font(VS.80).aspx

 

이에 대해서 다음과 같이 알아보도록 하겠습니다.

 

우선, OpenType Font TrueType Font 의 차이점은 무엇일까요?

1980년대에는 PostScript outline을 사용하는 Adobe Type 1 fonts 가 대세를 이루고 있었습니다. 

이에 대응해서 Apple TrueType Font 를 독자적으로 개발하게 됩니다. 그 후 TrueType 은 대부분의 OS에서 표준처럼 사용됩니다.

이에 반해 OpenType Font TrueType Font 보다 좀 더 확장된 Font Type 으로서 Adobe Microsoft가 제안하였습니다. (요즘 Adobe Apple과의 관계를 보는 듯 합니다.) 2000년대 중반에는 ISO 표준으로 채택되면서 OpenType TrueType 을 대체해 나갑니다.

결론적으로 두 Font Type 간의 차이점이라면 outline 을 어떻게 표현해내느냐 인데, OpenType TrueType Type1 모두를 지원하는 outline 중심의 Font라고 보시면 됩니다.  

당연히, OpenType Fontoutline 은 한 가지로 구성되어 있지 않습니다. OpenType Font PostScript, Type 1, CFF(Compact Font Format), TrueType outline 으로 분류할 수 있습니다.

 

위의 내용을 Debugging 하기 위해서, Windows 에 설치되어 있지만, FontDialog Class에서 보이지 않는 서체를 다음과 같이 추가하여 보았습니다. (여기서 Font Name 은 서체명입니다.)

Namespace WinformWithFont

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

 

            FontFamily fFamily = new FontFamily("Myriad Pro");

            Font f = new Font(fFamily, 20);

 

            label1.Font = f;

            string s = f.FontFamily.GetName(0);

 

            MessageBox.Show(s);

        }

    }

}

 

Windows 에 정상적으로 Font 가 설치되어 있는지 여부는 C:\windows\fonts 를 통해 확인이 가능합니다만, 다음의 Registry 를 통해 확인합니다.

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts

 

프로그램을 실행하면, 다음과 같은 Exception 이 발생합니다.

Exception object: 01354a2c

Exception type: System.ArgumentException

Message: 'Myriad Pro' 글꼴을 찾을 없습니다.

InnerException: <none>

StackTrace (generated):

<none>

StackTraceString: <none>

HResult: 80070057

 

정상적으로 설치되어 있는데, 글꼴을 찾을 수 없다니... 좀 이상합니다.

Reflector 로 해당 Code 를 확인하여 보면 다음과 같습니다.

 

private voidCreateFontFamily(stringname, FontCollectionfontCollection)

{

    IntPtrzero = IntPtr.Zero;

    IntPtrhandle = (fontCollection == null) ? IntPtr.Zero: fontCollection.nativeFontCollection;

    intstatus = SafeNativeMethods.Gdip.GdipCreateFontFamilyFromName(name, new HandleRef(fontCollection, handle), out zero);

    if (status != 0)

    {

        if (!this.createDefaultOnFail)

        {

            switch (status)

            {

                case 14:

                    throw new ArgumentException(SR.GetString("GdiplusFontFamilyNotFound", new object[] { name }));

 

                case 0x10:

                    throw new ArgumentException(SR.GetString("GdiplusNotTrueTypeFont", new object[] { name }));

            }

            throw SafeNativeMethods.Gdip.StatusException(status);

        }

        zero = GetGdipGenericSansSerif();

    }

    this.SetNativeFamily(zero);

}

 

 

status 의 값이 0x10 이길 바랬습니다만, 0x0E 입니다. 혹시 모르니 다음과 같이 확인 해 보았습니다.

 

아래와 같이 CLR Load 될 때 Break 하도록 Setting 합니다. (둘 다 같은 의미입니다.)

0:000> sxe -c "" clrn

0:000> sxe ld mscorwks

 

문제가 발생하는 부분의 Method Name 을 알고 있으니 break 걸 수 있습니다.

0:000> !bpmd System_Drawing_ni System.Drawing.FontFamily.CreateFontFamily

Adding pending breakpoints...

0:000> g

잠깐 !bpmd 의 설명을 보면 다음과 같습니다.

0:000> !bpmd

Usage: !bpmd -md <MethodDesc pointer>

Usage: !bpmd <module name> <managed function name>

Method Description 정보를 사용해서 Break 를 걸 수 도 있습니다.

 

해당 Code Disassembly 해 보면 다음과 같습니다.

0:000> !u 7adfd290

preJIT generated code

System.Drawing.FontFamily.CreateFontFamily(System.String, System.Drawing.Text.FontCollection)

Begin 7ae34280, size 5c. Cold region begin 7af335ac, size d4

Hot region:

...

e9070df0ff      jmp     System_Drawing_ni!System.Drawing.FontFamily.CreateFontFamily(System.String, System.Drawing.Text.FontCollection)+0x4e (7ae342ce)

7af335c7 83f90e          cmp     ecx,0Eh

7af335ca 7551            jne     System_Drawing_ni!System.Drawing.FontFamily.CreateFontFamily(System.String, System.Drawing.Text.FontCollection)+0xff39d (7af3361d)

7af335cc 8b0d1084de7a    mov     ecx,dword ptr [System_Drawing_ni+0x8410 (7ade8410)]

...

7af33618 e8b33eeeff      call    CORINFO_HELP_THROW (7ae174d0)

7af3361d 83f910          cmp     ecx,10h

7af33620 7551            jne     System_Drawing_ni!System.Drawing.FontFamily.CreateFontFamily(System.String, System.Drawing.Text.FontCollection)+0xff3f3 (7af33673)

...

지금 확인하고 싶은 내용은 status 0Eh 인지 아니면 10h 인지 확인하는 것이므로 해당 내용을 찾아가 보면...

0:000> p

eax=0000000e ebx=01333bc4 ecx=0000000e edx=4b3b7274 esi=00000000 edi=01354a04

eip=7af335c7 esp=0012f414 ebp=0012f424 iopl=0         nv up ei pl zr na pe nc

cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246

System_Drawing_ni!System.Drawing.FontFamily.CreateFontFamily(System.String, System.Drawing.Text.FontCollection)+0xff347:

7af335c7 83f90e          cmp     ecx,0Eh

0:000> r ecx

ecx=0000000e

0Eh 가 맞습니다. 예상과 다르지 않네요. Jitting 되어 있기 때문에 좀 복잡했습니다. Native Code 를 확인해 보면, Open Type 이더라도 PostScript Outlines 인지 TrueType Outlines 에 따라 GDI+ 에서 지원여부가 달라집니다. 결론적으로 말하면 OTF 일지라도 PostScript Outlines 는 지원을 하지 않습니다. TrueType Outlines 만 지원을 합니다. 


덧글

댓글 입력 영역