]> granicus.if.org Git - libass/commitdiff
directwrite: add initial fontselect implementation
authorfeliwir <stephan.vedder@gmail.com>
Tue, 19 May 2015 09:46:37 +0000 (11:46 +0200)
committerGrigori Goronzy <greg@chown.ath.cx>
Fri, 10 Jul 2015 08:42:40 +0000 (10:42 +0200)
Incomplete, leaks memory, but capable of rendering something.

configure.ac
libass/ass.h
libass/ass_directwrite.cpp [new file with mode: 0644]
libass/ass_directwrite.h [new file with mode: 0644]
libass/ass_fontselect.c
libass/ass_utils.h
test/test.c

index a044833cd9a361164924f562f0b2d24ac91b1d84..ac115ea5ae988e5a6200f0fd235d2efa5d6d3409 100644 (file)
@@ -133,6 +133,7 @@ AM_COND_IF([ENABLE_LARGE_TILES],
 
 PKG_CHECK_MODULES([FREETYPE], freetype2 >= 9.10.3, [
     CFLAGS="$CFLAGS $FREETYPE_CFLAGS"
+    CXXFLAGS="$CFLAGS $FREETYPE_CFLAGS"
     LIBS="$LIBS $FREETYPE_LIBS"
     AC_DEFINE(CONFIG_FREETYPE, 1, [found freetype2 via pkg-config])
     ])
index 1fb2234aa82a7f4ba66ef7b210509264f3075338..5fd11a6a722a54b81ab2223869374b42ab532f1b 100644 (file)
@@ -190,6 +190,7 @@ typedef enum {
     ASS_FONTPROVIDER_AUTODETECT = 1,
     ASS_FONTPROVIDER_CORETEXT,
     ASS_FONTPROVIDER_FONTCONFIG,
+    ASS_FONTPROVIDER_DIRECTWRITE,
 } ASS_DefaultFontProvider;
 
 /**
diff --git a/libass/ass_directwrite.cpp b/libass/ass_directwrite.cpp
new file mode 100644 (file)
index 0000000..abf7e67
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2015 Stephan Vedder <stefano.pigozzi@gmail.com>
+ *
+ * This file is part of libass.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#ifdef CONFIG_DIRECTWRITE
+
+#include <dwrite.h>
+
+extern "C"
+{
+#include "ass_directwrite.h"
+#include "ass_utils.h"
+}
+
+static size_t get_data(void * priv, unsigned char* buf, size_t offset, size_t length)
+{
+       HRESULT hr = S_OK;
+       IDWriteFontFace* face = NULL;
+       IDWriteFont* font = (IDWriteFont*)priv;
+       IDWriteFontFile* files = NULL;
+       IDWriteFontFileStream* stream = NULL;
+       IDWriteFontFileLoader* loader = NULL;
+       UINT32 n_files = 0;
+       UINT64 fileSize;
+       const void* fileBuf = NULL;
+
+       hr = font->CreateFontFace(&face);
+       const void* refKey = NULL;
+       UINT32 keySize = 0;
+       void* fragContext = NULL;
+
+       if (FAILED(hr) || !face)
+               return 0;
+
+       hr = face->GetFiles(&n_files, NULL);
+       if (FAILED(hr))
+               return 0;
+
+       hr = face->GetFiles(&n_files, &files);
+       if (FAILED(hr) || !files)
+               return 0;
+
+       hr = files[0].GetReferenceKey(&refKey, &keySize);
+       if (FAILED(hr))
+               return 0;
+
+       hr = files[0].GetLoader(&loader);
+       if (FAILED(hr) || !loader)
+               return 0;
+
+       hr = loader->CreateStreamFromKey(refKey,keySize,&stream);
+       if (FAILED(hr) || !stream)
+               return 0;
+
+       if (buf == NULL)
+       {
+               hr = stream->GetFileSize(&fileSize);
+               if (FAILED(hr))
+                       return 0;
+
+               return fileSize;
+       }
+       
+       hr = stream->ReadFileFragment(&fileBuf, offset, length, &fragContext);
+       if (FAILED(hr) || !fileBuf)
+               return 0;
+
+       memcpy(buf, fileBuf, length);
+
+       stream->ReleaseFileFragment(fragContext);
+
+       return length;
+}
+
+static int check_glyph(void *priv, uint32_t code)
+{
+       //TODO: use IDWriteFont::HasCharacter method 
+       //see: https://msdn.microsoft.com/en-us/library/windows/desktop/dd371165(v=vs.85).aspx
+       HRESULT hr = S_OK;
+       BOOL exists = FALSE;
+
+       ((IDWriteFont*)priv)->HasCharacter(code, &exists);
+
+       if (FAILED(hr))
+               return FALSE;
+
+       return exists;
+}
+
+static void destroy(void* priv)
+{
+       ((IDWriteFactory*)priv)->Release();
+}
+
+static void scan_fonts(IDWriteFactory *factory, ASS_FontProvider *provider)
+{
+       HRESULT hr = S_OK;
+       IDWriteFontCollection* fontCollection = NULL;
+       IDWriteFont* font = NULL;
+       DWRITE_FONT_METRICS metrics;
+       DWRITE_FONT_STYLE style;
+       ASS_FontProviderMetaData meta = ASS_FontProviderMetaData();
+       hr = factory->GetSystemFontCollection(&fontCollection,FALSE);
+       wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
+       int size_needed = 0;
+
+       if(FAILED(hr)||!fontCollection)
+               return;
+
+       UINT32 familyCount = fontCollection->GetFontFamilyCount();
+
+       for (UINT32 i = 0; i < familyCount; ++i)
+    {
+               IDWriteFontFamily* fontFamily = NULL;
+               IDWriteLocalizedStrings* familyNames = NULL;
+               IDWriteLocalizedStrings* fontNames = NULL;
+               IDWriteLocalizedStrings* psNames = NULL;
+               BOOL exists = FALSE;
+               char* psName = NULL;
+
+               // Get the font family.
+               hr = fontCollection->GetFontFamily(i, &fontFamily);
+               if (FAILED(hr))
+                       return;
+
+               UINT32 fontCount = fontFamily->GetFontCount();
+               for (UINT32 j = 0; j < fontCount; ++j)
+               {
+                       hr = fontFamily->GetFont(j, &font);
+                       if (FAILED(hr))
+                               return;
+                       
+                       meta.weight = font->GetWeight();
+                       font->GetMetrics(&metrics);
+                       style = font->GetStyle();
+                       meta.slant =    (style==DWRITE_FONT_STYLE_NORMAL)? FONT_SLANT_NONE:
+                                                       (style==DWRITE_FONT_STYLE_OBLIQUE)? FONT_SLANT_OBLIQUE: 
+                                                       (style==DWRITE_FONT_STYLE_ITALIC)? FONT_SLANT_ITALIC : FONT_SLANT_NONE;
+
+                       hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, &psNames, &exists);
+                       if (FAILED(hr))
+                               return;
+
+                       if (exists)
+                       {
+                               hr = psNames->GetString(0, localeName, LOCALE_NAME_MAX_LENGTH + 1);
+                               if (FAILED(hr))
+                                       return;
+
+                               size_needed = WideCharToMultiByte(CP_UTF8, 0, localeName, -1, NULL, 0, NULL, NULL);
+                               psName = (char*)ass_aligned_alloc(32, size_needed);
+                               WideCharToMultiByte(CP_UTF8, 0, localeName, -1, psName, size_needed, NULL, NULL);
+                       }
+               
+                       hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_FULL_NAME, &fontNames, &exists);
+                       if (FAILED(hr))
+                               return;
+
+                       meta.n_fullname = fontNames->GetCount();
+                       meta.fullnames = (char **)calloc(meta.n_fullname, sizeof(char *));
+                       for (UINT32 k = 0; k < meta.n_fullname; ++k)
+                       {
+                               hr = fontNames->GetString(k,localeName, LOCALE_NAME_MAX_LENGTH + 1);
+                               if (FAILED(hr))
+                                       return;
+
+                               size_needed = WideCharToMultiByte(CP_UTF8, 0, localeName, -1, NULL, 0, NULL, NULL);
+                               char* mbName = (char *)malloc(size_needed);
+                               WideCharToMultiByte(CP_UTF8, 0, localeName, -1, mbName, size_needed, NULL, NULL);
+                               meta.fullnames[k] = mbName;
+                       }
+
+                       hr = fontFamily->GetFamilyNames(&familyNames);
+                       if (FAILED(hr))
+                               return;
+                       
+                       meta.n_family = familyNames->GetCount();
+                       meta.families = (char **)calloc(meta.n_family, sizeof(char *));
+                       for (UINT32 k = 0; k < meta.n_family; ++k)
+                       {
+                               hr = familyNames->GetString(k, localeName, LOCALE_NAME_MAX_LENGTH + 1);
+                               if (FAILED(hr))
+                                       return;
+
+                               size_needed = WideCharToMultiByte(CP_UTF8, 0, localeName, -1, NULL, 0, NULL, NULL);
+                               char* mbName = (char *)malloc(size_needed);
+                               WideCharToMultiByte(CP_UTF8, 0, localeName, -1, mbName, size_needed, NULL, NULL);
+                               meta.families[k] = mbName;
+                       }
+
+                       ass_font_provider_add_font(provider, &meta, NULL, j, psName, font);
+                       free(meta.fullnames);
+                       free(meta.families);
+               }       
+    }
+}
+
+static ASS_FontProviderFuncs directwrite_callbacks = {
+    get_data,
+       check_glyph,
+    NULL,
+    destroy,
+    NULL
+};
+
+ASS_FontProvider *
+ass_directwrite_add_provider(ASS_Library *lib, ASS_FontSelector *selector,
+                          const char *config)
+{
+       HRESULT hr = S_OK;
+       IDWriteFactory* dwFactory = NULL;
+       ASS_FontProvider *provider = NULL;
+
+       hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
+            __uuidof(IDWriteFactory),
+            (IUnknown**)(&dwFactory));
+
+       if(FAILED(hr))
+       {
+               ass_msg(lib, MSGL_WARN, "Failed to initialize directwrite.");
+               goto exit;
+       }       
+       
+
+    provider = ass_font_provider_new(selector, &directwrite_callbacks, dwFactory);
+
+    scan_fonts(dwFactory,provider);
+exit: 
+    return provider;
+}
+
+#endif
diff --git a/libass/ass_directwrite.h b/libass/ass_directwrite.h
new file mode 100644 (file)
index 0000000..054ea6b
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 Stephan Vedder <stephan.vedder@gmail.com>
+ *
+ * This file is part of libass.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include "ass_types.h"
+#include "ass_fontselect.h"
+
+#ifndef ASS_DIRECTWRITE_H
+#define ASS_DIRECTWRITE_H
+
+#ifdef CONFIG_DIRECTWRITE
+
+ASS_FontProvider *
+ass_directwrite_add_provider(ASS_Library *lib, ASS_FontSelector *selector,
+                          const char *config);
+
+#endif
+
+#endif
index bc1dec53c9b7790e5a999836cc9feaded17338eb..174fe1d012bfc8b02f7d0ab545a74f0161be1294 100644 (file)
@@ -38,6 +38,7 @@
 #include "ass_fontselect.h"
 #include "ass_fontconfig.h"
 #include "ass_coretext.h"
+#include "ass_directwrite.h"
 #include "ass_font.h"
 
 #define ABS(x) ((x) < 0 ? -(x) : (x))
@@ -236,6 +237,24 @@ ass_font_provider_add_font(ASS_FontProvider *provider,
     ASS_FontSelector *selector = provider->parent;
     ASS_FontInfo *info;
 
+#if 0
+    int j;
+    printf("new font:\n");
+    printf("  families: ");
+    for (j = 0; j < meta->n_family; j++)
+        printf("'%s' ", meta->families[j]);
+    printf("\n");
+    printf("  fullnames: ");
+    for (j = 0; j < meta->n_fullname; j++)
+        printf("'%s' ", meta->fullnames[j]);
+    printf("\n");
+    printf("  slant: %d\n", meta->slant);
+    printf("  weight: %d\n", meta->weight);
+    printf("  width: %d\n", meta->width);
+    printf("  path: %s\n", path);
+    printf("  index: %d\n", index);
+#endif
+
     weight = meta->weight;
     slant  = meta->slant;
     width  = meta->width;
@@ -803,6 +822,9 @@ struct font_constructors font_constructors[] = {
 #endif
 #ifdef CONFIG_FONTCONFIG
     { ASS_FONTPROVIDER_FONTCONFIG, &ass_fontconfig_add_provider },
+#endif
+#ifdef CONFIG_DIRECTWRITE
+    { ASS_FONTPROVIDER_DIRECTWRITE, &ass_directwrite_add_provider },
 #endif
     { ASS_FONTPROVIDER_NONE, NULL },
 };
index f249bc9a78d4a31371f48a01ae3a1c2bd457c8b7..caff161588a47f69d4592edd9af5fd86f5a4e377 100644 (file)
@@ -184,7 +184,7 @@ static inline int rot_key(double a)
 
 static inline unsigned fnv_32a_buf(void *buf, size_t len, unsigned hval)
 {
-    unsigned char *bp = buf;
+    unsigned char *bp = (unsigned char*)buf;
     size_t n = (len + 3) / 4;
 
     switch (len % 4) {
index 72a6991190e799288a3a8dae1453f6ff9da5d8ce..175e8be4536cedb15378972e04a5ea5cfe7c98cf 100644 (file)
@@ -171,6 +171,7 @@ char *font_provider_labels[] = {
     [ASS_FONTPROVIDER_AUTODETECT] = "Autodetect",
     [ASS_FONTPROVIDER_CORETEXT]   = "CoreText",
     [ASS_FONTPROVIDER_FONTCONFIG] = "Fontconfig",
+    [ASS_FONTPROVIDER_DIRECTWRITE]= "DirectWrite",
 };
 
 static void print_font_providers(ASS_Library *ass_library)