summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorApache553 <Apache553@outlook.com>2021-02-22 01:25:29 +0800
committerOleg Oshmyan <chortos@inbox.lv>2021-05-01 19:49:12 +0300
commitd325c633f4ac32fcb4c76a3fb5926737a45c38d0 (patch)
treea7cee42ec7b56e2c6410872a10413e903bcfcd4c
parentd82f9994d1a8ee10e1e65332aada0789084f4d89 (diff)
downloadlibass-d325c633f4ac32fcb4c76a3fb5926737a45c38d0.tar.bz2
libass-d325c633f4ac32fcb4c76a3fb5926737a45c38d0.tar.xz
directwrite: request font on demand
scan_fonts can be very slow when many fonts were installed in the system. Use IDWriteGdiInterop to create a font by its name when needed instead of scanning all installed fonts during the initializing stage to get better performance. In case of a non-existent font, the fallback mechanism should do its work. Fixes https://github.com/libass/libass/issues/334. Signed-off-by: Oleg Oshmyan <chortos@inbox.lv>
-rw-r--r--libass/ass_directwrite.c80
-rw-r--r--libass/dwrite_c.h32
2 files changed, 77 insertions, 35 deletions
diff --git a/libass/ass_directwrite.c b/libass/ass_directwrite.c
index b5cc299..e666bd9 100644
--- a/libass/ass_directwrite.c
+++ b/libass/ass_directwrite.c
@@ -50,6 +50,7 @@ typedef struct {
typedef struct {
HMODULE directwrite_lib;
IDWriteFactory *factory;
+ IDWriteGdiInterop *gdi_interop;
} ProviderPrivate;
/**
@@ -389,6 +390,7 @@ static bool check_glyph(void *data, uint32_t code)
static void destroy_provider(void *priv)
{
ProviderPrivate *provider_priv = (ProviderPrivate *)priv;
+ provider_priv->gdi_interop->lpVtbl->Release(provider_priv->gdi_interop);
provider_priv->factory->lpVtbl->Release(provider_priv->factory);
FreeLibrary(provider_priv->directwrite_lib);
free(provider_priv);
@@ -668,50 +670,47 @@ cleanup:
}
/*
- * Scan every system font on the current machine and add it
- * to the libass lookup. Stores the FontPrivate as private data
- * for later memory reading
+ * When a new font name is requested, called to load that font from Windows
*/
-static void scan_fonts(IDWriteFactory *factory,
- ASS_FontProvider *provider)
+static void match_fonts(void *priv, ASS_Library *lib,
+ ASS_FontProvider *provider, char *name)
{
- HRESULT hr = S_OK;
- IDWriteFontCollection *fontCollection = NULL;
+ ProviderPrivate *provider_priv = (ProviderPrivate *)priv;
IDWriteFont *font = NULL;
- hr = IDWriteFactory_GetSystemFontCollection(factory, &fontCollection, FALSE);
+ 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;
+
+ // lfFaceName can hold up to LF_FACESIZE wchars; truncate longer names
+ MultiByteToWideChar(CP_UTF8, 0, name, -1, lf.lfFaceName, LF_FACESIZE-1);
- if (FAILED(hr) || !fontCollection)
+ hr = IDWriteGdiInterop_CreateFontFromLOGFONT(provider_priv->gdi_interop, &lf, &font);
+ if (FAILED(hr) || !font)
return;
- UINT32 familyCount = IDWriteFontCollection_GetFontFamilyCount(fontCollection);
+ hr = IDWriteFont_GetFontFamily(font, &fontFamily);
+ if (FAILED(hr) || !fontFamily)
+ goto cleanup;
- for (UINT32 i = 0; i < familyCount; ++i) {
- IDWriteFontFamily *fontFamily = NULL;
+ add_font(font, fontFamily, provider);
- hr = IDWriteFontCollection_GetFontFamily(fontCollection, i, &fontFamily);
- if (FAILED(hr))
- continue;
-
- UINT32 fontCount = IDWriteFontFamily_GetFontCount(fontFamily);
- for (UINT32 j = 0; j < fontCount; ++j) {
- hr = IDWriteFontFamily_GetFont(fontFamily, j, &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;
- }
+ IDWriteFontFamily_Release(fontFamily);
- add_font(font, fontFamily, provider);
- }
+ return;
+cleanup:
+ if (font)
+ IDWriteFont_Release(font);
+ if (fontFamily)
IDWriteFontFamily_Release(fontFamily);
- }
-
- IDWriteFontCollection_Release(fontCollection);
}
static void get_substitutions(void *priv, const char *name,
@@ -731,6 +730,7 @@ static ASS_FontProviderFuncs directwrite_callbacks = {
.check_glyph = check_glyph,
.destroy_font = destroy_font,
.destroy_provider = destroy_provider,
+ .match_fonts = match_fonts,
.get_substitutions = get_substitutions,
.get_fallback = get_fallback,
.get_font_index = get_font_index,
@@ -755,6 +755,7 @@ ASS_FontProvider *ass_directwrite_add_provider(ASS_Library *lib,
{
HRESULT hr = S_OK;
IDWriteFactory *dwFactory = NULL;
+ IDWriteGdiInterop *dwGdiInterop = NULL;
ASS_FontProvider *provider = NULL;
DWriteCreateFactoryFn DWriteCreateFactoryPtr = NULL;
ProviderPrivate *priv = NULL;
@@ -778,22 +779,33 @@ ASS_FontProvider *ass_directwrite_add_provider(ASS_Library *lib,
goto cleanup;
}
+ hr = IDWriteFactory_GetGdiInterop(dwFactory,
+ &dwGdiInterop);
+ if (FAILED(hr) || !dwGdiInterop) {
+ ass_msg(lib, MSGL_WARN, "Failed to get IDWriteGdiInterop.");
+ dwGdiInterop = NULL;
+ goto cleanup;
+ }
+
priv = (ProviderPrivate *)calloc(sizeof(*priv), 1);
if (!priv)
goto cleanup;
priv->directwrite_lib = directwrite_lib;
priv->factory = dwFactory;
+ priv->gdi_interop = dwGdiInterop;
+
provider = ass_font_provider_new(selector, &directwrite_callbacks, priv);
if (!provider)
goto cleanup;
- scan_fonts(dwFactory, provider);
return provider;
cleanup:
free(priv);
+ if (dwGdiInterop)
+ dwGdiInterop->lpVtbl->Release(dwGdiInterop);
if (dwFactory)
dwFactory->lpVtbl->Release(dwFactory);
if (directwrite_lib)
diff --git a/libass/dwrite_c.h b/libass/dwrite_c.h
index d20139b..5612e9f 100644
--- a/libass/dwrite_c.h
+++ b/libass/dwrite_c.h
@@ -29,6 +29,7 @@ typedef struct IDWritePixelSnapping IDWritePixelSnapping;
typedef struct IDWriteTextFormat IDWriteTextFormat;
typedef struct IDWriteTextLayout IDWriteTextLayout;
typedef struct IDWriteTextRenderer IDWriteTextRenderer;
+typedef struct IDWriteGdiInterop IDWriteGdiInterop;
#include <dcommon.h>
@@ -191,7 +192,8 @@ DECLARE_INTERFACE_(IDWriteFactory,IUnknown)
IDWriteTextFormat **textFormat) PURE;
STDMETHOD(dummy12)(THIS);
- STDMETHOD(dummy13)(THIS);
+ STDMETHOD(GetGdiInterop)(THIS_
+ IDWriteGdiInterop **gdiInterop) PURE;
STDMETHOD(CreateTextLayout)(THIS_
WCHAR const *string,
@@ -211,6 +213,7 @@ DECLARE_INTERFACE_(IDWriteFactory,IUnknown)
#define IDWriteFactory_GetSystemFontCollection(This,fontCollection,checkForUpdates) (This)->lpVtbl->GetSystemFontCollection(This,fontCollection,checkForUpdates)
#define IDWriteFactory_CreateTextFormat(This,fontFamilyName,fontCollection,fontWeight,fontStyle,fontStretch,fontSize,localeName,textFormat) (This)->lpVtbl->CreateTextFormat(This,fontFamilyName,fontCollection,fontWeight,fontStyle,fontStretch,fontSize,localeName,textFormat)
#define IDWriteFactory_CreateTextLayout(This,string,stringLength,textFormat,maxWidth,maxHeight,textLayout) (This)->lpVtbl->CreateTextLayout(This,string,stringLength,textFormat,maxWidth,maxHeight,textLayout)
+#define IDWriteFactory_GetGdiInterop(This,gdiInterop) (This)->lpVtbl->GetGdiInterop(This,gdiInterop)
#endif /*COBJMACROS*/
#undef INTERFACE
@@ -680,8 +683,35 @@ DECLARE_INTERFACE_(IDWriteTextRenderer,IDWritePixelSnapping)
END_INTERFACE
};
+#undef INTERFACE
+#define INTERFACE IDWriteGdiInterop
+DECLARE_INTERFACE_(IDWriteGdiInterop,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(CreateFontFromLOGFONT)(THIS_
+ LOGFONTW const *logFont,
+ IDWriteFont **font) PURE;
+ /* rest dropped */
+ END_INTERFACE
+};
+#ifdef COBJMACROS
+#define IDWriteGdiInterop_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
+#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)
+#endif /*COBJMACROS*/
+
DEFINE_GUID(IID_IDWriteFactory, 0xb859ee5a,0xd838,0x4b5b,0xa2,0xe8,0x1a,0xdc,0x7d,0x93,0xdb,0x48);
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);
+DEFINE_GUID(IID_IDWriteGdiInterop, 0x1edd9491,0x9853,0x4299,0x89,0x8f,0x64,0x32,0x98,0x3b,0x6f,0x3a);
#endif /* __INC_DWRITE__ */