1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Direct2D: Move Direct2DFactories to juce_DirectX_windows.h

This commit is contained in:
reuk 2025-04-09 13:30:32 +01:00 committed by Oli
parent 18b508343d
commit 6deb508e96
2 changed files with 514 additions and 514 deletions

View file

@ -35,520 +35,6 @@
namespace juce
{
static String getLocalisedName (IDWriteLocalizedStrings* names)
{
jassert (names != nullptr);
uint32 index = 0;
BOOL exists = false;
[[maybe_unused]] auto hr = names->FindLocaleName (L"en-us", &index, &exists);
if (! exists)
index = 0;
uint32 length = 0;
hr = names->GetStringLength (index, &length);
HeapBlock<wchar_t> name (length + 1);
hr = names->GetString (index, name, length + 1);
return static_cast<const wchar_t*> (name);
}
static String getFontFamilyName (IDWriteFontFamily* family)
{
jassert (family != nullptr);
ComSmartPtr<IDWriteLocalizedStrings> familyNames;
auto hr = family->GetFamilyNames (familyNames.resetAndGetPointerAddress());
jassertquiet (SUCCEEDED (hr));
return getLocalisedName (familyNames);
}
static String getFontFaceName (IDWriteFont* font)
{
jassert (font != nullptr);
ComSmartPtr<IDWriteLocalizedStrings> faceNames;
auto hr = font->GetFaceNames (faceNames.resetAndGetPointerAddress());
jassertquiet (SUCCEEDED (hr));
return getLocalisedName (faceNames);
}
template <typename Range>
static StringArray stringArrayFromRange (Range&& range)
{
StringArray result;
for (const auto& item : range)
result.add (item);
return result;
}
class AggregateFontCollection
{
public:
explicit AggregateFontCollection (ComSmartPtr<IDWriteFontCollection> baseCollection)
: collections { std::move (baseCollection) } {}
StringArray findAllTypefaceNames()
{
const std::scoped_lock lock { mutex };
std::set<String> strings;
for (const auto& collection : collections)
{
const auto count = collection->GetFontFamilyCount();
for (auto i = decltype (count){}; i < count; ++i)
{
ComSmartPtr<IDWriteFontFamily> family;
if (FAILED (collection->GetFontFamily (i, family.resetAndGetPointerAddress())) || family == nullptr)
continue;
strings.insert (getFontFamilyName (family));
}
}
return stringArrayFromRange (strings);
}
static std::vector<ComSmartPtr<IDWriteFont>> getAllFontsInFamily (IDWriteFontFamily* fontFamily)
{
const auto fontFacesCount = fontFamily->GetFontCount();
std::vector<ComSmartPtr<IDWriteFont>> result;
result.reserve (fontFacesCount);
for (UINT32 i = 0; i < fontFacesCount; ++i)
{
ComSmartPtr<IDWriteFont> dwFont;
if (FAILED (fontFamily->GetFont (i, dwFont.resetAndGetPointerAddress())))
continue;
if (dwFont->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE)
continue;
result.push_back (dwFont);
}
return result;
}
StringArray findAllTypefaceStyles (const String& family)
{
const std::scoped_lock lock { mutex };
for (const auto& collection : collections)
{
BOOL fontFound = false;
uint32 fontIndex = 0;
if (FAILED (collection->FindFamilyName (family.toWideCharPointer(), &fontIndex, &fontFound)) || ! fontFound)
continue;
ComSmartPtr<IDWriteFontFamily> fontFamily;
if (FAILED (collection->GetFontFamily (fontIndex, fontFamily.resetAndGetPointerAddress())) || fontFamily == nullptr)
continue;
std::set<String> uniqueResults;
StringArray orderedResults;
for (const auto& font : getAllFontsInFamily (fontFamily))
{
const auto name = getFontFaceName (font);
if (uniqueResults.insert (name).second)
orderedResults.add (name);
}
return orderedResults;
}
return {};
}
ComSmartPtr<IDWriteFontFamily> getFamilyByName (const wchar_t* name)
{
const std::scoped_lock lock { mutex };
for (const auto& collection : collections)
{
const auto fontIndex = [&]
{
BOOL found = false;
UINT32 index = 0;
return (SUCCEEDED (collection->FindFamilyName (name, &index, &found)) && found)
? index
: (UINT32) -1;
}();
if (fontIndex == (UINT32) -1)
continue;
ComSmartPtr<IDWriteFontFamily> family;
if (FAILED (collection->GetFontFamily (fontIndex, family.resetAndGetPointerAddress())) || family == nullptr)
continue;
return family;
}
return {};
}
ComSmartPtr<IDWriteFont> findFontForFace (IDWriteFontFace* face)
{
for (const auto& collection : collections)
{
ComSmartPtr<IDWriteFont> result;
if (SUCCEEDED (collection->GetFontFromFontFace (face, result.resetAndGetPointerAddress())))
return result;
}
return {};
}
void addCollection (ComSmartPtr<IDWriteFontCollection> collection)
{
const std::scoped_lock lock { mutex };
collections.push_back (std::move (collection));
}
void removeCollection (ComSmartPtr<IDWriteFontCollection> collection)
{
const std::scoped_lock lock { mutex };
const auto iter = std::find (collections.begin(), collections.end(), collection);
if (iter != collections.end())
collections.erase (iter);
}
struct MapResult
{
ComSmartPtr<IDWriteFont> font;
UINT32 length{};
float scale{};
};
/* Tries matching against each collection in turn.
If any collection is able to match the entire string, then uses the appropriate font
from that collection.
Otherwise, returns the font that is able to match the longest sequence of characters,
preferring user-provided fonts.
*/
MapResult mapCharacters (IDWriteFontFallback* fallback,
IDWriteTextAnalysisSource* analysisSource,
UINT32 textPosition,
UINT32 textLength,
wchar_t const* baseFamilyName,
DWRITE_FONT_WEIGHT baseWeight,
DWRITE_FONT_STYLE baseStyle,
DWRITE_FONT_STRETCH baseStretch) noexcept
{
const std::scoped_lock lock { mutex };
// For reasons I don't understand, the system may pick better substitutions when passing
// nullptr, instead of the system collection, as the "default collection to use".
auto collectionsToCheck = collections;
collectionsToCheck.insert (collectionsToCheck.begin(), nullptr);
MapResult bestMatch;
for (const auto& collection : collectionsToCheck)
{
MapResult result;
const auto status = fallback->MapCharacters (analysisSource,
textPosition,
textLength,
collection,
baseFamilyName,
baseWeight,
baseStyle,
baseStretch,
&result.length,
result.font.resetAndGetPointerAddress(),
&result.scale);
if (FAILED (status) || result.font == nullptr)
continue;
if (result.length == textLength)
return result;
if (result.length >= bestMatch.length)
bestMatch = result;
}
return bestMatch;
}
private:
std::vector<ComSmartPtr<IDWriteFontCollection>> collections;
std::mutex mutex;
};
class MemoryFontFileStream final : public ComBaseClassHelper<IDWriteFontFileStream>
{
public:
explicit MemoryFontFileStream (std::shared_ptr<const MemoryBlock> blockIn)
: block (std::move (blockIn))
{
}
JUCE_COMRESULT GetFileSize (UINT64* fileSize) noexcept override
{
*fileSize = block->getSize();
return S_OK;
}
JUCE_COMRESULT GetLastWriteTime (UINT64* lastWriteTime) noexcept override
{
*lastWriteTime = 0;
return S_OK;
}
JUCE_COMRESULT ReadFileFragment (const void** fragmentStart,
UINT64 fileOffset,
UINT64 fragmentSize,
void** fragmentContext) noexcept override
{
if (fileOffset + fragmentSize > block->getSize())
{
*fragmentStart = nullptr;
*fragmentContext = nullptr;
return E_INVALIDARG;
}
*fragmentStart = addBytesToPointer (block->getData(), fileOffset);
*fragmentContext = this;
return S_OK;
}
void WINAPI ReleaseFileFragment (void*) noexcept override {}
private:
std::shared_ptr<const MemoryBlock> block;
};
class MemoryFontFileLoader final : public ComBaseClassHelper<IDWriteFontFileLoader>
{
public:
explicit MemoryFontFileLoader (MemoryBlock blob)
: block (std::make_shared<const MemoryBlock> (std::move (blob)))
{
}
HRESULT WINAPI CreateStreamFromKey (const void* fontFileReferenceKey,
UINT32 keySize,
IDWriteFontFileStream** fontFileStream) noexcept override
{
if (keySize != Uuid::size())
return E_INVALIDARG;
Uuid requestedKey { static_cast<const uint8*> (fontFileReferenceKey) };
if (requestedKey == uuid)
{
*fontFileStream = new MemoryFontFileStream { block };
return S_OK;
}
return E_INVALIDARG;
}
Uuid getUuid() const { return uuid; }
private:
std::shared_ptr<const MemoryBlock> block;
Uuid uuid;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryFontFileLoader)
};
class FontFileEnumerator final : public ComBaseClassHelper<IDWriteFontFileEnumerator>
{
public:
FontFileEnumerator (IDWriteFactory& factoryIn, ComSmartPtr<MemoryFontFileLoader> loaderIn)
: factory (factoryIn), loader (loaderIn) {}
HRESULT WINAPI GetCurrentFontFile (IDWriteFontFile** fontFile) noexcept override
{
*fontFile = nullptr;
if (! isPositiveAndBelow (rawDataIndex, 1))
return E_FAIL;
const auto uuid = loader->getUuid();
return factory.CreateCustomFontFileReference (uuid.getRawData(),
(UINT32) uuid.size(),
loader,
fontFile);
}
HRESULT WINAPI MoveNext (BOOL* hasCurrentFile) noexcept override
{
++rawDataIndex;
*hasCurrentFile = rawDataIndex < 1 ? TRUE : FALSE;
return S_OK;
}
private:
IDWriteFactory& factory;
ComSmartPtr<MemoryFontFileLoader> loader;
size_t rawDataIndex = std::numeric_limits<size_t>::max();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FontFileEnumerator)
};
class DirectWriteCustomFontCollectionLoader final : public ComBaseClassHelper<IDWriteFontCollectionLoader>
{
public:
explicit DirectWriteCustomFontCollectionLoader (IDWriteFactory& factoryIn)
: factory (factoryIn)
{
}
~DirectWriteCustomFontCollectionLoader() override
{
for (const auto& loader : fileLoaders)
factory.UnregisterFontFileLoader (loader);
}
Uuid addRawFontData (Span<const std::byte> blob)
{
const auto loader = becomeComSmartPtrOwner (new MemoryFontFileLoader { { blob.data(), blob.size() } });
factory.RegisterFontFileLoader (loader);
fileLoaders.push_back (loader);
return fileLoaders.back()->getUuid();
}
HRESULT WINAPI CreateEnumeratorFromKey (IDWriteFactory* factoryIn,
const void* collectionKey,
UINT32 collectionKeySize,
IDWriteFontFileEnumerator** fontFileEnumerator) noexcept override
{
if (collectionKeySize != Uuid::size())
return E_INVALIDARG;
const Uuid requestedCollectionKey { static_cast<const uint8*> (collectionKey) };
for (const auto& loader : fileLoaders)
{
if (loader->getUuid() != requestedCollectionKey)
continue;
*fontFileEnumerator = new FontFileEnumerator { *factoryIn, loader };
return S_OK;
}
return E_INVALIDARG;
}
private:
IDWriteFactory& factory;
std::vector<ComSmartPtr<MemoryFontFileLoader>> fileLoaders;
};
//==============================================================================
class Direct2DFactories
{
public:
Direct2DFactories()
{
ComSmartPtr<IDWriteFontCollection> collection;
if (SUCCEEDED (directWriteFactory->GetSystemFontCollection (collection.resetAndGetPointerAddress(), FALSE)) && collection != nullptr)
fonts.emplace (collection);
else
jassertfalse;
}
~Direct2DFactories()
{
if (directWriteFactory == nullptr)
return;
directWriteFactory->UnregisterFontCollectionLoader (collectionLoader);
}
[[nodiscard]] ComSmartPtr<IDWriteFactory> getDWriteFactory() const { return directWriteFactory; }
[[nodiscard]] ComSmartPtr<IDWriteFactory4> getDWriteFactory4() const { return directWriteFactory4; }
[[nodiscard]] AggregateFontCollection& getFonts() { jassert (fonts.has_value()); return *fonts; }
[[nodiscard]] ComSmartPtr<DirectWriteCustomFontCollectionLoader> getCollectionLoader() const { return collectionLoader; }
private:
DynamicLibrary direct2dDll { "d2d1.dll" }, directWriteDll { "DWrite.dll" };
const ComSmartPtr<ID2D1Factory> d2dFactory = [&]() -> ComSmartPtr<ID2D1Factory>
{
JUCE_LOAD_WINAPI_FUNCTION (direct2dDll,
D2D1CreateFactory,
d2d1CreateFactory,
HRESULT,
(D2D1_FACTORY_TYPE, REFIID, D2D1_FACTORY_OPTIONS*, void**))
if (d2d1CreateFactory == nullptr)
return {};
D2D1_FACTORY_OPTIONS options;
options.debugLevel = D2D1_DEBUG_LEVEL_NONE;
ComSmartPtr<ID2D1Factory> result;
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
d2d1CreateFactory (D2D1_FACTORY_TYPE_SINGLE_THREADED,
__uuidof (ID2D1Factory),
&options,
(void**) result.resetAndGetPointerAddress());
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
return result;
}();
const ComSmartPtr<IDWriteFactory> directWriteFactory = [&]() -> ComSmartPtr<IDWriteFactory>
{
JUCE_LOAD_WINAPI_FUNCTION (directWriteDll,
DWriteCreateFactory,
dWriteCreateFactory,
HRESULT,
(DWRITE_FACTORY_TYPE, REFIID, IUnknown**))
if (dWriteCreateFactory == nullptr)
return {};
ComSmartPtr<IDWriteFactory> result;
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
dWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED,
__uuidof (IDWriteFactory),
(IUnknown**) result.resetAndGetPointerAddress());
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
return result;
}();
const ComSmartPtr<DirectWriteCustomFontCollectionLoader> collectionLoader = [&]() -> ComSmartPtr<DirectWriteCustomFontCollectionLoader>
{
auto result = becomeComSmartPtrOwner (new DirectWriteCustomFontCollectionLoader { *directWriteFactory });
directWriteFactory->RegisterFontCollectionLoader (result);
return result;
}();
const ComSmartPtr<IDWriteFactory4> directWriteFactory4 = directWriteFactory.getInterface<IDWriteFactory4>();
std::optional<AggregateFontCollection> fonts;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Direct2DFactories)
};
StringArray Font::findAllTypefaceNames()
{
SharedResourcePointer<Direct2DFactories> factories;

View file

@ -1423,4 +1423,518 @@ private:
ComSmartPtr<IDCompositionVisual> compositionVisual;
};
static String getLocalisedName (IDWriteLocalizedStrings* names)
{
jassert (names != nullptr);
uint32 index = 0;
BOOL exists = false;
[[maybe_unused]] auto hr = names->FindLocaleName (L"en-us", &index, &exists);
if (! exists)
index = 0;
uint32 length = 0;
hr = names->GetStringLength (index, &length);
HeapBlock<wchar_t> name (length + 1);
hr = names->GetString (index, name, length + 1);
return static_cast<const wchar_t*> (name);
}
static String getFontFamilyName (IDWriteFontFamily* family)
{
jassert (family != nullptr);
ComSmartPtr<IDWriteLocalizedStrings> familyNames;
auto hr = family->GetFamilyNames (familyNames.resetAndGetPointerAddress());
jassertquiet (SUCCEEDED (hr));
return getLocalisedName (familyNames);
}
static String getFontFaceName (IDWriteFont* font)
{
jassert (font != nullptr);
ComSmartPtr<IDWriteLocalizedStrings> faceNames;
auto hr = font->GetFaceNames (faceNames.resetAndGetPointerAddress());
jassertquiet (SUCCEEDED (hr));
return getLocalisedName (faceNames);
}
template <typename Range>
static StringArray stringArrayFromRange (Range&& range)
{
StringArray result;
for (const auto& item : range)
result.add (item);
return result;
}
class AggregateFontCollection
{
public:
explicit AggregateFontCollection (ComSmartPtr<IDWriteFontCollection> baseCollection)
: collections { std::move (baseCollection) } {}
StringArray findAllTypefaceNames()
{
const std::scoped_lock lock { mutex };
std::set<String> strings;
for (const auto& collection : collections)
{
const auto count = collection->GetFontFamilyCount();
for (auto i = decltype (count){}; i < count; ++i)
{
ComSmartPtr<IDWriteFontFamily> family;
if (FAILED (collection->GetFontFamily (i, family.resetAndGetPointerAddress())) || family == nullptr)
continue;
strings.insert (getFontFamilyName (family));
}
}
return stringArrayFromRange (strings);
}
static std::vector<ComSmartPtr<IDWriteFont>> getAllFontsInFamily (IDWriteFontFamily* fontFamily)
{
const auto fontFacesCount = fontFamily->GetFontCount();
std::vector<ComSmartPtr<IDWriteFont>> result;
result.reserve (fontFacesCount);
for (UINT32 i = 0; i < fontFacesCount; ++i)
{
ComSmartPtr<IDWriteFont> dwFont;
if (FAILED (fontFamily->GetFont (i, dwFont.resetAndGetPointerAddress())))
continue;
if (dwFont->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE)
continue;
result.push_back (dwFont);
}
return result;
}
StringArray findAllTypefaceStyles (const String& family)
{
const std::scoped_lock lock { mutex };
for (const auto& collection : collections)
{
BOOL fontFound = false;
uint32 fontIndex = 0;
if (FAILED (collection->FindFamilyName (family.toWideCharPointer(), &fontIndex, &fontFound)) || ! fontFound)
continue;
ComSmartPtr<IDWriteFontFamily> fontFamily;
if (FAILED (collection->GetFontFamily (fontIndex, fontFamily.resetAndGetPointerAddress())) || fontFamily == nullptr)
continue;
std::set<String> uniqueResults;
StringArray orderedResults;
for (const auto& font : getAllFontsInFamily (fontFamily))
{
const auto name = getFontFaceName (font);
if (uniqueResults.insert (name).second)
orderedResults.add (name);
}
return orderedResults;
}
return {};
}
ComSmartPtr<IDWriteFontFamily> getFamilyByName (const wchar_t* name)
{
const std::scoped_lock lock { mutex };
for (const auto& collection : collections)
{
const auto fontIndex = [&]
{
BOOL found = false;
UINT32 index = 0;
return (SUCCEEDED (collection->FindFamilyName (name, &index, &found)) && found)
? index
: (UINT32) -1;
}();
if (fontIndex == (UINT32) -1)
continue;
ComSmartPtr<IDWriteFontFamily> family;
if (FAILED (collection->GetFontFamily (fontIndex, family.resetAndGetPointerAddress())) || family == nullptr)
continue;
return family;
}
return {};
}
ComSmartPtr<IDWriteFont> findFontForFace (IDWriteFontFace* face)
{
for (const auto& collection : collections)
{
ComSmartPtr<IDWriteFont> result;
if (SUCCEEDED (collection->GetFontFromFontFace (face, result.resetAndGetPointerAddress())))
return result;
}
return {};
}
void addCollection (ComSmartPtr<IDWriteFontCollection> collection)
{
const std::scoped_lock lock { mutex };
collections.push_back (std::move (collection));
}
void removeCollection (ComSmartPtr<IDWriteFontCollection> collection)
{
const std::scoped_lock lock { mutex };
const auto iter = std::find (collections.begin(), collections.end(), collection);
if (iter != collections.end())
collections.erase (iter);
}
struct MapResult
{
ComSmartPtr<IDWriteFont> font;
UINT32 length{};
float scale{};
};
/* Tries matching against each collection in turn.
If any collection is able to match the entire string, then uses the appropriate font
from that collection.
Otherwise, returns the font that is able to match the longest sequence of characters,
preferring user-provided fonts.
*/
MapResult mapCharacters (IDWriteFontFallback* fallback,
IDWriteTextAnalysisSource* analysisSource,
UINT32 textPosition,
UINT32 textLength,
wchar_t const* baseFamilyName,
DWRITE_FONT_WEIGHT baseWeight,
DWRITE_FONT_STYLE baseStyle,
DWRITE_FONT_STRETCH baseStretch) noexcept
{
const std::scoped_lock lock { mutex };
// For reasons I don't understand, the system may pick better substitutions when passing
// nullptr, instead of the system collection, as the "default collection to use".
auto collectionsToCheck = collections;
collectionsToCheck.insert (collectionsToCheck.begin(), nullptr);
MapResult bestMatch;
for (const auto& collection : collectionsToCheck)
{
MapResult result;
const auto status = fallback->MapCharacters (analysisSource,
textPosition,
textLength,
collection,
baseFamilyName,
baseWeight,
baseStyle,
baseStretch,
&result.length,
result.font.resetAndGetPointerAddress(),
&result.scale);
if (FAILED (status) || result.font == nullptr)
continue;
if (result.length == textLength)
return result;
if (result.length >= bestMatch.length)
bestMatch = result;
}
return bestMatch;
}
private:
std::vector<ComSmartPtr<IDWriteFontCollection>> collections;
std::mutex mutex;
};
class MemoryFontFileStream final : public ComBaseClassHelper<IDWriteFontFileStream>
{
public:
explicit MemoryFontFileStream (std::shared_ptr<const MemoryBlock> blockIn)
: block (std::move (blockIn))
{
}
JUCE_COMRESULT GetFileSize (UINT64* fileSize) noexcept override
{
*fileSize = block->getSize();
return S_OK;
}
JUCE_COMRESULT GetLastWriteTime (UINT64* lastWriteTime) noexcept override
{
*lastWriteTime = 0;
return S_OK;
}
JUCE_COMRESULT ReadFileFragment (const void** fragmentStart,
UINT64 fileOffset,
UINT64 fragmentSize,
void** fragmentContext) noexcept override
{
if (fileOffset + fragmentSize > block->getSize())
{
*fragmentStart = nullptr;
*fragmentContext = nullptr;
return E_INVALIDARG;
}
*fragmentStart = addBytesToPointer (block->getData(), fileOffset);
*fragmentContext = this;
return S_OK;
}
void WINAPI ReleaseFileFragment (void*) noexcept override {}
private:
std::shared_ptr<const MemoryBlock> block;
};
class MemoryFontFileLoader final : public ComBaseClassHelper<IDWriteFontFileLoader>
{
public:
explicit MemoryFontFileLoader (MemoryBlock blob)
: block (std::make_shared<const MemoryBlock> (std::move (blob)))
{
}
HRESULT WINAPI CreateStreamFromKey (const void* fontFileReferenceKey,
UINT32 keySize,
IDWriteFontFileStream** fontFileStream) noexcept override
{
if (keySize != Uuid::size())
return E_INVALIDARG;
Uuid requestedKey { static_cast<const uint8*> (fontFileReferenceKey) };
if (requestedKey == uuid)
{
*fontFileStream = new MemoryFontFileStream { block };
return S_OK;
}
return E_INVALIDARG;
}
Uuid getUuid() const { return uuid; }
private:
std::shared_ptr<const MemoryBlock> block;
Uuid uuid;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryFontFileLoader)
};
class FontFileEnumerator final : public ComBaseClassHelper<IDWriteFontFileEnumerator>
{
public:
FontFileEnumerator (IDWriteFactory& factoryIn, ComSmartPtr<MemoryFontFileLoader> loaderIn)
: factory (factoryIn), loader (loaderIn) {}
HRESULT WINAPI GetCurrentFontFile (IDWriteFontFile** fontFile) noexcept override
{
*fontFile = nullptr;
if (! isPositiveAndBelow (rawDataIndex, 1))
return E_FAIL;
const auto uuid = loader->getUuid();
return factory.CreateCustomFontFileReference (uuid.getRawData(),
(UINT32) uuid.size(),
loader,
fontFile);
}
HRESULT WINAPI MoveNext (BOOL* hasCurrentFile) noexcept override
{
++rawDataIndex;
*hasCurrentFile = rawDataIndex < 1 ? TRUE : FALSE;
return S_OK;
}
private:
IDWriteFactory& factory;
ComSmartPtr<MemoryFontFileLoader> loader;
size_t rawDataIndex = std::numeric_limits<size_t>::max();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FontFileEnumerator)
};
class DirectWriteCustomFontCollectionLoader final : public ComBaseClassHelper<IDWriteFontCollectionLoader>
{
public:
explicit DirectWriteCustomFontCollectionLoader (IDWriteFactory& factoryIn)
: factory (factoryIn)
{
}
~DirectWriteCustomFontCollectionLoader() override
{
for (const auto& loader : fileLoaders)
factory.UnregisterFontFileLoader (loader);
}
Uuid addRawFontData (Span<const std::byte> blob)
{
const auto loader = becomeComSmartPtrOwner (new MemoryFontFileLoader { { blob.data(), blob.size() } });
factory.RegisterFontFileLoader (loader);
fileLoaders.push_back (loader);
return fileLoaders.back()->getUuid();
}
HRESULT WINAPI CreateEnumeratorFromKey (IDWriteFactory* factoryIn,
const void* collectionKey,
UINT32 collectionKeySize,
IDWriteFontFileEnumerator** fontFileEnumerator) noexcept override
{
if (collectionKeySize != Uuid::size())
return E_INVALIDARG;
const Uuid requestedCollectionKey { static_cast<const uint8*> (collectionKey) };
for (const auto& loader : fileLoaders)
{
if (loader->getUuid() != requestedCollectionKey)
continue;
*fontFileEnumerator = new FontFileEnumerator { *factoryIn, loader };
return S_OK;
}
return E_INVALIDARG;
}
private:
IDWriteFactory& factory;
std::vector<ComSmartPtr<MemoryFontFileLoader>> fileLoaders;
};
//==============================================================================
class Direct2DFactories
{
public:
Direct2DFactories()
{
ComSmartPtr<IDWriteFontCollection> collection;
if (SUCCEEDED (directWriteFactory->GetSystemFontCollection (collection.resetAndGetPointerAddress(), FALSE)) && collection != nullptr)
fonts.emplace (collection);
else
jassertfalse;
}
~Direct2DFactories()
{
if (directWriteFactory == nullptr)
return;
directWriteFactory->UnregisterFontCollectionLoader (collectionLoader);
}
[[nodiscard]] ComSmartPtr<IDWriteFactory> getDWriteFactory() const { return directWriteFactory; }
[[nodiscard]] ComSmartPtr<IDWriteFactory4> getDWriteFactory4() const { return directWriteFactory4; }
[[nodiscard]] AggregateFontCollection& getFonts() { jassert (fonts.has_value()); return *fonts; }
[[nodiscard]] ComSmartPtr<DirectWriteCustomFontCollectionLoader> getCollectionLoader() const { return collectionLoader; }
private:
DynamicLibrary direct2dDll { "d2d1.dll" }, directWriteDll { "DWrite.dll" };
const ComSmartPtr<ID2D1Factory> d2dFactory = [&]() -> ComSmartPtr<ID2D1Factory>
{
JUCE_LOAD_WINAPI_FUNCTION (direct2dDll,
D2D1CreateFactory,
d2d1CreateFactory,
HRESULT,
(D2D1_FACTORY_TYPE, REFIID, D2D1_FACTORY_OPTIONS*, void**))
if (d2d1CreateFactory == nullptr)
return {};
D2D1_FACTORY_OPTIONS options;
options.debugLevel = D2D1_DEBUG_LEVEL_NONE;
ComSmartPtr<ID2D1Factory> result;
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
d2d1CreateFactory (D2D1_FACTORY_TYPE_SINGLE_THREADED,
__uuidof (ID2D1Factory),
&options,
(void**) result.resetAndGetPointerAddress());
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
return result;
}();
const ComSmartPtr<IDWriteFactory> directWriteFactory = [&]() -> ComSmartPtr<IDWriteFactory>
{
JUCE_LOAD_WINAPI_FUNCTION (directWriteDll,
DWriteCreateFactory,
dWriteCreateFactory,
HRESULT,
(DWRITE_FACTORY_TYPE, REFIID, IUnknown**))
if (dWriteCreateFactory == nullptr)
return {};
ComSmartPtr<IDWriteFactory> result;
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
dWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED,
__uuidof (IDWriteFactory),
(IUnknown**) result.resetAndGetPointerAddress());
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
return result;
}();
const ComSmartPtr<DirectWriteCustomFontCollectionLoader> collectionLoader = [&]() -> ComSmartPtr<DirectWriteCustomFontCollectionLoader>
{
auto result = becomeComSmartPtrOwner (new DirectWriteCustomFontCollectionLoader { *directWriteFactory });
directWriteFactory->RegisterFontCollectionLoader (result);
return result;
}();
const ComSmartPtr<IDWriteFactory4> directWriteFactory4 = directWriteFactory.getInterface<IDWriteFactory4>();
std::optional<AggregateFontCollection> fonts;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Direct2DFactories)
};
} // namespace juce