summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Oshmyan <chortos@inbox.lv>2021-06-18 01:09:21 +0300
committerOleg Oshmyan <chortos@inbox.lv>2021-07-10 02:36:31 +0300
commitac254eb826ec11e676223a9df560ce246927d063 (patch)
treebebebcfe31853fd25ee213189c21fa01797e555d
parentc22b6d44ae9cdd7275602f467e70e7503250db52 (diff)
downloadlibass-ac254eb826ec11e676223a9df560ce246927d063.tar.bz2
libass-ac254eb826ec11e676223a9df560ce246927d063.tar.xz
directwrite: better match_fonts via GDI or IDWriteFontSet
CreateFontFromLOGFONT does not actually use GDI's font lookup logic and fails to emulate it faithfully. In particular: it fails to find CFF-outline fonts by PostScript name; it fails to find TrueType fonts by full name on older versions of Windows; it fails to find at least some fonts installed on demand by font managers. When GDI is available, invoke GDI directly. This commit uses EnumFontFamilies, which is almost perfect, except that if the user has two different fonts such that one font's family name equals another's full/PostScript name, this will find only the family name match. To fix this case as well, we'd need to invoke CreateFontIndirect separately for each font request, complete with its weight and slant. This requires larger changes in our fontselect, which this commit does not attempt yet. GDI is not available in WinRT/UWP. On UWP (Windows 10), use the new IDWriteFontSet API to emulate GDI's font lookup as well as we can. In WinRT (Windows 8), we have no choice but to keep using CreateFontFromLOGFONT (unless we go back to loading all fonts eagerly, which we stopped doing for performance reasons). It is the builder's responsibility to avoid linking in Gdi32.lib in WinRT/UWP builds, just as it is to link in Dwrite.lib.
-rw-r--r--configure.ac7
-rw-r--r--libass/ass_directwrite.c392
-rw-r--r--libass/ass_fontselect.c8
-rw-r--r--libass/dwrite_c.h234
4 files changed, 603 insertions, 38 deletions
diff --git a/configure.ac b/configure.ac
index 784b147..0d3fb58 100644
--- a/configure.ac
+++ b/configure.ac
@@ -158,15 +158,16 @@ AS_IF([test "x$enable_directwrite" != xno], [
#endif
]], [[;]])
], [
- # WinRT/UWP/app build: LoadLibrary is
+ # WinRT/UWP/app build: GDI and LoadLibrary are
# unavailable, but DirectWrite is always present
LIBS="$LIBS -ldwrite"
AC_DEFINE(CONFIG_DIRECTWRITE, 1, [found DirectWrite (WinRT/UWP)])
AC_MSG_RESULT([no])
], [
- # Win32/desktop build:
+ # Win32/desktop build: GDI is always present;
# DirectWrite is optional but can be loaded via LoadLibrary
- AC_DEFINE(CONFIG_DIRECTWRITE, 1, [found DirectWrite (Win32)])
+ LIBS="$LIBS -lgdi32"
+ AC_DEFINE(CONFIG_DIRECTWRITE, 1, [found DirectWrite and GDI (Win32)])
AC_MSG_RESULT([yes])
])
], [
diff --git a/libass/ass_directwrite.c b/libass/ass_directwrite.c
index e6ee298..7b80765 100644
--- a/libass/ass_directwrite.c
+++ b/libass/ass_directwrite.c
@@ -21,6 +21,7 @@
#include "ass_compat.h"
#include <initguid.h>
+#include <wchar.h>
#include "dwrite_c.h"
@@ -35,10 +36,38 @@ static const ASS_FontMapping font_substitutions[] = {
{"monospace", "Courier New"}
};
+typedef struct ASS_SharedHDC ASS_SharedHDC;
+
+#if ASS_WINAPI_DESKTOP
+
+struct ASS_SharedHDC {
+ HDC hdc;
+ unsigned ref_count;
+};
+
+static ASS_SharedHDC *hdc_retain(ASS_SharedHDC *shared_hdc)
+{
+ shared_hdc->ref_count++;
+ return shared_hdc;
+}
+
+static void hdc_release(ASS_SharedHDC *shared_hdc)
+{
+ if (!--shared_hdc->ref_count) {
+ DeleteDC(shared_hdc->hdc);
+ free(shared_hdc);
+ }
+}
+
+#endif
+
/*
* The private data stored for every font, detected by this backend.
*/
typedef struct {
+#if ASS_WINAPI_DESKTOP
+ ASS_SharedHDC *shared_hdc;
+#endif
IDWriteFont *font;
IDWriteFontFace *face;
IDWriteFontFileStream *stream;
@@ -376,9 +405,17 @@ static bool check_glyph(void *data, uint32_t code)
if (code == 0)
return true;
- hr = IDWriteFont_HasCharacter(priv->font, code, &exists);
- if (FAILED(hr))
- return false;
+ if (priv->font) {
+ hr = IDWriteFont_HasCharacter(priv->font, code, &exists);
+ if (FAILED(hr))
+ return false;
+ } else {
+ uint16_t glyph_index;
+ hr = IDWriteFontFace_GetGlyphIndices(priv->face, &code, 1, &glyph_index);
+ if (FAILED(hr))
+ return false;
+ exists = !!glyph_index;
+ }
return exists;
}
@@ -406,12 +443,17 @@ static void destroy_font(void *data)
{
FontPrivate *priv = (FontPrivate *) data;
- IDWriteFont_Release(priv->font);
+ if (priv->font != NULL)
+ IDWriteFont_Release(priv->font);
if (priv->face != NULL)
IDWriteFontFace_Release(priv->face);
if (priv->stream != NULL)
IDWriteFontFileStream_Release(priv->stream);
+#if ASS_WINAPI_DESKTOP
+ hdc_release(priv->shared_hdc);
+#endif
+
free(priv);
}
@@ -555,6 +597,178 @@ static int map_width(enum DWRITE_FONT_STRETCH stretch)
}
}
+static void add_font_face(IDWriteFontFace *face, ASS_FontProvider *provider,
+ ASS_SharedHDC *shared_hdc)
+{
+ ASS_FontProviderMetaData meta = {0};
+
+ FontPrivate *font_priv = (FontPrivate *) calloc(1, sizeof(*font_priv));
+ if (!font_priv) {
+ IDWriteFontFace_Release(face);
+ return;
+ }
+ font_priv->face = face;
+#if ASS_WINAPI_DESKTOP
+ font_priv->shared_hdc = hdc_retain(shared_hdc);
+#endif
+
+ ass_font_provider_add_font(provider, &meta, NULL, 0, font_priv);
+}
+
+#if ASS_WINAPI_DESKTOP
+
+struct font_enum_priv {
+ ASS_FontProvider *provider;
+ IDWriteGdiInterop *gdi_interop;
+ ASS_SharedHDC *shared_hdc;
+};
+
+/*
+ * Windows has three similar functions: EnumFonts, EnumFontFamilies
+ * and EnumFontFamiliesEx, which were introduced at different times.
+ * Each takes a callback, and the declared callback type is the same
+ * for all three. However, the actual arguments passed to the callback
+ * have also changed over time. Some changes match the introduction
+ * of new EnumFont... variants, and some don't. Documentation has
+ * changed over the years, too, so it can be hard to figure out what
+ * types, and when, are safe for the callback to take.
+ *
+ * In the header files, FONTENUMPROC is declared to take:
+ * CONST LOGFONT *, CONST TEXTMETRIC *
+ * These are the baseline structs dating back to 16-bit Windows EnumFont.
+ *
+ * As of 2021, current versions of Microsoft's docs
+ * for the EnumFontFamiliesEx callback use the same:
+ * const LOGFONT *, const TEXTMETRIC *
+ * and for the EnumFontFamilies callback use:
+ * ENUMLOGFONT *, NEWTEXTMETRIC *
+ * and mention that the first "can be cast as" ENUMLOGFONTEX or ENUMLOGFONTEXDV
+ * while the second "can be an ENUMTEXTMETRIC structure" but for
+ * non-TrueType fonts "is a pointer to a TEXTMETRIC structure".
+ *
+ * Docs from the 2000s (which include Win95/98/Me/NT/2000/XP details) use
+ * ENUMLOGFONTEX *, NEWTEXTMETRICEX *
+ * in the EnumFontFamiliesEx callback's definition:
+ * https://web.archive.org/web/20050907052149
+ * /http://msdn.microsoft.com/library/en-us/gdi/fontext_9rmr.asp
+ * and highlight these two extended struct types as advantages over
+ * the EnumFontFamilies callback, suggesting that the actual arguments
+ * to the EnumFontFamiliesEx callback have always been these two extended
+ * structs. This is also reflected in the callback's parameter names
+ * (which have stayed unchanged in the current docs).
+ * EnumFontFamiliesEx itself was added in Windows NT 4.0 and 95.
+ *
+ * Similarly, the EnumFontFamilies callback's parameter names support
+ * the idea that they have always used ENUMLOGFONT and NEWTEXTMETRIC.
+ *
+ * It seems the extra fields in NEWTEXTMETRIC[EX] compared to TEXTMETRIC
+ * are merely zero-filled when they are irrelevant, rather than nonexistent
+ * or inaccessible. This is further supported by the fact the later-still
+ * struct ENUMTEXTMETRIC extends NEWTEXTMETRICEX even though the former
+ * is/was (upon introduction) relevant only to PostScript fonts
+ * while the latter is (supposedly) relevant only to TrueType fonts.
+ *
+ * Docs from the 2000s for ENUMLOGFONTEXDV and ENUMTEXTMETRIC:
+ * https://web.archive.org/web/20050306200105
+ * /http://msdn.microsoft.com/library/en-us/gdi/fontext_15gy.asp
+ * seem to assert that the callback receives these two further-extended
+ * structs *if and only if* running on Windows 2000 or newer.
+ * We don't need them, but if we did, we'd have to check (or assume)
+ * Windows version, because this extension does not seem to have
+ * an associated feature check. Moreover, these structs are given
+ * to the callbacks of all three EnumFont... function variants.
+ * So even EnumFonts actually uses the extended structs in 21st-century
+ * Windows, but the declared callback type can no longer be changed
+ * without breaking existing C++ code due to its strongly-typed pointers.
+ * When targeting modern Windows, though, it seems safe for consumer
+ * code to take the newest structs and cast the function pointer
+ * to the declared callback type.
+ */
+static int CALLBACK font_enum_proc(const ENUMLOGFONTW *lpelf,
+ const NEWTEXTMETRICW *lpntm,
+ DWORD FontType, LPARAM lParam)
+{
+ struct font_enum_priv *priv = (struct font_enum_priv *) lParam;
+ HFONT hFont = NULL;
+ HRESULT hr;
+
+ if (FontType & RASTER_FONTTYPE)
+ goto cleanup;
+
+ hFont = CreateFontIndirectW(&lpelf->elfLogFont);
+ if (!hFont)
+ goto cleanup;
+
+ HDC hdc = priv->shared_hdc->hdc;
+ if (!SelectObject(hdc, hFont))
+ goto cleanup;
+
+ wchar_t selected_name[LF_FACESIZE];
+ if (!GetTextFaceW(hdc, LF_FACESIZE, selected_name))
+ goto cleanup;
+ if (wcsncmp(selected_name, lpelf->elfLogFont.lfFaceName, LF_FACESIZE)) {
+ // A different font was selected. This can happen if the requested
+ // name is subject to charset-specific font substitution while
+ // EnumFont... enumerates additional charsets contained in the font.
+ // Alternatively, the font may have disappeared in the meantime.
+ // Either way, there's no use looking at this font any further.
+ goto cleanup;
+ }
+
+ // For single-font files, we could also use GetFontData, but for font
+ // collection files, GDI does not expose the current font index.
+ // CreateFontFaceFromHdc is able to find it out using a private API;
+ // and it may also be more efficient if it doesn't copy the data.
+ // The downside is that we must keep the HDC alive, at least on Windows 7,
+ // to prevent the font from being deleted and breaking the IDWriteFontFace.
+ IDWriteFontFace *face = NULL;
+ hr = IDWriteGdiInterop_CreateFontFaceFromHdc(priv->gdi_interop,
+ hdc, &face);
+ if (FAILED(hr) || !face)
+ goto cleanup;
+
+ add_font_face(face, priv->provider, priv->shared_hdc);
+
+cleanup:
+ if (hFont)
+ DeleteObject(hFont);
+
+ return 1 /* continue enumerating */;
+}
+
+#else
+
+static void add_font_set(IDWriteFontSet *fontSet, ASS_FontProvider *provider)
+{
+ UINT32 n = IDWriteFontSet_GetFontCount(fontSet);
+ for (UINT32 i = 0; i < n; i++) {
+ HRESULT hr;
+
+ IDWriteFontFaceReference *faceRef;
+ hr = IDWriteFontSet_GetFontFaceReference(fontSet, i, &faceRef);
+ if (FAILED(hr) || !faceRef)
+ continue;
+
+ if (IDWriteFontFaceReference_GetLocality(faceRef) != DWRITE_LOCALITY_LOCAL)
+ goto cleanup;
+
+ // Simulations for bold or oblique are sometimes synthesized by
+ // DirectWrite. We are only interested in physical fonts.
+ if (IDWriteFontFaceReference_GetSimulations(faceRef) != 0)
+ goto cleanup;
+
+ IDWriteFontFace *face;
+ hr = IDWriteFontFaceReference_CreateFontFace(faceRef, &face);
+ if (FAILED(hr))
+ goto cleanup;
+
+ add_font_face(face, provider, NULL);
+
+cleanup:
+ IDWriteFontFaceReference_Release(faceRef);
+ }
+}
+
static void add_font(IDWriteFont *font, IDWriteFontFamily *fontFamily,
ASS_FontProvider *provider)
{
@@ -656,6 +870,8 @@ cleanup:
IDWriteFont_Release(font);
}
+#endif
+
/*
* When a new font name is requested, called to load that font from Windows
*/
@@ -663,48 +879,156 @@ static void match_fonts(void *priv, ASS_Library *lib,
ASS_FontProvider *provider, char *name)
{
ProviderPrivate *provider_priv = (ProviderPrivate *)priv;
- IDWriteFont *font = NULL;
- IDWriteFontFamily *fontFamily = NULL;
- LOGFONTW lf;
- HRESULT hr = S_OK;
-
- memset(&lf, 0, sizeof(LOGFONTW));
- lf.lfWeight = FW_DONTCARE;
- lf.lfCharSet = DEFAULT_CHARSET;
- lf.lfOutPrecision = OUT_TT_PRECIS;
- lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
- lf.lfQuality = ANTIALIASED_QUALITY;
- lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ LOGFONTW lf = {0};
// lfFaceName can hold up to LF_FACESIZE wchars; truncate longer names
MultiByteToWideChar(CP_UTF8, 0, name, -1, lf.lfFaceName, LF_FACESIZE-1);
- hr = IDWriteGdiInterop_CreateFontFromLOGFONT(provider_priv->gdi_interop, &lf, &font);
- if (FAILED(hr) || !font)
+#if ASS_WINAPI_DESKTOP
+ struct font_enum_priv enum_priv;
+
+ enum_priv.shared_hdc = calloc(1, sizeof(ASS_SharedHDC));
+ if (!enum_priv.shared_hdc)
return;
- hr = IDWriteFont_GetFontFamily(font, &fontFamily);
- IDWriteFont_Release(font);
- if (FAILED(hr) || !fontFamily)
+ // Keep this HDC alive to keep the fonts alive. This seems to be necessary
+ // on Windows 7, where the fonts can't be deleted as long as the DC lives
+ // and where the converted IDWriteFontFaces only work as long as the fonts
+ // aren't deleted, although not on Windows 10, where fonts can be deleted
+ // even if the DC still lives but IDWriteFontFaces keep working even if
+ // the fonts are deleted.
+ //
+ // But beware of threading: docs say CreateCompatibleDC(NULL) creates a DC
+ // that is bound to the current thread and is deleted when the thread dies.
+ // It's not forbidden to call libass functions from multiple threads
+ // over the lifetime of a font provider, so this doesn't work for us.
+ // Practical tests suggest that the docs are wrong and the DC actually
+ // persists after its creating thread dies, but let's not rely on that.
+ // The workaround is to do a longer dance that is effectively equivalent to
+ // CreateCompatibleDC(NULL) but isn't specifically CreateCompatibleDC(NULL).
+ HDC screen_dc = GetDC(NULL);
+ if (!screen_dc) {
+ free(enum_priv.shared_hdc);
+ return;
+ }
+ HDC hdc = CreateCompatibleDC(screen_dc);
+ ReleaseDC(NULL, screen_dc);
+ if (!hdc) {
+ free(enum_priv.shared_hdc);
return;
+ }
- UINT32 n = IDWriteFontFamily_GetFontCount(fontFamily);
- for (UINT32 i = 0; i < n; i++) {
- hr = IDWriteFontFamily_GetFont(fontFamily, i, &font);
- if (FAILED(hr))
- continue;
+ enum_priv.provider = provider;
+ enum_priv.gdi_interop = provider_priv->gdi_interop;
+ enum_priv.shared_hdc->hdc = hdc;
+ enum_priv.shared_hdc->ref_count = 1;
+
+ // EnumFontFamilies gives each font once, plus repeats for charset-specific
+ // aliases. EnumFontFamiliesEx gives each charset of each font separately,
+ // so it repeats each font as many times as it has charsets, regardless
+ // of whether they have aliases. Other than this, the two functions are
+ // equivalent. There's no reliable way to distinguish when two items
+ // enumerated by either function refer to the same font (but different
+ // aliases or charsets) or actually distinct fonts, so we add every item
+ // as a separate font to our database and simply prefer the enumeration
+ // function that tends to give fewer duplicates. Generally, many fonts
+ // cover multiple charsets while very few have aliases, so we prefer
+ // EnumFontFamilies.
+ //
+ // Furthermore, the requested name might be an empty string. In this case,
+ // EnumFontFamilies will give us only fonts with empty names, whereas
+ // EnumFontFamiliesEx would give us a list of all installed font families.
+ EnumFontFamiliesW(hdc, lf.lfFaceName,
+ (FONTENUMPROCW) font_enum_proc, (LPARAM) &enum_priv);
+
+ hdc_release(enum_priv.shared_hdc);
+#else
+ HRESULT hr;
+ IDWriteFactory3 *factory3;
+ hr = IDWriteFactory_QueryInterface(provider_priv->factory,
+ &IID_IDWriteFactory3, (void **) &factory3);
+ if (SUCCEEDED(hr) && factory3) {
+ IDWriteFontSet *fontSet;
+ hr = IDWriteFactory3_GetSystemFontSet(factory3, &fontSet);
+ IDWriteFactory3_Release(factory3);
+ if (FAILED(hr) || !fontSet)
+ return;
+
+ DWRITE_FONT_PROPERTY_ID property_ids[] = {
+ DWRITE_FONT_PROPERTY_ID_WIN32_FAMILY_NAME,
+ DWRITE_FONT_PROPERTY_ID_FULL_NAME,
+ DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME,
+ };
+ for (int i = 0; i < sizeof property_ids / sizeof *property_ids; i++) {
+ DWRITE_FONT_PROPERTY property = {
+ property_ids[i],
+ lf.lfFaceName,
+ L"",
+ };
+
+ IDWriteFontSet *filteredSet;
+ hr = IDWriteFontSet_GetMatchingFonts(fontSet, &property,
+ 1, &filteredSet);
+ if (FAILED(hr) || !filteredSet)
+ continue;
+
+ add_font_set(filteredSet, provider);
+
+ IDWriteFontSet_Release(filteredSet);
+ }
- // Simulations for bold or oblique are sometimes synthesized by
- // DirectWrite. We are only interested in physical fonts.
- if (IDWriteFont_GetSimulations(font) != 0) {
- IDWriteFont_Release(font);
- continue;
+ IDWriteFontSet_Release(fontSet);
+ } else {
+ // We must be in Windows 8 WinRT. IDWriteFontSet is not yet
+ // supported, but GDI calls are forbidden. Our only options are
+ // FindFamilyName, CreateFontFromLOGFONT, and eager preloading
+ // of all fonts. The two lazy options are similar, with the
+ // difference that FindFamilyName searches by WWS_FAMILY_NAME
+ // whereas CreateFontFromLOGFONT searches by WIN32_FAMILY_NAME.
+ // The latter is what GDI uses, so pick that. In at least some
+ // versions of Windows, it also searches by FULL_NAME, which is
+ // even better, but it's unclear whether this includes Windows 8.
+ // It never searches by POSTSCRIPT_NAME. This means we won't
+ // find CFF-outline fonts by their PostScript name and may not
+ // find TrueType fonts by their full name; but we can't fix this
+ // without loading the entire font list.
+ lf.lfWeight = FW_DONTCARE;
+ lf.lfCharSet = DEFAULT_CHARSET;
+ lf.lfOutPrecision = OUT_TT_PRECIS;
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf.lfQuality = ANTIALIASED_QUALITY;
+ lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ IDWriteFont *font = NULL;
+ hr = IDWriteGdiInterop_CreateFontFromLOGFONT(provider_priv->gdi_interop,
+ &lf, &font);
+ if (FAILED(hr) || !font)
+ return;
+
+ IDWriteFontFamily *fontFamily = NULL;
+ hr = IDWriteFont_GetFontFamily(font, &fontFamily);
+ IDWriteFont_Release(font);
+ if (FAILED(hr) || !fontFamily)
+ return;
+
+ UINT32 n = IDWriteFontFamily_GetFontCount(fontFamily);
+ for (UINT32 i = 0; i < n; i++) {
+ hr = IDWriteFontFamily_GetFont(fontFamily, i, &font);
+ if (FAILED(hr))
+ continue;
+
+ // Simulations for bold or oblique are sometimes synthesized by
+ // DirectWrite. We are only interested in physical fonts.
+ if (IDWriteFont_GetSimulations(font) != 0) {
+ IDWriteFont_Release(font);
+ continue;
+ }
+
+ add_font(font, fontFamily, provider);
}
- add_font(font, fontFamily, provider);
+ IDWriteFontFamily_Release(fontFamily);
}
-
- IDWriteFontFamily_Release(fontFamily);
+#endif
}
static void get_substitutions(void *priv, const char *name,
diff --git a/libass/ass_fontselect.c b/libass/ass_fontselect.c
index 68a4407..e2d1cb1 100644
--- a/libass/ass_fontselect.c
+++ b/libass/ass_fontselect.c
@@ -1052,7 +1052,13 @@ struct font_constructors font_constructors[] = {
{ ASS_FONTPROVIDER_CORETEXT, &ass_coretext_add_provider, "coretext"},
#endif
#ifdef CONFIG_DIRECTWRITE
- { ASS_FONTPROVIDER_DIRECTWRITE, &ass_directwrite_add_provider, "directwrite"},
+ { ASS_FONTPROVIDER_DIRECTWRITE, &ass_directwrite_add_provider, "directwrite"
+#if ASS_WINAPI_DESKTOP
+ " (with GDI)"
+#else
+ " (without GDI)"
+#endif
+ },
#endif
#ifdef CONFIG_FONTCONFIG
{ ASS_FONTPROVIDER_FONTCONFIG, &ass_fontconfig_add_provider, "fontconfig"},
diff --git a/libass/dwrite_c.h b/libass/dwrite_c.h
index 15f9b11..5537832 100644
--- a/libass/dwrite_c.h
+++ b/libass/dwrite_c.h
@@ -15,14 +15,17 @@
#include <unknwn.h>
typedef struct IDWriteFactory IDWriteFactory;
+typedef struct IDWriteFactory3 IDWriteFactory3;
typedef struct IDWriteFont IDWriteFont;
typedef struct IDWriteFontCollection IDWriteFontCollection;
typedef struct IDWriteFontFace IDWriteFontFace;
+typedef struct IDWriteFontFaceReference IDWriteFontFaceReference;
typedef struct IDWriteFontFamily IDWriteFontFamily;
typedef struct IDWriteFontList IDWriteFontList;
typedef struct IDWriteFontFile IDWriteFontFile;
typedef struct IDWriteFontFileLoader IDWriteFontFileLoader;
typedef struct IDWriteFontFileStream IDWriteFontFileStream;
+typedef struct IDWriteFontSet IDWriteFontSet;
typedef struct IDWriteInlineObject IDWriteInlineObject;
typedef struct IDWriteLocalizedStrings IDWriteLocalizedStrings;
typedef struct IDWritePixelSnapping IDWritePixelSnapping;
@@ -71,6 +74,24 @@ typedef enum DWRITE_FONT_FACE_TYPE {
DWRITE_FONT_FACE_TYPE_RAW_CFF
} DWRITE_FONT_FACE_TYPE;
+typedef enum DWRITE_FONT_PROPERTY_ID {
+ DWRITE_FONT_PROPERTY_ID_NONE = 0,
+ DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FAMILY_NAME,
+ DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FAMILY_NAME,
+ DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FACE_NAME,
+ DWRITE_FONT_PROPERTY_ID_FULL_NAME,
+ DWRITE_FONT_PROPERTY_ID_WIN32_FAMILY_NAME,
+ DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME,
+ DWRITE_FONT_PROPERTY_ID_DESIGN_SCRIPT_LANGUAGE_TAG,
+ DWRITE_FONT_PROPERTY_ID_SUPPORTED_SCRIPT_LANGUAGE_TAG,
+ DWRITE_FONT_PROPERTY_ID_SEMANTIC_TAG,
+ DWRITE_FONT_PROPERTY_ID_WEIGHT,
+ DWRITE_FONT_PROPERTY_ID_STRETCH,
+ DWRITE_FONT_PROPERTY_ID_STYLE,
+ DWRITE_FONT_PROPERTY_ID_TYPOGRAPHIC_FACE_NAME,
+ /* rest dropped */
+} DWRITE_FONT_PROPERTY_ID;
+
typedef enum DWRITE_FONT_SIMULATIONS {
DWRITE_FONT_SIMULATIONS_NONE = 0x0000,
DWRITE_FONT_SIMULATIONS_BOLD = 0x0001,
@@ -102,6 +123,12 @@ typedef enum DWRITE_FONT_WEIGHT {
/* rest dropped */
} DWRITE_FONT_WEIGHT;
+typedef enum DWRITE_LOCALITY {
+ DWRITE_LOCALITY_REMOTE = 0,
+ DWRITE_LOCALITY_PARTIAL,
+ DWRITE_LOCALITY_LOCAL
+} DWRITE_LOCALITY;
+
typedef struct DWRITE_FONT_METRICS {
UINT16 designUnitsPerEm;
UINT16 ascent;
@@ -115,6 +142,12 @@ typedef struct DWRITE_FONT_METRICS {
UINT16 strikethroughThickness;
} DWRITE_FONT_METRICS;
+typedef struct DWRITE_FONT_PROPERTY {
+ DWRITE_FONT_PROPERTY_ID propertyId;
+ const WCHAR *propertyValue;
+ const WCHAR *localeName;
+} DWRITE_FONT_PROPERTY;
+
typedef struct DWRITE_GLYPH_OFFSET DWRITE_GLYPH_OFFSET;
typedef struct DWRITE_GLYPH_RUN {
@@ -192,6 +225,7 @@ DECLARE_INTERFACE_(IDWriteFactory,IUnknown)
IDWriteTextFormat **textFormat) PURE;
STDMETHOD(dummy12)(THIS);
+
STDMETHOD(GetGdiInterop)(THIS_
IDWriteGdiInterop **gdiInterop) PURE;
@@ -217,6 +251,99 @@ DECLARE_INTERFACE_(IDWriteFactory,IUnknown)
#endif /*COBJMACROS*/
#undef INTERFACE
+#define INTERFACE IDWriteFactory3
+DECLARE_INTERFACE_(IDWriteFactory3,IDWriteFactory)
+{
+ BEGIN_INTERFACE
+
+#ifndef __cplusplus
+ /* IUnknown methods */
+ STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+
+ /* IDWriteFactory methods */
+ STDMETHOD(GetSystemFontCollection)(THIS_
+ IDWriteFontCollection **fontCollection,
+ BOOL checkForUpdates __MINGW_DEF_ARG_VAL(FALSE)) PURE;
+
+ STDMETHOD(dummy1)(THIS);
+ STDMETHOD(dummy2)(THIS);
+ STDMETHOD(dummy3)(THIS);
+ STDMETHOD(dummy4)(THIS);
+ STDMETHOD(dummy5)(THIS);
+ STDMETHOD(dummy6)(THIS);
+ STDMETHOD(dummy7)(THIS);
+ STDMETHOD(dummy8)(THIS);
+ STDMETHOD(dummy9)(THIS);
+ STDMETHOD(dummy10)(THIS);
+ STDMETHOD(dummy11)(THIS);
+
+ STDMETHOD(CreateTextFormat)(THIS_
+ WCHAR const *fontFamilyName,
+ IDWriteFontCollection *fontCollection,
+ DWRITE_FONT_WEIGHT fontWeight,
+ DWRITE_FONT_STYLE fontStyle,
+ DWRITE_FONT_STRETCH fontStretch,
+ FLOAT fontSize,
+ WCHAR const *localeName,
+ IDWriteTextFormat **textFormat) PURE;
+
+ STDMETHOD(dummy12)(THIS);
+
+ STDMETHOD(GetGdiInterop)(THIS_
+ IDWriteGdiInterop **gdiInterop) PURE;
+
+ STDMETHOD(CreateTextLayout)(THIS_
+ WCHAR const *string,
+ UINT32 stringLength,
+ IDWriteTextFormat *textFormat,
+ FLOAT maxWidth,
+ FLOAT maxHeight,
+ IDWriteTextLayout **textLayout) PURE;
+#endif
+
+ STDMETHOD(dummy13)(THIS);
+ STDMETHOD(dummy14)(THIS);
+ STDMETHOD(dummy15)(THIS);
+ STDMETHOD(dummy16)(THIS);
+ STDMETHOD(dummy17)(THIS);
+
+ /* IDWriteFactory1 methods */
+ STDMETHOD(dummy18)(THIS);
+ STDMETHOD(dummy19)(THIS);
+
+ /* IDWriteFactory2 methods */
+ STDMETHOD(dummy20)(THIS);
+ STDMETHOD(dummy21)(THIS);
+ STDMETHOD(dummy22)(THIS);
+ STDMETHOD(dummy23)(THIS);
+ STDMETHOD(dummy24)(THIS);
+
+ /* IDWriteFactory3 methods */
+ STDMETHOD(dummy25)(THIS);
+ STDMETHOD(dummy26)(THIS);
+ STDMETHOD(dummy27)(THIS);
+ STDMETHOD(dummy28)(THIS);
+
+ STDMETHOD(GetSystemFontSet)(THIS_
+ IDWriteFontSet **fontSet) PURE;
+
+ /* rest dropped */
+ END_INTERFACE
+};
+#ifdef COBJMACROS
+#define IDWriteFactory3_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
+#define IDWriteFactory3_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IDWriteFactory3_Release(This) (This)->lpVtbl->Release(This)
+#define IDWriteFactory3_GetSystemFontCollection(This,fontCollection,checkForUpdates) (This)->lpVtbl->GetSystemFontCollection(This,fontCollection,checkForUpdates)
+#define IDWriteFactory3_CreateTextFormat(This,fontFamilyName,fontCollection,fontWeight,fontStyle,fontStretch,fontSize,localeName,textFormat) (This)->lpVtbl->CreateTextFormat(This,fontFamilyName,fontCollection,fontWeight,fontStyle,fontStretch,fontSize,localeName,textFormat)
+#define IDWriteFactory3_CreateTextLayout(This,string,stringLength,textFormat,maxWidth,maxHeight,textLayout) (This)->lpVtbl->CreateTextLayout(This,string,stringLength,textFormat,maxWidth,maxHeight,textLayout)
+#define IDWriteFactory3_GetGdiInterop(This,gdiInterop) (This)->lpVtbl->GetGdiInterop(This,gdiInterop)
+#define IDWriteFactory3_GetSystemFontSet(This,fontSet) (This)->lpVtbl->GetSystemFontSet(This,fontSet)
+#endif /*COBJMACROS*/
+
+#undef INTERFACE
#define INTERFACE IDWriteFont
DECLARE_INTERFACE_(IDWriteFont,IUnknown)
{
@@ -340,6 +467,17 @@ DECLARE_INTERFACE_(IDWriteFontFace,IUnknown)
STDMETHOD_(UINT32, GetIndex)(THIS) PURE;
+ STDMETHOD(dummy1)(THIS);
+ STDMETHOD(dummy2)(THIS);
+ STDMETHOD(dummy3)(THIS);
+ STDMETHOD(dummy4)(THIS);
+ STDMETHOD(dummy5)(THIS);
+
+ STDMETHOD(GetGlyphIndices)(THIS_
+ UINT32 const *codePoints,
+ UINT32 codePointCount,
+ UINT16 *glyphIndices) PURE;
+
/* rest dropped */
END_INTERFACE
};
@@ -348,6 +486,48 @@ DECLARE_INTERFACE_(IDWriteFontFace,IUnknown)
#define IDWriteFontFace_GetType(This) (This)->lpVtbl->GetType(This)
#define IDWriteFontFace_GetFiles(This,numberOfFiles,fontFiles) (This)->lpVtbl->GetFiles(This,numberOfFiles,fontFiles)
#define IDWriteFontFace_GetIndex(This) (This)->lpVtbl->GetIndex(This)
+#define IDWriteFontFace_GetGlyphIndices(This,codePoints,codePointCount,glyphIndices) (This)->lpVtbl->GetGlyphIndices(This,codePoints,codePointCount,glyphIndices)
+#endif /*COBJMACROS*/
+
+#undef INTERFACE
+#define INTERFACE IDWriteFontFaceReference
+DECLARE_INTERFACE_(IDWriteFontFaceReference,IUnknown)
+{
+ BEGIN_INTERFACE
+
+#ifndef __cplusplus
+ /* IUnknown methods */
+ STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+#endif
+
+ STDMETHOD(CreateFontFace)(THIS_
+ IDWriteFontFace/*3*/ **fontFace) PURE;
+
+ STDMETHOD(dummy1)(THIS);
+ STDMETHOD(dummy2)(THIS);
+ STDMETHOD(dummy3)(THIS);
+
+ STDMETHOD_(DWRITE_FONT_SIMULATIONS, GetSimulations)(THIS) PURE;
+
+ STDMETHOD(dummy4)(THIS);
+ STDMETHOD(dummy5)(THIS);
+ STDMETHOD(dummy6)(THIS);
+ STDMETHOD(dummy7)(THIS);
+
+ STDMETHOD_(DWRITE_LOCALITY, GetLocality)(THIS) PURE;
+
+ /* rest dropped */
+ END_INTERFACE
+};
+#ifdef COBJMACROS
+#define IDWriteFontFaceReference_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
+#define IDWriteFontFaceReference_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IDWriteFontFaceReference_Release(This) (This)->lpVtbl->Release(This)
+#define IDWriteFontFaceReference_CreateFontFace(This,fontFace) (This)->lpVtbl->CreateFontFace(This,fontFace)
+#define IDWriteFontFaceReference_GetSimulations(This) (This)->lpVtbl->GetSimulations(This)
+#define IDWriteFontFaceReference_GetLocality(This) (This)->lpVtbl->GetLocality(This)
#endif /*COBJMACROS*/
#undef INTERFACE
@@ -488,6 +668,51 @@ DECLARE_INTERFACE_(IDWriteFontFileStream,IUnknown)
#endif /*COBJMACROS*/
#undef INTERFACE
+#define INTERFACE IDWriteFontSet
+DECLARE_INTERFACE_(IDWriteFontSet,IUnknown)
+{
+ BEGIN_INTERFACE
+
+#ifndef __cplusplus
+ /* IUnknown methods */
+ STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+#endif
+
+ /* IDWriteFontSet methods */
+ STDMETHOD_(UINT32, GetFontCount)(THIS) PURE;
+
+ STDMETHOD(GetFontFaceReference)(THIS_
+ UINT32 listIndex,
+ IDWriteFontFaceReference **fontFaceReference) PURE;
+
+ STDMETHOD(dummy1)(THIS);
+ STDMETHOD(dummy2)(THIS);
+ STDMETHOD(dummy3)(THIS);
+ STDMETHOD(dummy4)(THIS);
+ STDMETHOD(dummy5)(THIS);
+ STDMETHOD(dummy6)(THIS);
+ STDMETHOD(dummy7)(THIS);
+
+ STDMETHOD(GetMatchingFonts)(THIS_
+ DWRITE_FONT_PROPERTY const *properties,
+ UINT32 propertyCount,
+ IDWriteFontSet **filteredSet) PURE;
+
+ /* rest dropped */
+ END_INTERFACE
+};
+#ifdef COBJMACROS
+#define IDWriteFontSet_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
+#define IDWriteFontSet_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IDWriteFontSet_Release(This) (This)->lpVtbl->Release(This)
+#define IDWriteFontSet_GetFontCount(This) (This)->lpVtbl->GetFontCount(This)
+#define IDWriteFontSet_GetFontFaceReference(This,listIndex,fontFaceReference) (This)->lpVtbl->GetFontFaceReference(This,listIndex,fontFaceReference)
+#define IDWriteFontSet_GetMatchingFonts(This,properties,propertyCount,filteredSet) (This)->lpVtbl->GetMatchingFonts(This,properties,propertyCount,filteredSet)
+#endif /*COBJMACROS*/
+
+#undef INTERFACE
#define INTERFACE IDWriteLocalizedStrings
DECLARE_INTERFACE_(IDWriteLocalizedStrings,IUnknown)
{
@@ -702,6 +927,13 @@ DECLARE_INTERFACE_(IDWriteGdiInterop,IUnknown)
STDMETHOD(CreateFontFromLOGFONT)(THIS_
LOGFONTW const *logFont,
IDWriteFont **font) PURE;
+
+ STDMETHOD(dummy1)(THIS);
+ STDMETHOD(dummy2)(THIS);
+
+ STDMETHOD(CreateFontFaceFromHdc)(THIS_
+ HDC hdc,
+ IDWriteFontFace **fontFace) PURE;
/* rest dropped */
END_INTERFACE
};
@@ -710,9 +942,11 @@ DECLARE_INTERFACE_(IDWriteGdiInterop,IUnknown)
#define IDWriteGdiInterop_AddRef(This) (This)->lpVtbl->AddRef(This)
#define IDWriteGdiInterop_Release(This) (This)->lpVtbl->Release(This)
#define IDWriteGdiInterop_CreateFontFromLOGFONT(This,logFont,font) (This)->lpVtbl->CreateFontFromLOGFONT(This,logFont,font)
+#define IDWriteGdiInterop_CreateFontFaceFromHdc(This,hdc,fontFace) (This)->lpVtbl->CreateFontFaceFromHdc(This,hdc,fontFace)
#endif /*COBJMACROS*/
DEFINE_GUID(IID_IDWriteFactory, 0xb859ee5a,0xd838,0x4b5b,0xa2,0xe8,0x1a,0xdc,0x7d,0x93,0xdb,0x48);
+DEFINE_GUID(IID_IDWriteFactory3, 0x9a1b41c3,0xd3bb,0x466a,0x87,0xfc,0xfe,0x67,0x55,0x6a,0x3b,0x65);
DEFINE_GUID(IID_IDWritePixelSnapping, 0xeaf3a2da,0xecf4,0x4d24,0xb6,0x44,0xb3,0x4f,0x68,0x42,0x02,0x4b);
DEFINE_GUID(IID_IDWriteTextRenderer, 0xef8a8135,0x5cc6,0x45fe,0x88,0x25,0xc5,0xa0,0x72,0x4e,0xb8,0x19);