blob: 1f0ff0721678eedb3904d1e327d29eb7313db10c [file] [log] [blame]
/*
* Copyright (C) 2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "DirectWriteUtilities.h"
#if USE(DIRECT2D)
#include "COMPtr.h"
#include "SharedBuffer.h"
#include <dwrite_3.h>
namespace WebCore {
namespace DirectWrite {
IDWriteFactory5* factory()
{
static IDWriteFactory5* directWriteFactory = nullptr;
if (!directWriteFactory) {
HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(directWriteFactory), reinterpret_cast<IUnknown**>(&directWriteFactory));
directWriteFactory->AddRef();
RELEASE_ASSERT(SUCCEEDED(hr));
}
return directWriteFactory;
}
IDWriteGdiInterop* gdiInterop()
{
static IDWriteGdiInterop* directWriteGdiInterop = nullptr;
if (!directWriteGdiInterop) {
HRESULT hr = factory()->GetGdiInterop(&directWriteGdiInterop);
directWriteGdiInterop->AddRef();
RELEASE_ASSERT(SUCCEEDED(hr));
}
return directWriteGdiInterop;
}
static IDWriteInMemoryFontFileLoader* memoryFontLoader()
{
static IDWriteInMemoryFontFileLoader* memoryFontLoader = nullptr;
if (!memoryFontLoader) {
HRESULT hr = factory()->CreateInMemoryFontFileLoader(&memoryFontLoader);
RELEASE_ASSERT(SUCCEEDED(hr));
memoryFontLoader->AddRef();
hr = factory()->RegisterFontFileLoader(memoryFontLoader);
RELEASE_ASSERT(SUCCEEDED(hr));
}
return memoryFontLoader;
}
static IDWriteFontSetBuilder1* fontSetBuilder()
{
static IDWriteFontSetBuilder1* fontSetBuilder = nullptr;
if (!fontSetBuilder) {
HRESULT hr = factory()->CreateFontSetBuilder(&fontSetBuilder);
RELEASE_ASSERT(SUCCEEDED(hr));
fontSetBuilder->AddRef();
}
return fontSetBuilder;
}
static COMPtr<IDWriteFontSet> fontSet;
static COMPtr<IDWriteFontCollection1> fontCollection;
static UINT32 fontCount = 0;
IDWriteFontCollection1* webProcessFontCollection()
{
HRESULT hr = S_OK;
if (!fontSet) {
hr = fontSetBuilder()->CreateFontSet(&fontSet);
if (!SUCCEEDED(hr))
return nullptr;
fontCollection = nullptr;
hr = factory()->CreateFontCollectionFromFontSet(fontSet.get(), &fontCollection);
if (!SUCCEEDED(hr))
return nullptr;
ASSERT(fontCollection->GetFontFamilyCount() == fontCount);
}
return fontCollection.get();
}
HRESULT addFontFromDataToProcessCollection(const Vector<char>& fontData)
{
COMPtr<IDWriteFontFile> fontFile;
HRESULT hr = memoryFontLoader()->CreateInMemoryFontFileReference(factory(), fontData.data(), fontData.size(), nullptr, &fontFile);
if (!SUCCEEDED(hr))
return hr;
hr = fontSetBuilder()->AddFontFile(fontFile.get());
if (!SUCCEEDED(hr))
return hr;
fontSet = nullptr;
++fontCount;
return hr;
}
Vector<wchar_t> familyNameForLocale(IDWriteFontFamily* fontFamily, const Vector<wchar_t>& localeName)
{
COMPtr<IDWriteLocalizedStrings> familyNames;
HRESULT hr = fontFamily->GetFamilyNames(&familyNames);
if (FAILED(hr))
return { };
BOOL exists = false;
unsigned localeIndex = 0;
if (!localeName.isEmpty())
hr = familyNames->FindLocaleName(localeName.data(), &localeIndex, &exists);
if (SUCCEEDED(hr) && !exists)
hr = familyNames->FindLocaleName(L"en-us", &localeIndex, &exists);
if (FAILED(hr))
return { };
unsigned familyNameLength = 0;
hr = familyNames->GetStringLength(localeIndex, &familyNameLength);
if (!SUCCEEDED(hr))
return { };
Vector<wchar_t> familyName(familyNameLength + 1);
hr = familyNames->GetString(localeIndex, familyName.data(), familyName.size());
if (!SUCCEEDED(hr))
return { };
return familyName;
}
COMPtr<IDWriteFontFamily> fontFamilyForCollection(IDWriteFontCollection* fontCollection, const Vector<wchar_t>& localeName, const LOGFONT& logFont)
{
COMPtr<IDWriteFontFamily> fontFamily;
unsigned fontFamilyCount = fontCollection->GetFontFamilyCount();
for (unsigned fontIndex = 0; fontIndex < fontFamilyCount; ++fontIndex) {
HRESULT hr = fontCollection->GetFontFamily(fontIndex, &fontFamily);
if (FAILED(hr))
return nullptr;
auto familyName = familyNameForLocale(fontFamily.get(), localeName);
if (!wcscmp(logFont.lfFaceName, familyName.data()))
return fontFamily;
fontFamily = nullptr;
}
return nullptr;
}
COMPtr<IDWriteFont> createWithPlatformFont(const LOGFONT& logFont)
{
COMPtr<IDWriteFontCollection> systemFontCollection;
HRESULT hr = factory()->GetSystemFontCollection(&systemFontCollection);
if (FAILED(hr))
return nullptr;
Vector<wchar_t> localeName(LOCALE_NAME_MAX_LENGTH);
int localeLength = GetUserDefaultLocaleName(localeName.data(), LOCALE_NAME_MAX_LENGTH);
COMPtr<IDWriteFontFamily> fontFamily = fontFamilyForCollection(systemFontCollection.get(), localeName, logFont);
if (!fontFamily)
fontFamily = fontFamilyForCollection(webProcessFontCollection(), localeName, logFont);
if (!fontFamily) {
// Just return the first system font.
hr = systemFontCollection->GetFontFamily(0, &fontFamily);
if (FAILED(hr))
return nullptr;
#ifndef NDEBUG
auto familyName = familyNameForLocale(fontFamily.get(), localeName);
UNUSED_VARIABLE(familyName);
#endif
}
DWRITE_FONT_WEIGHT weight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight);
DWRITE_FONT_STRETCH stretch = static_cast<DWRITE_FONT_STRETCH>(logFont.lfQuality);
DWRITE_FONT_STYLE style = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL;
COMPtr<IDWriteFont> dwFont;
hr = fontFamily->GetFirstMatchingFont(weight, stretch, style, &dwFont);
ASSERT(SUCCEEDED(hr));
return dwFont;
}
} // namespace DirectWrite
} // namespace WebCore
#endif // USE(DIRECT2D)