2010-02-26 09:36:07 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
2012-05-21 15:12:37 +04:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2011-10-11 09:50:08 +04:00
|
|
|
|
2013-12-09 06:52:54 +04:00
|
|
|
#include "mozilla/ArrayUtils.h"
|
2018-04-13 22:34:37 +03:00
|
|
|
#include "mozilla/FontPropertyTypes.h"
|
2013-06-23 16:03:39 +04:00
|
|
|
#include "mozilla/MemoryReporting.h"
|
2017-03-22 10:38:55 +03:00
|
|
|
#include "mozilla/intl/OSPreferences.h"
|
2011-10-11 09:50:08 +04:00
|
|
|
|
2010-02-26 09:36:07 +03:00
|
|
|
#include "gfxDWriteFontList.h"
|
|
|
|
#include "gfxDWriteFonts.h"
|
|
|
|
#include "nsUnicharUtils.h"
|
2011-01-21 19:44:32 +03:00
|
|
|
#include "nsServiceManagerUtils.h"
|
2011-06-03 08:31:07 +04:00
|
|
|
#include "nsCharSeparatedTokenizer.h"
|
2011-06-12 06:30:16 +04:00
|
|
|
#include "mozilla/Preferences.h"
|
2016-08-17 01:41:12 +03:00
|
|
|
#include "mozilla/Sprintf.h"
|
2011-07-27 10:42:53 +04:00
|
|
|
#include "mozilla/Telemetry.h"
|
2014-05-29 16:01:07 +04:00
|
|
|
#include "nsDirectoryServiceUtils.h"
|
|
|
|
#include "nsDirectoryServiceDefs.h"
|
|
|
|
#include "nsAppDirectoryServiceDefs.h"
|
|
|
|
#include "nsISimpleEnumerator.h"
|
2010-02-26 09:36:07 +03:00
|
|
|
|
|
|
|
#include "gfxGDIFontList.h"
|
|
|
|
|
2010-03-03 09:57:43 +03:00
|
|
|
#include "nsIWindowsRegKey.h"
|
|
|
|
|
2013-05-16 20:29:20 +04:00
|
|
|
#include "harfbuzz/hb.h"
|
|
|
|
|
2011-01-25 12:17:18 +03:00
|
|
|
using namespace mozilla;
|
2017-04-07 00:41:02 +03:00
|
|
|
using namespace mozilla::gfx;
|
2017-03-22 10:38:55 +03:00
|
|
|
using mozilla::intl::OSPreferences;
|
2011-01-25 12:17:18 +03:00
|
|
|
|
2015-05-21 23:22:04 +03:00
|
|
|
#define LOG_FONTLIST(args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
|
2015-06-04 01:25:57 +03:00
|
|
|
LogLevel::Debug, args)
|
2015-06-04 01:22:28 +03:00
|
|
|
#define LOG_FONTLIST_ENABLED() MOZ_LOG_TEST( \
|
2011-01-21 19:44:33 +03:00
|
|
|
gfxPlatform::GetLog(eGfxLog_fontlist), \
|
2015-06-04 01:25:57 +03:00
|
|
|
LogLevel::Debug)
|
2011-01-21 19:44:33 +03:00
|
|
|
|
2015-05-21 23:22:04 +03:00
|
|
|
#define LOG_FONTINIT(args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), \
|
2015-06-04 01:25:57 +03:00
|
|
|
LogLevel::Debug, args)
|
2015-06-04 01:22:28 +03:00
|
|
|
#define LOG_FONTINIT_ENABLED() MOZ_LOG_TEST( \
|
2011-01-21 19:44:33 +03:00
|
|
|
gfxPlatform::GetLog(eGfxLog_fontinit), \
|
2015-06-04 01:25:57 +03:00
|
|
|
LogLevel::Debug)
|
2011-01-21 19:44:33 +03:00
|
|
|
|
2015-06-04 01:22:28 +03:00
|
|
|
#define LOG_CMAPDATA_ENABLED() MOZ_LOG_TEST( \
|
2012-03-09 06:05:14 +04:00
|
|
|
gfxPlatform::GetLog(eGfxLog_cmapdata), \
|
2015-06-04 01:25:57 +03:00
|
|
|
LogLevel::Debug)
|
2012-03-09 06:05:14 +04:00
|
|
|
|
2010-02-26 09:36:07 +03:00
|
|
|
static __inline void
|
|
|
|
BuildKeyNameFromFontName(nsAString &aName)
|
|
|
|
{
|
|
|
|
if (aName.Length() >= LF_FACESIZE)
|
|
|
|
aName.Truncate(LF_FACESIZE - 1);
|
|
|
|
ToLowerCase(aName);
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// gfxDWriteFontFamily
|
|
|
|
|
|
|
|
gfxDWriteFontFamily::~gfxDWriteFontFamily()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-01-18 20:45:26 +03:00
|
|
|
static bool
|
|
|
|
GetEnglishOrFirstName(nsAString& aName, IDWriteLocalizedStrings* aStrings)
|
2013-12-11 04:58:19 +04:00
|
|
|
{
|
|
|
|
UINT32 englishIdx = 0;
|
2018-01-18 20:45:26 +03:00
|
|
|
BOOL exists;
|
|
|
|
HRESULT hr = aStrings->FindLocaleName(L"en-us", &englishIdx, &exists);
|
2013-12-11 04:58:19 +04:00
|
|
|
if (FAILED(hr)) {
|
2018-01-18 20:45:26 +03:00
|
|
|
return false;
|
2013-12-11 04:58:19 +04:00
|
|
|
}
|
|
|
|
if (!exists) {
|
2018-01-18 20:45:26 +03:00
|
|
|
// Use 0 index if english is not found.
|
2013-12-11 04:58:19 +04:00
|
|
|
englishIdx = 0;
|
|
|
|
}
|
2018-01-18 20:45:26 +03:00
|
|
|
AutoTArray<WCHAR, 32> enName;
|
2013-12-11 04:58:19 +04:00
|
|
|
UINT32 length;
|
2018-01-18 20:45:26 +03:00
|
|
|
hr = aStrings->GetStringLength(englishIdx, &length);
|
2013-12-11 04:58:19 +04:00
|
|
|
if (FAILED(hr)) {
|
2018-01-18 20:45:26 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!enName.SetLength(length + 1, fallible)) {
|
|
|
|
// Eeep - running out of memory. Unlikely to end well.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
hr = aStrings->GetString(englishIdx, enName.Elements(), length + 1);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return false;
|
2013-12-11 04:58:19 +04:00
|
|
|
}
|
2018-01-18 20:45:26 +03:00
|
|
|
aName.Assign(enName.Elements());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT
|
|
|
|
GetDirectWriteFontName(IDWriteFont *aFont, nsAString& aFontName)
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
RefPtr<IDWriteLocalizedStrings> names;
|
|
|
|
hr = aFont->GetFaceNames(getter_AddRefs(names));
|
2013-12-11 04:58:19 +04:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
2018-01-18 20:45:26 +03:00
|
|
|
if (!GetEnglishOrFirstName(aFontName, names)) {
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
2013-12-11 04:58:19 +04:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define FULLNAME_ID DWRITE_INFORMATIONAL_STRING_FULL_NAME
|
|
|
|
#define PSNAME_ID DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME
|
|
|
|
|
|
|
|
// for use in reading postscript or fullname
|
|
|
|
static HRESULT
|
|
|
|
GetDirectWriteFaceName(IDWriteFont *aFont,
|
|
|
|
DWRITE_INFORMATIONAL_STRING_ID aWhichName,
|
|
|
|
nsAString& aFontName)
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
BOOL exists;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteLocalizedStrings> infostrings;
|
2013-12-11 04:58:19 +04:00
|
|
|
hr = aFont->GetInformationalStrings(aWhichName, getter_AddRefs(infostrings), &exists);
|
|
|
|
if (FAILED(hr) || !exists) {
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
2018-01-18 20:45:26 +03:00
|
|
|
if (!GetEnglishOrFirstName(aFontName, infostrings)) {
|
|
|
|
return E_FAIL;
|
2013-12-11 04:58:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2010-02-26 09:36:07 +03:00
|
|
|
void
|
2014-01-29 11:39:01 +04:00
|
|
|
gfxDWriteFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
|
2010-02-26 09:36:07 +03:00
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
if (mHasStyles) {
|
|
|
|
return;
|
|
|
|
}
|
2011-10-17 18:59:28 +04:00
|
|
|
mHasStyles = true;
|
2010-02-26 09:36:07 +03:00
|
|
|
|
2013-12-11 04:58:19 +04:00
|
|
|
gfxPlatformFontList *fp = gfxPlatformFontList::PlatformFontList();
|
|
|
|
|
|
|
|
bool skipFaceNames = mFaceNamesInitialized ||
|
|
|
|
!fp->NeedFullnamePostscriptNames();
|
2014-01-29 11:39:01 +04:00
|
|
|
bool fontInfoShouldHaveFaceNames = !mFaceNamesInitialized &&
|
|
|
|
fp->NeedFullnamePostscriptNames() &&
|
|
|
|
aFontInfoData;
|
2013-12-11 04:58:19 +04:00
|
|
|
|
2010-02-26 09:36:07 +03:00
|
|
|
for (UINT32 i = 0; i < mDWFamily->GetFontCount(); i++) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteFont> font;
|
2010-02-26 09:36:07 +03:00
|
|
|
hr = mDWFamily->GetFont(i, getter_AddRefs(font));
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
// This should never happen.
|
|
|
|
NS_WARNING("Failed to get existing font from family.");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-06-19 11:08:58 +04:00
|
|
|
if (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) {
|
|
|
|
// We don't want these in the font list; we'll apply simulations
|
|
|
|
// on the fly when appropriate.
|
2010-02-26 09:36:07 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-12-11 04:58:19 +04:00
|
|
|
// name
|
|
|
|
nsString fullID(mName);
|
|
|
|
nsAutoString faceName;
|
|
|
|
hr = GetDirectWriteFontName(font, faceName);
|
2010-02-26 09:36:07 +03:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
continue;
|
|
|
|
}
|
2014-05-22 07:48:50 +04:00
|
|
|
fullID.Append(' ');
|
2013-12-11 04:58:19 +04:00
|
|
|
fullID.Append(faceName);
|
|
|
|
|
2017-03-29 12:38:41 +03:00
|
|
|
// Ignore italic style's "Meiryo" because "Meiryo (Bold) Italic" has
|
|
|
|
// non-italic style glyphs as Japanese characters. However, using it
|
|
|
|
// causes serious problem if web pages wants some elements to be
|
|
|
|
// different style from others only with font-style. For example,
|
|
|
|
// <em> and <i> should be rendered as italic in the default style.
|
|
|
|
if (fullID.EqualsLiteral("Meiryo Italic") ||
|
|
|
|
fullID.EqualsLiteral("Meiryo Bold Italic")) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-11-07 04:20:43 +03:00
|
|
|
gfxDWriteFontEntry *fe = new gfxDWriteFontEntry(fullID, font, mIsSystemFontFamily);
|
2011-06-03 08:31:07 +04:00
|
|
|
fe->SetForceGDIClassic(mForceGDIClassic);
|
2018-04-25 09:18:23 +03:00
|
|
|
|
|
|
|
fe->SetupVariationRanges();
|
|
|
|
|
2011-01-27 06:05:55 +03:00
|
|
|
AddFontEntry(fe);
|
2010-02-26 09:36:07 +03:00
|
|
|
|
2013-12-11 04:58:19 +04:00
|
|
|
// postscript/fullname if needed
|
|
|
|
nsAutoString psname, fullname;
|
2014-01-29 11:39:01 +04:00
|
|
|
if (fontInfoShouldHaveFaceNames) {
|
|
|
|
aFontInfoData->GetFaceNames(fe->Name(), fullname, psname);
|
|
|
|
if (!fullname.IsEmpty()) {
|
|
|
|
fp->AddFullname(fe, fullname);
|
|
|
|
}
|
|
|
|
if (!psname.IsEmpty()) {
|
|
|
|
fp->AddPostscriptName(fe, psname);
|
|
|
|
}
|
|
|
|
} else if (!skipFaceNames) {
|
2013-12-11 04:58:19 +04:00
|
|
|
hr = GetDirectWriteFaceName(font, PSNAME_ID, psname);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
skipFaceNames = true;
|
|
|
|
} else if (psname.Length() > 0) {
|
|
|
|
fp->AddPostscriptName(fe, psname);
|
|
|
|
}
|
|
|
|
|
|
|
|
hr = GetDirectWriteFaceName(font, FULLNAME_ID, fullname);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
skipFaceNames = true;
|
|
|
|
} else if (fullname.Length() > 0) {
|
|
|
|
fp->AddFullname(fe, fullname);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-27 06:05:55 +03:00
|
|
|
if (LOG_FONTLIST_ENABLED()) {
|
2018-04-25 09:18:23 +03:00
|
|
|
nsAutoCString weightString;
|
|
|
|
fe->Weight().ToString(weightString);
|
2011-01-27 06:05:55 +03:00
|
|
|
LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
|
2018-04-25 09:18:23 +03:00
|
|
|
" with style: %s weight: %s stretch: %d psname: %s fullname: %s",
|
2011-01-27 06:05:55 +03:00
|
|
|
NS_ConvertUTF16toUTF8(fe->Name()).get(),
|
|
|
|
NS_ConvertUTF16toUTF8(Name()).get(),
|
2015-10-19 05:16:43 +03:00
|
|
|
(fe->IsItalic()) ?
|
|
|
|
"italic" : (fe->IsOblique() ? "oblique" : "normal"),
|
2018-04-25 09:18:23 +03:00
|
|
|
weightString.get(),
|
|
|
|
fe->Stretch(),
|
2013-12-11 04:58:19 +04:00
|
|
|
NS_ConvertUTF16toUTF8(psname).get(),
|
|
|
|
NS_ConvertUTF16toUTF8(fullname).get()));
|
2011-01-27 06:05:55 +03:00
|
|
|
}
|
2010-02-26 09:36:07 +03:00
|
|
|
}
|
2011-01-27 06:05:55 +03:00
|
|
|
|
2013-12-11 04:58:19 +04:00
|
|
|
// assume that if no error, all postscript/fullnames were initialized
|
|
|
|
if (!skipFaceNames) {
|
|
|
|
mFaceNamesInitialized = true;
|
|
|
|
}
|
|
|
|
|
2010-02-26 09:36:07 +03:00
|
|
|
if (!mAvailableFonts.Length()) {
|
|
|
|
NS_WARNING("Family with no font faces in it.");
|
|
|
|
}
|
|
|
|
|
2010-06-25 00:38:57 +04:00
|
|
|
if (mIsBadUnderlineFamily) {
|
|
|
|
SetBadUnderlineFonts();
|
|
|
|
}
|
2010-02-26 09:36:07 +03:00
|
|
|
}
|
|
|
|
|
2013-12-11 04:58:19 +04:00
|
|
|
void
|
|
|
|
gfxDWriteFontFamily::ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
|
2016-08-22 23:38:50 +03:00
|
|
|
bool aNeedFullnamePostscriptNames,
|
|
|
|
FontInfoData *aFontInfoData)
|
2013-12-11 04:58:19 +04:00
|
|
|
{
|
|
|
|
// if all needed names have already been read, skip
|
|
|
|
if (mOtherFamilyNamesInitialized &&
|
|
|
|
(mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-08-22 23:38:50 +03:00
|
|
|
// If we've been passed a FontInfoData, we skip the DWrite implementation
|
|
|
|
// here and fall back to the generic code which will use that info.
|
|
|
|
if (!aFontInfoData) {
|
|
|
|
// DirectWrite version of this will try to read
|
|
|
|
// postscript/fullnames via DirectWrite API
|
|
|
|
FindStyleVariations();
|
|
|
|
}
|
2013-12-11 04:58:19 +04:00
|
|
|
|
|
|
|
// fallback to looking up via name table
|
|
|
|
if (!mOtherFamilyNamesInitialized || !mFaceNamesInitialized) {
|
|
|
|
gfxFontFamily::ReadFaceNames(aPlatformFontList,
|
2016-08-22 23:38:50 +03:00
|
|
|
aNeedFullnamePostscriptNames,
|
|
|
|
aFontInfoData);
|
2013-12-11 04:58:19 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-26 09:36:07 +03:00
|
|
|
void
|
|
|
|
gfxDWriteFontFamily::LocalizedName(nsAString &aLocalizedName)
|
|
|
|
{
|
2017-08-01 13:25:35 +03:00
|
|
|
aLocalizedName = Name(); // just return canonical name in case of failure
|
|
|
|
|
|
|
|
if (!mDWFamily) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-02-26 09:36:07 +03:00
|
|
|
HRESULT hr;
|
2017-03-13 06:39:22 +03:00
|
|
|
nsAutoCString locale;
|
2017-03-22 10:38:55 +03:00
|
|
|
// We use system locale here because it's what user expects to see.
|
|
|
|
// See bug 1349454 for details.
|
|
|
|
OSPreferences::GetInstance()->GetSystemLocale(locale);
|
2010-02-26 09:36:07 +03:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteLocalizedStrings> names;
|
2010-02-26 09:36:07 +03:00
|
|
|
|
|
|
|
hr = mDWFamily->GetFamilyNames(getter_AddRefs(names));
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
UINT32 idx = 0;
|
|
|
|
BOOL exists;
|
2017-03-13 06:39:22 +03:00
|
|
|
hr = names->FindLocaleName(NS_ConvertUTF8toUTF16(locale).get(),
|
2010-02-26 09:36:07 +03:00
|
|
|
&idx,
|
|
|
|
&exists);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!exists) {
|
|
|
|
// Use english is localized is not found.
|
|
|
|
hr = names->FindLocaleName(L"en-us", &idx, &exists);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!exists) {
|
|
|
|
// Use 0 index if english is not found.
|
|
|
|
idx = 0;
|
|
|
|
}
|
|
|
|
}
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<WCHAR, 32> famName;
|
2010-02-26 09:36:07 +03:00
|
|
|
UINT32 length;
|
|
|
|
|
|
|
|
hr = names->GetStringLength(idx, &length);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-06-11 00:30:41 +03:00
|
|
|
if (!famName.SetLength(length + 1, fallible)) {
|
2010-02-26 09:36:07 +03:00
|
|
|
// Eeep - running out of memory. Unlikely to end well.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
hr = names->GetString(idx, famName.Elements(), length + 1);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
aLocalizedName = nsDependentString(famName.Elements());
|
|
|
|
}
|
|
|
|
|
2017-09-11 21:22:57 +03:00
|
|
|
bool
|
|
|
|
gfxDWriteFontFamily::IsSymbolFontFamily() const
|
|
|
|
{
|
|
|
|
// Just check the first font in the family
|
|
|
|
if (mDWFamily->GetFontCount() > 0) {
|
|
|
|
RefPtr<IDWriteFont> font;
|
|
|
|
if (SUCCEEDED(mDWFamily->GetFont(0, getter_AddRefs(font)))) {
|
|
|
|
return font->IsSymbolFont();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-03-28 01:38:39 +04:00
|
|
|
void
|
2013-10-15 06:19:47 +04:00
|
|
|
gfxDWriteFontFamily::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
|
|
|
|
FontListSizes* aSizes) const
|
2012-03-28 01:38:39 +04:00
|
|
|
{
|
2013-10-15 06:19:47 +04:00
|
|
|
gfxFontFamily::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
2012-03-28 01:38:39 +04:00
|
|
|
// TODO:
|
|
|
|
// This doesn't currently account for |mDWFamily|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-10-15 06:19:47 +04:00
|
|
|
gfxDWriteFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
|
|
|
|
FontListSizes* aSizes) const
|
2012-03-28 01:38:39 +04:00
|
|
|
{
|
|
|
|
aSizes->mFontListSize += aMallocSizeOf(this);
|
2013-10-15 06:19:47 +04:00
|
|
|
AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
2012-03-28 01:38:39 +04:00
|
|
|
}
|
|
|
|
|
2010-02-26 09:36:07 +03:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// gfxDWriteFontEntry
|
|
|
|
|
2017-08-01 13:25:35 +03:00
|
|
|
gfxFontEntry*
|
|
|
|
gfxDWriteFontEntry::Clone() const
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!");
|
2018-04-25 09:18:23 +03:00
|
|
|
gfxDWriteFontEntry* fe = new gfxDWriteFontEntry(Name(), mFont);
|
|
|
|
fe->mWeightRange = mWeightRange;
|
|
|
|
fe->mStretchRange = mStretchRange;
|
|
|
|
fe->mStyleRange = mStyleRange;
|
|
|
|
return fe;
|
2017-08-01 13:25:35 +03:00
|
|
|
}
|
|
|
|
|
2010-02-26 09:36:07 +03:00
|
|
|
gfxDWriteFontEntry::~gfxDWriteFontEntry()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-02-03 15:12:10 +03:00
|
|
|
static bool
|
2013-05-01 23:40:19 +04:00
|
|
|
UsingArabicOrHebrewScriptSystemLocale()
|
2011-02-03 15:12:10 +03:00
|
|
|
{
|
|
|
|
LANGID langid = PRIMARYLANGID(::GetSystemDefaultLangID());
|
|
|
|
switch (langid) {
|
|
|
|
case LANG_ARABIC:
|
|
|
|
case LANG_DARI:
|
|
|
|
case LANG_PASHTO:
|
|
|
|
case LANG_PERSIAN:
|
|
|
|
case LANG_SINDHI:
|
|
|
|
case LANG_UIGHUR:
|
|
|
|
case LANG_URDU:
|
2013-05-01 23:40:19 +04:00
|
|
|
case LANG_HEBREW:
|
2011-02-03 15:12:10 +03:00
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-26 09:36:07 +03:00
|
|
|
nsresult
|
2013-05-16 20:29:20 +04:00
|
|
|
gfxDWriteFontEntry::CopyFontTable(uint32_t aTableTag,
|
2016-02-02 18:36:30 +03:00
|
|
|
nsTArray<uint8_t> &aBuffer)
|
2010-02-26 09:36:07 +03:00
|
|
|
{
|
2011-01-21 19:44:32 +03:00
|
|
|
gfxDWriteFontList *pFontList = gfxDWriteFontList::PlatformFontList();
|
2016-05-11 01:16:05 +03:00
|
|
|
const uint32_t tagBE = NativeEndian::swapToBigEndian(aTableTag);
|
2011-01-21 19:44:32 +03:00
|
|
|
|
2013-05-01 23:40:19 +04:00
|
|
|
// Don't use GDI table loading for symbol fonts or for
|
2011-02-03 15:12:10 +03:00
|
|
|
// italic fonts in Arabic-script system locales because of
|
2013-05-01 23:40:19 +04:00
|
|
|
// potential cmap discrepancies, see bug 629386.
|
|
|
|
// Ditto for Hebrew, bug 837498.
|
2011-02-03 15:12:10 +03:00
|
|
|
if (mFont && pFontList->UseGDIFontTableAccess() &&
|
2018-04-23 20:42:49 +03:00
|
|
|
!(!IsUpright() && UsingArabicOrHebrewScriptSystemLocale()) &&
|
2011-02-03 15:12:10 +03:00
|
|
|
!mFont->IsSymbolFont())
|
|
|
|
{
|
2011-01-21 19:44:32 +03:00
|
|
|
LOGFONTW logfont = { 0 };
|
2016-05-11 01:16:05 +03:00
|
|
|
if (InitLogFont(mFont, &logfont)) {
|
|
|
|
AutoDC dc;
|
|
|
|
AutoSelectFont font(dc.GetDC(), &logfont);
|
|
|
|
if (font.IsValid()) {
|
|
|
|
uint32_t tableSize =
|
|
|
|
::GetFontData(dc.GetDC(), tagBE, 0, nullptr, 0);
|
|
|
|
if (tableSize != GDI_ERROR) {
|
|
|
|
if (aBuffer.SetLength(tableSize, fallible)) {
|
|
|
|
::GetFontData(dc.GetDC(), tagBE, 0,
|
|
|
|
aBuffer.Elements(), aBuffer.Length());
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
2011-01-21 19:44:32 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteFontFace> fontFace;
|
2013-05-16 20:29:20 +04:00
|
|
|
nsresult rv = CreateFontFace(getter_AddRefs(fontFace));
|
2010-02-26 09:36:07 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint8_t *tableData;
|
|
|
|
uint32_t len;
|
2013-07-31 19:44:31 +04:00
|
|
|
void *tableContext = nullptr;
|
2010-02-26 09:36:07 +03:00
|
|
|
BOOL exists;
|
2013-05-16 20:29:20 +04:00
|
|
|
HRESULT hr =
|
2016-05-11 01:16:05 +03:00
|
|
|
fontFace->TryGetFontTable(tagBE, (const void**)&tableData, &len,
|
2013-05-16 20:29:20 +04:00
|
|
|
&tableContext, &exists);
|
2010-02-26 09:36:07 +03:00
|
|
|
if (FAILED(hr) || !exists) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2013-05-16 20:29:20 +04:00
|
|
|
|
2015-06-11 00:30:41 +03:00
|
|
|
if (aBuffer.SetLength(len, fallible)) {
|
2013-05-16 20:29:20 +04:00
|
|
|
memcpy(aBuffer.Elements(), tableData, len);
|
|
|
|
rv = NS_OK;
|
|
|
|
} else {
|
|
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
2010-02-26 09:36:07 +03:00
|
|
|
}
|
2013-05-16 20:29:20 +04:00
|
|
|
|
2010-02-26 09:36:07 +03:00
|
|
|
if (tableContext) {
|
|
|
|
fontFace->ReleaseFontTable(&tableContext);
|
|
|
|
}
|
2013-05-16 20:29:20 +04:00
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Access to font tables packaged in hb_blob_t form
|
|
|
|
|
|
|
|
// object attached to the Harfbuzz blob, used to release
|
|
|
|
// the table when the blob is destroyed
|
|
|
|
class FontTableRec {
|
|
|
|
public:
|
|
|
|
FontTableRec(IDWriteFontFace *aFontFace, void *aContext)
|
|
|
|
: mFontFace(aFontFace), mContext(aContext)
|
2015-03-09 15:16:22 +03:00
|
|
|
{
|
|
|
|
MOZ_COUNT_CTOR(FontTableRec);
|
|
|
|
}
|
2013-05-16 20:29:20 +04:00
|
|
|
|
|
|
|
~FontTableRec() {
|
2015-03-09 15:16:22 +03:00
|
|
|
MOZ_COUNT_DTOR(FontTableRec);
|
2013-05-16 20:29:20 +04:00
|
|
|
mFontFace->ReleaseFontTable(mContext);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteFontFace> mFontFace;
|
2013-05-16 20:29:20 +04:00
|
|
|
void *mContext;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
DestroyBlobFunc(void* aUserData)
|
|
|
|
{
|
|
|
|
FontTableRec *ftr = static_cast<FontTableRec*>(aUserData);
|
|
|
|
delete ftr;
|
|
|
|
}
|
|
|
|
|
|
|
|
hb_blob_t *
|
|
|
|
gfxDWriteFontEntry::GetFontTable(uint32_t aTag)
|
|
|
|
{
|
|
|
|
// try to avoid potentially expensive DWrite call if we haven't actually
|
|
|
|
// created the font face yet, by using the gfxFontEntry method that will
|
|
|
|
// use CopyFontTable and then cache the data
|
|
|
|
if (!mFontFace) {
|
|
|
|
return gfxFontEntry::GetFontTable(aTag);
|
|
|
|
}
|
|
|
|
|
|
|
|
const void *data;
|
|
|
|
UINT32 size;
|
|
|
|
void *context;
|
|
|
|
BOOL exists;
|
|
|
|
HRESULT hr = mFontFace->TryGetFontTable(NativeEndian::swapToBigEndian(aTag),
|
|
|
|
&data, &size, &context, &exists);
|
|
|
|
if (SUCCEEDED(hr) && exists) {
|
|
|
|
FontTableRec *ftr = new FontTableRec(mFontFace, context);
|
|
|
|
return hb_blob_create(static_cast<const char*>(data), size,
|
|
|
|
HB_MEMORY_MODE_READONLY,
|
|
|
|
ftr, DestroyBlobFunc);
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
2010-02-26 09:36:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2014-01-29 11:39:01 +04:00
|
|
|
gfxDWriteFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
|
2010-02-26 09:36:07 +03:00
|
|
|
{
|
Bug 1375392 - Tweak the PROFILER_LABEL* macros. r=mstange.
This patch makes the following changes to the macros.
- Removes PROFILER_LABEL_FUNC. It's only suitable for use in functions outside
classes, due to PROFILER_FUNCTION_NAME not getting class names, and it was
mostly misused.
- Removes PROFILER_FUNCTION_NAME. It's no longer used, and __func__ is
universally available now anyway.
- Combines the first two string literal arguments of PROFILER_LABEL and
PROFILER_LABEL_DYNAMIC into a single argument. There was no good reason for
them to be separate, and it forced a '::' in the label, which isn't always
appropriate. Also, the meaning of the "name_space" argument was interpreted
in an interesting variety of ways.
- Adds an "AUTO_" prefix to PROFILER_LABEL and PROFILER_LABEL_DYNAMIC, to make
it clearer they construct RAII objects rather than just being function calls.
(I myself have screwed up the scoping because of this in the past.)
- Fills in the 'js::ProfileEntry::Category::' qualifier within the macro, so
the caller doesn't need to. This makes a *lot* more of the uses fit onto a
single line.
The patch also makes the following changes to the macro uses (beyond those
required by the changes described above).
- Fixes a bunch of labels that had gotten out of sync with the name of the
class and/or function that encloses them.
- Removes a useless PROFILER_LABEL use within a trivial scope in
EventStateManager::DispatchMouseOrPointerEvent(). It clearly wasn't serving
any useful purpose. It also serves as extra evidence that the AUTO_ prefix is
a good idea.
- Tweaks DecodePool::SyncRunIf{Preferred,Possible} so that the labelling is
done within them, instead of at their callsites, because that's a more
standard way of doing things.
--HG--
extra : rebase_source : 318d1bc6fc1425a94aacbf489dd46e4f83211de4
2017-06-22 10:08:53 +03:00
|
|
|
AUTO_PROFILER_LABEL("gfxDWriteFontEntry::ReadCMAP", GRAPHICS);
|
2016-01-15 13:38:03 +03:00
|
|
|
|
2011-01-21 19:44:32 +03:00
|
|
|
// attempt this once, if errors occur leave a blank cmap
|
2012-04-19 03:59:43 +04:00
|
|
|
if (mCharacterMap) {
|
2011-01-21 19:44:32 +03:00
|
|
|
return NS_OK;
|
2012-04-19 03:59:43 +04:00
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<gfxCharacterMap> charmap;
|
2014-01-29 11:39:01 +04:00
|
|
|
nsresult rv;
|
2011-01-21 19:44:32 +03:00
|
|
|
|
2014-01-29 11:39:01 +04:00
|
|
|
if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData,
|
2017-09-11 21:23:30 +03:00
|
|
|
mUVSOffset))) {
|
2014-01-29 11:39:01 +04:00
|
|
|
rv = NS_OK;
|
2013-05-21 08:25:47 +04:00
|
|
|
} else {
|
2014-01-29 11:39:01 +04:00
|
|
|
uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
|
|
|
|
charmap = new gfxCharacterMap();
|
|
|
|
AutoTable cmapTable(this, kCMAP);
|
|
|
|
|
|
|
|
if (cmapTable) {
|
|
|
|
uint32_t cmapLen;
|
|
|
|
const uint8_t* cmapData =
|
|
|
|
reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable,
|
|
|
|
&cmapLen));
|
|
|
|
rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen,
|
2017-09-11 21:23:30 +03:00
|
|
|
*charmap, mUVSOffset);
|
2014-01-29 11:39:01 +04:00
|
|
|
} else {
|
|
|
|
rv = NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
2012-04-09 17:03:28 +04:00
|
|
|
}
|
|
|
|
|
2012-04-19 03:59:43 +04:00
|
|
|
mHasCmapTable = NS_SUCCEEDED(rv);
|
|
|
|
if (mHasCmapTable) {
|
2014-02-17 15:23:57 +04:00
|
|
|
// Bug 969504: exclude U+25B6 from Segoe UI family, because it's used
|
|
|
|
// by sites to represent a "Play" icon, but the glyph in Segoe UI Light
|
|
|
|
// and Semibold on Windows 7 is too thin. (Ditto for leftward U+25C0.)
|
|
|
|
// Fallback to Segoe UI Symbol is preferred.
|
|
|
|
if (FamilyName().EqualsLiteral("Segoe UI")) {
|
|
|
|
charmap->clear(0x25b6);
|
|
|
|
charmap->clear(0x25c0);
|
|
|
|
}
|
2012-04-19 03:59:43 +04:00
|
|
|
gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList();
|
|
|
|
mCharacterMap = pfl->FindCharMap(charmap);
|
|
|
|
} else {
|
|
|
|
// if error occurred, initialize to null cmap
|
|
|
|
mCharacterMap = new gfxCharacterMap();
|
2010-02-26 09:36:07 +03:00
|
|
|
}
|
|
|
|
|
2012-04-19 03:59:43 +04:00
|
|
|
LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d hash: %8.8x%s\n",
|
2012-03-28 01:38:39 +04:00
|
|
|
NS_ConvertUTF16toUTF8(mName).get(),
|
2012-04-19 03:59:43 +04:00
|
|
|
charmap->SizeOfIncludingThis(moz_malloc_size_of),
|
|
|
|
charmap->mHash, mCharacterMap == charmap ? " new" : ""));
|
2012-03-09 06:05:14 +04:00
|
|
|
if (LOG_CMAPDATA_ENABLED()) {
|
|
|
|
char prefix[256];
|
2016-08-17 01:41:12 +03:00
|
|
|
SprintfLiteral(prefix, "(cmapdata) name: %.220s",
|
|
|
|
NS_ConvertUTF16toUTF8(mName).get());
|
2012-04-19 03:59:43 +04:00
|
|
|
charmap->Dump(prefix, eGfxLog_cmapdata);
|
2012-03-09 06:05:14 +04:00
|
|
|
}
|
2011-01-21 19:44:33 +03:00
|
|
|
|
2010-02-26 09:36:07 +03:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2018-01-18 20:45:24 +03:00
|
|
|
bool
|
|
|
|
gfxDWriteFontEntry::HasVariations()
|
|
|
|
{
|
|
|
|
if (mHasVariationsInitialized) {
|
|
|
|
return mHasVariations;
|
|
|
|
}
|
|
|
|
mHasVariationsInitialized = true;
|
|
|
|
if (!mFontFace) {
|
|
|
|
// CreateFontFace will initialize the mFontFace field, and also
|
|
|
|
// mFontFace5 if available on the current DWrite version.
|
|
|
|
RefPtr<IDWriteFontFace> fontFace;
|
|
|
|
if (NS_FAILED(CreateFontFace(getter_AddRefs(fontFace)))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mFontFace5) {
|
|
|
|
mHasVariations = mFontFace5->HasVariations();
|
|
|
|
}
|
|
|
|
return mHasVariations;
|
|
|
|
}
|
|
|
|
|
2018-01-18 20:45:27 +03:00
|
|
|
void
|
|
|
|
gfxDWriteFontEntry::GetVariationAxes(nsTArray<gfxFontVariationAxis>& aAxes)
|
|
|
|
{
|
|
|
|
if (!HasVariations()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// HasVariations() will have ensured the mFontFace5 interface is available;
|
|
|
|
// so we can get an IDWriteFontResource and ask it for the axis info.
|
|
|
|
RefPtr<IDWriteFontResource> resource;
|
|
|
|
HRESULT hr = mFontFace5->GetFontResource(getter_AddRefs(resource));
|
|
|
|
MOZ_ASSERT(SUCCEEDED(hr));
|
|
|
|
|
|
|
|
uint32_t count = resource->GetFontAxisCount();
|
|
|
|
AutoTArray<DWRITE_FONT_AXIS_VALUE, 4> defaultValues;
|
|
|
|
AutoTArray<DWRITE_FONT_AXIS_RANGE, 4> ranges;
|
|
|
|
defaultValues.SetLength(count);
|
|
|
|
ranges.SetLength(count);
|
|
|
|
resource->GetDefaultFontAxisValues(defaultValues.Elements(), count);
|
|
|
|
resource->GetFontAxisRanges(ranges.Elements(), count);
|
|
|
|
for (uint32_t i = 0; i < count; ++i) {
|
|
|
|
gfxFontVariationAxis axis;
|
|
|
|
MOZ_ASSERT(ranges[i].axisTag == defaultValues[i].axisTag);
|
|
|
|
DWRITE_FONT_AXIS_ATTRIBUTES attrs = resource->GetFontAxisAttributes(i);
|
|
|
|
if (attrs & DWRITE_FONT_AXIS_ATTRIBUTES_HIDDEN) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!(attrs & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// Extract the 4 chars of the tag from DWrite's packed version,
|
|
|
|
// and reassemble them in the order we use for TRUETYPE_TAG.
|
|
|
|
uint32_t t = defaultValues[i].axisTag;
|
|
|
|
axis.mTag = TRUETYPE_TAG(t & 0xff,
|
|
|
|
(t >> 8) & 0xff,
|
|
|
|
(t >> 16) & 0xff,
|
|
|
|
(t >> 24) & 0xff);
|
|
|
|
// Try to get a human-friendly name (may not be present)
|
|
|
|
RefPtr<IDWriteLocalizedStrings> names;
|
|
|
|
resource->GetAxisNames(i, getter_AddRefs(names));
|
|
|
|
if (names) {
|
|
|
|
GetEnglishOrFirstName(axis.mName, names);
|
|
|
|
}
|
|
|
|
axis.mMinValue = ranges[i].minValue;
|
|
|
|
axis.mMaxValue = ranges[i].maxValue;
|
|
|
|
axis.mDefaultValue = defaultValues[i].value;
|
|
|
|
aAxes.AppendElement(axis);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-29 16:24:11 +03:00
|
|
|
void
|
|
|
|
gfxDWriteFontEntry::GetVariationInstances(
|
|
|
|
nsTArray<gfxFontVariationInstance>& aInstances)
|
|
|
|
{
|
|
|
|
gfxFontUtils::GetVariationInstances(this, aInstances);
|
|
|
|
}
|
|
|
|
|
2010-02-26 09:36:07 +03:00
|
|
|
gfxFont *
|
Bug 1449605 - part 1 - Rearrange thebes font code so that the decision whether to apply synthetic-bold is deferred until actually instantiating a font, not made during the font-matching process. r=jwatt
This rearranges how synthetic-bold use is determined in the font selection
& rendering code. Previously, we would decide during the font-selection
algorithm whether we need to apply synthetic-bold to the chosen face, and
then pass that decision through the fontgroup (storing it in the FamilyFace
entries of the mFonts array there) down to the actual rendering code that
instantiates fonts from the faces (font entries) we've selected.
That became a problem for variation fonts because in the case of a user
font, we may not have downloaded the resource yet, so we just have a "user
font container" entry, which carries the descriptors from the @font-face
rule and will fetch the actual resource when needed. But in the case of a
@font-face rule without a weight descriptor, we don't actually know at
font-selection time whether the face will support "true" bold (via a
variation axis) or not, so we can't reliably make the right decision about
applying synthetic bold.
So we now defer that decision until we actually instantiate a platform font
object to shape/measure/draw text. At that point, we have the requested
style and we also have the real font resource, so we can easily determine
whether fake-bold is required.
(This patch should not result in any visible behavior change; that will
come in a second patch now that the architecture supports it.)
2018-05-01 12:30:50 +03:00
|
|
|
gfxDWriteFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle)
|
2010-02-26 09:36:07 +03:00
|
|
|
{
|
Bug 1449605 - part 1 - Rearrange thebes font code so that the decision whether to apply synthetic-bold is deferred until actually instantiating a font, not made during the font-matching process. r=jwatt
This rearranges how synthetic-bold use is determined in the font selection
& rendering code. Previously, we would decide during the font-selection
algorithm whether we need to apply synthetic-bold to the chosen face, and
then pass that decision through the fontgroup (storing it in the FamilyFace
entries of the mFonts array there) down to the actual rendering code that
instantiates fonts from the faces (font entries) we've selected.
That became a problem for variation fonts because in the case of a user
font, we may not have downloaded the resource yet, so we just have a "user
font container" entry, which carries the descriptors from the @font-face
rule and will fetch the actual resource when needed. But in the case of a
@font-face rule without a weight descriptor, we don't actually know at
font-selection time whether the face will support "true" bold (via a
variation axis) or not, so we can't reliably make the right decision about
applying synthetic bold.
So we now defer that decision until we actually instantiate a platform font
object to shape/measure/draw text. At that point, we have the requested
style and we also have the real font resource, so we can easily determine
whether fake-bold is required.
(This patch should not result in any visible behavior change; that will
come in a second patch now that the architecture supports it.)
2018-05-01 12:30:50 +03:00
|
|
|
bool needsBold = aFontStyle->NeedsSyntheticBold(this);
|
2018-01-18 20:45:24 +03:00
|
|
|
DWRITE_FONT_SIMULATIONS sims =
|
Bug 1449605 - part 1 - Rearrange thebes font code so that the decision whether to apply synthetic-bold is deferred until actually instantiating a font, not made during the font-matching process. r=jwatt
This rearranges how synthetic-bold use is determined in the font selection
& rendering code. Previously, we would decide during the font-selection
algorithm whether we need to apply synthetic-bold to the chosen face, and
then pass that decision through the fontgroup (storing it in the FamilyFace
entries of the mFonts array there) down to the actual rendering code that
instantiates fonts from the faces (font entries) we've selected.
That became a problem for variation fonts because in the case of a user
font, we may not have downloaded the resource yet, so we just have a "user
font container" entry, which carries the descriptors from the @font-face
rule and will fetch the actual resource when needed. But in the case of a
@font-face rule without a weight descriptor, we don't actually know at
font-selection time whether the face will support "true" bold (via a
variation axis) or not, so we can't reliably make the right decision about
applying synthetic bold.
So we now defer that decision until we actually instantiate a platform font
object to shape/measure/draw text. At that point, we have the requested
style and we also have the real font resource, so we can easily determine
whether fake-bold is required.
(This patch should not result in any visible behavior change; that will
come in a second patch now that the architecture supports it.)
2018-05-01 12:30:50 +03:00
|
|
|
needsBold ? DWRITE_FONT_SIMULATIONS_BOLD : DWRITE_FONT_SIMULATIONS_NONE;
|
2018-01-18 20:45:24 +03:00
|
|
|
if (HasVariations() && !aFontStyle->variationSettings.IsEmpty()) {
|
|
|
|
// If we need to apply variations, we can't use the cached mUnscaledFont
|
|
|
|
// or mUnscaledFontBold here.
|
|
|
|
// XXX todo: consider caching a small number of variation instances?
|
|
|
|
RefPtr<IDWriteFontFace> fontFace;
|
|
|
|
nsresult rv = CreateFontFace(getter_AddRefs(fontFace),
|
2018-04-25 09:18:23 +03:00
|
|
|
aFontStyle,
|
2018-01-18 20:45:24 +03:00
|
|
|
sims);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
RefPtr<UnscaledFontDWrite> unscaledFont =
|
|
|
|
new UnscaledFontDWrite(fontFace, mIsSystemFont ? mFont : nullptr, sims);
|
Bug 1449605 - part 1 - Rearrange thebes font code so that the decision whether to apply synthetic-bold is deferred until actually instantiating a font, not made during the font-matching process. r=jwatt
This rearranges how synthetic-bold use is determined in the font selection
& rendering code. Previously, we would decide during the font-selection
algorithm whether we need to apply synthetic-bold to the chosen face, and
then pass that decision through the fontgroup (storing it in the FamilyFace
entries of the mFonts array there) down to the actual rendering code that
instantiates fonts from the faces (font entries) we've selected.
That became a problem for variation fonts because in the case of a user
font, we may not have downloaded the resource yet, so we just have a "user
font container" entry, which carries the descriptors from the @font-face
rule and will fetch the actual resource when needed. But in the case of a
@font-face rule without a weight descriptor, we don't actually know at
font-selection time whether the face will support "true" bold (via a
variation axis) or not, so we can't reliably make the right decision about
applying synthetic bold.
So we now defer that decision until we actually instantiate a platform font
object to shape/measure/draw text. At that point, we have the requested
style and we also have the real font resource, so we can easily determine
whether fake-bold is required.
(This patch should not result in any visible behavior change; that will
come in a second patch now that the architecture supports it.)
2018-05-01 12:30:50 +03:00
|
|
|
return new gfxDWriteFont(unscaledFont, this, aFontStyle);
|
2018-01-18 20:45:24 +03:00
|
|
|
}
|
|
|
|
|
2017-10-18 21:22:09 +03:00
|
|
|
ThreadSafeWeakPtr<UnscaledFontDWrite>& unscaledFontPtr =
|
Bug 1449605 - part 1 - Rearrange thebes font code so that the decision whether to apply synthetic-bold is deferred until actually instantiating a font, not made during the font-matching process. r=jwatt
This rearranges how synthetic-bold use is determined in the font selection
& rendering code. Previously, we would decide during the font-selection
algorithm whether we need to apply synthetic-bold to the chosen face, and
then pass that decision through the fontgroup (storing it in the FamilyFace
entries of the mFonts array there) down to the actual rendering code that
instantiates fonts from the faces (font entries) we've selected.
That became a problem for variation fonts because in the case of a user
font, we may not have downloaded the resource yet, so we just have a "user
font container" entry, which carries the descriptors from the @font-face
rule and will fetch the actual resource when needed. But in the case of a
@font-face rule without a weight descriptor, we don't actually know at
font-selection time whether the face will support "true" bold (via a
variation axis) or not, so we can't reliably make the right decision about
applying synthetic bold.
So we now defer that decision until we actually instantiate a platform font
object to shape/measure/draw text. At that point, we have the requested
style and we also have the real font resource, so we can easily determine
whether fake-bold is required.
(This patch should not result in any visible behavior change; that will
come in a second patch now that the architecture supports it.)
2018-05-01 12:30:50 +03:00
|
|
|
needsBold ? mUnscaledFontBold : mUnscaledFont;
|
2017-10-18 21:22:09 +03:00
|
|
|
RefPtr<UnscaledFontDWrite> unscaledFont(unscaledFontPtr);
|
2017-04-07 00:41:02 +03:00
|
|
|
if (!unscaledFont) {
|
|
|
|
RefPtr<IDWriteFontFace> fontFace;
|
2018-04-25 09:18:23 +03:00
|
|
|
nsresult rv = CreateFontFace(getter_AddRefs(fontFace), aFontStyle, sims);
|
2017-04-07 00:41:02 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2018-01-18 20:45:24 +03:00
|
|
|
unscaledFont =
|
|
|
|
new UnscaledFontDWrite(fontFace,
|
|
|
|
mIsSystemFont ? mFont : nullptr, sims);
|
2017-04-07 00:41:02 +03:00
|
|
|
unscaledFontPtr = unscaledFont;
|
|
|
|
}
|
Bug 1449605 - part 1 - Rearrange thebes font code so that the decision whether to apply synthetic-bold is deferred until actually instantiating a font, not made during the font-matching process. r=jwatt
This rearranges how synthetic-bold use is determined in the font selection
& rendering code. Previously, we would decide during the font-selection
algorithm whether we need to apply synthetic-bold to the chosen face, and
then pass that decision through the fontgroup (storing it in the FamilyFace
entries of the mFonts array there) down to the actual rendering code that
instantiates fonts from the faces (font entries) we've selected.
That became a problem for variation fonts because in the case of a user
font, we may not have downloaded the resource yet, so we just have a "user
font container" entry, which carries the descriptors from the @font-face
rule and will fetch the actual resource when needed. But in the case of a
@font-face rule without a weight descriptor, we don't actually know at
font-selection time whether the face will support "true" bold (via a
variation axis) or not, so we can't reliably make the right decision about
applying synthetic bold.
So we now defer that decision until we actually instantiate a platform font
object to shape/measure/draw text. At that point, we have the requested
style and we also have the real font resource, so we can easily determine
whether fake-bold is required.
(This patch should not result in any visible behavior change; that will
come in a second patch now that the architecture supports it.)
2018-05-01 12:30:50 +03:00
|
|
|
return new gfxDWriteFont(unscaledFont, this, aFontStyle);
|
2010-02-26 09:36:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
gfxDWriteFontEntry::CreateFontFace(IDWriteFontFace **aFontFace,
|
2018-04-25 09:18:23 +03:00
|
|
|
const gfxFontStyle* aFontStyle,
|
2010-02-26 09:36:07 +03:00
|
|
|
DWRITE_FONT_SIMULATIONS aSimulations)
|
|
|
|
{
|
2018-02-14 14:02:05 +03:00
|
|
|
// Convert an OpenType font tag from our uint32_t representation
|
|
|
|
// (as constructed by TRUETYPE_TAG(...)) to the order DWrite wants.
|
|
|
|
auto makeDWriteAxisTag = [](uint32_t aTag) {
|
|
|
|
return DWRITE_MAKE_FONT_AXIS_TAG((aTag >> 24) & 0xff,
|
|
|
|
(aTag >> 16) & 0xff,
|
|
|
|
(aTag >> 8) & 0xff,
|
|
|
|
aTag & 0xff);
|
|
|
|
};
|
|
|
|
|
2013-05-16 20:29:20 +04:00
|
|
|
// initialize mFontFace if this hasn't been done before
|
|
|
|
if (!mFontFace) {
|
|
|
|
HRESULT hr;
|
|
|
|
if (mFont) {
|
|
|
|
hr = mFont->CreateFontFace(getter_AddRefs(mFontFace));
|
|
|
|
} else if (mFontFile) {
|
|
|
|
IDWriteFontFile *fontFile = mFontFile.get();
|
2017-06-30 21:09:05 +03:00
|
|
|
hr = Factory::GetDWriteFactory()->
|
2013-05-16 20:29:20 +04:00
|
|
|
CreateFontFace(mFaceType,
|
|
|
|
1,
|
|
|
|
&fontFile,
|
|
|
|
0,
|
|
|
|
DWRITE_FONT_SIMULATIONS_NONE,
|
|
|
|
getter_AddRefs(mFontFace));
|
|
|
|
} else {
|
|
|
|
NS_NOTREACHED("invalid font entry");
|
|
|
|
return NS_ERROR_FAILURE;
|
2012-01-19 01:18:10 +04:00
|
|
|
}
|
2013-05-16 20:29:20 +04:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2018-01-18 20:45:24 +03:00
|
|
|
// Also get the IDWriteFontFace5 interface if we're running on a
|
|
|
|
// sufficiently new DWrite version where it is available.
|
|
|
|
if (mFontFace) {
|
|
|
|
mFontFace->QueryInterface(__uuidof(IDWriteFontFace5),
|
|
|
|
(void**)getter_AddRefs(mFontFace5));
|
2018-02-14 14:02:05 +03:00
|
|
|
if (!mVariationSettings.IsEmpty()) {
|
|
|
|
// If the font entry has variations specified, mFontFace5 will
|
|
|
|
// be a distinct face that has the variations applied.
|
|
|
|
RefPtr<IDWriteFontResource> resource;
|
|
|
|
HRESULT hr =
|
|
|
|
mFontFace5->GetFontResource(getter_AddRefs(resource));
|
|
|
|
MOZ_ASSERT(SUCCEEDED(hr));
|
|
|
|
AutoTArray<DWRITE_FONT_AXIS_VALUE, 4> fontAxisValues;
|
|
|
|
for (const auto& v : mVariationSettings) {
|
|
|
|
DWRITE_FONT_AXIS_VALUE axisValue = {
|
|
|
|
makeDWriteAxisTag(v.mTag),
|
|
|
|
v.mValue
|
|
|
|
};
|
|
|
|
fontAxisValues.AppendElement(axisValue);
|
|
|
|
}
|
|
|
|
resource->CreateFontFace(mFontFace->GetSimulations(),
|
|
|
|
fontAxisValues.Elements(),
|
|
|
|
fontAxisValues.Length(),
|
|
|
|
getter_AddRefs(mFontFace5));
|
|
|
|
}
|
2018-01-18 20:45:24 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do we need to modify DWrite simulations from what mFontFace has?
|
|
|
|
bool needSimulations =
|
|
|
|
(aSimulations & DWRITE_FONT_SIMULATIONS_BOLD) &&
|
|
|
|
!(mFontFace->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD);
|
|
|
|
|
|
|
|
// If the IDWriteFontFace5 interface is available, we can go via
|
|
|
|
// IDWriteFontResource to create a new modified face.
|
2018-04-25 09:18:23 +03:00
|
|
|
if (mFontFace5 && (HasVariations() || needSimulations)) {
|
2018-01-18 20:45:24 +03:00
|
|
|
RefPtr<IDWriteFontResource> resource;
|
|
|
|
HRESULT hr = mFontFace5->GetFontResource(getter_AddRefs(resource));
|
|
|
|
MOZ_ASSERT(SUCCEEDED(hr));
|
|
|
|
AutoTArray<DWRITE_FONT_AXIS_VALUE, 4> fontAxisValues;
|
2018-04-25 09:18:23 +03:00
|
|
|
|
|
|
|
// Get the variation settings needed to instantiate the fontEntry
|
2018-05-10 16:45:19 +03:00
|
|
|
// for a particular fontStyle, or use default style if no aFontStyle
|
|
|
|
// was passed (e.g. instantiating a face just to read font tables).
|
2018-04-25 09:18:23 +03:00
|
|
|
AutoTArray<gfxFontVariation,4> vars;
|
2018-05-10 16:45:19 +03:00
|
|
|
GetVariationsForStyle(vars, aFontStyle ? *aFontStyle : gfxFontStyle());
|
2018-04-25 09:18:23 +03:00
|
|
|
|
|
|
|
// Copy variation settings to DWrite's type.
|
|
|
|
if (!vars.IsEmpty()) {
|
|
|
|
for (const auto& v : vars) {
|
2018-01-18 20:45:24 +03:00
|
|
|
DWRITE_FONT_AXIS_VALUE axisValue = {
|
2018-02-14 14:02:05 +03:00
|
|
|
makeDWriteAxisTag(v.mTag),
|
2018-01-18 20:45:24 +03:00
|
|
|
v.mValue
|
|
|
|
};
|
|
|
|
fontAxisValues.AppendElement(axisValue);
|
|
|
|
}
|
|
|
|
}
|
2018-04-25 09:18:23 +03:00
|
|
|
|
2018-01-18 20:45:24 +03:00
|
|
|
IDWriteFontFace5* ff5;
|
|
|
|
resource->CreateFontFace(aSimulations,
|
|
|
|
fontAxisValues.Elements(),
|
|
|
|
fontAxisValues.Length(),
|
|
|
|
&ff5);
|
|
|
|
if (ff5) {
|
|
|
|
*aFontFace = ff5;
|
|
|
|
}
|
|
|
|
return FAILED(hr) ? NS_ERROR_FAILURE : NS_OK;
|
2013-05-16 20:29:20 +04:00
|
|
|
}
|
|
|
|
|
2018-01-18 20:45:24 +03:00
|
|
|
// Do we need to add DWrite simulations to the face?
|
|
|
|
if (needSimulations) {
|
2013-05-16 20:29:20 +04:00
|
|
|
// if so, we need to return not mFontFace itself but a version that
|
2018-01-18 20:45:24 +03:00
|
|
|
// has the Bold simulation - unfortunately, old DWrite doesn't provide
|
2013-05-16 20:29:20 +04:00
|
|
|
// a simple API for this
|
|
|
|
UINT32 numberOfFiles = 0;
|
2013-07-31 19:44:31 +04:00
|
|
|
if (FAILED(mFontFace->GetFiles(&numberOfFiles, nullptr))) {
|
2013-05-16 20:29:20 +04:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<IDWriteFontFile*,1> files;
|
2013-05-16 20:29:20 +04:00
|
|
|
files.AppendElements(numberOfFiles);
|
|
|
|
if (FAILED(mFontFace->GetFiles(&numberOfFiles, files.Elements()))) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2017-06-30 21:09:05 +03:00
|
|
|
HRESULT hr = Factory::GetDWriteFactory()->
|
2013-05-16 20:29:20 +04:00
|
|
|
CreateFontFace(mFontFace->GetType(),
|
|
|
|
numberOfFiles,
|
|
|
|
files.Elements(),
|
|
|
|
mFontFace->GetIndex(),
|
2010-02-26 09:36:07 +03:00
|
|
|
aSimulations,
|
|
|
|
aFontFace);
|
2013-05-16 20:29:20 +04:00
|
|
|
for (UINT32 i = 0; i < numberOfFiles; ++i) {
|
|
|
|
files[i]->Release();
|
|
|
|
}
|
|
|
|
return FAILED(hr) ? NS_ERROR_FAILURE : NS_OK;
|
2010-02-26 09:36:07 +03:00
|
|
|
}
|
2013-05-16 20:29:20 +04:00
|
|
|
|
2018-02-14 14:02:05 +03:00
|
|
|
// no simulation: we can just add a reference to mFontFace5 (if present)
|
|
|
|
// or mFontFace (otherwise) and return that
|
|
|
|
if (mFontFace5) {
|
|
|
|
*aFontFace = mFontFace5;
|
|
|
|
} else {
|
|
|
|
*aFontFace = mFontFace;
|
|
|
|
}
|
2013-05-16 20:29:20 +04:00
|
|
|
(*aFontFace)->AddRef();
|
2010-02-26 09:36:07 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2011-01-21 19:44:32 +03:00
|
|
|
gfxDWriteFontEntry::InitLogFont(IDWriteFont *aFont, LOGFONTW *aLogFont)
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
BOOL isInSystemCollection;
|
|
|
|
IDWriteGdiInterop *gdi =
|
|
|
|
gfxDWriteFontList::PlatformFontList()->GetGDIInterop();
|
|
|
|
hr = gdi->ConvertFontToLOGFONT(aFont, aLogFont, &isInSystemCollection);
|
2016-05-11 01:16:05 +03:00
|
|
|
// If the font is not in the system collection, GDI will be unable to
|
|
|
|
// select it and load its tables, so we return false here to indicate
|
|
|
|
// failure, and let CopyFontTable fall back to DWrite native methods.
|
|
|
|
return (SUCCEEDED(hr) && isInSystemCollection);
|
2011-01-21 19:44:32 +03:00
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2011-01-25 12:17:18 +03:00
|
|
|
gfxDWriteFontEntry::IsCJKFont()
|
|
|
|
{
|
|
|
|
if (mIsCJK != UNINITIALIZED_VALUE) {
|
|
|
|
return mIsCJK;
|
|
|
|
}
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
mIsCJK = false;
|
2011-01-25 12:17:18 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
const uint32_t kOS2Tag = TRUETYPE_TAG('O','S','/','2');
|
2017-09-20 12:10:01 +03:00
|
|
|
hb_blob_t* blob = GetFontTable(kOS2Tag);
|
|
|
|
if (!blob) {
|
2011-01-25 12:17:18 +03:00
|
|
|
return mIsCJK;
|
|
|
|
}
|
2017-09-20 12:10:01 +03:00
|
|
|
// |blob| is an owning reference, but is not RAII-managed, so it must be
|
|
|
|
// explicitly freed using |hb_blob_destroy| before we return. (Beware of
|
|
|
|
// adding any early-return codepaths!)
|
2011-01-25 12:17:18 +03:00
|
|
|
|
2017-09-20 12:10:01 +03:00
|
|
|
uint32_t len;
|
|
|
|
const OS2Table* os2 =
|
|
|
|
reinterpret_cast<const OS2Table*>(hb_blob_get_data(blob, &len));
|
2011-01-25 12:17:18 +03:00
|
|
|
// ulCodePageRange bit definitions for the CJK codepages,
|
|
|
|
// from http://www.microsoft.com/typography/otspec/os2.htm#cpr
|
2012-08-22 19:56:38 +04:00
|
|
|
const uint32_t CJK_CODEPAGE_BITS =
|
2011-01-25 12:17:18 +03:00
|
|
|
(1 << 17) | // codepage 932 - JIS/Japan
|
|
|
|
(1 << 18) | // codepage 936 - Chinese (simplified)
|
|
|
|
(1 << 19) | // codepage 949 - Korean Wansung
|
|
|
|
(1 << 20) | // codepage 950 - Chinese (traditional)
|
|
|
|
(1 << 21); // codepage 1361 - Korean Johab
|
2017-09-20 12:10:01 +03:00
|
|
|
if (len >= offsetof(OS2Table, sxHeight)) {
|
2012-08-22 19:56:38 +04:00
|
|
|
if ((uint32_t(os2->codePageRange1) & CJK_CODEPAGE_BITS) != 0) {
|
2011-10-17 18:59:28 +04:00
|
|
|
mIsCJK = true;
|
2011-01-25 12:17:18 +03:00
|
|
|
}
|
|
|
|
}
|
2017-09-20 12:10:01 +03:00
|
|
|
hb_blob_destroy(blob);
|
2011-01-25 12:17:18 +03:00
|
|
|
|
|
|
|
return mIsCJK;
|
|
|
|
}
|
|
|
|
|
2012-03-28 01:38:39 +04:00
|
|
|
void
|
2013-10-15 06:19:47 +04:00
|
|
|
gfxDWriteFontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
|
|
|
|
FontListSizes* aSizes) const
|
2012-03-28 01:38:39 +04:00
|
|
|
{
|
2013-10-15 06:19:47 +04:00
|
|
|
gfxFontEntry::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
2012-03-28 01:38:39 +04:00
|
|
|
// TODO:
|
|
|
|
// This doesn't currently account for the |mFont| and |mFontFile| members
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-10-15 06:19:47 +04:00
|
|
|
gfxDWriteFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
|
|
|
|
FontListSizes* aSizes) const
|
2012-03-28 01:38:39 +04:00
|
|
|
{
|
|
|
|
aSizes->mFontListSize += aMallocSizeOf(this);
|
2013-10-15 06:19:47 +04:00
|
|
|
AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
2012-03-28 01:38:39 +04:00
|
|
|
}
|
|
|
|
|
2010-02-26 09:36:07 +03:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// gfxDWriteFontList
|
|
|
|
|
|
|
|
gfxDWriteFontList::gfxDWriteFontList()
|
2015-08-13 09:04:25 +03:00
|
|
|
: mForceGDIClassicMaxFontSize(0.0)
|
2010-02-26 09:36:07 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-01-21 19:44:32 +03:00
|
|
|
// bug 602792 - CJK systems default to large CJK fonts which cause excessive
|
|
|
|
// I/O strain during cold startup due to dwrite caching bugs. Default to
|
|
|
|
// Arial to avoid this.
|
|
|
|
|
2012-12-19 13:42:25 +04:00
|
|
|
gfxFontFamily *
|
2016-08-23 03:06:07 +03:00
|
|
|
gfxDWriteFontList::GetDefaultFontForPlatform(const gfxFontStyle *aStyle)
|
2010-02-26 09:36:07 +03:00
|
|
|
{
|
2011-01-21 19:44:32 +03:00
|
|
|
nsAutoString resolvedName;
|
|
|
|
|
|
|
|
// try Arial first
|
2014-06-06 10:09:23 +04:00
|
|
|
gfxFontFamily *ff;
|
2014-11-27 12:58:41 +03:00
|
|
|
if ((ff = FindFamily(NS_LITERAL_STRING("Arial")))) {
|
2014-06-06 10:09:23 +04:00
|
|
|
return ff;
|
2011-01-21 19:44:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise, use local default
|
2010-02-26 09:36:07 +03:00
|
|
|
NONCLIENTMETRICSW ncm;
|
|
|
|
ncm.cbSize = sizeof(ncm);
|
|
|
|
BOOL status = ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
|
|
|
|
sizeof(ncm), &ncm, 0);
|
2014-06-06 10:09:23 +04:00
|
|
|
|
2010-02-26 09:36:07 +03:00
|
|
|
if (status) {
|
2014-06-06 10:09:23 +04:00
|
|
|
ff = FindFamily(nsDependentString(ncm.lfMessageFont.lfFaceName));
|
|
|
|
if (ff) {
|
|
|
|
return ff;
|
2010-02-26 09:36:07 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2010-02-26 09:36:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
gfxFontEntry *
|
2014-09-08 11:23:19 +04:00
|
|
|
gfxDWriteFontList::LookupLocalFont(const nsAString& aFontName,
|
2018-04-25 09:18:23 +03:00
|
|
|
WeightRange aWeightForEntry,
|
|
|
|
StretchRange aStretchForEntry,
|
|
|
|
SlantStyleRange aStyleForEntry)
|
2010-02-26 09:36:07 +03:00
|
|
|
{
|
|
|
|
gfxFontEntry *lookup;
|
|
|
|
|
2014-09-08 11:23:19 +04:00
|
|
|
lookup = LookupInFaceNameLists(aFontName);
|
2014-04-23 09:20:20 +04:00
|
|
|
if (!lookup) {
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2010-02-26 09:36:07 +03:00
|
|
|
}
|
2014-04-23 09:20:20 +04:00
|
|
|
|
2011-06-03 08:31:08 +04:00
|
|
|
gfxDWriteFontEntry* dwriteLookup = static_cast<gfxDWriteFontEntry*>(lookup);
|
|
|
|
gfxDWriteFontEntry *fe =
|
2010-02-26 09:36:07 +03:00
|
|
|
new gfxDWriteFontEntry(lookup->Name(),
|
2011-06-03 08:31:08 +04:00
|
|
|
dwriteLookup->mFont,
|
2018-04-25 09:18:23 +03:00
|
|
|
aWeightForEntry,
|
|
|
|
aStretchForEntry,
|
|
|
|
aStyleForEntry);
|
2011-06-03 08:31:08 +04:00
|
|
|
fe->SetForceGDIClassic(dwriteLookup->GetForceGDIClassic());
|
2010-02-26 09:36:07 +03:00
|
|
|
return fe;
|
|
|
|
}
|
|
|
|
|
|
|
|
gfxFontEntry *
|
2014-09-08 11:23:19 +04:00
|
|
|
gfxDWriteFontList::MakePlatformFont(const nsAString& aFontName,
|
2018-04-25 09:18:23 +03:00
|
|
|
WeightRange aWeightForEntry,
|
|
|
|
StretchRange aStretchForEntry,
|
|
|
|
SlantStyleRange aStyleForEntry,
|
2014-09-08 11:23:19 +04:00
|
|
|
const uint8_t* aFontData,
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t aLength)
|
2010-02-26 09:36:07 +03:00
|
|
|
{
|
2016-01-05 13:08:57 +03:00
|
|
|
RefPtr<IDWriteFontFileStream> fontFileStream;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteFontFile> fontFile;
|
2016-01-05 13:08:57 +03:00
|
|
|
HRESULT hr =
|
2018-01-26 20:26:19 +03:00
|
|
|
gfxDWriteFontFileLoader::CreateCustomFontFile(aFontData, aLength,
|
2016-01-05 13:08:57 +03:00
|
|
|
getter_AddRefs(fontFile),
|
|
|
|
getter_AddRefs(fontFileStream));
|
2018-01-26 20:26:19 +03:00
|
|
|
free((void*)aFontData);
|
2010-02-26 09:36:07 +03:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
NS_WARNING("Failed to create custom font file reference.");
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2010-02-26 09:36:07 +03:00
|
|
|
}
|
|
|
|
|
2018-01-26 20:26:19 +03:00
|
|
|
nsAutoString uniqueName;
|
|
|
|
nsresult rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2010-02-26 09:36:07 +03:00
|
|
|
BOOL isSupported;
|
|
|
|
DWRITE_FONT_FILE_TYPE fileType;
|
|
|
|
UINT32 numFaces;
|
|
|
|
|
|
|
|
gfxDWriteFontEntry *entry =
|
2018-01-26 20:26:19 +03:00
|
|
|
new gfxDWriteFontEntry(uniqueName,
|
2010-02-26 09:36:07 +03:00
|
|
|
fontFile,
|
2016-01-05 13:08:57 +03:00
|
|
|
fontFileStream,
|
2018-04-25 09:18:23 +03:00
|
|
|
aWeightForEntry,
|
|
|
|
aStretchForEntry,
|
|
|
|
aStyleForEntry);
|
2010-02-26 09:36:07 +03:00
|
|
|
|
|
|
|
fontFile->Analyze(&isSupported, &fileType, &entry->mFaceType, &numFaces);
|
|
|
|
if (!isSupported || numFaces > 1) {
|
|
|
|
// We don't know how to deal with 0 faces either.
|
|
|
|
delete entry;
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2010-02-26 09:36:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
2015-08-18 09:15:45 +03:00
|
|
|
enum DWriteInitError {
|
|
|
|
errGDIInterop = 1,
|
|
|
|
errSystemFontCollection = 2,
|
|
|
|
errNoFonts = 3
|
|
|
|
};
|
|
|
|
|
2010-11-08 14:02:27 +03:00
|
|
|
nsresult
|
2016-08-23 03:06:07 +03:00
|
|
|
gfxDWriteFontList::InitFontListForPlatform()
|
2010-02-26 09:36:07 +03:00
|
|
|
{
|
2015-08-13 09:04:25 +03:00
|
|
|
LARGE_INTEGER frequency; // ticks per second
|
|
|
|
LARGE_INTEGER t1, t2, t3, t4, t5; // ticks
|
2011-01-21 19:44:32 +03:00
|
|
|
double elapsedTime, upTime;
|
|
|
|
char nowTime[256], nowDate[256];
|
|
|
|
|
2015-08-13 09:04:25 +03:00
|
|
|
if (LOG_FONTINIT_ENABLED()) {
|
2016-01-05 13:08:56 +03:00
|
|
|
GetTimeFormatA(LOCALE_INVARIANT, TIME_FORCE24HOURFORMAT,
|
2013-07-31 19:44:31 +04:00
|
|
|
nullptr, nullptr, nowTime, 256);
|
2016-01-05 13:08:56 +03:00
|
|
|
GetDateFormatA(LOCALE_INVARIANT, 0, nullptr, nullptr, nowDate, 256);
|
2015-08-13 09:04:25 +03:00
|
|
|
upTime = (double) GetTickCount();
|
2011-01-21 19:44:32 +03:00
|
|
|
}
|
2011-07-27 10:42:53 +04:00
|
|
|
QueryPerformanceFrequency(&frequency);
|
2015-08-13 09:04:25 +03:00
|
|
|
QueryPerformanceCounter(&t1); // start
|
2011-01-21 19:44:32 +03:00
|
|
|
|
2010-02-26 09:36:07 +03:00
|
|
|
HRESULT hr;
|
2015-08-13 09:04:25 +03:00
|
|
|
mGDIFontTableAccess =
|
|
|
|
Preferences::GetBool("gfx.font_rendering.directwrite.use_gdi_table_loading",
|
|
|
|
false);
|
2011-01-21 19:44:32 +03:00
|
|
|
|
2010-03-03 09:57:43 +03:00
|
|
|
mFontSubstitutes.Clear();
|
|
|
|
mNonExistingFonts.Clear();
|
|
|
|
|
2017-06-30 21:09:05 +03:00
|
|
|
hr = Factory::GetDWriteFactory()->
|
2011-01-21 19:44:33 +03:00
|
|
|
GetGdiInterop(getter_AddRefs(mGDIInterop));
|
2010-11-08 14:02:27 +03:00
|
|
|
if (FAILED(hr)) {
|
2015-08-18 09:15:45 +03:00
|
|
|
Telemetry::Accumulate(Telemetry::DWRITEFONT_INIT_PROBLEM,
|
|
|
|
uint32_t(errGDIInterop));
|
2010-11-08 14:02:27 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2015-08-13 09:04:25 +03:00
|
|
|
QueryPerformanceCounter(&t2); // base-class/interop initialization
|
2011-01-21 19:44:33 +03:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteFactory> factory =
|
2017-06-30 21:09:05 +03:00
|
|
|
Factory::GetDWriteFactory();
|
2011-01-21 19:44:33 +03:00
|
|
|
|
2014-05-29 16:01:07 +04:00
|
|
|
hr = factory->GetSystemFontCollection(getter_AddRefs(mSystemFonts));
|
2011-01-21 19:44:33 +03:00
|
|
|
NS_ASSERTION(SUCCEEDED(hr), "GetSystemFontCollection failed!");
|
|
|
|
|
2011-01-21 19:44:32 +03:00
|
|
|
if (FAILED(hr)) {
|
2015-08-18 09:15:45 +03:00
|
|
|
Telemetry::Accumulate(Telemetry::DWRITEFONT_INIT_PROBLEM,
|
|
|
|
uint32_t(errSystemFontCollection));
|
2011-01-21 19:44:32 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2015-08-13 09:04:25 +03:00
|
|
|
QueryPerformanceCounter(&t3); // system font collection
|
2011-01-21 19:44:32 +03:00
|
|
|
|
2014-05-29 16:01:07 +04:00
|
|
|
GetFontsFromCollection(mSystemFonts);
|
2011-01-07 15:29:49 +03:00
|
|
|
|
2015-08-13 09:04:25 +03:00
|
|
|
// if no fonts found, something is out of whack, bail and use GDI backend
|
|
|
|
NS_ASSERTION(mFontFamilies.Count() != 0,
|
|
|
|
"no fonts found in the system fontlist -- holy crap batman!");
|
|
|
|
if (mFontFamilies.Count() == 0) {
|
2015-08-18 09:15:45 +03:00
|
|
|
Telemetry::Accumulate(Telemetry::DWRITEFONT_INIT_PROBLEM,
|
|
|
|
uint32_t(errNoFonts));
|
2015-08-13 09:04:25 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
QueryPerformanceCounter(&t4); // iterate over system fonts
|
|
|
|
|
2014-05-29 16:01:07 +04:00
|
|
|
#ifdef MOZ_BUNDLED_FONTS
|
|
|
|
mBundledFonts = CreateBundledFontsCollection(factory);
|
|
|
|
if (mBundledFonts) {
|
|
|
|
GetFontsFromCollection(mBundledFonts);
|
2010-02-26 09:36:07 +03:00
|
|
|
}
|
2014-05-29 16:01:07 +04:00
|
|
|
#endif
|
2010-02-26 09:36:07 +03:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
mOtherFamilyNamesInitialized = true;
|
2010-03-03 09:57:43 +03:00
|
|
|
GetFontSubstitutes();
|
|
|
|
|
2011-03-24 23:11:38 +03:00
|
|
|
// bug 642093 - DirectWrite does not support old bitmap (.fon)
|
|
|
|
// font files, but a few of these such as "Courier" and "MS Sans Serif"
|
|
|
|
// are frequently specified in shoddy CSS, without appropriate fallbacks.
|
|
|
|
// By mapping these to TrueType equivalents, we provide better consistency
|
|
|
|
// with both pre-DW systems and with IE9, which appears to do the same.
|
|
|
|
GetDirectWriteSubstitutes();
|
|
|
|
|
2015-08-13 09:04:25 +03:00
|
|
|
// bug 551313 - DirectWrite creates a Gill Sans family out of
|
2011-01-27 06:05:55 +03:00
|
|
|
// poorly named members of the Gill Sans MT family containing
|
|
|
|
// only Ultra Bold weights. This causes big problems for pages
|
|
|
|
// using Gill Sans which is usually only available on OSX
|
|
|
|
|
|
|
|
nsAutoString nameGillSans(L"Gill Sans");
|
|
|
|
nsAutoString nameGillSansMT(L"Gill Sans MT");
|
|
|
|
BuildKeyNameFromFontName(nameGillSans);
|
|
|
|
BuildKeyNameFromFontName(nameGillSansMT);
|
|
|
|
|
|
|
|
gfxFontFamily *gillSansFamily = mFontFamilies.GetWeak(nameGillSans);
|
|
|
|
gfxFontFamily *gillSansMTFamily = mFontFamilies.GetWeak(nameGillSansMT);
|
|
|
|
|
|
|
|
if (gillSansFamily && gillSansMTFamily) {
|
|
|
|
gillSansFamily->FindStyleVariations();
|
2015-10-18 08:24:48 +03:00
|
|
|
nsTArray<RefPtr<gfxFontEntry> >& faces = gillSansFamily->GetFontList();
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t i;
|
2011-01-27 06:05:55 +03:00
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool allUltraBold = true;
|
2011-01-27 06:05:55 +03:00
|
|
|
for (i = 0; i < faces.Length(); i++) {
|
|
|
|
// does the face have 'Ultra Bold' in the name?
|
|
|
|
if (faces[i]->Name().Find(NS_LITERAL_STRING("Ultra Bold")) == -1) {
|
2011-10-17 18:59:28 +04:00
|
|
|
allUltraBold = false;
|
2011-01-27 06:05:55 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if all the Gill Sans faces are Ultra Bold ==> move faces
|
|
|
|
// for Gill Sans into Gill Sans MT family
|
|
|
|
if (allUltraBold) {
|
|
|
|
|
|
|
|
// add faces to Gill Sans MT
|
|
|
|
for (i = 0; i < faces.Length(); i++) {
|
2014-07-22 14:41:31 +04:00
|
|
|
// change the entry's family name to match its adoptive family
|
|
|
|
faces[i]->mFamilyName = gillSansMTFamily->Name();
|
2011-01-27 06:05:55 +03:00
|
|
|
gillSansMTFamily->AddFontEntry(faces[i]);
|
|
|
|
|
|
|
|
if (LOG_FONTLIST_ENABLED()) {
|
|
|
|
gfxFontEntry *fe = faces[i];
|
2018-04-25 09:18:23 +03:00
|
|
|
nsAutoCString weightString;
|
|
|
|
fe->Weight().ToString(weightString);
|
2011-01-27 06:05:55 +03:00
|
|
|
LOG_FONTLIST(("(fontlist) moved (%s) to family (%s)"
|
2018-04-25 09:18:23 +03:00
|
|
|
" with style: %s weight: %s stretch: %d",
|
2011-01-27 06:05:55 +03:00
|
|
|
NS_ConvertUTF16toUTF8(fe->Name()).get(),
|
|
|
|
NS_ConvertUTF16toUTF8(gillSansMTFamily->Name()).get(),
|
2015-10-19 05:16:43 +03:00
|
|
|
(fe->IsItalic()) ?
|
|
|
|
"italic" : (fe->IsOblique() ? "oblique" : "normal"),
|
2018-04-25 09:18:23 +03:00
|
|
|
weightString.get(),
|
|
|
|
fe->Stretch()));
|
2011-01-27 06:05:55 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove Gills Sans
|
|
|
|
mFontFamilies.Remove(nameGillSans);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-31 07:28:48 +03:00
|
|
|
nsAutoCString classicFamilies;
|
|
|
|
nsresult rv = Preferences::GetCString(
|
|
|
|
"gfx.font_rendering.cleartype_params.force_gdi_classic_for_families",
|
|
|
|
classicFamilies);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
2011-06-03 08:31:07 +04:00
|
|
|
nsCCharSeparatedTokenizer tokenizer(classicFamilies, ',');
|
|
|
|
while (tokenizer.hasMoreTokens()) {
|
|
|
|
NS_ConvertUTF8toUTF16 name(tokenizer.nextToken());
|
|
|
|
BuildKeyNameFromFontName(name);
|
|
|
|
gfxFontFamily *family = mFontFamilies.GetWeak(name);
|
|
|
|
if (family) {
|
|
|
|
static_cast<gfxDWriteFontFamily*>(family)->SetForceGDIClassic(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-06-12 06:30:16 +04:00
|
|
|
mForceGDIClassicMaxFontSize =
|
|
|
|
Preferences::GetInt("gfx.font_rendering.cleartype_params.force_gdi_classic_max_size",
|
|
|
|
mForceGDIClassicMaxFontSize);
|
2011-06-03 08:31:07 +04:00
|
|
|
|
2013-04-26 11:40:44 +04:00
|
|
|
GetPrefsAndStartLoader();
|
2010-11-08 14:02:27 +03:00
|
|
|
|
2015-08-13 09:04:25 +03:00
|
|
|
QueryPerformanceCounter(&t5); // misc initialization
|
2011-01-21 19:44:32 +03:00
|
|
|
|
2011-07-27 10:42:53 +04:00
|
|
|
if (LOG_FONTINIT_ENABLED()) {
|
2011-01-21 19:44:32 +03:00
|
|
|
// determine dwrite version
|
|
|
|
nsAutoString dwriteVers;
|
2011-04-21 23:36:49 +04:00
|
|
|
gfxWindowsPlatform::GetDLLVersion(L"dwrite.dll", dwriteVers);
|
2015-08-13 09:04:25 +03:00
|
|
|
LOG_FONTINIT(("(fontinit) Start: %s %s\n", nowDate, nowTime));
|
|
|
|
LOG_FONTINIT(("(fontinit) Uptime: %9.3f s\n", upTime/1000));
|
|
|
|
LOG_FONTINIT(("(fontinit) dwrite version: %s\n",
|
2011-01-21 19:44:33 +03:00
|
|
|
NS_ConvertUTF16toUTF8(dwriteVers).get()));
|
2011-01-21 19:44:32 +03:00
|
|
|
}
|
2011-07-27 10:42:53 +04:00
|
|
|
|
2015-08-13 09:04:25 +03:00
|
|
|
elapsedTime = (t5.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
|
2011-07-27 10:42:53 +04:00
|
|
|
Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_TOTAL, elapsedTime);
|
|
|
|
Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_COUNT,
|
2014-05-29 16:01:07 +04:00
|
|
|
mSystemFonts->GetFontFamilyCount());
|
2011-07-27 10:42:53 +04:00
|
|
|
LOG_FONTINIT((
|
2015-08-13 09:04:25 +03:00
|
|
|
"(fontinit) Total time in InitFontList: %9.3f ms (families: %d, %s)\n",
|
2014-05-29 16:01:07 +04:00
|
|
|
elapsedTime, mSystemFonts->GetFontFamilyCount(),
|
2011-07-27 10:42:53 +04:00
|
|
|
(mGDIFontTableAccess ? "gdi table access" : "dwrite table access")));
|
|
|
|
|
|
|
|
elapsedTime = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
|
2015-08-13 09:04:25 +03:00
|
|
|
LOG_FONTINIT(("(fontinit) --- base/interop obj initialization init: %9.3f ms\n", elapsedTime));
|
2011-07-27 10:42:53 +04:00
|
|
|
|
|
|
|
elapsedTime = (t3.QuadPart - t2.QuadPart) * 1000.0 / frequency.QuadPart;
|
2015-08-13 09:04:25 +03:00
|
|
|
Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_COLLECT, elapsedTime);
|
|
|
|
LOG_FONTINIT(("(fontinit) --- GetSystemFontCollection: %9.3f ms\n", elapsedTime));
|
|
|
|
|
|
|
|
elapsedTime = (t4.QuadPart - t3.QuadPart) * 1000.0 / frequency.QuadPart;
|
|
|
|
LOG_FONTINIT(("(fontinit) --- iterate over families: %9.3f ms\n", elapsedTime));
|
|
|
|
|
|
|
|
elapsedTime = (t5.QuadPart - t4.QuadPart) * 1000.0 / frequency.QuadPart;
|
|
|
|
LOG_FONTINIT(("(fontinit) --- misc initialization: %9.3f ms\n", elapsedTime));
|
2011-01-21 19:44:32 +03:00
|
|
|
|
2010-11-08 14:02:27 +03:00
|
|
|
return NS_OK;
|
2010-02-26 09:36:07 +03:00
|
|
|
}
|
2010-02-28 10:27:22 +03:00
|
|
|
|
2014-05-29 16:01:07 +04:00
|
|
|
void
|
|
|
|
gfxDWriteFontList::GetFontsFromCollection(IDWriteFontCollection* aCollection)
|
|
|
|
{
|
|
|
|
for (UINT32 i = 0; i < aCollection->GetFontFamilyCount(); i++) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteFontFamily> family;
|
2014-05-29 16:01:07 +04:00
|
|
|
aCollection->GetFontFamily(i, getter_AddRefs(family));
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteLocalizedStrings> names;
|
2014-05-29 16:01:07 +04:00
|
|
|
HRESULT hr = family->GetFamilyNames(getter_AddRefs(names));
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-18 20:45:26 +03:00
|
|
|
nsAutoString name;
|
|
|
|
if (!GetEnglishOrFirstName(name, names)) {
|
2014-05-29 16:01:07 +04:00
|
|
|
continue;
|
|
|
|
}
|
2018-01-18 20:45:26 +03:00
|
|
|
nsAutoString familyName(name); // keep a copy before we lowercase it as a key
|
2014-05-29 16:01:07 +04:00
|
|
|
|
|
|
|
BuildKeyNameFromFontName(name);
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<gfxFontFamily> fam;
|
2014-05-29 16:01:07 +04:00
|
|
|
|
|
|
|
if (mFontFamilies.GetWeak(name)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-11-07 04:20:43 +03:00
|
|
|
fam = new gfxDWriteFontFamily(familyName, family, aCollection == mSystemFonts);
|
2014-05-29 16:01:07 +04:00
|
|
|
if (!fam) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mBadUnderlineFamilyNames.Contains(name)) {
|
|
|
|
fam->SetBadUnderlineFamily();
|
|
|
|
}
|
|
|
|
mFontFamilies.Put(name, fam);
|
|
|
|
|
|
|
|
// now add other family name localizations, if present
|
|
|
|
uint32_t nameCount = names->GetCount();
|
|
|
|
uint32_t nameIndex;
|
|
|
|
|
2018-01-18 20:45:26 +03:00
|
|
|
if (nameCount > 1) {
|
|
|
|
UINT32 englishIdx = 0;
|
|
|
|
BOOL exists;
|
|
|
|
// if this fails/doesn't exist, we'll have used name index 0,
|
|
|
|
// so that's the one we'll want to skip here
|
|
|
|
names->FindLocaleName(L"en-us", &englishIdx, &exists);
|
2014-05-29 16:01:07 +04:00
|
|
|
|
2018-01-18 20:45:26 +03:00
|
|
|
for (nameIndex = 0; nameIndex < nameCount; nameIndex++) {
|
|
|
|
UINT32 nameLen;
|
|
|
|
AutoTArray<WCHAR, 32> localizedName;
|
2014-05-29 16:01:07 +04:00
|
|
|
|
2018-01-18 20:45:26 +03:00
|
|
|
// only add other names
|
|
|
|
if (nameIndex == englishIdx) {
|
|
|
|
continue;
|
|
|
|
}
|
2014-05-29 16:01:07 +04:00
|
|
|
|
2018-01-18 20:45:26 +03:00
|
|
|
hr = names->GetStringLength(nameIndex, &nameLen);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
continue;
|
|
|
|
}
|
2014-05-29 16:01:07 +04:00
|
|
|
|
2018-01-18 20:45:26 +03:00
|
|
|
if (!localizedName.SetLength(nameLen + 1, fallible)) {
|
|
|
|
continue;
|
|
|
|
}
|
2014-05-29 16:01:07 +04:00
|
|
|
|
2018-01-18 20:45:26 +03:00
|
|
|
hr = names->GetString(nameIndex, localizedName.Elements(),
|
|
|
|
nameLen + 1);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
continue;
|
|
|
|
}
|
2014-05-29 16:01:07 +04:00
|
|
|
|
2018-01-18 20:45:26 +03:00
|
|
|
nsDependentString locName(localizedName.Elements());
|
2014-05-29 16:01:07 +04:00
|
|
|
|
2018-01-18 20:45:26 +03:00
|
|
|
if (!familyName.Equals(locName)) {
|
|
|
|
AddOtherFamilyName(fam, locName);
|
|
|
|
}
|
|
|
|
}
|
2014-05-29 16:01:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// at this point, all family names have been read in
|
|
|
|
fam->SetOtherFamilyNamesInitialized();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-03 09:57:43 +03:00
|
|
|
static void
|
|
|
|
RemoveCharsetFromFontSubstitute(nsAString &aName)
|
|
|
|
{
|
2014-01-04 19:02:17 +04:00
|
|
|
int32_t comma = aName.FindChar(char16_t(','));
|
2010-03-03 09:57:43 +03:00
|
|
|
if (comma >= 0)
|
|
|
|
aName.Truncate(comma);
|
|
|
|
}
|
|
|
|
|
2011-01-21 19:44:32 +03:00
|
|
|
#define MAX_VALUE_NAME 512
|
|
|
|
#define MAX_VALUE_DATA 512
|
|
|
|
|
2010-03-03 09:57:43 +03:00
|
|
|
nsresult
|
|
|
|
gfxDWriteFontList::GetFontSubstitutes()
|
|
|
|
{
|
2011-01-21 19:44:32 +03:00
|
|
|
HKEY hKey;
|
|
|
|
DWORD i, rv, lenAlias, lenActual, valueType;
|
|
|
|
WCHAR aliasName[MAX_VALUE_NAME];
|
|
|
|
WCHAR actualName[MAX_VALUE_DATA];
|
|
|
|
|
|
|
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
|
|
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes",
|
|
|
|
0, KEY_READ, &hKey) != ERROR_SUCCESS)
|
|
|
|
{
|
2010-03-03 09:57:43 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2011-01-21 19:44:32 +03:00
|
|
|
for (i = 0, rv = ERROR_SUCCESS; rv != ERROR_NO_MORE_ITEMS; i++) {
|
|
|
|
aliasName[0] = 0;
|
2011-10-11 09:50:08 +04:00
|
|
|
lenAlias = ArrayLength(aliasName);
|
2011-01-21 19:44:32 +03:00
|
|
|
actualName[0] = 0;
|
|
|
|
lenActual = sizeof(actualName);
|
2013-07-31 19:44:31 +04:00
|
|
|
rv = RegEnumValueW(hKey, i, aliasName, &lenAlias, nullptr, &valueType,
|
2011-01-21 19:44:32 +03:00
|
|
|
(LPBYTE)actualName, &lenActual);
|
2010-03-03 09:57:43 +03:00
|
|
|
|
2011-01-21 19:44:32 +03:00
|
|
|
if (rv != ERROR_SUCCESS || valueType != REG_SZ || lenAlias == 0) {
|
2010-03-03 09:57:43 +03:00
|
|
|
continue;
|
|
|
|
}
|
2011-01-21 19:44:32 +03:00
|
|
|
|
|
|
|
if (aliasName[0] == WCHAR('@')) {
|
2010-03-03 09:57:43 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-01-04 19:02:17 +04:00
|
|
|
nsAutoString substituteName((char16_t*) aliasName);
|
|
|
|
nsAutoString actualFontName((char16_t*) actualName);
|
2010-03-03 09:57:43 +03:00
|
|
|
RemoveCharsetFromFontSubstitute(substituteName);
|
|
|
|
BuildKeyNameFromFontName(substituteName);
|
|
|
|
RemoveCharsetFromFontSubstitute(actualFontName);
|
|
|
|
BuildKeyNameFromFontName(actualFontName);
|
|
|
|
gfxFontFamily *ff;
|
|
|
|
if (!actualFontName.IsEmpty() &&
|
|
|
|
(ff = mFontFamilies.GetWeak(actualFontName))) {
|
|
|
|
mFontSubstitutes.Put(substituteName, ff);
|
|
|
|
} else {
|
|
|
|
mNonExistingFonts.AppendElement(substituteName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-03-24 23:11:38 +03:00
|
|
|
struct FontSubstitution {
|
|
|
|
const WCHAR* aliasName;
|
|
|
|
const WCHAR* actualName;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const FontSubstitution sDirectWriteSubs[] = {
|
|
|
|
{ L"MS Sans Serif", L"Microsoft Sans Serif" },
|
|
|
|
{ L"MS Serif", L"Times New Roman" },
|
|
|
|
{ L"Courier", L"Courier New" },
|
|
|
|
{ L"Small Fonts", L"Arial" },
|
|
|
|
{ L"Roman", L"Times New Roman" },
|
|
|
|
{ L"Script", L"Mistral" }
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
gfxDWriteFontList::GetDirectWriteSubstitutes()
|
|
|
|
{
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t i = 0; i < ArrayLength(sDirectWriteSubs); ++i) {
|
2011-03-24 23:11:38 +03:00
|
|
|
const FontSubstitution& sub(sDirectWriteSubs[i]);
|
2014-01-04 19:02:17 +04:00
|
|
|
nsAutoString substituteName((char16_t*)sub.aliasName);
|
2011-03-24 23:11:38 +03:00
|
|
|
BuildKeyNameFromFontName(substituteName);
|
2012-07-30 18:20:58 +04:00
|
|
|
if (nullptr != mFontFamilies.GetWeak(substituteName)) {
|
2011-03-24 23:11:38 +03:00
|
|
|
// don't do the substitution if user actually has a usable font
|
|
|
|
// with this name installed
|
|
|
|
continue;
|
|
|
|
}
|
2014-01-04 19:02:17 +04:00
|
|
|
nsAutoString actualFontName((char16_t*)sub.actualName);
|
2011-03-24 23:11:38 +03:00
|
|
|
BuildKeyNameFromFontName(actualFontName);
|
|
|
|
gfxFontFamily *ff;
|
2012-07-30 18:20:58 +04:00
|
|
|
if (nullptr != (ff = mFontFamilies.GetWeak(actualFontName))) {
|
2011-03-24 23:11:38 +03:00
|
|
|
mFontSubstitutes.Put(substituteName, ff);
|
|
|
|
} else {
|
|
|
|
mNonExistingFonts.AppendElement(substituteName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2010-02-28 10:27:22 +03:00
|
|
|
gfxDWriteFontList::GetStandardFamilyName(const nsAString& aFontName,
|
|
|
|
nsAString& aFamilyName)
|
|
|
|
{
|
|
|
|
gfxFontFamily *family = FindFamily(aFontName);
|
|
|
|
if (family) {
|
|
|
|
family->LocalizedName(aFamilyName);
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2010-02-28 10:27:22 +03:00
|
|
|
}
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2010-02-28 10:27:22 +03:00
|
|
|
}
|
2010-03-03 09:57:43 +03:00
|
|
|
|
2016-04-12 09:06:22 +03:00
|
|
|
bool
|
|
|
|
gfxDWriteFontList::FindAndAddFamilies(const nsAString& aFamily,
|
2018-05-25 16:07:57 +03:00
|
|
|
nsTArray<FamilyAndGeneric>* aOutput,
|
2017-08-01 13:25:35 +03:00
|
|
|
FindFamiliesFlags aFlags,
|
2016-04-12 09:06:22 +03:00
|
|
|
gfxFontStyle* aStyle,
|
|
|
|
gfxFloat aDevToCssSize)
|
2011-01-21 19:44:33 +03:00
|
|
|
{
|
2014-06-06 10:09:23 +04:00
|
|
|
nsAutoString keyName(aFamily);
|
|
|
|
BuildKeyNameFromFontName(keyName);
|
|
|
|
|
|
|
|
gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName);
|
|
|
|
if (ff) {
|
2018-05-25 16:07:57 +03:00
|
|
|
aOutput->AppendElement(FamilyAndGeneric(ff));
|
2016-04-12 09:06:22 +03:00
|
|
|
return true;
|
2014-06-06 10:09:23 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mNonExistingFonts.Contains(keyName)) {
|
2016-04-12 09:06:22 +03:00
|
|
|
return false;
|
2014-06-06 10:09:23 +04:00
|
|
|
}
|
|
|
|
|
2017-08-03 03:33:00 +03:00
|
|
|
return gfxPlatformFontList::FindAndAddFamilies(aFamily,
|
|
|
|
aOutput,
|
2017-08-01 13:25:35 +03:00
|
|
|
aFlags,
|
2017-08-03 03:33:00 +03:00
|
|
|
aStyle,
|
2016-04-12 09:06:22 +03:00
|
|
|
aDevToCssSize);
|
2011-01-21 19:44:33 +03:00
|
|
|
}
|
|
|
|
|
2012-03-28 01:38:39 +04:00
|
|
|
void
|
2013-10-15 06:19:47 +04:00
|
|
|
gfxDWriteFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
|
|
|
|
FontListSizes* aSizes) const
|
2012-03-28 01:38:39 +04:00
|
|
|
{
|
2013-10-15 06:19:47 +04:00
|
|
|
gfxPlatformFontList::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
2012-03-28 01:38:39 +04:00
|
|
|
|
2018-04-05 23:27:07 +03:00
|
|
|
// We are a singleton, so include the font loader singleton's memory.
|
|
|
|
MOZ_ASSERT(static_cast<const gfxPlatformFontList*>(this) == gfxPlatformFontList::PlatformFontList());
|
|
|
|
gfxDWriteFontFileLoader* loader =
|
|
|
|
static_cast<gfxDWriteFontFileLoader*>(gfxDWriteFontFileLoader::Instance());
|
|
|
|
aSizes->mLoaderSize += loader->SizeOfIncludingThis(aMallocSizeOf);
|
|
|
|
|
2012-03-28 01:38:39 +04:00
|
|
|
aSizes->mFontListSize +=
|
2015-07-31 07:19:57 +03:00
|
|
|
SizeOfFontFamilyTableExcludingThis(mFontSubstitutes, aMallocSizeOf);
|
2012-03-28 01:38:39 +04:00
|
|
|
|
|
|
|
aSizes->mFontListSize +=
|
2015-07-29 09:24:24 +03:00
|
|
|
mNonExistingFonts.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t i = 0; i < mNonExistingFonts.Length(); ++i) {
|
2012-03-28 01:38:39 +04:00
|
|
|
aSizes->mFontListSize +=
|
|
|
|
mNonExistingFonts[i].SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-10-15 06:19:47 +04:00
|
|
|
gfxDWriteFontList::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
|
|
|
|
FontListSizes* aSizes) const
|
2012-03-28 01:38:39 +04:00
|
|
|
{
|
|
|
|
aSizes->mFontListSize += aMallocSizeOf(this);
|
2013-10-15 06:19:47 +04:00
|
|
|
AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
|
2012-03-28 01:38:39 +04:00
|
|
|
}
|
|
|
|
|
2012-08-16 15:58:11 +04:00
|
|
|
static HRESULT GetFamilyName(IDWriteFont *aFont, nsString& aFamilyName)
|
2012-03-09 06:05:55 +04:00
|
|
|
{
|
|
|
|
HRESULT hr;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteFontFamily> family;
|
2012-03-09 06:05:55 +04:00
|
|
|
|
|
|
|
// clean out previous value
|
|
|
|
aFamilyName.Truncate();
|
|
|
|
|
|
|
|
hr = aFont->GetFontFamily(getter_AddRefs(family));
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteLocalizedStrings> familyNames;
|
2012-03-09 06:05:55 +04:00
|
|
|
|
|
|
|
hr = family->GetFamilyNames(getter_AddRefs(familyNames));
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
2018-01-18 20:45:26 +03:00
|
|
|
if (!GetEnglishOrFirstName(aFamilyName, familyNames)) {
|
2012-08-16 15:58:11 +04:00
|
|
|
return E_FAIL;
|
2012-03-09 06:05:55 +04:00
|
|
|
}
|
|
|
|
|
2012-08-16 15:58:11 +04:00
|
|
|
return S_OK;
|
2012-03-09 06:05:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// bug 705594 - the method below doesn't actually do any "drawing", it's only
|
|
|
|
// used to invoke the DirectWrite layout engine to determine the fallback font
|
|
|
|
// for a given character.
|
|
|
|
|
2015-12-18 21:53:25 +03:00
|
|
|
IFACEMETHODIMP DWriteFontFallbackRenderer::DrawGlyphRun(
|
2012-04-04 13:12:11 +04:00
|
|
|
void* clientDrawingContext,
|
2012-03-09 06:05:55 +04:00
|
|
|
FLOAT baselineOriginX,
|
|
|
|
FLOAT baselineOriginY,
|
|
|
|
DWRITE_MEASURING_MODE measuringMode,
|
2012-04-04 13:12:11 +04:00
|
|
|
DWRITE_GLYPH_RUN const* glyphRun,
|
|
|
|
DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
|
|
|
|
IUnknown* clientDrawingEffect
|
2012-03-09 06:05:55 +04:00
|
|
|
)
|
|
|
|
{
|
|
|
|
if (!mSystemFonts) {
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteFont> font;
|
2012-03-09 06:05:55 +04:00
|
|
|
hr = mSystemFonts->GetFontFromFontFace(glyphRun->fontFace,
|
|
|
|
getter_AddRefs(font));
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// copy the family name
|
|
|
|
hr = GetFamilyName(font, mFamilyName);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Arial is used as the default fallback font
|
|
|
|
// so if it matches ==> no font found
|
|
|
|
if (mFamilyName.EqualsLiteral("Arial")) {
|
|
|
|
mFamilyName.Truncate();
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
gfxFontEntry*
|
2017-07-13 11:40:33 +03:00
|
|
|
gfxDWriteFontList::PlatformGlobalFontFallback(const uint32_t aCh,
|
|
|
|
Script aRunScript,
|
|
|
|
const gfxFontStyle* aMatchStyle,
|
|
|
|
gfxFontFamily** aMatchedFamily)
|
2012-03-09 06:05:55 +04:00
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteFactory> dwFactory =
|
2017-06-30 21:09:05 +03:00
|
|
|
Factory::GetDWriteFactory();
|
2012-03-09 06:05:55 +04:00
|
|
|
if (!dwFactory) {
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2012-03-09 06:05:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// initialize fallback renderer
|
|
|
|
if (!mFallbackRenderer) {
|
2015-12-18 21:53:25 +03:00
|
|
|
mFallbackRenderer = new DWriteFontFallbackRenderer(dwFactory);
|
2012-03-09 06:05:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// initialize text format
|
|
|
|
if (!mFallbackFormat) {
|
2013-07-31 19:44:31 +04:00
|
|
|
hr = dwFactory->CreateTextFormat(L"Arial", nullptr,
|
2012-03-09 06:05:55 +04:00
|
|
|
DWRITE_FONT_WEIGHT_REGULAR,
|
|
|
|
DWRITE_FONT_STYLE_NORMAL,
|
|
|
|
DWRITE_FONT_STRETCH_NORMAL,
|
|
|
|
72.0f, L"en-us",
|
|
|
|
getter_AddRefs(mFallbackFormat));
|
|
|
|
if (FAILED(hr)) {
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2012-03-09 06:05:55 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// set up string with fallback character
|
|
|
|
wchar_t str[16];
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t strLen;
|
2012-03-09 06:05:55 +04:00
|
|
|
|
|
|
|
if (IS_IN_BMP(aCh)) {
|
|
|
|
str[0] = static_cast<wchar_t> (aCh);
|
|
|
|
str[1] = 0;
|
|
|
|
strLen = 1;
|
|
|
|
} else {
|
|
|
|
str[0] = static_cast<wchar_t> (H_SURROGATE(aCh));
|
|
|
|
str[1] = static_cast<wchar_t> (L_SURROGATE(aCh));
|
|
|
|
str[2] = 0;
|
|
|
|
strLen = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set up layout
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteTextLayout> fallbackLayout;
|
2012-03-09 06:05:55 +04:00
|
|
|
|
|
|
|
hr = dwFactory->CreateTextLayout(str, strLen, mFallbackFormat,
|
|
|
|
200.0f, 200.0f,
|
|
|
|
getter_AddRefs(fallbackLayout));
|
|
|
|
if (FAILED(hr)) {
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2012-03-09 06:05:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// call the draw method to invoke the DirectWrite layout functions
|
|
|
|
// which determine the fallback font
|
2013-07-31 19:44:31 +04:00
|
|
|
hr = fallbackLayout->Draw(nullptr, mFallbackRenderer, 50.0f, 50.0f);
|
2012-03-09 06:05:55 +04:00
|
|
|
if (FAILED(hr)) {
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2012-03-09 06:05:55 +04:00
|
|
|
}
|
|
|
|
|
2012-12-19 13:42:25 +04:00
|
|
|
gfxFontFamily *family = FindFamily(mFallbackRenderer->FallbackFamilyName());
|
|
|
|
if (family) {
|
|
|
|
gfxFontEntry *fontEntry;
|
Bug 1449605 - part 1 - Rearrange thebes font code so that the decision whether to apply synthetic-bold is deferred until actually instantiating a font, not made during the font-matching process. r=jwatt
This rearranges how synthetic-bold use is determined in the font selection
& rendering code. Previously, we would decide during the font-selection
algorithm whether we need to apply synthetic-bold to the chosen face, and
then pass that decision through the fontgroup (storing it in the FamilyFace
entries of the mFonts array there) down to the actual rendering code that
instantiates fonts from the faces (font entries) we've selected.
That became a problem for variation fonts because in the case of a user
font, we may not have downloaded the resource yet, so we just have a "user
font container" entry, which carries the descriptors from the @font-face
rule and will fetch the actual resource when needed. But in the case of a
@font-face rule without a weight descriptor, we don't actually know at
font-selection time whether the face will support "true" bold (via a
variation axis) or not, so we can't reliably make the right decision about
applying synthetic bold.
So we now defer that decision until we actually instantiate a platform font
object to shape/measure/draw text. At that point, we have the requested
style and we also have the real font resource, so we can easily determine
whether fake-bold is required.
(This patch should not result in any visible behavior change; that will
come in a second patch now that the architecture supports it.)
2018-05-01 12:30:50 +03:00
|
|
|
fontEntry = family->FindFontForStyle(*aMatchStyle);
|
2015-01-15 14:07:24 +03:00
|
|
|
if (fontEntry && fontEntry->HasCharacter(aCh)) {
|
2012-12-19 13:42:25 +04:00
|
|
|
*aMatchedFamily = family;
|
|
|
|
return fontEntry;
|
|
|
|
}
|
2012-03-09 06:05:55 +04:00
|
|
|
Telemetry::Accumulate(Telemetry::BAD_FALLBACK_FONT, true);
|
|
|
|
}
|
2012-12-19 13:42:25 +04:00
|
|
|
|
|
|
|
return nullptr;
|
2012-03-09 06:05:55 +04:00
|
|
|
}
|
2014-01-29 11:39:01 +04:00
|
|
|
|
|
|
|
// used to load system-wide font info on off-main thread
|
|
|
|
class DirectWriteFontInfo : public FontInfoData {
|
|
|
|
public:
|
|
|
|
DirectWriteFontInfo(bool aLoadOtherNames,
|
|
|
|
bool aLoadFaceNames,
|
2014-05-29 16:01:07 +04:00
|
|
|
bool aLoadCmaps,
|
|
|
|
IDWriteFontCollection* aSystemFonts
|
|
|
|
#ifdef MOZ_BUNDLED_FONTS
|
|
|
|
, IDWriteFontCollection* aBundledFonts
|
|
|
|
#endif
|
|
|
|
) :
|
2014-01-29 11:39:01 +04:00
|
|
|
FontInfoData(aLoadOtherNames, aLoadFaceNames, aLoadCmaps)
|
2014-05-29 16:01:07 +04:00
|
|
|
, mSystemFonts(aSystemFonts)
|
|
|
|
#ifdef MOZ_BUNDLED_FONTS
|
|
|
|
, mBundledFonts(aBundledFonts)
|
|
|
|
#endif
|
2014-01-29 11:39:01 +04:00
|
|
|
{}
|
|
|
|
|
|
|
|
virtual ~DirectWriteFontInfo() {}
|
|
|
|
|
|
|
|
// loads font data for all members of a given family
|
|
|
|
virtual void LoadFontFamilyData(const nsAString& aFamilyName);
|
|
|
|
|
2014-05-29 16:01:07 +04:00
|
|
|
private:
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteFontCollection> mSystemFonts;
|
2014-05-29 16:01:07 +04:00
|
|
|
#ifdef MOZ_BUNDLED_FONTS
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteFontCollection> mBundledFonts;
|
2014-05-29 16:01:07 +04:00
|
|
|
#endif
|
2014-01-29 11:39:01 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
DirectWriteFontInfo::LoadFontFamilyData(const nsAString& aFamilyName)
|
|
|
|
{
|
|
|
|
// lookup the family
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<wchar_t, 32> famName;
|
2014-01-29 11:39:01 +04:00
|
|
|
|
|
|
|
uint32_t len = aFamilyName.Length();
|
2015-09-11 03:40:30 +03:00
|
|
|
if(!famName.SetLength(len + 1, fallible)) {
|
|
|
|
return;
|
|
|
|
}
|
2014-01-29 11:39:01 +04:00
|
|
|
memcpy(famName.Elements(), aFamilyName.BeginReading(), len * sizeof(char16_t));
|
|
|
|
famName[len] = 0;
|
|
|
|
|
|
|
|
HRESULT hr;
|
|
|
|
BOOL exists = false;
|
|
|
|
|
|
|
|
uint32_t index;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteFontFamily> family;
|
2014-01-29 11:39:01 +04:00
|
|
|
hr = mSystemFonts->FindFamilyName(famName.Elements(), &index, &exists);
|
2014-05-29 16:01:07 +04:00
|
|
|
if (SUCCEEDED(hr) && exists) {
|
|
|
|
mSystemFonts->GetFontFamily(index, getter_AddRefs(family));
|
|
|
|
if (!family) {
|
|
|
|
return;
|
|
|
|
}
|
2014-01-29 11:39:01 +04:00
|
|
|
}
|
|
|
|
|
2014-05-29 16:01:07 +04:00
|
|
|
#ifdef MOZ_BUNDLED_FONTS
|
|
|
|
if (!family && mBundledFonts) {
|
|
|
|
hr = mBundledFonts->FindFamilyName(famName.Elements(), &index, &exists);
|
|
|
|
if (SUCCEEDED(hr) && exists) {
|
|
|
|
mBundledFonts->GetFontFamily(index, getter_AddRefs(family));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-01-29 11:39:01 +04:00
|
|
|
if (!family) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// later versions of DirectWrite support querying the fullname/psname
|
|
|
|
bool loadFaceNamesUsingDirectWrite = mLoadFaceNames;
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < family->GetFontCount(); i++) {
|
|
|
|
// get the font
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteFont> dwFont;
|
2014-01-29 11:39:01 +04:00
|
|
|
hr = family->GetFont(i, getter_AddRefs(dwFont));
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
// This should never happen.
|
|
|
|
NS_WARNING("Failed to get existing font from family.");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-06-19 11:08:58 +04:00
|
|
|
if (dwFont->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) {
|
|
|
|
// We don't want these in the font list; we'll apply simulations
|
|
|
|
// on the fly when appropriate.
|
2014-01-29 11:39:01 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
mLoadStats.fonts++;
|
|
|
|
|
|
|
|
// get the name of the face
|
|
|
|
nsString fullID(aFamilyName);
|
|
|
|
nsAutoString fontName;
|
|
|
|
hr = GetDirectWriteFontName(dwFont, fontName);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
continue;
|
|
|
|
}
|
2014-05-22 07:48:50 +04:00
|
|
|
fullID.Append(' ');
|
2014-01-29 11:39:01 +04:00
|
|
|
fullID.Append(fontName);
|
|
|
|
|
|
|
|
FontFaceData fontData;
|
|
|
|
bool haveData = true;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteFontFace> dwFontFace;
|
2014-01-29 11:39:01 +04:00
|
|
|
|
|
|
|
if (mLoadFaceNames) {
|
|
|
|
// try to load using DirectWrite first
|
|
|
|
if (loadFaceNamesUsingDirectWrite) {
|
|
|
|
hr = GetDirectWriteFaceName(dwFont, PSNAME_ID, fontData.mPostscriptName);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
loadFaceNamesUsingDirectWrite = false;
|
|
|
|
}
|
|
|
|
hr = GetDirectWriteFaceName(dwFont, FULLNAME_ID, fontData.mFullName);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
loadFaceNamesUsingDirectWrite = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if DirectWrite read fails, load directly from name table
|
|
|
|
if (!loadFaceNamesUsingDirectWrite) {
|
|
|
|
hr = dwFont->CreateFontFace(getter_AddRefs(dwFontFace));
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
uint32_t kNAME =
|
|
|
|
NativeEndian::swapToBigEndian(TRUETYPE_TAG('n','a','m','e'));
|
|
|
|
const char *nameData;
|
|
|
|
BOOL exists;
|
|
|
|
void* ctx;
|
|
|
|
uint32_t nameSize;
|
|
|
|
|
|
|
|
hr = dwFontFace->TryGetFontTable(
|
|
|
|
kNAME,
|
|
|
|
(const void**)&nameData, &nameSize, &ctx, &exists);
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr) && nameData && nameSize > 0) {
|
|
|
|
gfxFontUtils::ReadCanonicalName(nameData, nameSize,
|
|
|
|
gfxFontUtils::NAME_ID_FULL,
|
|
|
|
fontData.mFullName);
|
|
|
|
gfxFontUtils::ReadCanonicalName(nameData, nameSize,
|
|
|
|
gfxFontUtils::NAME_ID_POSTSCRIPT,
|
|
|
|
fontData.mPostscriptName);
|
|
|
|
dwFontFace->ReleaseFontTable(ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
haveData = !fontData.mPostscriptName.IsEmpty() ||
|
|
|
|
!fontData.mFullName.IsEmpty();
|
|
|
|
if (haveData) {
|
|
|
|
mLoadStats.facenames++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// cmaps
|
|
|
|
if (mLoadCmaps) {
|
|
|
|
if (!dwFontFace) {
|
|
|
|
hr = dwFont->CreateFontFace(getter_AddRefs(dwFontFace));
|
|
|
|
if (!SUCCEEDED(hr)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t kCMAP =
|
|
|
|
NativeEndian::swapToBigEndian(TRUETYPE_TAG('c','m','a','p'));
|
|
|
|
const uint8_t *cmapData;
|
|
|
|
BOOL exists;
|
|
|
|
void* ctx;
|
|
|
|
uint32_t cmapSize;
|
|
|
|
|
|
|
|
hr = dwFontFace->TryGetFontTable(kCMAP,
|
|
|
|
(const void**)&cmapData, &cmapSize, &ctx, &exists);
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
bool cmapLoaded = false;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
|
2014-01-29 11:39:01 +04:00
|
|
|
uint32_t offset;
|
|
|
|
|
|
|
|
if (cmapData &&
|
|
|
|
cmapSize > 0 &&
|
|
|
|
NS_SUCCEEDED(
|
|
|
|
gfxFontUtils::ReadCMAP(cmapData, cmapSize, *charmap,
|
2017-09-11 21:23:30 +03:00
|
|
|
offset))) {
|
2014-01-29 11:39:01 +04:00
|
|
|
fontData.mCharacterMap = charmap;
|
|
|
|
fontData.mUVSOffset = offset;
|
|
|
|
cmapLoaded = true;
|
|
|
|
mLoadStats.cmaps++;
|
|
|
|
}
|
|
|
|
dwFontFace->ReleaseFontTable(ctx);
|
|
|
|
haveData = haveData || cmapLoaded;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if have data, load
|
|
|
|
if (haveData) {
|
|
|
|
mFontFaceData.Put(fullID, fontData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<FontInfoData>
|
|
|
|
gfxDWriteFontList::CreateFontInfoData()
|
|
|
|
{
|
|
|
|
bool loadCmaps = !UsesSystemFallback() ||
|
|
|
|
gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<DirectWriteFontInfo> fi =
|
2014-05-29 16:01:07 +04:00
|
|
|
new DirectWriteFontInfo(false, NeedFullnamePostscriptNames(), loadCmaps,
|
|
|
|
mSystemFonts
|
|
|
|
#ifdef MOZ_BUNDLED_FONTS
|
|
|
|
, mBundledFonts
|
|
|
|
#endif
|
|
|
|
);
|
2014-01-29 11:39:01 +04:00
|
|
|
|
|
|
|
return fi.forget();
|
|
|
|
}
|
2014-05-29 16:01:07 +04:00
|
|
|
|
2017-08-01 13:25:35 +03:00
|
|
|
gfxFontFamily*
|
|
|
|
gfxDWriteFontList::CreateFontFamily(const nsAString& aName) const
|
|
|
|
{
|
|
|
|
return new gfxDWriteFontFamily(aName, nullptr);
|
|
|
|
}
|
|
|
|
|
2014-05-29 16:01:07 +04:00
|
|
|
|
|
|
|
#ifdef MOZ_BUNDLED_FONTS
|
|
|
|
|
|
|
|
#define IMPL_QI_FOR_DWRITE(_interface) \
|
|
|
|
public: \
|
|
|
|
IFACEMETHOD(QueryInterface) (IID const& riid, void** ppvObject) \
|
|
|
|
{ \
|
|
|
|
if (__uuidof(_interface) == riid) { \
|
|
|
|
*ppvObject = this; \
|
|
|
|
} else if (__uuidof(IUnknown) == riid) { \
|
|
|
|
*ppvObject = this; \
|
|
|
|
} else { \
|
|
|
|
*ppvObject = nullptr; \
|
|
|
|
return E_NOINTERFACE; \
|
|
|
|
} \
|
|
|
|
this->AddRef(); \
|
|
|
|
return S_OK; \
|
|
|
|
}
|
|
|
|
|
|
|
|
class BundledFontFileEnumerator
|
|
|
|
: public IDWriteFontFileEnumerator
|
|
|
|
{
|
|
|
|
IMPL_QI_FOR_DWRITE(IDWriteFontFileEnumerator)
|
|
|
|
|
|
|
|
NS_INLINE_DECL_REFCOUNTING(BundledFontFileEnumerator)
|
|
|
|
|
|
|
|
public:
|
|
|
|
BundledFontFileEnumerator(IDWriteFactory *aFactory,
|
|
|
|
nsIFile *aFontDir);
|
|
|
|
|
|
|
|
IFACEMETHODIMP MoveNext(BOOL * hasCurrentFile);
|
|
|
|
|
|
|
|
IFACEMETHODIMP GetCurrentFontFile(IDWriteFontFile ** fontFile);
|
|
|
|
|
|
|
|
private:
|
2015-01-07 02:35:02 +03:00
|
|
|
BundledFontFileEnumerator() = delete;
|
|
|
|
BundledFontFileEnumerator(const BundledFontFileEnumerator&) = delete;
|
|
|
|
BundledFontFileEnumerator& operator=(const BundledFontFileEnumerator&) = delete;
|
2015-08-03 21:59:00 +03:00
|
|
|
virtual ~BundledFontFileEnumerator() {}
|
2014-05-29 16:01:07 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteFactory> mFactory;
|
2014-05-29 16:01:07 +04:00
|
|
|
|
|
|
|
nsCOMPtr<nsIFile> mFontDir;
|
|
|
|
nsCOMPtr<nsISimpleEnumerator> mEntries;
|
|
|
|
nsCOMPtr<nsISupports> mCurrent;
|
|
|
|
};
|
|
|
|
|
|
|
|
BundledFontFileEnumerator::BundledFontFileEnumerator(IDWriteFactory *aFactory,
|
|
|
|
nsIFile *aFontDir)
|
|
|
|
: mFactory(aFactory)
|
|
|
|
, mFontDir(aFontDir)
|
|
|
|
{
|
|
|
|
mFontDir->GetDirectoryEntries(getter_AddRefs(mEntries));
|
|
|
|
}
|
|
|
|
|
|
|
|
IFACEMETHODIMP
|
|
|
|
BundledFontFileEnumerator::MoveNext(BOOL * aHasCurrentFile)
|
|
|
|
{
|
|
|
|
bool hasMore = false;
|
|
|
|
if (mEntries) {
|
|
|
|
if (NS_SUCCEEDED(mEntries->HasMoreElements(&hasMore)) && hasMore) {
|
|
|
|
if (NS_SUCCEEDED(mEntries->GetNext(getter_AddRefs(mCurrent)))) {
|
|
|
|
hasMore = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*aHasCurrentFile = hasMore;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
IFACEMETHODIMP
|
|
|
|
BundledFontFileEnumerator::GetCurrentFontFile(IDWriteFontFile ** aFontFile)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIFile> file = do_QueryInterface(mCurrent);
|
|
|
|
if (!file) {
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
nsString path;
|
|
|
|
if (NS_FAILED(file->GetPath(path))) {
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
return mFactory->CreateFontFileReference((const WCHAR*)path.get(),
|
|
|
|
nullptr, aFontFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
class BundledFontLoader
|
|
|
|
: public IDWriteFontCollectionLoader
|
|
|
|
{
|
|
|
|
IMPL_QI_FOR_DWRITE(IDWriteFontCollectionLoader)
|
|
|
|
|
|
|
|
NS_INLINE_DECL_REFCOUNTING(BundledFontLoader)
|
|
|
|
|
|
|
|
public:
|
|
|
|
BundledFontLoader()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
IFACEMETHODIMP CreateEnumeratorFromKey(
|
|
|
|
IDWriteFactory *aFactory,
|
|
|
|
const void *aCollectionKey,
|
|
|
|
UINT32 aCollectionKeySize,
|
|
|
|
IDWriteFontFileEnumerator **aFontFileEnumerator);
|
|
|
|
|
|
|
|
private:
|
2015-01-07 02:35:02 +03:00
|
|
|
BundledFontLoader(const BundledFontLoader&) = delete;
|
|
|
|
BundledFontLoader& operator=(const BundledFontLoader&) = delete;
|
2015-08-03 21:59:00 +03:00
|
|
|
virtual ~BundledFontLoader() { }
|
2014-05-29 16:01:07 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
IFACEMETHODIMP
|
|
|
|
BundledFontLoader::CreateEnumeratorFromKey(
|
|
|
|
IDWriteFactory *aFactory,
|
|
|
|
const void *aCollectionKey,
|
|
|
|
UINT32 aCollectionKeySize,
|
|
|
|
IDWriteFontFileEnumerator **aFontFileEnumerator)
|
|
|
|
{
|
|
|
|
nsIFile *fontDir = *(nsIFile**)aCollectionKey;
|
|
|
|
*aFontFileEnumerator = new BundledFontFileEnumerator(aFactory, fontDir);
|
2016-05-09 20:02:45 +03:00
|
|
|
NS_ADDREF(*aFontFileEnumerator);
|
2014-05-29 16:01:07 +04:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<IDWriteFontCollection>
|
|
|
|
gfxDWriteFontList::CreateBundledFontsCollection(IDWriteFactory* aFactory)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIFile> localDir;
|
|
|
|
nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(localDir));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (NS_FAILED(localDir->Append(NS_LITERAL_STRING("fonts")))) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
bool isDir;
|
|
|
|
if (NS_FAILED(localDir->IsDirectory(&isDir)) || !isDir) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<BundledFontLoader> loader = new BundledFontLoader();
|
2014-05-29 16:01:07 +04:00
|
|
|
if (FAILED(aFactory->RegisterFontCollectionLoader(loader))) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
const void *key = localDir.get();
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IDWriteFontCollection> collection;
|
2014-05-29 16:01:07 +04:00
|
|
|
HRESULT hr =
|
|
|
|
aFactory->CreateCustomFontCollection(loader, &key, sizeof(key),
|
|
|
|
getter_AddRefs(collection));
|
|
|
|
|
|
|
|
aFactory->UnregisterFontCollectionLoader(loader);
|
|
|
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return nullptr;
|
|
|
|
} else {
|
|
|
|
return collection.forget();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|