I need to determine whether two IDWriteFontFace
instances represent the same font file (and index for .ttc font). Would using this solution be a reliable approach?
From my testing, even if two IDWriteFontFace
instances reference the same font file, their IUnknown
values can differ depending on how they were created.
For example:
IDWriteFontFace
using IDWriteGdiInterop::CreateFontFaceFromHdc
, calling this method twice (even with different HDCs but the same LOGFONT
) results in the same IUnknown
value.IDWriteFontFace
obtained via IDWriteFontSet::GetMatchingFonts
with one created using IDWriteGdiInterop::CreateFontFaceFromHdc
, the IUnknown
values sometimes match and sometimes don’t, even when they reference the same file.Given this inconsistency, is this solution only reliable when both IDWriteFontFace
instances are created using the same method? Or even, is it reliable?
The IDWriteFontFace5::Equals
method compares the following things:
IDWriteFontFileLoader
objects are the sameComparing axis values is necessary because two instances of a variable font may not be the same even if they were created from the same file and face index and with the same simulations.
Note that even static (non-variable) fonts can have axis values declared in the OpenType STAT table. Also, DWrite always treats every font as having at least the WGHT
, WDTH
, ITAL
, and SLNT
axes. If the font file does not actually specify these axes, DWrite derives them from the weight, stretch, and style.
DWrite does have internal logic in the CreateFontFace method to try to return an existing object if a font face with the specified parameters already exists. For this reason, simply comparing IUnknown pointers may be good enough, depending on your requirements. However, as the OP observed, there are cases where you can end up with two different IDWriteFontFace objects (different addresses) that are actually equivalent (Equals returns true). This occurs if the parameters passed in to create the font face were different but the resulting font faces actually ended up being equivalent after the axis values were normalized (put in canonical order and clamped to their respective ranges). Also, this logic did not exist at all in Windows 7; the Windows 7 implementation of CreateFontFace always returned a new object.
So my recommendations would be:
QueryInterface
for IDWriteFontFace5
, use its Equals
method. This takes into account axis values and is future-proof.IDWriteFontFace5
.