author | Myk Melez <myk@mykzilla.org> |
Tue, 12 Sep 2017 11:05:37 -0700 | |
changeset 380330 | f255ec4e8c361e4526b7bfb1083cecb41fabbdd1 |
parent 380329 | e58e11f74cc02a5aec2b4588190385b1980654e0 |
child 380331 | 246cba2233e3103ac3e0f160c40ccec9e6946ec9 |
push id | 32486 |
push user | archaeopteryx@coole-files.de |
push date | Wed, 13 Sep 2017 09:28:25 +0000 |
treeherder | mozilla-central@987326974635 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jfkthame, nhnt11 |
bugs | 1375978 |
milestone | 57.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/components/preferences/fonts.js +++ b/browser/components/preferences/fonts.js @@ -14,17 +14,28 @@ const kFontNameFmtMonospace = "font. const kFontNameListFmtSerif = "font.name-list.serif.%LANG%"; const kFontNameListFmtSansSerif = "font.name-list.sans-serif.%LANG%"; const kFontNameListFmtMonospace = "font.name-list.monospace.%LANG%"; const kFontSizeFmtVariable = "font.size.variable.%LANG%"; const kFontSizeFmtFixed = "font.size.fixed.%LANG%"; const kFontMinSizeFmt = "font.minimum-size.%LANG%"; var gFontsDialog = { - _selectLanguageGroup(aLanguageGroup) { + _selectLanguageGroupPromise: Promise.resolve(), + + async _selectLanguageGroup(aLanguageGroup) { + // Avoid overlapping language group selections by awaiting the resolution + // of the previous one. We do this because this function is re-entrant, + // as inserting <preference> elements into the DOM sometimes triggers a call + // back into this function. And since this function is also asynchronous, + // that call can enter this function before the previous run has completed, + // which would corrupt the font menulists. Awaiting the previous call's + // resolution avoids that fate. + await this._selectLanguageGroupPromise; + var prefs = [{ format: kDefaultFontType, type: "string", element: "defaultFontType", fonttype: null}, { format: kFontNameFmtSerif, type: "fontname", element: "serif", fonttype: "serif" }, { format: kFontNameFmtSansSerif, type: "fontname", element: "sans-serif", fonttype: "sans-serif" }, { format: kFontNameFmtMonospace, type: "fontname", element: "monospace", fonttype: "monospace" }, { format: kFontNameListFmtSerif, type: "unichar", element: null, fonttype: "serif" }, { format: kFontNameListFmtSansSerif, type: "unichar", element: null, fonttype: "sans-serif" }, { format: kFontNameListFmtMonospace, type: "unichar", element: null, fonttype: "monospace" }, { format: kFontSizeFmtVariable, type: "int", element: "sizeVar", fonttype: null }, @@ -45,26 +56,32 @@ var gFontsDialog = { if (!prefs[i].element) continue; var element = document.getElementById(prefs[i].element); if (element) { element.setAttribute("preference", preference.id); if (prefs[i].fonttype) - FontBuilder.buildFontList(aLanguageGroup, prefs[i].fonttype, element); + await FontBuilder.buildFontList(aLanguageGroup, prefs[i].fonttype, element); preference.setElementValue(element); } } }, + _safelySelectLanguageGroup(aLanguageGroup) { + this._selectLanguageGroupPromise = + this._selectLanguageGroup(aLanguageGroup) + .catch(Components.utils.reportError); + }, + readFontLanguageGroup() { var languagePref = document.getElementById("font.language.group"); - this._selectLanguageGroup(languagePref.value); + this._safelySelectLanguageGroup(languagePref.value); return undefined; }, readUseDocumentFonts() { var preference = document.getElementById("browser.display.use_document_fonts"); return preference.value == 1; },
--- a/browser/components/preferences/in-content/main.js +++ b/browser/components/preferences/in-content/main.js @@ -992,18 +992,17 @@ var gMainPane = { */ _rebuildFonts() { var preferences = document.getElementById("mainPreferences"); // Ensure preferences are "visible" to ensure bindings work. preferences.hidden = false; // Force flush: preferences.clientHeight; var langGroupPref = document.getElementById("font.language.group"); - this._selectDefaultLanguageGroup(langGroupPref.value, - this._readDefaultFontTypeForLanguage(langGroupPref.value) == "serif"); + this._safelySelectDefaultLanguageGroup(langGroupPref.value); }, /** * Returns the type of the current default font for the language denoted by * aLanguageGroup. */ _readDefaultFontTypeForLanguage(aLanguageGroup) { const kDefaultFontType = "font.default.%LANG%"; @@ -1015,17 +1014,28 @@ var gMainPane = { preference.setAttribute("name", defaultFontTypePref); preference.setAttribute("type", "string"); preference.setAttribute("onchange", "gMainPane._rebuildFonts();"); document.getElementById("mainPreferences").appendChild(preference); } return preference.value; }, - _selectDefaultLanguageGroup(aLanguageGroup, aIsSerif) { + _selectDefaultLanguageGroupPromise: Promise.resolve(), + + async _selectDefaultLanguageGroup(aLanguageGroup, aIsSerif) { + // Avoid overlapping language group selections by awaiting the resolution + // of the previous one. We do this because this function is re-entrant, + // as inserting <preference> elements into the DOM sometimes triggers a call + // back into this function. And since this function is also asynchronous, + // that call can enter this function before the previous run has completed, + // which would corrupt the font menulists. Awaiting the previous call's + // resolution avoids that fate. + await this._selectDefaultLanguageGroupPromise; + const kFontNameFmtSerif = "font.name.serif.%LANG%"; const kFontNameFmtSansSerif = "font.name.sans-serif.%LANG%"; const kFontNameListFmtSerif = "font.name-list.serif.%LANG%"; const kFontNameListFmtSansSerif = "font.name-list.sans-serif.%LANG%"; const kFontSizeFmtVariable = "font.size.variable.%LANG%"; var preferences = document.getElementById("mainPreferences"); var prefs = [{ @@ -1060,23 +1070,30 @@ var gMainPane = { if (!prefs[i].element) continue; var element = document.getElementById(prefs[i].element); if (element) { element.setAttribute("preference", preference.id); if (prefs[i].fonttype) - FontBuilder.buildFontList(aLanguageGroup, prefs[i].fonttype, element); + await FontBuilder.buildFontList(aLanguageGroup, prefs[i].fonttype, element); preference.setElementValue(element); } } }, + _safelySelectDefaultLanguageGroup(aLanguageGroup) { + var isSerif = this._readDefaultFontTypeForLanguage(aLanguageGroup) == "serif"; + this._selectDefaultLanguageGroupPromise = + this._selectDefaultLanguageGroup(aLanguageGroup, isSerif) + .catch(Components.utils.reportError); + }, + /** * Stores the original value of the spellchecking preference to enable proper * restoration if unchanged (since we're mapping a tristate onto a checkbox). */ _storedSpellCheck: 0, /** * Returns true if any spellchecking is enabled and false otherwise, caching
--- a/browser/components/preferences/in-content/tests/browser_basic_rebuild_fonts_test.js +++ b/browser/components/preferences/in-content/tests/browser_basic_rebuild_fonts_test.js @@ -1,16 +1,17 @@ Services.prefs.setBoolPref("browser.preferences.instantApply", true); registerCleanupFunction(function() { Services.prefs.clearUserPref("browser.preferences.instantApply"); }); add_task(async function() { await openPreferencesViaOpenPreferencesAPI("general", { leaveOpen: true }); + await gBrowser.contentWindow.gMainPane._selectDefaultLanguageGroupPromise; let doc = gBrowser.contentDocument; var langGroup = Services.prefs.getComplexValue("font.language.group", Ci.nsIPrefLocalizedString).data is(doc.getElementById("font.language.group").value, langGroup, "Language group should be set correctly."); let defaultFontType = Services.prefs.getCharPref("font.default." + langGroup); let fontFamily = Services.prefs.getCharPref("font.name." + defaultFontType + "." + langGroup); let fontFamilyField = doc.getElementById("defaultFont"); @@ -24,87 +25,104 @@ add_task(async function() { doc.getElementById("advancedFonts").click(); let win = await promiseSubDialogLoaded; doc = win.document; // Simulate a dumb font backend. win.FontBuilder._enumerator = { _list: ["MockedFont1", "MockedFont2", "MockedFont3"], _defaultFont: null, - EnumerateFonts(lang, type, list) { - return this._list; + EnumerateFontsAsync(lang, type) { + return Promise.resolve(this._list); }, - EnumerateAllFonts() { - return this._list; + EnumerateAllFontsAsync() { + return Promise.resolve(this._list); }, getDefaultFont() { return this._defaultFont; }, getStandardFamilyName(name) { return name; }, }; win.FontBuilder._allFonts = null; win.FontBuilder._langGroupSupported = false; let langGroupElement = doc.getElementById("font.language.group"); let selectLangsField = doc.getElementById("selectLangs"); let serifField = doc.getElementById("serif"); let armenian = "x-armn"; let western = "x-western"; + // Await rebuilding of the font lists, which happens asynchronously in + // gFontsDialog._selectLanguageGroup. Testing code needs to call this + // function and await its resolution after changing langGroupElement's value + // (or doing anything else that triggers a call to _selectLanguageGroup). + function fontListsRebuilt() { + return win.gFontsDialog._selectLanguageGroupPromise; + } + langGroupElement.value = armenian; + await fontListsRebuilt(); selectLangsField.value = armenian; is(serifField.value, "", "Font family should not be set."); let armenianSerifElement = doc.getElementById("font.name.serif.x-armn"); langGroupElement.value = western; + await fontListsRebuilt(); selectLangsField.value = western; // Simulate a font backend supporting language-specific enumeration. // NB: FontBuilder has cached the return value from EnumerateAllFonts(), // so _allFonts will always have 3 elements regardless of subsequent // _list changes. win.FontBuilder._enumerator._list = ["MockedFont2"]; langGroupElement.value = armenian; + await fontListsRebuilt(); selectLangsField.value = armenian; is(serifField.value, "", "Font family should still be empty for indicating using 'default' font."); langGroupElement.value = western; + await fontListsRebuilt(); selectLangsField.value = western; // Simulate a system that has no fonts for the specified language. win.FontBuilder._enumerator._list = []; langGroupElement.value = armenian; + await fontListsRebuilt(); selectLangsField.value = armenian; is(serifField.value, "", "Font family should not be set."); // Setting default font to "MockedFont3". Then, when serifField.value is // empty, it should indicate using "MockedFont3" but it shouldn't be saved // to "MockedFont3" in the pref. It should be resolved at runtime. win.FontBuilder._enumerator._list = ["MockedFont1", "MockedFont2", "MockedFont3"]; win.FontBuilder._enumerator._defaultFont = "MockedFont3"; langGroupElement.value = armenian; + await fontListsRebuilt(); selectLangsField.value = armenian; is(serifField.value, "", "Font family should be empty even if there is a default font."); armenianSerifElement.value = "MockedFont2"; serifField.value = "MockedFont2"; is(serifField.value, "MockedFont2", "Font family should be \"MockedFont2\" for now."); langGroupElement.value = western; + await fontListsRebuilt(); selectLangsField.value = western; is(serifField.value, "", "Font family of other language should not be set."); langGroupElement.value = armenian; + await fontListsRebuilt(); selectLangsField.value = armenian; is(serifField.value, "MockedFont2", "Font family should not be changed even after switching the language."); // If MochedFont2 is removed from the system, the value should be treated // as empty (i.e., 'default' font) after rebuilding the font list. win.FontBuilder._enumerator._list = ["MockedFont1", "MockedFont3"]; win.FontBuilder._enumerator._allFonts = ["MockedFont1", "MockedFont3"]; serifField.removeAllItems(); // This will cause rebuilding the font list from available fonts. langGroupElement.value = armenian; + await fontListsRebuilt(); selectLangsField.value = armenian; is(serifField.value, "", "Font family should become empty due to the font uninstalled."); gBrowser.removeCurrentTab(); });
--- a/browser/themes/shared/incontentprefs/preferences.inc.css +++ b/browser/themes/shared/incontentprefs/preferences.inc.css @@ -424,19 +424,23 @@ separator.thin:not([orient="vertical"]) -moz-box-flex: 1; } /** * End Dialog */ /** - * Font dialog menulist fixes + * Font group and font dialog menulist fixes */ +#defaultFont { + width: 0; +} + #defaultFontType, #serif, #sans-serif, #monospace { min-width: 30ch; } /**
--- a/gfx/src/nsIFontEnumerator.idl +++ b/gfx/src/nsIFontEnumerator.idl @@ -28,16 +28,37 @@ interface nsIFontEnumerator : nsISupport * @param aCount returns number of names returned * @param aResult returns array of names * @return void */ void EnumerateFonts(in string aLangGroup, in string aGeneric, out uint32_t aCount, [retval, array, size_is(aCount)] out wstring aResult); /** + * Return a promise that resolves to a sorted array of the names of all + * installed fonts. + * + * @return Promise that resolves to Array + */ + [implicit_jscontext] + jsval EnumerateAllFontsAsync(); + + /** + * Return a promise that resolves to a sorted array of names of fonts + * that support the given language group and are suitable for use as the given + * CSS generic font. + * + * @param aLangGroup language group + * @param aGeneric CSS generic font + * @return Promise that resolves to Array + */ + [implicit_jscontext] + jsval EnumerateFontsAsync(in string aLangGroup, in string aGeneric); + + /** @param aLangGroup language group @return bool do we have a font for this language group */ void HaveFontFor(in string aLangGroup, [retval] out boolean aResult); /** * @param aLangGroup language group * @param aGeneric CSS generic font
--- a/gfx/src/nsThebesFontEnumerator.cpp +++ b/gfx/src/nsThebesFontEnumerator.cpp @@ -2,16 +2,17 @@ /* 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/. */ #include "nsThebesFontEnumerator.h" #include <stdint.h> // for uint32_t #include "gfxPlatform.h" // for gfxPlatform #include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2 +#include "mozilla/dom/Promise.h" // for mozilla::dom::Promise #include "nsCOMPtr.h" // for nsCOMPtr #include "nsDebug.h" // for NS_ENSURE_ARG_POINTER #include "nsError.h" // for NS_OK, NS_FAILED, nsresult #include "nsIAtom.h" // for nsIAtom, NS_Atomize #include "nsID.h" #include "nsMemory.h" // for nsMemory #include "nsString.h" // for nsAutoCString, nsAutoString, etc #include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc @@ -71,16 +72,157 @@ nsThebesFontEnumerator::EnumerateFonts(c } *aResult = fs; *aCount = fontList.Length(); return NS_OK; } +struct EnumerateFontsPromise final +{ + explicit EnumerateFontsPromise(mozilla::dom::Promise* aPromise) + : mPromise(aPromise) + { + MOZ_ASSERT(aPromise); + MOZ_ASSERT(NS_IsMainThread()); + } + + RefPtr<mozilla::dom::Promise> mPromise; +}; + +class EnumerateFontsResult final : public Runnable +{ +public: + EnumerateFontsResult(nsresult aRv, + UniquePtr<EnumerateFontsPromise> aEnumerateFontsPromise, + nsTArray<nsString> aFontList) + : Runnable("EnumerateFontsResult") + , mRv(aRv) + , mEnumerateFontsPromise(Move(aEnumerateFontsPromise)) + , mFontList(aFontList) + , mWorkerThread(do_GetCurrentThread()) + { + MOZ_ASSERT(!NS_IsMainThread()); + } + + NS_IMETHOD Run() + { + MOZ_ASSERT(NS_IsMainThread()); + + if (NS_FAILED(mRv)) { + mEnumerateFontsPromise->mPromise->MaybeReject(mRv); + } else { + mEnumerateFontsPromise->mPromise->MaybeResolve(mFontList); + } + + mWorkerThread->Shutdown(); + + return NS_OK; + } + +private: + nsresult mRv; + UniquePtr<EnumerateFontsPromise> mEnumerateFontsPromise; + nsTArray<nsString> mFontList; + nsCOMPtr<nsIThread> mWorkerThread; +}; + +class EnumerateFontsTask final : public Runnable +{ +public: + EnumerateFontsTask(nsIAtom* aLangGroupAtom, + const nsAutoCString& aGeneric, + UniquePtr<EnumerateFontsPromise> aEnumerateFontsPromise) + : Runnable("EnumerateFontsTask") + , mLangGroupAtom(aLangGroupAtom) + , mGeneric(aGeneric) + , mEnumerateFontsPromise(Move(aEnumerateFontsPromise)) + { + MOZ_ASSERT(NS_IsMainThread()); + } + + NS_IMETHOD Run() + { + MOZ_ASSERT(!NS_IsMainThread()); + + nsTArray<nsString> fontList; + + nsresult rv = gfxPlatform::GetPlatform()-> + GetFontList(mLangGroupAtom, mGeneric, fontList); + nsCOMPtr<nsIRunnable> runnable = new EnumerateFontsResult( + rv, Move(mEnumerateFontsPromise), Move(fontList)); + NS_DispatchToMainThread(runnable.forget()); + + return NS_OK; + } + +private: + nsCOMPtr<nsIAtom> mLangGroupAtom; + nsAutoCStringN<16> mGeneric; + UniquePtr<EnumerateFontsPromise> mEnumerateFontsPromise; +}; + +NS_IMETHODIMP +nsThebesFontEnumerator::EnumerateAllFontsAsync(JSContext* aCx, + JS::MutableHandleValue aRval) +{ + return EnumerateFontsAsync(nullptr, nullptr, aCx, aRval); +} + +NS_IMETHODIMP +nsThebesFontEnumerator::EnumerateFontsAsync(const char* aLangGroup, + const char* aGeneric, + JSContext* aCx, + JS::MutableHandleValue aRval) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr<nsIGlobalObject> global = + xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx)); + NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED); + + ErrorResult errv; + RefPtr<mozilla::dom::Promise> promise = dom::Promise::Create(global, errv); + if (errv.Failed()) { + return errv.StealNSResult(); + } + + auto enumerateFontsPromise = MakeUnique<EnumerateFontsPromise>(promise); + + nsCOMPtr<nsIThread> thread; + nsresult rv = NS_NewNamedThread("FontEnumThread", getter_AddRefs(thread)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIAtom> langGroupAtom; + if (aLangGroup) { + nsAutoCStringN<16> lowered; + lowered.Assign(aLangGroup); + ToLowerCase(lowered); + langGroupAtom = NS_Atomize(lowered); + } + + nsAutoCString generic; + if (aGeneric) { + generic.Assign(aGeneric); + } else { + generic.SetIsVoid(true); + } + + nsCOMPtr<nsIRunnable> runnable = new EnumerateFontsTask( + langGroupAtom, generic, Move(enumerateFontsPromise)); + thread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL); + + if (!ToJSValue(aCx, promise, aRval)) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + NS_IMETHODIMP nsThebesFontEnumerator::HaveFontFor(const char *aLangGroup, bool *aResult) { NS_ENSURE_ARG_POINTER(aResult); *aResult = true; return NS_OK;
--- a/gfx/thebes/gfxMacPlatformFontList.mm +++ b/gfx/thebes/gfxMacPlatformFontList.mm @@ -45,16 +45,17 @@ #import <AppKit/AppKit.h> #include "gfxPlatformMac.h" #include "gfxMacPlatformFontList.h" #include "gfxMacFont.h" #include "gfxUserFontSet.h" #include "harfbuzz/hb.h" +#include "MainThreadUtils.h" #include "nsServiceManagerUtils.h" #include "nsTArray.h" #include "nsDirectoryServiceUtils.h" #include "nsDirectoryServiceDefs.h" #include "nsAppDirectoryServiceDefs.h" #include "nsISimpleEnumerator.h" #include "nsCharTraits.h" @@ -497,17 +498,21 @@ protected: double mSizeHint; }; void gfxMacFontFamily::LocalizedName(nsAString& aLocalizedName) { nsAutoreleasePool localPool; - if (!HasOtherFamilyNames()) { + // It's unsafe to call HasOtherFamilyNames off the main thread because + // it entrains FindStyleVariations, which calls GetWeightOverride, which + // retrieves prefs. And the pref names can change (via user overrides), + // so we can't use gfxPrefs to access them. + if (NS_IsMainThread() && !HasOtherFamilyNames()) { aLocalizedName = mName; return; } NSString *family = GetNSStringForString(mName); NSString *localized = [sFontManager localizedNameForFamily:family face:nil];
--- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -16,16 +16,17 @@ #include "nsServiceManagerUtils.h" #include "nsUnicharUtils.h" #include "nsUnicodeRange.h" #include "nsUnicodeProperties.h" #include "mozilla/Attributes.h" #include "mozilla/Likely.h" #include "mozilla/MemoryReporting.h" +#include "mozilla/Mutex.h" #include "mozilla/Preferences.h" #include "mozilla/Telemetry.h" #include "mozilla/TimeStamp.h" #include "mozilla/gfx/2D.h" #include <locale.h> using namespace mozilla; @@ -171,18 +172,18 @@ gfxPlatformFontList::MemoryReporter::Col sizes.mFontTableCacheSize, "Memory used for cached font metrics and layout tables."); } return NS_OK; } gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames) - : mFontFamilies(64), mOtherFamilyNames(16), - mBadUnderlineFamilyNames(8), mSharedCmaps(8), + : mFontFamiliesMutex("gfxPlatformFontList::mFontFamiliesMutex"), mFontFamilies(64), + mOtherFamilyNames(16), mBadUnderlineFamilyNames(8), mSharedCmaps(8), mStartIndex(0), mIncrement(1), mNumFamilies(0), mFontlistInitCount(0), mFontFamilyWhitelistActive(false) { mOtherFamilyNamesInitialized = false; if (aNeedFullnamePostscriptNames) { mExtraNames = MakeUnique<ExtraNames>(); } @@ -281,16 +282,17 @@ gfxPlatformFontList::InitFontList() if (fontCache) { fontCache->AgeAllGenerations(); fontCache->FlushShapedWordCaches(); } gfxPlatform::PurgeSkiaFontCache(); CancelInitOtherFamilyNamesTask(); + MutexAutoLock lock(mFontFamiliesMutex); mFontFamilies.Clear(); mOtherFamilyNames.Clear(); mOtherFamilyNamesInitialized = false; if (mExtraNames) { mExtraNames->mFullnames.Clear(); mExtraNames->mPostscriptNames.Clear(); } @@ -476,16 +478,17 @@ gfxPlatformFontList::UpdateFontList() RebuildLocalFonts(); } void gfxPlatformFontList::GetFontList(nsIAtom *aLangGroup, const nsACString& aGenericFamily, nsTArray<nsString>& aListOfFonts) { + MutexAutoLock lock(mFontFamiliesMutex); for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) { RefPtr<gfxFontFamily>& family = iter.Data(); if (family->FilterForFontList(aLangGroup, aGenericFamily)) { nsAutoString localizedFamilyName; family->LocalizedName(localizedFamilyName); aListOfFonts.AppendElement(localizedFamilyName); } }
--- a/gfx/thebes/gfxPlatformFontList.h +++ b/gfx/thebes/gfxPlatformFontList.h @@ -15,16 +15,17 @@ #include "gfxFont.h" #include "gfxFontConstants.h" #include "gfxPlatform.h" #include "gfxFontFamilyList.h" #include "nsIMemoryReporter.h" #include "mozilla/Attributes.h" #include "mozilla/MemoryReporting.h" +#include "mozilla/Mutex.h" #include "mozilla/RangedArray.h" #include "nsLanguageAtomService.h" class CharMapHashKey : public PLDHashEntryHdr { public: typedef gfxCharacterMap* KeyType; typedef const gfxCharacterMap* KeyTypePointer; @@ -511,16 +512,19 @@ protected: static size_t SizeOfFontEntryTableExcludingThis(const FontEntryTable& aTable, mozilla::MallocSizeOf aMallocSizeOf); // Platform-specific helper for GetDefaultFont(...). virtual gfxFontFamily* GetDefaultFontForPlatform(const gfxFontStyle* aStyle) = 0; + // Protects mFontFamilies. + mozilla::Mutex mFontFamiliesMutex; + // canonical family name ==> family entry (unique, one name per family entry) FontFamilyTable mFontFamilies; // other family name ==> family entry (not unique, can have multiple names per // family entry, only names *other* than the canonical names are stored here) FontFamilyTable mOtherFamilyNames; // flag set after InitOtherFamilyNames is called upon first name lookup miss
--- a/toolkit/mozapps/preferences/fontbuilder.js +++ b/toolkit/mozapps/preferences/fontbuilder.js @@ -11,34 +11,34 @@ var FontBuilder = { this._enumerator = Components.classes["@mozilla.org/gfx/fontenumerator;1"] .createInstance(Components.interfaces.nsIFontEnumerator); } return this._enumerator; }, _allFonts: null, _langGroupSupported: false, - buildFontList(aLanguage, aFontType, aMenuList) { + async buildFontList(aLanguage, aFontType, aMenuList) { // Reset the list while (aMenuList.hasChildNodes()) aMenuList.firstChild.remove(); var defaultFont = null; // Load Font Lists - var fonts = this.enumerator.EnumerateFonts(aLanguage, aFontType, { } ); + var fonts = await this.enumerator.EnumerateFontsAsync(aLanguage, aFontType); if (fonts.length > 0) defaultFont = this.enumerator.getDefaultFont(aLanguage, aFontType); else { - fonts = this.enumerator.EnumerateFonts(aLanguage, "", { }); + fonts = await this.enumerator.EnumerateFontsAsync(aLanguage, ""); if (fonts.length > 0) defaultFont = this.enumerator.getDefaultFont(aLanguage, ""); } if (!this._allFonts) - this._allFonts = this.enumerator.EnumerateAllFonts({}); + this._allFonts = await this.enumerator.EnumerateAllFontsAsync({}); // Build the UI for the Default Font and Fonts for this CSS type. var popup = document.createElement("menupopup"); var separator; if (fonts.length > 0) { if (defaultFont) { var bundlePreferences = document.getElementById("bundlePreferences"); var label = bundlePreferences.getFormattedString("labelDefaultFont", [defaultFont]);