diff --git a/build/libass/config.h b/build/libass/config.h index fda7ef5cf..d2fc12117 100644 --- a/build/libass/config.h +++ b/build/libass/config.h @@ -3,3 +3,4 @@ #define CONFIG_ASM 1 #define CONFIG_RASTERIZER 1 +#define CONFIG_DIRECTWRITE 1 diff --git a/build/libass/libass.vcxproj b/build/libass/libass.vcxproj index df487b6b8..61408f354 100644 --- a/build/libass/libass.vcxproj +++ b/build/libass/libass.vcxproj @@ -96,6 +96,7 @@ + @@ -107,4 +108,4 @@ {fb8e8d19-a4d6-4181-943c-282075f49b41} - + \ No newline at end of file diff --git a/build/libass/libass.vcxproj.filters b/build/libass/libass.vcxproj.filters index 2ef6efedf..db35379ba 100644 --- a/build/libass/libass.vcxproj.filters +++ b/build/libass/libass.vcxproj.filters @@ -19,9 +19,6 @@ - - Assembly Files - Assembly Files @@ -49,6 +46,9 @@ Assembly Files + + Assembly Files + @@ -87,22 +87,13 @@ Header Files - + Header Files - + Header Files - - Header Files - - - Header Files - - - Header Files - - + Header Files @@ -158,5 +149,8 @@ Source Files + + Source Files + - + \ No newline at end of file diff --git a/src/libass_gdi_fontselect.cpp b/src/libass_gdi_fontselect.cpp new file mode 100644 index 000000000..3623968e5 --- /dev/null +++ b/src/libass_gdi_fontselect.cpp @@ -0,0 +1,120 @@ +// Copyright (c) 2016, Thomas Goyne +// +// 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 + +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include + +namespace { +class GdiFont { + HFONT font; + std::shared_ptr dc; + + size_t size = 0; + std::unique_ptr font_data; + +public: + GdiFont(HFONT font, std::shared_ptr 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 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(malloc(sizeof(char *))); + meta.n_family = 1; + + auto name = static_cast(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(lParam))(*lf); + return 1; + }, (LPARAM)&cb, 0); +} + +template struct wrapper; +template +struct wrapper { + static R call(void *obj, Args... args) { + return (static_cast(obj)->*method)(args...); + } +}; +} + +extern "C" +ASS_FontProvider *ass_directwrite_add_provider(ASS_Library *, + ASS_FontSelector *selector, + const char *) { +#define WRAP(method) &wrapper::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); +}