سؤال

I would like to create a Direct2D path geometry from text. As I understood, I'll need to create an IDWriteFontFace, from which I'll have to call GetGlyphRunOutline.

Unfortunately, I cannot figure out how to create that font face. So far, I stumble on even creating a font file reference, which I think I have to use to create the font face.

procedure CreateFontFace;
var
  hr: HRESULT;
  FontDir: string;
  FontPath: string;
  ft: _FILETIME;
  FontFile: IDWriteFontFile;
  FontFace: IDWriteFontFace;
begin

  FontDir := GetSpecialFolder(CSIDL_FONTS);
  FontPath := IncludeTrailingPathDelimiter(FontDir) + 'Arial.ttf';

  // Here, FontPath contains 'C:\Windows\Fonts\Arial.ttf' 
  // (which exists on my machine)

  ft.dwLowDateTime := 0;
  ft.dwHighDateTime := 0;

  hr := DWriteFactory.CreateFontFileReference( 
   FontPath, // DOES NOT COMPILE
   ft,
   FontFile);

  if Succeeded(hr) then begin
    hr := DWriteFactory.CreateFontFace(
      DWRITE_FONT_FACE_TYPE_TRUETYPE,
      1,
      @FontFile,
      0,
      DWRITE_FONT_SIMULATIONS_NONE,
      FontFace);
  end;

end;

The prototype of CreateFontFileReference in Winapi.D2D1 is as follow:

    function CreateFontFileReference(var filePath: WCHAR;
      var lastWriteTime: FILETIME;
      out fontFile: IDWriteFontFile): HResult; stdcall;

I understand that putting a string instead of a WCHAR can bother the compiler, but how should this be written? I'm also interested if there is another, simpler way...

UPDATE: As stated by Remy Lebeau, there are other similar buggy declarations in the Winapi.D2D1 unit. The second one that I encountered is even in CreateFontFileReference too: parameter lastWriteTime should be a pointer, so to make my code work, I had to change my use of the ft variable as follows:

var
  ...
  ft: ^_FILETIME;
  ...
begin
  ...
  ft := nil;

  hr := DWriteFactory.CreateFontFileReference( 
    PChar(FontPath)^,
    ft^, // Yes, I am dereferencing nil, and it's working!
    FontFile);
  ...
end;
هل كانت مفيدة؟

المحلول

If you are using Delphi 2009 or later, where String is Unicode, you need to typecast your String to PChar when passing it to CreateFontFileReference():

hr := DWriteFactory.CreateFontFileReference( 
  PChar(FontPath),
  ft,
  FontFile);

If you are using Delphi 2007 or earlier, where String is Ansi, you need to convert your String to a WideString first and then typecast that to PWideChar:

hr := DWriteFactory.CreateFontFileReference( 
  PWideChar(WideString(FontPath)),
  ft,
  FontFile);

Update: turns out there is a bug in the declaration of the first parameter of CreateFontFileReference(). Embarcadero declares it as var filePath: WCHAR, but it should have been declared as const filePath: PWCHAR instead. So you will have to account for that bug by dereferencing the PChar/PWideChar pointer, eg:

hr := DWriteFactory.CreateFontFileReference( 
  PChar(FontPath)^,
  ...);

hr := DWriteFactory.CreateFontFileReference( 
  PWideChar(WideString(FontPath))^,
  ...);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top