Add a GDI-based font selector for libass
This deliberately doesn't perform any font substitutions as the sort of people that use libass on Windows tend to perfer to manually pick fonts with the correctly glyphs.
This commit is contained in:
parent
e06385b6d4
commit
e5a6abd215
4 changed files with 133 additions and 17 deletions
|
@ -3,3 +3,4 @@
|
|||
|
||||
#define CONFIG_ASM 1
|
||||
#define CONFIG_RASTERIZER 1
|
||||
#define CONFIG_DIRECTWRITE 1
|
||||
|
|
|
@ -96,6 +96,7 @@
|
|||
<ClCompile Include="$(LibassSrcDir)\libass\ass_string.c" />
|
||||
<ClCompile Include="$(LibassSrcDir)\libass\ass_strtod.c" />
|
||||
<ClCompile Include="$(LibassSrcDir)\libass\ass_utils.c" />
|
||||
<ClCompile Include="..\..\src\libass_gdi_fontselect.cpp" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Project References -->
|
||||
|
|
|
@ -19,9 +19,6 @@
|
|||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="$(LibassSrcDir)\libass\x86\x86inc.h">
|
||||
<Filter>Assembly Files</Filter>
|
||||
</None>
|
||||
<Yasm Include="$(LibassSrcDir)\libass\x86\be_blur.asm">
|
||||
<Filter>Assembly Files</Filter>
|
||||
</Yasm>
|
||||
|
@ -49,6 +46,9 @@
|
|||
<ClInclude Include="$(LibassSrcDir)\libass\x86\rasterizer.h">
|
||||
<Filter>Assembly Files</Filter>
|
||||
</ClInclude>
|
||||
<None Include="$(LibassSrcDir)\libass\x86\x86inc.asm">
|
||||
<Filter>Assembly Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(LibassSrcDir)\libass\ass.h">
|
||||
|
@ -87,22 +87,13 @@
|
|||
<ClInclude Include="$(LibassSrcDir)\libass\ass_utils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(LibassSrcDir)\win32\config.h">
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)config.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(LibassSrcDir)\win32\headers\enca.h">
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)strings.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(LibassSrcDir)\win32\headers\inttypes.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(LibassSrcDir)\win32\headers\stdint.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(LibassSrcDir)\win32\headers\strings.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(LibassSrcDir)\win32\headers\unistd.h">
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)unistd.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
|
@ -158,5 +149,8 @@
|
|||
<ClCompile Include="$(LibassSrcDir)\libass\ass_utils.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\libass_gdi_fontselect.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
120
src/libass_gdi_fontselect.cpp
Normal file
120
src/libass_gdi_fontselect.cpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
// Copyright (c) 2016, Thomas Goyne <plorkyeran@aegisub.org>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Aegisub Project http://www.aegisub.org/
|
||||
|
||||
extern "C" {
|
||||
#include "ass_fontselect.h"
|
||||
}
|
||||
|
||||
#undef inline
|
||||
|
||||
#include <memory>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
|
||||
namespace {
|
||||
class GdiFont {
|
||||
HFONT font;
|
||||
std::shared_ptr<HDC__> dc;
|
||||
|
||||
size_t size = 0;
|
||||
std::unique_ptr<char[]> font_data;
|
||||
|
||||
public:
|
||||
GdiFont(HFONT font, std::shared_ptr<HDC__> dc) : font(font), dc(dc) { }
|
||||
~GdiFont() { DeleteObject(font); }
|
||||
|
||||
size_t GetData(unsigned char *data, size_t offset, size_t len);
|
||||
bool CheckPostscript() { return false; }
|
||||
bool CheckGlyph(uint32_t codepoint) { return true; }
|
||||
void Destroy() { delete this; }
|
||||
};
|
||||
|
||||
size_t GdiFont::GetData(unsigned char *data, size_t offset, size_t len) {
|
||||
if (!font_data) {
|
||||
SelectObject(dc.get(), font);
|
||||
size = GetFontData(dc.get(), 0, 0, 0, 0);
|
||||
if (size == GDI_ERROR)
|
||||
return 0;
|
||||
font_data.reset(new char[size]);
|
||||
GetFontData(dc.get(), 0, 0, font_data.get(), size);
|
||||
}
|
||||
|
||||
if (!data)
|
||||
return size;
|
||||
memcpy(data, font_data.get() + offset, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
void match_fonts(ASS_Library *lib, ASS_FontProvider *provider, char *name) {
|
||||
std::shared_ptr<HDC__> dc(CreateCompatibleDC(nullptr), [](HDC dc) { DeleteDC(dc); });
|
||||
|
||||
LOGFONTW lf{};
|
||||
lf.lfCharSet = DEFAULT_CHARSET;
|
||||
MultiByteToWideChar(CP_UTF8, 0, name, -1, lf.lfFaceName, LF_FACESIZE);
|
||||
auto cb = [=](LOGFONTW const& lf) {
|
||||
ASS_FontProviderMetaData meta{};
|
||||
meta.weight = lf.lfWeight;
|
||||
meta.slant = lf.lfItalic ? FONT_SLANT_ITALIC : FONT_SLANT_NONE;
|
||||
meta.width = FONT_WIDTH_NORMAL;
|
||||
|
||||
meta.families= static_cast<char **>(malloc(sizeof(char *)));
|
||||
meta.n_family = 1;
|
||||
|
||||
auto name = static_cast<char *>(malloc(LF_FACESIZE * 4));
|
||||
auto len = wcsnlen(lf.lfFaceName, LF_FACESIZE);
|
||||
auto written = WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, len,
|
||||
name, LF_FACESIZE * 4, nullptr, nullptr);
|
||||
name[written] = 0;
|
||||
meta.families[0] = name;
|
||||
|
||||
auto hfont = CreateFontIndirectW(&lf);
|
||||
ass_font_provider_add_font(provider, &meta, nullptr, 0, new GdiFont(hfont, dc));
|
||||
};
|
||||
using type = decltype(cb);
|
||||
EnumFontFamiliesEx(dc.get(), &lf, [](const LOGFONT *lf, const TEXTMETRIC *, DWORD, LPARAM lParam) -> int {
|
||||
(*reinterpret_cast<type*>(lParam))(*lf);
|
||||
return 1;
|
||||
}, (LPARAM)&cb, 0);
|
||||
}
|
||||
|
||||
template <typename T, T> struct wrapper;
|
||||
template <typename T, typename R, typename... Args, R (T::*method)(Args...)>
|
||||
struct wrapper<R (T::*)(Args...), method> {
|
||||
static R call(void *obj, Args... args) {
|
||||
return (static_cast<T*>(obj)->*method)(args...);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
extern "C"
|
||||
ASS_FontProvider *ass_directwrite_add_provider(ASS_Library *,
|
||||
ASS_FontSelector *selector,
|
||||
const char *) {
|
||||
#define WRAP(method) &wrapper<decltype(&method), &method>::call
|
||||
static ASS_FontProviderFuncs callbacks = {
|
||||
WRAP(GdiFont::GetData),
|
||||
WRAP(GdiFont::CheckPostscript),
|
||||
WRAP(GdiFont::CheckGlyph),
|
||||
WRAP(GdiFont::Destroy),
|
||||
nullptr, // destroy_provider
|
||||
&match_fonts,
|
||||
nullptr, // get_substitution
|
||||
nullptr, // get_fallback
|
||||
};
|
||||
return ass_font_provider_new(selector, &callbacks, nullptr);
|
||||
}
|
Loading…
Reference in a new issue