/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- * 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/. */
// for use in reading postscript or fullname static HRESULT GetDirectWriteFaceName(IDWriteFont* aFont,
DWRITE_INFORMATIONAL_STRING_ID aWhichName,
nsACString& aFontName) {
HRESULT hr;
for (UINT32 i = 0; i < mDWFamily->GetFontCount(); i++) {
RefPtr<IDWriteFont> font;
hr = mDWFamily->GetFont(i, getter_AddRefs(font)); if (FAILED(hr)) { // This should never happen.
NS_WARNING("Failed to get existing font from family."); continue;
}
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. continue;
}
// name
nsCString fullID(mName);
nsAutoCString faceName;
hr = GetDirectWriteFontName(font, faceName); if (FAILED(hr)) { continue;
}
fullID.Append(' ');
fullID.Append(faceName);
// 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;
}
gfxDWriteFontEntry* fe = new gfxDWriteFontEntry(fullID, font, mIsSystemFontFamily);
fe->SetForceGDIClassic(mForceGDIClassic);
fe->SetupVariationRanges();
AddFontEntryLocked(fe);
// postscript/fullname if needed
nsAutoCString psname, fullname; if (fontInfoShouldHaveFaceNames) {
aFontInfoData->GetFaceNames(fe->Name(), fullname, psname); if (!fullname.IsEmpty()) {
fp->AddFullname(fe, fullname);
} if (!psname.IsEmpty()) {
fp->AddPostscriptName(fe, psname);
}
} elseif (!skipFaceNames) {
hr = GetDirectWriteFaceName(font, PSNAME_ID, psname); if (FAILED(hr)) {
skipFaceNames = true;
} elseif (psname.Length() > 0) {
fp->AddPostscriptName(fe, psname);
}
// assume that if no error, all postscript/fullnames were initialized if (!skipFaceNames) {
mFaceNamesInitialized = true;
}
if (!mAvailableFonts.Length()) {
NS_WARNING("Family with no font faces in it.");
}
if (mIsBadUnderlineFamily) {
SetBadUnderlineFonts();
}
CheckForSimpleFamily(); if (mIsSimpleFamily) { for (auto& f : mAvailableFonts) { if (f) { static_cast<gfxDWriteFontEntry*>(f.get())->mMayUseGDIAccess = true;
}
}
}
}
void gfxDWriteFontFamily::ReadFaceNames(gfxPlatformFontList* aPlatformFontList, bool aNeedFullnamePostscriptNames,
FontInfoData* aFontInfoData) { // if all needed names have already been read, skip if (mOtherFamilyNamesInitialized &&
(mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) { return;
}
// 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();
}
// fallback to looking up via name table if (!mOtherFamilyNamesInitialized || !mFaceNamesInitialized) {
gfxFontFamily::ReadFaceNames(aPlatformFontList,
aNeedFullnamePostscriptNames, aFontInfoData);
}
}
void gfxDWriteFontFamily::LocalizedName(nsACString& aLocalizedName) {
aLocalizedName = Name(); // just return canonical name in case of failure
if (!mDWFamily) { return;
}
HRESULT hr;
nsAutoCString locale; // We use system locale here because it's what user expects to see. // See bug 1349454 for details.
RefPtr<OSPreferences> osprefs = OSPreferences::GetInstanceAddRefed(); if (!osprefs) { return;
}
osprefs->GetSystemLocale(locale);
RefPtr<IDWriteLocalizedStrings> names;
hr = mDWFamily->GetFamilyNames(getter_AddRefs(names)); if (FAILED(hr)) { return;
}
UINT32 idx = 0; BOOL exists;
hr =
names->FindLocaleName(NS_ConvertUTF8toUTF16(locale).get(), &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;
}
}
AutoTArray<WCHAR, 32> famName;
UINT32 length;
hr = names->GetStringLength(idx, &length); if (FAILED(hr)) { return;
}
if (!famName.SetLength(length + 1, fallible)) { // Eeep - running out of memory. Unlikely to end well. return;
}
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();
}
} returnfalse;
}
void gfxDWriteFontFamily::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
FontListSizes* aSizes) const {
gfxFontFamily::AddSizeOfExcludingThis(aMallocSizeOf, aSizes); // TODO: // This doesn't currently account for |mDWFamily|
}
gfxFontEntry* gfxDWriteFontEntry::Clone() const {
MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!");
gfxDWriteFontEntry* fe = new gfxDWriteFontEntry(Name(), mFont);
fe->mWeightRange = mWeightRange;
fe->mStretchRange = mStretchRange;
fe->mStyleRange = mStyleRange; return fe;
}
gfxDWriteFontEntry::~gfxDWriteFontEntry() {}
staticbool UsingArabicOrHebrewScriptSystemLocale() {
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: case LANG_HEBREW: returntrue; default: returnfalse;
}
}
if (tableContext) {
fontFace->ReleaseFontTable(&tableContext);
}
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) {
MOZ_COUNT_CTOR(FontTableRec);
}
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);
}
bool setCharMap = true; if (NS_SUCCEEDED(rv)) { // 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);
}
gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
fontlist::FontList* sharedFontList = pfl->SharedFontList(); if (!IsUserFont() && mShmemFace) {
mShmemFace->SetCharacterMap(sharedFontList, charmap, mShmemFamily); if (TrySetShmemCharacterMap()) {
setCharMap = false;
}
} else {
charmap = pfl->FindCharMap(charmap);
}
mHasCmapTable = true;
} else { // if error occurred, initialize to null cmap
charmap = new gfxCharacterMap();
mHasCmapTable = false;
} if (setCharMap) { // Temporarily retain charmap, until the shared version is // ready for use. if (mCharacterMap.compareExchange(nullptr, charmap.get())) {
charmap.get()->AddRef();
}
}
if (!gfxPlatform::HasVariationFontSupport()) { return mHasVariations;
}
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 mHasVariations;
}
} if (mFontFace5) {
mHasVariations = mFontFace5->HasVariations();
} return mHasVariations;
}
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)); if (FAILED(hr) || !resource) { return;
}
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);
}
}
gfxFont* gfxDWriteFontEntry::CreateFontInstance( const gfxFontStyle* aFontStyle) { // We use the DirectWrite bold simulation for installed fonts, but NOT for // webfonts; those will use multi-strike synthetic bold instead. bool useBoldSim = false; if (aFontStyle->NeedsSyntheticBold(this)) { switch (StaticPrefs::gfx_font_rendering_directwrite_bold_simulation()) { case 0: // never use the DWrite simulation break; case 1: // use DWrite simulation for installed fonts except COLR fonts, // but not webfonts
useBoldSim =
!mIsDataUserFont && !HasFontTable(TRUETYPE_TAG('C', 'O', 'L', 'R')); break; default: // always use DWrite bold simulation, except for COLR fonts
useBoldSim = !HasFontTable(TRUETYPE_TAG('C', 'O', 'L', 'R')); break;
}
}
DWRITE_FONT_SIMULATIONS sims =
useBoldSim ? DWRITE_FONT_SIMULATIONS_BOLD : DWRITE_FONT_SIMULATIONS_NONE;
ThreadSafeWeakPtr<UnscaledFontDWrite>& unscaledFontPtr =
useBoldSim ? mUnscaledFontBold : mUnscaledFont;
RefPtr<UnscaledFontDWrite> unscaledFont(unscaledFontPtr); if (!unscaledFont) {
RefPtr<IDWriteFontFace> fontFace;
nsresult rv =
CreateFontFace(getter_AddRefs(fontFace), nullptr, sims, nullptr); if (NS_FAILED(rv)) { return nullptr;
} // Only pass in the underlying IDWriteFont if the unscaled font doesn't // reflect a data font. This signals whether or not we can safely query // a descriptor to represent the font for various transport use-cases.
unscaledFont = new UnscaledFontDWrite(fontFace, !mIsDataUserFont ? mFont : nullptr);
unscaledFontPtr = unscaledFont;
}
RefPtr<IDWriteFontFace> fontFace; if (HasVariations()) { // Get the variation settings needed to instantiate the fontEntry // for a particular fontStyle.
AutoTArray<gfxFontVariation, 4> vars;
GetVariationsForStyle(vars, *aFontStyle);
nsresult gfxDWriteFontEntry::CreateFontFace(
IDWriteFontFace** aFontFace, const gfxFontStyle* aFontStyle,
DWRITE_FONT_SIMULATIONS aSimulations, const nsTArray<gfxFontVariation>* aVariations) { // 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);
};
MOZ_SEH_TRY { // initialize mFontFace if this hasn't been done before if (!mFontFace) {
HRESULT hr; if (mFont) {
hr = mFont->CreateFontFace(getter_AddRefs(mFontFace));
} elseif (mFontFile) {
IDWriteFontFile* fontFile = mFontFile.get();
hr = Factory::GetDWriteFactory()->CreateFontFace(
mFaceType, 1, &fontFile, 0, DWRITE_FONT_SIMULATIONS_NONE,
getter_AddRefs(mFontFace));
} else {
MOZ_ASSERT_UNREACHABLE("invalid font entry"); return NS_ERROR_FAILURE;
} if (FAILED(hr)) { return NS_ERROR_FAILURE;
} // 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)); 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)); if (SUCCEEDED(hr) && resource) {
AutoTArray<DWRITE_FONT_AXIS_VALUE, 4> fontAxisValues; for (constauto& 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));
}
}
}
}
// 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 try using // IDWriteFontResource to create a new modified face. if (mFontFace5 && (HasVariations() || needSimulations)) {
RefPtr<IDWriteFontResource> resource;
HRESULT hr = mFontFace5->GetFontResource(getter_AddRefs(resource)); if (SUCCEEDED(hr) && resource) {
AutoTArray<DWRITE_FONT_AXIS_VALUE, 4> fontAxisValues;
// Copy variation settings to DWrite's type. if (aVariations) { for (constauto& v : *aVariations) {
DWRITE_FONT_AXIS_VALUE axisValue = {makeDWriteAxisTag(v.mTag),
v.mValue};
fontAxisValues.AppendElement(axisValue);
}
}
// Do we need to add DWrite simulations to the face? if (needSimulations) { // if so, we need to return not mFontFace itself but a version that // has the Bold simulation - unfortunately, old DWrite doesn't provide // a simple API for this
UINT32 numberOfFiles = 0; if (FAILED(mFontFace->GetFiles(&numberOfFiles, nullptr))) { return NS_ERROR_FAILURE;
}
AutoTArray<IDWriteFontFile*, 1> files;
files.AppendElements(numberOfFiles); if (FAILED(mFontFace->GetFiles(&numberOfFiles, files.Elements()))) { return NS_ERROR_FAILURE;
}
HRESULT hr = Factory::GetDWriteFactory()->CreateFontFace(
mFontFace->GetType(), numberOfFiles, files.Elements(),
mFontFace->GetIndex(), aSimulations, aFontFace); for (UINT32 i = 0; i < numberOfFiles; ++i) {
files[i]->Release();
} return FAILED(hr) ? NS_ERROR_FAILURE : NS_OK;
}
}
MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
gfxCriticalNote << "Exception occurred creating font face for "
<< mName.get();
}
// 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;
}
(*aFontFace)->AddRef(); return NS_OK;
}
BOOL isInSystemCollection;
IDWriteGdiInterop* gdi =
gfxDWriteFontList::PlatformFontList()->GetGDIInterop();
hr = gdi->ConvertFontToLOGFONT(aFont, aLogFont, &isInSystemCollection); // 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);
}
uint32_t len; const OS2Table* os2 = reinterpret_cast<const OS2Table*>(hb_blob_get_data(blob, &len)); // ulCodePageRange bit definitions for the CJK codepages, // from http://www.microsoft.com/typography/otspec/os2.htm#cpr const uint32_t CJK_CODEPAGE_BITS =
(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 if (len >= offsetof(OS2Table, sxHeight)) { if ((uint32_t(os2->codePageRange1) & CJK_CODEPAGE_BITS) != 0) {
mIsCJK = true;
}
}
return mIsCJK;
}
void gfxDWriteFontEntry::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
FontListSizes* aSizes) const {
gfxFontEntry::AddSizeOfExcludingThis(aMallocSizeOf, aSizes); // TODO: // This doesn't currently account for the |mFont| and |mFontFile| members
}
// 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.
nsAutoString uniqueName;
nsresult rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to make unique user font name"); if (NS_FAILED(rv)) { return nullptr;
}
auto entry = MakeUnique<gfxDWriteFontEntry>(
NS_ConvertUTF16toUTF8(uniqueName), fontFile, fontFileStream,
aWeightForEntry, aStretchForEntry, aStyleForEntry);
hr = fontFile->Analyze(&isSupported, &fileType, &entry->mFaceType, &numFaces);
NS_ASSERTION(SUCCEEDED(hr), "IDWriteFontFile::Analyze failed"); if (FAILED(hr)) { return nullptr;
}
NS_ASSERTION(isSupported, "Unsupported font file"); if (!isSupported) { return nullptr;
}
NS_ASSERTION(numFaces == 1, "Font file does not contain exactly 1 face"); if (numFaces != 1) { // We don't know how to deal with 0 faces either. return nullptr;
}
return entry.release();
}
bool gfxDWriteFontList::UseGDIFontTableAccess() const { // Using GDI font table access for DWrite is controlled by a pref, but also we // must be able to make win32k calls. return mGDIFontTableAccess && !IsWin32kLockedDown();
}
// The DirectWrite calls here might throw exceptions, e.g. in case of disk // errors when trying to read the font file.
MOZ_SEH_TRY { if (aFamily->Index() < collection->GetFontFamilyCount()) {
HRESULT hr =
collection->GetFontFamily(aFamily->Index(), getter_AddRefs(family)); // Check that the family name is what we expected; if not, fall back to // search by name. It's sad we have to do this, but it is possible for // Windows to have given different versions of the system font collection // to the parent and child processes. if (SUCCEEDED(hr) && family) {
RefPtr<IDWriteLocalizedStrings> names;
hr = family->GetFamilyNames(getter_AddRefs(names)); if (SUCCEEDED(hr) && names) {
nsAutoCString name; if (GetEnglishOrFirstName(name, names)) {
foundExpectedFamily = name.Equals(familyName);
}
}
}
} if (!foundExpectedFamily) { // Try to get family by name instead of index (to deal with the case of // collection mismatch).
UINT32 index; BOOL exists;
NS_ConvertUTF8toUTF16 name16(familyName);
HRESULT hr = collection->FindFamilyName( reinterpret_cast<const WCHAR*>(name16.BeginReading()), &index,
&exists); if (FAILED(hr) || !exists || index == UINT_MAX ||
FAILED(collection->GetFontFamily(index, getter_AddRefs(family))) ||
!family) { return nullptr;
}
}
// Retrieve the required face by index within the family.
RefPtr<IDWriteFont> font; if (FAILED(family->GetFont(aFace->mIndex, getter_AddRefs(font))) || !font) { return nullptr;
}
// Retrieve the psName from the font, so we can check we've found the // expected face.
nsAutoCString psName; if (FAILED(GetDirectWriteFaceName(font, PSNAME_ID, psName))) {
RefPtr<IDWriteFontFace> dwFontFace; if (SUCCEEDED(font->CreateFontFace(getter_AddRefs(dwFontFace)))) {
GetPostScriptNameFromNameTable(dwFontFace, psName);
}
}
// If it doesn't match, DirectWrite must have shuffled the order of faces // returned for the family; search by name as a fallback.
nsCString faceName = aFace->mDescriptor.AsString(SharedFontList()); if (psName != faceName) {
gfxWarning() << "Face name mismatch for index " << aFace->mIndex
<< " in family " << familyName.get() << ": expected "
<< faceName.get() << ", found " << psName.get(); for (uint32_t i = 0; i < family->GetFontCount(); ++i) { if (i == aFace->mIndex) { continue; // this was the face we already tried
} if (FAILED(family->GetFont(i, getter_AddRefs(font))) || !font) { return nullptr; // this font family is broken!
} if (FAILED(GetDirectWriteFaceName(font, PSNAME_ID, psName))) {
RefPtr<IDWriteFontFace> dwFontFace; if (SUCCEEDED(font->CreateFontFace(getter_AddRefs(dwFontFace)))) {
GetPostScriptNameFromNameTable(dwFontFace, psName);
}
} if (psName == faceName) { break;
}
}
} if (psName != faceName) { return nullptr;
}
auto fe = new gfxDWriteFontEntry(faceName, font, !aFamily->IsBundled());
fe->InitializeFrom(aFace, aFamily);
fe->mForceGDIClassic = aFamily->IsForceClassic();
fe->mMayUseGDIAccess = aFamily->IsSimple(); return fe;
}
MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
gfxCriticalNote << "Exception occurred while creating font entry for "
<< familyName.get();
} return nullptr;
}
auto visibilityForName = [&](const nsACString& aName) -> FontVisibility { // Special case: hide the "Gill Sans" family that contains only UltraBold // faces, as this leads to breakage on sites with CSS that targeted the // Gill Sans family as found on macOS. (Bug 551313, bug 1632738) // TODO (jfkthame): the ultrabold faces from Gill Sans should be treated // as belonging to the Gill Sans MT family. if (aName.EqualsLiteral("Gill Sans") && allFacesUltraBold(family)) { return FontVisibility::Hidden;
} // Bundled fonts are always available, so only system fonts are checked // against the standard font names list. return aCollection == mSystemFonts ? GetVisibilityForFamily(aName)
: FontVisibility::Base;
};
unsigned count = localizedNames->GetCount(); if (count == 1) { // This is the common case: the great majority of fonts only provide an // en-US family name.
nsAutoCString name; if (!GetNameAsUtf8(name, localizedNames, 0)) {
gfxWarning() << "GetNameAsUtf8 failed for index 0 in font-family " << i; continue;
}
addFamily(name, visibilityForName(name));
} else {
AutoTArray<nsCString, 4> names; int sysLocIndex = -1;
FontVisibility visibility = FontVisibility::User; for (unsigned index = 0; index < count; ++index) {
nsAutoCString name; if (!GetNameAsUtf8(name, localizedNames, index)) {
gfxWarning() << "GetNameAsUtf8 failed for index " << index
<< " in font-family " << i; continue;
} if (names.Contains(name)) { continue;
} if (sysLocIndex == -1) {
WCHAR buf[32]; if (SUCCEEDED(localizedNames->GetLocaleName(index, buf, 32))) { if (loc16.Equals(buf)) {
sysLocIndex = names.Length();
}
}
}
names.AppendElement(name); // We give the family the least-restrictive visibility of all its // localized names, so that the used visibility will not depend on // locale; with the exception that if any name is explicitly Hidden, // this hides the family as a whole. if (visibility != FontVisibility::Hidden) {
FontVisibility v = visibilityForName(name); if (v == FontVisibility::Hidden) {
visibility = FontVisibility::Hidden;
} else {
visibility = std::min(visibility, v);
}
}
} // If we didn't find a name that matched the system locale, use the // first (which is most often en-US). if (sysLocIndex == -1) {
sysLocIndex = 0;
} // Hack to work around EPSON fonts with bad names (tagged as MacRoman // but actually contain MacJapanese data): if we've chosen the first // name, *and* it is non-ASCII, *and* there is an alternative present, // use the next option instead as being more likely to be valid. if (sysLocIndex == 0 && names.Length() > 1 && !IsAscii(names[0])) {
sysLocIndex = 1;
} for (unsigned index = 0; index < names.Length(); ++index) {
addFamily(names[index], visibility,
index != static_cast<unsigned>(sysLocIndex));
}
}
}
}
void gfxDWriteFontList::GetFacesInitDataForFamily( const fontlist::Family* aFamily, nsTArray<fontlist::Face::InitData>& aFaces, bool aLoadCmaps) const {
IDWriteFontCollection* collection = #ifdef MOZ_BUNDLED_FONTS
aFamily->IsBundled() ? mBundledFonts : mSystemFonts; #else
mSystemFonts; #endif if (!collection) { return;
}
RefPtr<IDWriteFontFamily> family;
collection->GetFontFamily(aFamily->Index(), getter_AddRefs(family)); for (unsigned i = 0; i < family->GetFontCount(); ++i) {
RefPtr<IDWriteFont> dwFont;
family->GetFont(i, getter_AddRefs(dwFont)); if (!dwFont || dwFont->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) { continue;
}
DWRITE_FONT_STYLE dwstyle = dwFont->GetStyle(); // Ignore italic styles of 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 (dwstyle != DWRITE_FONT_STYLE_NORMAL &&
aFamily->Key().AsString(SharedFontList()).EqualsLiteral("meiryo")) { continue;
}
WeightRange weight(FontWeight::FromInt(dwFont->GetWeight()));
StretchRange stretch(FontStretchFromDWriteStretch(dwFont->GetStretch())); // Try to read PSName as a unique face identifier; if this fails we'll get // it directly from the 'name' table, and if that also fails we consider // the face unusable.
MOZ_SEH_TRY {
nsAutoCString name;
RefPtr<gfxCharacterMap> charmap; if (FAILED(GetDirectWriteFaceName(dwFont, PSNAME_ID, name)) ||
aLoadCmaps) {
RefPtr<IDWriteFontFace> dwFontFace; if (SUCCEEDED(dwFont->CreateFontFace(getter_AddRefs(dwFontFace)))) { if (name.IsEmpty()) {
GetPostScriptNameFromNameTable(dwFontFace, name);
} constauto kCMAP =
NativeEndian::swapToBigEndian(TRUETYPE_TAG('c', 'm', 'a', 'p')); constchar* data;
UINT32 size; void* context; BOOL exists; if (aLoadCmaps) { if (SUCCEEDED(dwFontFace->TryGetFontTable(
kCMAP, (constvoid**)&data, &size, &context, &exists)) &&
exists) {
charmap = new gfxCharacterMap();
uint32_t offset;
gfxFontUtils::ReadCMAP((const uint8_t*)data, size, *charmap,
offset);
dwFontFace->ReleaseFontTable(context);
}
}
}
} if (name.IsEmpty()) {
gfxWarning() << "Failed to get name for face " << i << " in family "
<< aFamily->Key().AsString(SharedFontList()).get(); continue;
}
SlantStyleRange slant(
dwstyle == DWRITE_FONT_STYLE_NORMAL ? FontSlantStyle::NORMAL
: dwstyle == DWRITE_FONT_STYLE_ITALIC ? FontSlantStyle::ITALIC
: FontSlantStyle::OBLIQUE);
aFaces.AppendElement(fontlist::Face::InitData{
name, uint16_t(i), false, weight, stretch, slant, charmap});
}
MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { // Exception (e.g. disk i/o error) occurred when DirectWrite tried to use // the font resource. We'll just skip the bad face.
gfxCriticalNote << "Exception occurred reading faces for "
<< aFamily->Key().AsString(SharedFontList()).get();
}
}
}
bool gfxDWriteFontList::ReadFaceNames(const fontlist::Family* aFamily, const fontlist::Face* aFace,
nsCString& aPSName,
nsCString& aFullName) {
IDWriteFontCollection* collection = #ifdef MOZ_BUNDLED_FONTS
aFamily->IsBundled() ? mBundledFonts : mSystemFonts; #else
mSystemFonts; #endif
RefPtr<IDWriteFontFamily> family; if (FAILED(collection->GetFontFamily(aFamily->Index(),
getter_AddRefs(family)))) {
MOZ_ASSERT_UNREACHABLE("failed to get font-family"); returnfalse;
}
RefPtr<IDWriteFont> dwFont; if (FAILED(family->GetFont(aFace->mIndex, getter_AddRefs(dwFont)))) {
MOZ_ASSERT_UNREACHABLE("failed to get font from family"); returnfalse;
}
HRESULT ps = GetDirectWriteFaceName(dwFont, PSNAME_ID, aPSName);
HRESULT full = GetDirectWriteFaceName(dwFont, FULLNAME_ID, aFullName); if (FAILED(ps) || FAILED(full) || aPSName.IsEmpty() || aFullName.IsEmpty()) { // We'll return true if either name was found, false if both fail. // Note that on older Win7 systems, GetDirectWriteFaceName may "succeed" // but return an empty string, so we have to check for non-empty strings // to be sure we actually got a usable name.
// Initialize result to true if either name was already found. bool result = (SUCCEEDED(ps) && !aPSName.IsEmpty()) ||
(SUCCEEDED(full) && !aFullName.IsEmpty());
RefPtr<IDWriteFontFace> dwFontFace; if (FAILED(dwFont->CreateFontFace(getter_AddRefs(dwFontFace)))) {
NS_WARNING("failed to create font face"); return result;
} void* context; constchar* data;
UINT32 size; BOOL exists; if (FAILED(dwFontFace->TryGetFontTable(
NativeEndian::swapToBigEndian(TRUETYPE_TAG('n', 'a', 'm', 'e')),
(constvoid**)&data, &size, &context, &exists)) ||
!exists) {
NS_WARNING("failed to get name table"); return result;
}
MOZ_SEH_TRY { // Try to read the name table entries, and ensure result is true if either // one succeeds. if (FAILED(ps) || aPSName.IsEmpty()) { if (NS_SUCCEEDED(gfxFontUtils::ReadCanonicalName(
data, size, gfxFontUtils::NAME_ID_POSTSCRIPT, aPSName))) {
result = true;
} else {
NS_WARNING("failed to read psname");
}
} if (FAILED(full) || aFullName.IsEmpty()) { if (NS_SUCCEEDED(gfxFontUtils::ReadCanonicalName(
data, size, gfxFontUtils::NAME_ID_FULL, aFullName))) {
result = true;
} else {
NS_WARNING("failed to read fullname");
}
}
}
MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
gfxCriticalNote << "Exception occurred reading face names for "
<< aFamily->Key().AsString(SharedFontList()).get();
} if (dwFontFace && context) {
dwFontFace->ReleaseFontTable(context);
} return result;
} returntrue;
}
MOZ_SEH_TRY { // Read PS-names and fullnames of the faces, and any alternate family names // (either localizations or legacy subfamily names) for (unsigned i = 0; i < aFamily->NumFaces(); ++i) { auto* face = facePtrs[i].ToPtr<fontlist::Face>(list); if (!face) { continue;
}
RefPtr<IDWriteFont> dwFont; if (FAILED(family->GetFont(face->mIndex, getter_AddRefs(dwFont)))) { continue;
}
RefPtr<IDWriteFontFace> dwFontFace; if (FAILED(dwFont->CreateFontFace(getter_AddRefs(dwFontFace)))) { continue;
}
AutoTArray<nsCString, 4> otherFamilyNames;
gfxFontUtils::ReadOtherFamilyNamesForFace(familyName, data, size,
otherFamilyNames, false); for (constauto& alias : otherFamilyNames) {
nsAutoCString key(alias);
ToLowerCase(key); auto aliasData = mAliasTable.GetOrInsertNew(key);
aliasData->InitFromFamily(aFamily, familyName);
aliasData->mFaces.AppendElement(facePtrs[i]);
}
nsAutoCString psname, fullname; // Bug 1854090: don't load PSname if the family name ends with ".tmp", // as some PDF-related software appears to pollute the font collection // with spurious re-encoded versions of standard fonts like Arial, fails // to alter the PSname, and thus can result in garbled rendering because // the wrong resource may be found via src:local(...). if (!StringEndsWith(key, ".tmp"_ns)) { if (NS_SUCCEEDED(gfxFontUtils::ReadCanonicalName(
data, size, gfxFontUtils::NAME_ID_POSTSCRIPT, psname))) {
ToLowerCase(psname);
MaybeAddToLocalNameTable(psname,
fontlist::LocalFaceRec::InitData(key, i));
}
} if (NS_SUCCEEDED(gfxFontUtils::ReadCanonicalName(
data, size, gfxFontUtils::NAME_ID_FULL, fullname))) {
ToLowerCase(fullname); if (fullname != psname) {
MaybeAddToLocalNameTable(fullname,
fontlist::LocalFaceRec::InitData(key, i));
}
}
if (!mSystemFonts) {
glean::fontlist::dwritefont_init_problem.AccumulateSingleSample(
uint32_t(errSystemFontCollection)); return NS_ERROR_FAILURE;
}
#ifdef MOZ_BUNDLED_FONTS // Get bundled fonts before the system collection, so that in the case of // duplicate names, we have recorded the family as bundled (and therefore // available regardless of visibility settings). // We activate bundled fonts if the pref is > 0 (on) or < 0 (auto), only an // explicit value of 0 (off) will disable them. if (StaticPrefs::gfx_bundled_fonts_activate_AtStartup() != 0) { auto timerId = glean::fontlist::bundledfonts_activate.Start();
mBundledFonts = CreateBundledFontsCollection(factory); if (mBundledFonts) {
GetFontsFromCollection(mBundledFonts);
}
glean::fontlist::bundledfonts_activate.StopAndAccumulate(
std::move(timerId));
} #endif const uint32_t kBundledCount = mFontFamilies.Count();
QueryPerformanceCounter(&t3); // system font collection
GetFontsFromCollection(mSystemFonts);
// if no fonts found, something is out of whack, bail and use GDI backend
NS_ASSERTION(mFontFamilies.Count() > kBundledCount, "no fonts found in the system fontlist -- holy crap batman!"); if (mFontFamilies.Count() == kBundledCount) {
glean::fontlist::dwritefont_init_problem.AccumulateSingleSample(
uint32_t(errNoFonts)); return NS_ERROR_FAILURE;
}
QueryPerformanceCounter(&t4); // iterate over system fonts
// 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();
// bug 551313 - DirectWrite creates a Gill Sans family out of // 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
nsAutoCString nameGillSans("Gill Sans");
nsAutoCString nameGillSansMT("Gill Sans MT");
BuildKeyNameFromFontName(nameGillSans);
BuildKeyNameFromFontName(nameGillSansMT);
bool allUltraBold = true; for (constauto& face : faces) { // does the face have 'Ultra Bold' in the name? if (face->Name().Find("Ultra Bold"_ns) == -1) {
allUltraBold = false; 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 (constauto& face : faces) { // change the entry's family name to match its adoptive family
face->mFamilyName = gillSansMTFamily->Name();
gillSansMTFamily->AddFontEntry(face);
if (LOG_FONTLIST_ENABLED()) {
nsAutoCString weightString;
face->Weight().ToString(weightString);
LOG_FONTLIST(
("(fontlist) moved (%s) to family (%s)" " with style: %s weight: %s stretch: %d",
face->Name().get(), gillSansMTFamily->Name().get(),
(face->IsItalic()) ? "italic"
: (face->IsOblique() ? "oblique" : "normal"),
weightString.get(), face->Stretch().AsScalar()));
}
}
gillSansFamily->ReadUnlock();
nsAutoCString name; if (!GetEnglishOrFirstName(name, names)) { continue;
}
nsAutoCString familyName(
name); // keep a copy before we lowercase it as a key
BuildKeyNameFromFontName(name);
RefPtr<gfxFontFamily> fam;
if (mFontFamilies.GetWeak(name)) { continue;
}
--> --------------------
--> maximum size reached
--> --------------------
¤ Dauer der Verarbeitung: 0.20 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.