зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central r=merge a=merge
This commit is contained in:
Коммит
6185875025
|
@ -549,14 +549,14 @@ mozilla::ipc::IPCResult
|
|||
ContentChild::RecvSetXPCOMProcessAttributes(const XPCOMInitData& aXPCOMInit,
|
||||
const StructuredCloneData& aInitialData,
|
||||
nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache,
|
||||
nsTArray<FontFamilyListEntry>&& aFontFamilyList)
|
||||
nsTArray<SystemFontListEntry>&& aFontList)
|
||||
{
|
||||
if (!sShutdownCanary) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mLookAndFeelCache = Move(aLookAndFeelIntCache);
|
||||
mFontFamilies = Move(aFontFamilyList);
|
||||
mFontList = Move(aFontList);
|
||||
gfx::gfxVars::SetValuesForInitialize(aXPCOMInit.gfxNonDefaultVarUpdates());
|
||||
InitXPCOM(aXPCOMInit, aInitialData);
|
||||
InitGraphicsDeviceData(aXPCOMInit.contentDeviceData());
|
||||
|
@ -2541,6 +2541,14 @@ ContentChild::RecvUpdateDictionaryList(InfallibleTArray<nsString>&& aDictionarie
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentChild::RecvUpdateFontList(InfallibleTArray<SystemFontListEntry>&& aFontList)
|
||||
{
|
||||
mFontList = Move(aFontList);
|
||||
gfxPlatform::GetPlatform()->UpdateFontList();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentChild::RecvUpdateAppLocales(nsTArray<nsCString>&& aAppLocales)
|
||||
{
|
||||
|
|
|
@ -399,6 +399,8 @@ public:
|
|||
|
||||
virtual mozilla::ipc::IPCResult RecvUpdateDictionaryList(InfallibleTArray<nsString>&& aDictionaries) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvUpdateFontList(InfallibleTArray<SystemFontListEntry>&& aFontList) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvUpdateAppLocales(nsTArray<nsCString>&& aAppLocales) override;
|
||||
virtual mozilla::ipc::IPCResult RecvUpdateRequestedLocales(nsTArray<nsCString>&& aRequestedLocales) override;
|
||||
|
||||
|
@ -603,7 +605,7 @@ public:
|
|||
RecvSetXPCOMProcessAttributes(const XPCOMInitData& aXPCOMInit,
|
||||
const StructuredCloneData& aInitialData,
|
||||
nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache,
|
||||
nsTArray<FontFamilyListEntry>&& aFontFamilyList) override;
|
||||
nsTArray<SystemFontListEntry>&& aFontList) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvProvideAnonymousTemporaryFile(const uint64_t& aID, const FileDescOrError& aFD) override;
|
||||
|
@ -641,11 +643,11 @@ public:
|
|||
SendGetA11yContentId();
|
||||
#endif // defined(XP_WIN) && defined(ACCESSIBILITY)
|
||||
|
||||
// Get a reference to the font family list passed from the chrome process,
|
||||
// Get a reference to the font list passed from the chrome process,
|
||||
// for use during gfx initialization.
|
||||
InfallibleTArray<mozilla::dom::FontFamilyListEntry>&
|
||||
SystemFontFamilyList() {
|
||||
return mFontFamilies;
|
||||
InfallibleTArray<mozilla::dom::SystemFontListEntry>&
|
||||
SystemFontList() {
|
||||
return mFontList;
|
||||
}
|
||||
|
||||
// PURLClassifierChild
|
||||
|
@ -749,10 +751,10 @@ private:
|
|||
|
||||
InfallibleTArray<nsString> mAvailableDictionaries;
|
||||
|
||||
// Temporary storage for a list of available font families, passed from the
|
||||
// Temporary storage for a list of available fonts, passed from the
|
||||
// parent process and used to initialize gfx in the child. Currently used
|
||||
// only on MacOSX.
|
||||
InfallibleTArray<mozilla::dom::FontFamilyListEntry> mFontFamilies;
|
||||
// only on MacOSX and Linux.
|
||||
InfallibleTArray<mozilla::dom::SystemFontListEntry> mFontList;
|
||||
// Temporary storage for nsXPLookAndFeel flags.
|
||||
nsTArray<LookAndFeelInt> mLookAndFeelCache;
|
||||
|
||||
|
|
|
@ -171,6 +171,7 @@
|
|||
#include "nsDocShell.h"
|
||||
#include "nsOpenURIInFrameParams.h"
|
||||
#include "mozilla/net/NeckoMessageUtils.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "prio.h"
|
||||
#include "private/pprio.h"
|
||||
|
@ -2224,9 +2225,10 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority,
|
|||
}
|
||||
}
|
||||
}
|
||||
// This is only implemented (returns a non-empty list) by MacOSX at present.
|
||||
nsTArray<FontFamilyListEntry> fontFamilies;
|
||||
gfxPlatform::GetPlatform()->GetSystemFontFamilyList(&fontFamilies);
|
||||
// This is only implemented (returns a non-empty list) by MacOSX and Linux
|
||||
// at present.
|
||||
nsTArray<SystemFontListEntry> fontList;
|
||||
gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList);
|
||||
nsTArray<LookAndFeelInt> lnfCache = LookAndFeel::GetIntCache();
|
||||
|
||||
// Content processes have no permission to access profile directory, so we
|
||||
|
@ -2269,7 +2271,7 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority,
|
|||
screenManager.CopyScreensToRemote(this);
|
||||
|
||||
Unused << SendSetXPCOMProcessAttributes(xpcomInit, initialData, lnfCache,
|
||||
fontFamilies);
|
||||
fontList);
|
||||
|
||||
if (aSendRegisteredChrome) {
|
||||
nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
|
||||
|
@ -4262,6 +4264,17 @@ ContentParent::NotifyUpdatedDictionaries()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
ContentParent::NotifyUpdatedFonts()
|
||||
{
|
||||
InfallibleTArray<SystemFontListEntry> fontList;
|
||||
gfxPlatform::GetPlatform()->ReadSystemFontList(&fontList);
|
||||
|
||||
for (auto* cp : AllProcesses(eLive)) {
|
||||
Unused << cp->SendUpdateFontList(fontList);
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
ContentParent::UnregisterRemoteFrame(const TabId& aTabId,
|
||||
const ContentParentId& aCpId,
|
||||
|
|
|
@ -269,6 +269,8 @@ public:
|
|||
|
||||
static void NotifyUpdatedDictionaries();
|
||||
|
||||
static void NotifyUpdatedFonts();
|
||||
|
||||
#if defined(XP_WIN)
|
||||
/**
|
||||
* Windows helper for firing off an update window request to a plugin
|
||||
|
|
|
@ -132,6 +132,19 @@ struct FontFamilyListEntry {
|
|||
uint8_t entryType;
|
||||
};
|
||||
|
||||
// Used on Linux to pass list of font patterns from chrome to content.
|
||||
struct FontPatternListEntry {
|
||||
nsCString pattern;
|
||||
bool appFontFamily;
|
||||
};
|
||||
|
||||
// Wrap the Font*ListEntry records in a union so the SetXPCOMProcessAttributes
|
||||
// message can pass an array of either type.
|
||||
union SystemFontListEntry {
|
||||
FontFamilyListEntry;
|
||||
FontPatternListEntry;
|
||||
};
|
||||
|
||||
union PrefValue {
|
||||
nsCString;
|
||||
int32_t;
|
||||
|
@ -429,6 +442,8 @@ child:
|
|||
|
||||
async UpdateDictionaryList(nsString[] dictionaries);
|
||||
|
||||
async UpdateFontList(SystemFontListEntry[] fontList);
|
||||
|
||||
async UpdateAppLocales(nsCString[] appLocales);
|
||||
async UpdateRequestedLocales(nsCString[] requestedLocales);
|
||||
|
||||
|
@ -476,8 +491,8 @@ child:
|
|||
async SetXPCOMProcessAttributes(XPCOMInitData xpcomInit,
|
||||
StructuredCloneData initialData,
|
||||
LookAndFeelInt[] lookAndFeelIntCache,
|
||||
/* used on MacOSX only: */
|
||||
FontFamilyListEntry[] fontFamilyList);
|
||||
/* used on MacOSX and Linux only: */
|
||||
SystemFontListEntry[] systemFontList);
|
||||
|
||||
// Notify child that last-pb-context-exited notification was observed
|
||||
async LastPrivateDocShellDestroyed();
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "gfxFT2Utils.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
@ -22,10 +24,12 @@
|
|||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
#include "mozilla/gfx/HelpersCairo.h"
|
||||
|
||||
#include <fontconfig/fcfreetype.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
#include <gdk/gdk.h>
|
||||
|
@ -36,10 +40,18 @@
|
|||
#include "mozilla/X11Util.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_CONTENT_SANDBOX
|
||||
#include "mozilla/SandboxBrokerPolicyFactory.h"
|
||||
#include "mozilla/SandboxSettings.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::unicode;
|
||||
|
||||
using mozilla::dom::SystemFontListEntry;
|
||||
using mozilla::dom::FontPatternListEntry;
|
||||
|
||||
#ifndef FC_POSTSCRIPT_NAME
|
||||
#define FC_POSTSCRIPT_NAME "postscriptname" /* String */
|
||||
#endif
|
||||
|
@ -1205,6 +1217,25 @@ gfxFontconfigFontFamily::~gfxFontconfigFontFamily()
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
template<typename Func>
|
||||
void
|
||||
gfxFontconfigFontFamily::AddFacesToFontList(Func aAddPatternFunc)
|
||||
{
|
||||
if (HasStyles()) {
|
||||
for (auto& fe : mAvailableFonts) {
|
||||
if (!fe) {
|
||||
continue;
|
||||
}
|
||||
auto fce = static_cast<gfxFontconfigFontEntry*>(fe.get());
|
||||
aAddPatternFunc(fce->GetPattern(), mContainsAppFonts);
|
||||
}
|
||||
} else {
|
||||
for (auto& pat : mFontPatterns) {
|
||||
aAddPatternFunc(pat, mContainsAppFonts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gfxFontconfigFont::gfxFontconfigFont(const RefPtr<UnscaledFontFontconfig>& aUnscaledFont,
|
||||
cairo_scaled_font_t *aScaledFont,
|
||||
FcPattern *aPattern,
|
||||
|
@ -1244,18 +1275,20 @@ gfxFcPlatformFontList::gfxFcPlatformFontList()
|
|||
, mLastConfig(nullptr)
|
||||
, mAlwaysUseFontconfigGenerics(true)
|
||||
{
|
||||
// if the rescan interval is set, start the timer
|
||||
int rescanInterval = FcConfigGetRescanInterval(nullptr);
|
||||
if (rescanInterval) {
|
||||
mLastConfig = FcConfigGetCurrent();
|
||||
NS_NewTimerWithFuncCallback(getter_AddRefs(mCheckFontUpdatesTimer),
|
||||
CheckFontUpdates,
|
||||
this,
|
||||
(rescanInterval + 1) * 1000,
|
||||
nsITimer::TYPE_REPEATING_SLACK,
|
||||
"gfxFcPlatformFontList::gfxFcPlatformFontList");
|
||||
if (!mCheckFontUpdatesTimer) {
|
||||
NS_WARNING("Failure to create font updates timer");
|
||||
if (XRE_IsParentProcess()) {
|
||||
// if the rescan interval is set, start the timer
|
||||
int rescanInterval = FcConfigGetRescanInterval(nullptr);
|
||||
if (rescanInterval) {
|
||||
mLastConfig = FcConfigGetCurrent();
|
||||
NS_NewTimerWithFuncCallback(getter_AddRefs(mCheckFontUpdatesTimer),
|
||||
CheckFontUpdates,
|
||||
this,
|
||||
(rescanInterval + 1) * 1000,
|
||||
nsITimer::TYPE_REPEATING_SLACK,
|
||||
"gfxFcPlatformFontList::gfxFcPlatformFontList");
|
||||
if (!mCheckFontUpdatesTimer) {
|
||||
NS_WARNING("Failure to create font updates timer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1273,14 +1306,15 @@ gfxFcPlatformFontList::~gfxFcPlatformFontList()
|
|||
}
|
||||
|
||||
void
|
||||
gfxFcPlatformFontList::AddFontSetFamilies(FcFontSet* aFontSet, bool aAppFonts)
|
||||
gfxFcPlatformFontList::AddFontSetFamilies(FcFontSet* aFontSet,
|
||||
const SandboxPolicy* aPolicy,
|
||||
bool aAppFonts)
|
||||
{
|
||||
// This iterates over the fonts in a font set and adds in gfxFontFamily
|
||||
// objects for each family. The patterns for individual fonts are not
|
||||
// copied here. When a family is actually used, the fonts in the family
|
||||
// are enumerated and the patterns copied. Note that we're explicitly
|
||||
// excluding non-scalable fonts such as X11 bitmap fonts, which
|
||||
// Chrome Skia/Webkit code does also.
|
||||
// objects for each family. Individual gfxFontEntry objects for each face
|
||||
// are not created here; the patterns are just stored in the family. When
|
||||
// a family is actually used, it will be populated with gfxFontEntry
|
||||
// records and the patterns moved to those.
|
||||
|
||||
if (!aFontSet) {
|
||||
NS_WARNING("AddFontSetFamilies called with a null font set.");
|
||||
|
@ -1291,95 +1325,241 @@ gfxFcPlatformFontList::AddFontSetFamilies(FcFontSet* aFontSet, bool aAppFonts)
|
|||
RefPtr<gfxFontconfigFontFamily> fontFamily;
|
||||
nsAutoString familyName;
|
||||
for (int f = 0; f < aFontSet->nfont; f++) {
|
||||
FcPattern* font = aFontSet->fonts[f];
|
||||
FcPattern* pattern = aFontSet->fonts[f];
|
||||
|
||||
// get canonical name
|
||||
uint32_t cIndex = FindCanonicalNameIndex(font, FC_FAMILYLANG);
|
||||
FcChar8* canonical = nullptr;
|
||||
FcPatternGetString(font, FC_FAMILY, cIndex, &canonical);
|
||||
if (!canonical) {
|
||||
// Skip any fonts that aren't readable for us (e.g. due to restrictive
|
||||
// file ownership/permissions).
|
||||
FcChar8* path;
|
||||
if (FcPatternGetString(pattern, FC_FILE, 0, &path) != FcResultMatch) {
|
||||
continue;
|
||||
}
|
||||
if (access(reinterpret_cast<const char*>(path), F_OK | R_OK) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// same as the last one? no need to add a new family, skip
|
||||
if (FcStrCmp(canonical, lastFamilyName) != 0) {
|
||||
lastFamilyName = canonical;
|
||||
#ifdef MOZ_CONTENT_SANDBOX
|
||||
// Skip any fonts that will be blocked by the content-process sandbox
|
||||
// policy.
|
||||
if (aPolicy && !(aPolicy->Lookup(reinterpret_cast<const char*>(path)) &
|
||||
SandboxBroker::Perms::MAY_READ)) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
// add new family if one doesn't already exist
|
||||
familyName.Truncate();
|
||||
AppendUTF8toUTF16(ToCharPtr(canonical), familyName);
|
||||
nsAutoString keyName(familyName);
|
||||
ToLowerCase(keyName);
|
||||
AddPatternToFontList(pattern, lastFamilyName,
|
||||
familyName, fontFamily, aAppFonts);
|
||||
}
|
||||
}
|
||||
|
||||
fontFamily = static_cast<gfxFontconfigFontFamily*>
|
||||
(mFontFamilies.GetWeak(keyName));
|
||||
if (!fontFamily) {
|
||||
fontFamily = new gfxFontconfigFontFamily(familyName);
|
||||
mFontFamilies.Put(keyName, fontFamily);
|
||||
}
|
||||
// Record if the family contains fonts from the app font set
|
||||
// (in which case we won't rely on fontconfig's charmap, due to
|
||||
// bug 1276594).
|
||||
if (aAppFonts) {
|
||||
fontFamily->SetFamilyContainsAppFonts(true);
|
||||
}
|
||||
void
|
||||
gfxFcPlatformFontList::AddPatternToFontList(FcPattern* aFont,
|
||||
FcChar8*& aLastFamilyName,
|
||||
nsAString& aFamilyName,
|
||||
RefPtr<gfxFontconfigFontFamily>& aFontFamily,
|
||||
bool aAppFonts)
|
||||
{
|
||||
// get canonical name
|
||||
uint32_t cIndex = FindCanonicalNameIndex(aFont, FC_FAMILYLANG);
|
||||
FcChar8* canonical = nullptr;
|
||||
FcPatternGetString(aFont, FC_FAMILY, cIndex, &canonical);
|
||||
if (!canonical) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add pointers to other localized family names. Most fonts
|
||||
// only have a single name, so the first call to GetString
|
||||
// will usually not match
|
||||
FcChar8* otherName;
|
||||
int n = (cIndex == 0 ? 1 : 0);
|
||||
while (FcPatternGetString(font, FC_FAMILY, n, &otherName) == FcResultMatch) {
|
||||
NS_ConvertUTF8toUTF16 otherFamilyName(ToCharPtr(otherName));
|
||||
AddOtherFamilyName(fontFamily, otherFamilyName);
|
||||
n++;
|
||||
if (n == int(cIndex)) {
|
||||
n++; // skip over canonical name
|
||||
}
|
||||
}
|
||||
// same as the last one? no need to add a new family, skip
|
||||
if (FcStrCmp(canonical, aLastFamilyName) != 0) {
|
||||
aLastFamilyName = canonical;
|
||||
|
||||
// add new family if one doesn't already exist
|
||||
aFamilyName.Truncate();
|
||||
AppendUTF8toUTF16(ToCharPtr(canonical), aFamilyName);
|
||||
nsAutoString keyName(aFamilyName);
|
||||
ToLowerCase(keyName);
|
||||
|
||||
aFontFamily = static_cast<gfxFontconfigFontFamily*>
|
||||
(mFontFamilies.GetWeak(keyName));
|
||||
if (!aFontFamily) {
|
||||
aFontFamily = new gfxFontconfigFontFamily(aFamilyName);
|
||||
mFontFamilies.Put(keyName, aFontFamily);
|
||||
}
|
||||
// Record if the family contains fonts from the app font set
|
||||
// (in which case we won't rely on fontconfig's charmap, due to
|
||||
// bug 1276594).
|
||||
if (aAppFonts) {
|
||||
aFontFamily->SetFamilyContainsAppFonts(true);
|
||||
}
|
||||
|
||||
NS_ASSERTION(fontFamily, "font must belong to a font family");
|
||||
fontFamily->AddFontPattern(font);
|
||||
// Add pointers to other localized family names. Most fonts
|
||||
// only have a single name, so the first call to GetString
|
||||
// will usually not match
|
||||
FcChar8* otherName;
|
||||
int n = (cIndex == 0 ? 1 : 0);
|
||||
while (FcPatternGetString(aFont, FC_FAMILY, n, &otherName) ==
|
||||
FcResultMatch) {
|
||||
NS_ConvertUTF8toUTF16 otherFamilyName(ToCharPtr(otherName));
|
||||
AddOtherFamilyName(aFontFamily, otherFamilyName);
|
||||
n++;
|
||||
if (n == int(cIndex)) {
|
||||
n++; // skip over canonical name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// map the psname, fullname ==> font family for local font lookups
|
||||
nsAutoString psname, fullname;
|
||||
GetFaceNames(font, familyName, psname, fullname);
|
||||
if (!psname.IsEmpty()) {
|
||||
ToLowerCase(psname);
|
||||
mLocalNames.Put(psname, font);
|
||||
}
|
||||
if (!fullname.IsEmpty()) {
|
||||
ToLowerCase(fullname);
|
||||
mLocalNames.Put(fullname, font);
|
||||
}
|
||||
MOZ_ASSERT(aFontFamily, "font must belong to a font family");
|
||||
aFontFamily->AddFontPattern(aFont);
|
||||
|
||||
// map the psname, fullname ==> font family for local font lookups
|
||||
nsAutoString psname, fullname;
|
||||
GetFaceNames(aFont, aFamilyName, psname, fullname);
|
||||
if (!psname.IsEmpty()) {
|
||||
ToLowerCase(psname);
|
||||
mLocalNames.Put(psname, aFont);
|
||||
}
|
||||
if (!fullname.IsEmpty()) {
|
||||
ToLowerCase(fullname);
|
||||
mLocalNames.Put(fullname, aFont);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
gfxFcPlatformFontList::InitFontListForPlatform()
|
||||
{
|
||||
mLastConfig = FcConfigGetCurrent();
|
||||
#ifdef MOZ_BUNDLED_FONTS
|
||||
ActivateBundledFonts();
|
||||
#endif
|
||||
|
||||
mLocalNames.Clear();
|
||||
mFcSubstituteCache.Clear();
|
||||
|
||||
// iterate over available fonts
|
||||
FcFontSet* systemFonts = FcConfigGetFonts(nullptr, FcSetSystem);
|
||||
AddFontSetFamilies(systemFonts, /* aAppFonts = */ false);
|
||||
mAlwaysUseFontconfigGenerics = PrefFontListsUseOnlyGenerics();
|
||||
|
||||
#ifdef MOZ_BUNDLED_FONTS
|
||||
ActivateBundledFonts();
|
||||
FcFontSet* appFonts = FcConfigGetFonts(nullptr, FcSetApplication);
|
||||
AddFontSetFamilies(appFonts, /* aAppFonts = */ true);
|
||||
#endif
|
||||
|
||||
mOtherFamilyNamesInitialized = true;
|
||||
|
||||
if (XRE_IsContentProcess()) {
|
||||
// Content process: use the font list passed from the chrome process,
|
||||
// because we can't rely on fontconfig in the presence of sandboxing;
|
||||
// it may report fonts that we can't actually access.
|
||||
|
||||
FcChar8* lastFamilyName = (FcChar8*)"";
|
||||
RefPtr<gfxFontconfigFontFamily> fontFamily;
|
||||
nsAutoString familyName;
|
||||
|
||||
// Get font list that was passed during XPCOM startup
|
||||
// or in an UpdateFontList message.
|
||||
auto& fontList = dom::ContentChild::GetSingleton()->SystemFontList();
|
||||
|
||||
// For fontconfig versions between 2.10.94 and 2.11.1 inclusive,
|
||||
// we need to escape any leading space in the charset element,
|
||||
// otherwise FcNameParse will fail. :(
|
||||
//
|
||||
// The bug was introduced on 2013-05-24 by
|
||||
// https://cgit.freedesktop.org/fontconfig/commit/?id=cd9b1033a68816a7acfbba1718ba0aa5888f6ec7
|
||||
// "Bug 64906 - FcNameParse() should ignore leading whitespace in parameters"
|
||||
// because ignoring a leading space in the encoded value of charset
|
||||
// causes erroneous decoding of the whole element.
|
||||
// This first shipped in version 2.10.94, and was eventually fixed as
|
||||
// a side-effect of switching to the "human-readable" representation of
|
||||
// charsets on 2014-07-03 in
|
||||
// https://cgit.freedesktop.org/fontconfig/commit/?id=e708e97c351d3bc9f7030ef22ac2f007d5114730
|
||||
// "Change charset parse/unparse format to be human readable"
|
||||
// (with a followup fix next day) which means a leading space is no
|
||||
// longer significant. This fix landed after 2.11.1 had been shipped,
|
||||
// so the first version tag without the bug is 2.11.91.
|
||||
int fcVersion = FcGetVersion();
|
||||
bool fcCharsetParseBug = fcVersion >= 21094 && fcVersion <= 21101;
|
||||
|
||||
for (SystemFontListEntry& fle : fontList) {
|
||||
MOZ_ASSERT(fle.type() ==
|
||||
SystemFontListEntry::Type::TFontPatternListEntry);
|
||||
FontPatternListEntry& fpe(fle);
|
||||
nsCString& patternStr = fpe.pattern();
|
||||
if (fcCharsetParseBug) {
|
||||
int32_t index = patternStr.Find(":charset= ");
|
||||
if (index != kNotFound) {
|
||||
// insert backslash after the =, before the space
|
||||
patternStr.Insert('\\', index + 9);
|
||||
}
|
||||
}
|
||||
FcPattern* pattern =
|
||||
FcNameParse((const FcChar8*)patternStr.get());
|
||||
AddPatternToFontList(pattern, lastFamilyName, familyName,
|
||||
fontFamily, fpe.appFontFamily());
|
||||
FcPatternDestroy(pattern);
|
||||
}
|
||||
|
||||
LOG_FONTLIST(("got font list from chrome process: "
|
||||
"%u faces in %u families",
|
||||
(unsigned)fontList.Length(), mFontFamilies.Count()));
|
||||
|
||||
fontList.Clear();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mLastConfig = FcConfigGetCurrent();
|
||||
|
||||
UniquePtr<SandboxPolicy> policy;
|
||||
|
||||
#ifdef MOZ_CONTENT_SANDBOX
|
||||
// Create a temporary SandboxPolicy to check font paths; use a fake PID
|
||||
// to avoid picking up any PID-specific rules by accident.
|
||||
SandboxBrokerPolicyFactory policyFactory;
|
||||
if (GetEffectiveContentSandboxLevel() > 0 &&
|
||||
!PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX")) {
|
||||
policy = policyFactory.GetContentPolicy(-1, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
// iterate over available fonts
|
||||
FcFontSet* systemFonts = FcConfigGetFonts(nullptr, FcSetSystem);
|
||||
AddFontSetFamilies(systemFonts, policy.get(), /* aAppFonts = */ false);
|
||||
|
||||
#ifdef MOZ_BUNDLED_FONTS
|
||||
FcFontSet* appFonts = FcConfigGetFonts(nullptr, FcSetApplication);
|
||||
AddFontSetFamilies(appFonts, policy.get(), /* aAppFonts = */ true);
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
gfxFcPlatformFontList::ReadSystemFontList(
|
||||
InfallibleTArray<SystemFontListEntry>* retValue)
|
||||
{
|
||||
// Fontconfig versions below 2.9 drop the FC_FILE element in FcNameUnparse
|
||||
// (see https://bugs.freedesktop.org/show_bug.cgi?id=26718), so when using
|
||||
// an older version, we manually append it to the unparsed pattern.
|
||||
if (FcGetVersion() < 20900) {
|
||||
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
|
||||
auto family =
|
||||
static_cast<gfxFontconfigFontFamily*>(iter.Data().get());
|
||||
family->AddFacesToFontList([&](FcPattern* aPat, bool aAppFonts) {
|
||||
char* s = (char*)FcNameUnparse(aPat);
|
||||
nsAutoCString patternStr(s);
|
||||
free(s);
|
||||
if (FcResultMatch ==
|
||||
FcPatternGetString(aPat, FC_FILE, 0, (FcChar8**)&s)) {
|
||||
patternStr.Append(":file=");
|
||||
patternStr.Append(s);
|
||||
}
|
||||
retValue->AppendElement(FontPatternListEntry(patternStr,
|
||||
aAppFonts));
|
||||
});
|
||||
}
|
||||
} else {
|
||||
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
|
||||
auto family =
|
||||
static_cast<gfxFontconfigFontFamily*>(iter.Data().get());
|
||||
family->AddFacesToFontList([&](FcPattern* aPat, bool aAppFonts) {
|
||||
char* s = (char*)FcNameUnparse(aPat);
|
||||
nsDependentCString patternStr(s);
|
||||
retValue->AppendElement(FontPatternListEntry(patternStr,
|
||||
aAppFonts));
|
||||
free(s);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For displaying the fontlist in UI, use explicit call to FcFontList. Using
|
||||
// FcFontList results in the list containing the localized names as dictated
|
||||
// by system defaults.
|
||||
|
@ -1978,6 +2158,10 @@ gfxFcPlatformFontList::PrefFontListsUseOnlyGenerics()
|
|||
/* static */ void
|
||||
gfxFcPlatformFontList::CheckFontUpdates(nsITimer *aTimer, void *aThis)
|
||||
{
|
||||
// A content process is not supposed to check this directly;
|
||||
// it will be notified by the parent when the font list changes.
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
// check for font updates
|
||||
FcInitBringUptoDate();
|
||||
|
||||
|
@ -1987,6 +2171,8 @@ gfxFcPlatformFontList::CheckFontUpdates(nsITimer *aTimer, void *aThis)
|
|||
if (current != pfl->GetLastConfig()) {
|
||||
pfl->UpdateFontList();
|
||||
pfl->ForceGlobalReflow();
|
||||
|
||||
mozilla::dom::ContentParent::NotifyUpdatedFonts();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,16 @@
|
|||
#include <cairo.h>
|
||||
#include <cairo-ft.h>
|
||||
|
||||
#ifdef MOZ_CONTENT_SANDBOX
|
||||
#include "mozilla/SandboxBroker.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class SystemFontListEntry;
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
class nsAutoRefTraits<FcPattern> : public nsPointerRefTraits<FcPattern>
|
||||
{
|
||||
|
@ -182,6 +192,9 @@ public:
|
|||
mForceScalable(false)
|
||||
{ }
|
||||
|
||||
template<typename Func>
|
||||
void AddFacesToFontList(Func aAddPatternFunc);
|
||||
|
||||
void FindStyleVariations(FontInfoData *aFontInfoData = nullptr) override;
|
||||
|
||||
// Families are constructed initially with just references to patterns.
|
||||
|
@ -254,6 +267,8 @@ public:
|
|||
const nsACString& aGenericFamily,
|
||||
nsTArray<nsString>& aListOfFonts) override;
|
||||
|
||||
void ReadSystemFontList(
|
||||
InfallibleTArray<mozilla::dom::SystemFontListEntry>* retValue);
|
||||
|
||||
gfxFontEntry*
|
||||
LookupLocalFont(const nsAString& aFontName, uint16_t aWeight,
|
||||
|
@ -294,9 +309,23 @@ public:
|
|||
protected:
|
||||
virtual ~gfxFcPlatformFontList();
|
||||
|
||||
#ifdef MOZ_CONTENT_SANDBOX
|
||||
typedef mozilla::SandboxBroker::Policy SandboxPolicy;
|
||||
#else
|
||||
// Dummy type just so we can still have a SandboxPolicy* parameter.
|
||||
struct SandboxPolicy {};
|
||||
#endif
|
||||
|
||||
// Add all the font families found in a font set.
|
||||
// aAppFonts indicates whether this is the system or application fontset.
|
||||
void AddFontSetFamilies(FcFontSet* aFontSet, bool aAppFonts);
|
||||
void AddFontSetFamilies(FcFontSet* aFontSet, const SandboxPolicy* aPolicy,
|
||||
bool aAppFonts);
|
||||
|
||||
// Helper for above, to add a single font pattern.
|
||||
void AddPatternToFontList(FcPattern* aFont, FcChar8*& aLastFamilyName,
|
||||
nsAString& aFamilyName,
|
||||
RefPtr<gfxFontconfigFontFamily>& aFontFamily,
|
||||
bool aAppFonts);
|
||||
|
||||
// figure out which families fontconfig maps a generic to
|
||||
// (aGeneric assumed already lowercase)
|
||||
|
|
|
@ -159,8 +159,8 @@ public:
|
|||
kTextSizeSystemFontFamily = 2, // name of 'system' font at text sizes
|
||||
kDisplaySizeSystemFontFamily = 3 // 'system' font at display sizes
|
||||
};
|
||||
void GetSystemFontFamilyList(
|
||||
InfallibleTArray<mozilla::dom::FontFamilyListEntry>* aList);
|
||||
void ReadSystemFontList(
|
||||
InfallibleTArray<mozilla::dom::SystemFontListEntry>* aList);
|
||||
|
||||
protected:
|
||||
gfxFontFamily*
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
#include "gfxFontConstants.h"
|
||||
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
|
@ -76,6 +77,7 @@
|
|||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
using mozilla::dom::SystemFontListEntry;
|
||||
using mozilla::dom::FontFamilyListEntry;
|
||||
|
||||
// indexes into the NSArray objects that the Cocoa font manager returns
|
||||
|
@ -987,12 +989,17 @@ gfxMacPlatformFontList::gfxMacPlatformFontList() :
|
|||
}
|
||||
}
|
||||
|
||||
::CFNotificationCenterAddObserver(::CFNotificationCenterGetLocalCenter(),
|
||||
this,
|
||||
RegisteredFontsChangedNotificationCallback,
|
||||
kCTFontManagerRegisteredFontsChangedNotification,
|
||||
0,
|
||||
CFNotificationSuspensionBehaviorDeliverImmediately);
|
||||
// Only the parent process listens for OS font-changed notifications;
|
||||
// after rebuilding its list, it will update the content processes.
|
||||
if (XRE_IsParentProcess()) {
|
||||
::CFNotificationCenterAddObserver(
|
||||
::CFNotificationCenterGetLocalCenter(),
|
||||
this,
|
||||
RegisteredFontsChangedNotificationCallback,
|
||||
kCTFontManagerRegisteredFontsChangedNotification,
|
||||
0,
|
||||
CFNotificationSuspensionBehaviorDeliverImmediately);
|
||||
}
|
||||
|
||||
// cache this in a static variable so that MacOSFontFamily objects
|
||||
// don't have to repeatedly look it up
|
||||
|
@ -1001,10 +1008,13 @@ gfxMacPlatformFontList::gfxMacPlatformFontList() :
|
|||
|
||||
gfxMacPlatformFontList::~gfxMacPlatformFontList()
|
||||
{
|
||||
::CFNotificationCenterRemoveObserver(::CFNotificationCenterGetLocalCenter(),
|
||||
this,
|
||||
kCTFontManagerRegisteredFontsChangedNotification,
|
||||
0);
|
||||
if (XRE_IsParentProcess()) {
|
||||
::CFNotificationCenterRemoveObserver(
|
||||
::CFNotificationCenterGetLocalCenter(),
|
||||
this,
|
||||
kCTFontManagerRegisteredFontsChangedNotification,
|
||||
0);
|
||||
}
|
||||
|
||||
if (mDefaultFont) {
|
||||
::CFRelease(mDefaultFont);
|
||||
|
@ -1056,8 +1066,8 @@ gfxMacPlatformFontList::AddFamily(CFStringRef aFamily)
|
|||
}
|
||||
|
||||
void
|
||||
gfxMacPlatformFontList::GetSystemFontFamilyList(
|
||||
InfallibleTArray<FontFamilyListEntry>* aList)
|
||||
gfxMacPlatformFontList::ReadSystemFontList(
|
||||
InfallibleTArray<SystemFontListEntry>* aList)
|
||||
{
|
||||
// Note: We rely on the records for mSystemTextFontFamilyName and
|
||||
// mSystemDisplayFontFamilyName (if present) being *before* the main
|
||||
|
@ -1099,32 +1109,31 @@ gfxMacPlatformFontList::InitFontListForPlatform()
|
|||
// Content process: use font list passed from the chrome process via
|
||||
// the GetXPCOMProcessAttributes message, because it's much faster than
|
||||
// querying Core Text again in the child.
|
||||
mozilla::dom::ContentChild* cc =
|
||||
mozilla::dom::ContentChild::GetSingleton();
|
||||
for (auto f : cc->SystemFontFamilyList()) {
|
||||
switch (f.entryType()) {
|
||||
auto& fontList = dom::ContentChild::GetSingleton()->SystemFontList();
|
||||
for (SystemFontListEntry& fle : fontList) {
|
||||
MOZ_ASSERT(fle.type() ==
|
||||
SystemFontListEntry::Type::TFontFamilyListEntry);
|
||||
FontFamilyListEntry& ffe(fle);
|
||||
switch (ffe.entryType()) {
|
||||
case kStandardFontFamily:
|
||||
AddFamily(f.familyName(), false);
|
||||
AddFamily(ffe.familyName(), false);
|
||||
break;
|
||||
case kHiddenSystemFontFamily:
|
||||
AddFamily(f.familyName(), true);
|
||||
AddFamily(ffe.familyName(), true);
|
||||
break;
|
||||
case kTextSizeSystemFontFamily:
|
||||
mSystemTextFontFamilyName = f.familyName();
|
||||
mSystemTextFontFamilyName = ffe.familyName();
|
||||
break;
|
||||
case kDisplaySizeSystemFontFamily:
|
||||
mSystemDisplayFontFamilyName = f.familyName();
|
||||
mSystemDisplayFontFamilyName = ffe.familyName();
|
||||
mUseSizeSensitiveSystemFont = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// The ContentChild doesn't need the font list any longer.
|
||||
cc->SystemFontFamilyList().Clear();
|
||||
}
|
||||
|
||||
// If this is the chrome process, or if for some reason we failed to get
|
||||
// a usable list above, get the available fonts from Core Text.
|
||||
if (!mFontFamilies.Count()) {
|
||||
fontList.Clear();
|
||||
} else {
|
||||
// We're not a content process, so get the available fonts directly
|
||||
// from Core Text.
|
||||
InitSystemFontNames();
|
||||
CFArrayRef familyNames = CTFontManagerCopyAvailableFontFamilyNames();
|
||||
for (NSString* familyName in (NSArray*)familyNames) {
|
||||
|
@ -1343,6 +1352,8 @@ gfxMacPlatformFontList::RegisteredFontsChangedNotificationCallback(CFNotificatio
|
|||
|
||||
// modify a preference that will trigger reflow everywhere
|
||||
fl->ForceGlobalReflow();
|
||||
|
||||
mozilla::dom::ContentParent::NotifyUpdatedFonts();
|
||||
}
|
||||
|
||||
gfxFontEntry*
|
||||
|
|
|
@ -64,7 +64,7 @@ BackendTypeBit(BackendType b)
|
|||
|
||||
} // namespace gfx
|
||||
namespace dom {
|
||||
class FontFamilyListEntry;
|
||||
class SystemFontListEntry;
|
||||
}
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -337,12 +337,12 @@ public:
|
|||
nsTArray<nsString>& aListOfFonts);
|
||||
|
||||
/**
|
||||
* Fill aFontFamilies with a list of FontFamilyListEntry records for the
|
||||
* Fill aFontList with a list of SystemFontListEntry records for the
|
||||
* available fonts on the platform; used to pass the list from chrome to
|
||||
* content process. Currently implemented only on MacOSX.
|
||||
* content process. Currently implemented only on MacOSX and Linux.
|
||||
*/
|
||||
virtual void GetSystemFontFamilyList(
|
||||
InfallibleTArray<mozilla::dom::FontFamilyListEntry>* aFontFamilies)
|
||||
virtual void ReadSystemFontList(
|
||||
InfallibleTArray<mozilla::dom::SystemFontListEntry>* aFontList)
|
||||
{ }
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "nsUnicharUtils.h"
|
||||
#include "nsUnicodeRange.h"
|
||||
#include "nsUnicodeProperties.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Likely.h"
|
||||
|
@ -25,6 +26,7 @@
|
|||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
||||
#include <locale.h>
|
||||
|
@ -200,8 +202,12 @@ gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames)
|
|||
NS_ADDREF(gFontListPrefObserver);
|
||||
Preferences::AddStrongObservers(gFontListPrefObserver, kObservedPrefs);
|
||||
|
||||
Preferences::RegisterCallback(FontWhitelistPrefChanged,
|
||||
kFontSystemWhitelistPref);
|
||||
// Only the parent process listens for whitelist changes; it will then
|
||||
// notify its children to rebuild their font lists.
|
||||
if (XRE_IsParentProcess()) {
|
||||
Preferences::RegisterCallback(FontWhitelistPrefChanged,
|
||||
kFontSystemWhitelistPref);
|
||||
}
|
||||
|
||||
RegisterStrongMemoryReporter(new MemoryReporter());
|
||||
}
|
||||
|
@ -212,11 +218,23 @@ gfxPlatformFontList::~gfxPlatformFontList()
|
|||
ClearLangGroupPrefFonts();
|
||||
NS_ASSERTION(gFontListPrefObserver, "There is no font list pref observer");
|
||||
Preferences::RemoveObservers(gFontListPrefObserver, kObservedPrefs);
|
||||
Preferences::UnregisterCallback(FontWhitelistPrefChanged,
|
||||
kFontSystemWhitelistPref);
|
||||
if (XRE_IsParentProcess()) {
|
||||
Preferences::UnregisterCallback(FontWhitelistPrefChanged,
|
||||
kFontSystemWhitelistPref);
|
||||
}
|
||||
NS_RELEASE(gFontListPrefObserver);
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
gfxPlatformFontList::FontWhitelistPrefChanged(const char *aPref,
|
||||
void *aClosure)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
gfxPlatformFontList::PlatformFontList()->UpdateFontList();
|
||||
mozilla::dom::ContentParent::NotifyUpdatedFonts();
|
||||
}
|
||||
|
||||
// number of CSS generic font families
|
||||
const uint32_t kNumGenerics = 5;
|
||||
|
||||
|
|
|
@ -283,9 +283,7 @@ public:
|
|||
// Returns true if the font family whitelist is not empty.
|
||||
bool IsFontFamilyWhitelistActive();
|
||||
|
||||
static void FontWhitelistPrefChanged(const char *aPref, void *aClosure) {
|
||||
gfxPlatformFontList::PlatformFontList()->UpdateFontList();
|
||||
}
|
||||
static void FontWhitelistPrefChanged(const char *aPref, void *aClosure);
|
||||
|
||||
bool AddWithLegacyFamilyName(const nsAString& aLegacyName,
|
||||
gfxFontEntry* aFontEntry);
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::unicode;
|
||||
using mozilla::dom::SystemFontListEntry;
|
||||
|
||||
#if (MOZ_WIDGET_GTK == 2)
|
||||
static cairo_user_data_key_t cairo_gdk_drawable_key;
|
||||
|
@ -249,6 +250,13 @@ gfxPlatformGtk::GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
gfxPlatformGtk::ReadSystemFontList(
|
||||
InfallibleTArray<SystemFontListEntry>* retValue)
|
||||
{
|
||||
gfxFcPlatformFontList::PlatformFontList()->ReadSystemFontList(retValue);
|
||||
}
|
||||
|
||||
gfxPlatformFontList*
|
||||
gfxPlatformGtk::CreatePlatformFontList()
|
||||
{
|
||||
|
|
|
@ -22,6 +22,12 @@ struct _XDisplay;
|
|||
typedef struct _XDisplay Display;
|
||||
#endif // MOZ_X11
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class SystemFontListEntry;
|
||||
};
|
||||
};
|
||||
|
||||
class gfxPlatformGtk : public gfxPlatform {
|
||||
public:
|
||||
gfxPlatformGtk();
|
||||
|
@ -31,6 +37,9 @@ public:
|
|||
return (gfxPlatformGtk*) gfxPlatform::GetPlatform();
|
||||
}
|
||||
|
||||
void ReadSystemFontList(
|
||||
InfallibleTArray<mozilla::dom::SystemFontListEntry>* retValue) override;
|
||||
|
||||
virtual already_AddRefed<gfxASurface>
|
||||
CreateOffscreenSurface(const IntSize& aSize,
|
||||
gfxImageFormat aFormat) override;
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
using mozilla::dom::FontFamilyListEntry;
|
||||
using mozilla::dom::SystemFontListEntry;
|
||||
|
||||
// cribbed from CTFontManager.h
|
||||
enum {
|
||||
|
@ -113,11 +113,10 @@ gfxPlatformMac::CreatePlatformFontList()
|
|||
}
|
||||
|
||||
void
|
||||
gfxPlatformMac::GetSystemFontFamilyList(
|
||||
InfallibleTArray<FontFamilyListEntry>* aFontFamilies)
|
||||
gfxPlatformMac::ReadSystemFontList(
|
||||
InfallibleTArray<SystemFontListEntry>* aFontList)
|
||||
{
|
||||
gfxMacPlatformFontList::PlatformFontList()->
|
||||
GetSystemFontFamilyList(aFontFamilies);
|
||||
gfxMacPlatformFontList::PlatformFontList()->ReadSystemFontList(aFontList);
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
|
|
|
@ -40,8 +40,8 @@ public:
|
|||
virtual gfxPlatformFontList* CreatePlatformFontList() override;
|
||||
|
||||
void
|
||||
GetSystemFontFamilyList(InfallibleTArray<mozilla::dom::FontFamilyListEntry>*
|
||||
aFontFamilies) override;
|
||||
ReadSystemFontList(InfallibleTArray<mozilla::dom::SystemFontListEntry>*
|
||||
aFontList) override;
|
||||
|
||||
bool IsFontFormatSupported(uint32_t aFormatFlags) override;
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ MSG_DEF(JSMSG_TOPRIMITIVE_RETURNED_OBJECT, 2, JSEXN_TYPEERR, "can't convert {0}
|
|||
MSG_DEF(JSMSG_NO_PROPERTIES, 1, JSEXN_TYPEERR, "{0} has no properties")
|
||||
MSG_DEF(JSMSG_BAD_REGEXP_FLAG, 1, JSEXN_SYNTAXERR, "invalid regular expression flag {0}")
|
||||
MSG_DEF(JSMSG_INVALID_DATA_VIEW_LENGTH, 0, JSEXN_RANGEERR, "invalid data view length")
|
||||
MSG_DEF(JSMSG_ARG_INDEX_OUT_OF_RANGE, 1, JSEXN_RANGEERR, "argument {0} accesses an index that is out of range")
|
||||
MSG_DEF(JSMSG_OFFSET_LARGER_THAN_FILESIZE, 0, JSEXN_RANGEERR, "offset is larger than filesize")
|
||||
MSG_DEF(JSMSG_OFFSET_OUT_OF_BUFFER, 0, JSEXN_RANGEERR, "start offset is outside the bounds of the buffer")
|
||||
MSG_DEF(JSMSG_OFFSET_OUT_OF_DATAVIEW, 0, JSEXN_RANGEERR, "offset is outside the bounds of the DataView")
|
||||
MSG_DEF(JSMSG_SPREAD_TOO_LARGE, 0, JSEXN_RANGEERR, "array too large due to spread operand(s)")
|
||||
|
|
|
@ -1157,7 +1157,7 @@ CreateMappedArrayBuffer(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
if (off_t(offset) >= st.st_size) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_ARG_INDEX_OUT_OF_RANGE, "2");
|
||||
JSMSG_OFFSET_LARGER_THAN_FILESIZE);
|
||||
return false;
|
||||
}
|
||||
size = st.st_size - offset;
|
||||
|
|
|
@ -283,17 +283,21 @@ RetainedDisplayListBuilder::IncrementSubDocPresShellPaintCount(nsDisplayItem* aI
|
|||
}
|
||||
|
||||
void UpdateASR(nsDisplayItem* aItem,
|
||||
const ActiveScrolledRoot* aContainerASR)
|
||||
Maybe<const ActiveScrolledRoot*>& aContainerASR)
|
||||
{
|
||||
if (!aContainerASR) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsDisplayWrapList* wrapList = aItem->AsDisplayWrapList();
|
||||
if (!wrapList) {
|
||||
aItem->SetActiveScrolledRoot(aContainerASR);
|
||||
aItem->SetActiveScrolledRoot(aContainerASR.value());
|
||||
return;
|
||||
}
|
||||
|
||||
wrapList->SetActiveScrolledRoot(
|
||||
ActiveScrolledRoot::PickAncestor(wrapList->GetFrameActiveScrolledRoot(),
|
||||
aContainerASR));
|
||||
aContainerASR.value()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -347,25 +351,27 @@ void
|
|||
RetainedDisplayListBuilder::MergeDisplayLists(nsDisplayList* aNewList,
|
||||
nsDisplayList* aOldList,
|
||||
nsDisplayList* aOutList,
|
||||
const ActiveScrolledRoot** aOutContainerASR)
|
||||
Maybe<const ActiveScrolledRoot*>& aOutContainerASR)
|
||||
{
|
||||
nsDisplayList merged(&mBuilder);
|
||||
const ActiveScrolledRoot* containerASR = nullptr;
|
||||
|
||||
const auto ReuseItem = [&](nsDisplayItem* aItem) {
|
||||
const auto UseItem = [&](nsDisplayItem* aItem) {
|
||||
const ActiveScrolledRoot* itemClipASR =
|
||||
aItem->GetClipChain() ? aItem->GetClipChain()->mASR : nullptr;
|
||||
|
||||
const ActiveScrolledRoot* finiteBoundsASR = ActiveScrolledRoot::PickDescendant(
|
||||
itemClipASR, aItem->GetActiveScrolledRoot());
|
||||
if (merged.IsEmpty()) {
|
||||
containerASR = finiteBoundsASR;
|
||||
if (!aOutContainerASR) {
|
||||
aOutContainerASR = Some(finiteBoundsASR);
|
||||
} else {
|
||||
containerASR =
|
||||
ActiveScrolledRoot::PickAncestor(containerASR, finiteBoundsASR);
|
||||
aOutContainerASR =
|
||||
Some(ActiveScrolledRoot::PickAncestor(aOutContainerASR.value(), finiteBoundsASR));
|
||||
}
|
||||
|
||||
merged.AppendToTop(aItem);
|
||||
};
|
||||
|
||||
const auto ReuseItem = [&](nsDisplayItem* aItem) {
|
||||
UseItem(aItem);
|
||||
aItem->SetReused(true);
|
||||
|
||||
if (aItem->GetType() == DisplayItemType::TYPE_SUBDOCUMENT) {
|
||||
|
@ -408,9 +414,9 @@ RetainedDisplayListBuilder::MergeDisplayLists(nsDisplayList* aNewList,
|
|||
|
||||
if (oldItem->GetChildren()) {
|
||||
MOZ_ASSERT(newItem->GetChildren());
|
||||
const ActiveScrolledRoot* containerASRForChildren;
|
||||
Maybe<const ActiveScrolledRoot*> containerASRForChildren;
|
||||
MergeDisplayLists(newItem->GetChildren(), oldItem->GetChildren(),
|
||||
oldItem->GetChildren(), &containerASRForChildren);
|
||||
oldItem->GetChildren(), containerASRForChildren);
|
||||
UpdateASR(oldItem, containerASRForChildren);
|
||||
oldItem->UpdateBounds(&mBuilder);
|
||||
}
|
||||
|
@ -428,9 +434,9 @@ RetainedDisplayListBuilder::MergeDisplayLists(nsDisplayList* aNewList,
|
|||
// ensure that we find and remove any invalidated items.
|
||||
if (old->GetChildren()) {
|
||||
nsDisplayList empty(&mBuilder);
|
||||
const ActiveScrolledRoot* containerASRForChildren;
|
||||
Maybe<const ActiveScrolledRoot*> containerASRForChildren;
|
||||
MergeDisplayLists(&empty, old->GetChildren(),
|
||||
old->GetChildren(), &containerASRForChildren);
|
||||
old->GetChildren(), containerASRForChildren);
|
||||
UpdateASR(old, containerASRForChildren);
|
||||
old->UpdateBounds(&mBuilder);
|
||||
}
|
||||
|
@ -458,21 +464,21 @@ RetainedDisplayListBuilder::MergeDisplayLists(nsDisplayList* aNewList,
|
|||
if (!IsAnyAncestorModified(old->FrameForInvalidation()) &&
|
||||
old->GetChildren()) {
|
||||
MOZ_ASSERT(newItem->GetChildren());
|
||||
const ActiveScrolledRoot* containerASRForChildren;
|
||||
Maybe<const ActiveScrolledRoot*> containerASRForChildren;
|
||||
MergeDisplayLists(newItem->GetChildren(), old->GetChildren(),
|
||||
newItem->GetChildren(), &containerASRForChildren);
|
||||
newItem->GetChildren(), containerASRForChildren);
|
||||
UpdateASR(newItem, containerASRForChildren);
|
||||
newItem->UpdateBounds(&mBuilder);
|
||||
}
|
||||
|
||||
old->Destroy(&mBuilder);
|
||||
merged.AppendToTop(newItem);
|
||||
UseItem(newItem);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If there was no matching item in the old list, then we only need to
|
||||
// add the new item to the merged list.
|
||||
merged.AppendToTop(newItem);
|
||||
UseItem(newItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -485,10 +491,10 @@ RetainedDisplayListBuilder::MergeDisplayLists(nsDisplayList* aNewList,
|
|||
// Passing an empty new display list as an argument skips the merging
|
||||
// loop above and jumps back here.
|
||||
nsDisplayList empty(&mBuilder);
|
||||
const ActiveScrolledRoot* containerASRForChildren;
|
||||
Maybe<const ActiveScrolledRoot*> containerASRForChildren;
|
||||
|
||||
MergeDisplayLists(&empty, old->GetChildren(),
|
||||
old->GetChildren(), &containerASRForChildren);
|
||||
old->GetChildren(), containerASRForChildren);
|
||||
UpdateASR(old, containerASRForChildren);
|
||||
old->UpdateBounds(&mBuilder);
|
||||
}
|
||||
|
@ -502,9 +508,6 @@ RetainedDisplayListBuilder::MergeDisplayLists(nsDisplayList* aNewList,
|
|||
}
|
||||
|
||||
aOutList->AppendToTop(&merged);
|
||||
if (aOutContainerASR) {
|
||||
*aOutContainerASR = containerASR;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -846,7 +849,8 @@ RetainedDisplayListBuilder::AttemptPartialUpdate(nscolor aBackstop)
|
|||
// are not visible anymore) from the old list.
|
||||
// TODO: Optimization opportunity. In this case, MergeDisplayLists()
|
||||
// unnecessarily creates a hashtable of the old items.
|
||||
MergeDisplayLists(&modifiedDL, &mList, &mList, nullptr);
|
||||
Maybe<const ActiveScrolledRoot*> dummy;
|
||||
MergeDisplayLists(&modifiedDL, &mList, &mList, dummy);
|
||||
|
||||
//printf_stderr("Painting --- Merged list:\n");
|
||||
//nsFrame::PrintDisplayList(&mBuilder, mList);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#define RETAINEDDISPLAYLISTBUILDER_H_
|
||||
|
||||
#include "nsDisplayList.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
struct RetainedDisplayListBuilder {
|
||||
RetainedDisplayListBuilder(nsIFrame* aReferenceFrame,
|
||||
|
@ -35,7 +36,7 @@ private:
|
|||
void MergeDisplayLists(nsDisplayList* aNewList,
|
||||
nsDisplayList* aOldList,
|
||||
nsDisplayList* aOutList,
|
||||
const mozilla::ActiveScrolledRoot** aOutContainerASR = nullptr);
|
||||
mozilla::Maybe<const mozilla::ActiveScrolledRoot*>& aOutContainerASR);
|
||||
|
||||
bool ComputeRebuildRegion(nsTArray<nsIFrame*>& aModifiedFrames,
|
||||
nsRect* aOutDirty,
|
||||
|
|
147
mfbt/Maybe.h
147
mfbt/Maybe.h
|
@ -225,7 +225,11 @@ public:
|
|||
bool isNothing() const { return !mIsSome; }
|
||||
|
||||
/* Returns the contents of this Maybe<T> by value. Unsafe unless |isSome()|. */
|
||||
T value() const;
|
||||
T value() const
|
||||
{
|
||||
MOZ_ASSERT(mIsSome);
|
||||
return ref();
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the contents of this Maybe<T> by value. If |isNothing()|, returns
|
||||
|
@ -254,8 +258,17 @@ public:
|
|||
}
|
||||
|
||||
/* Returns the contents of this Maybe<T> by pointer. Unsafe unless |isSome()|. */
|
||||
T* ptr();
|
||||
const T* ptr() const;
|
||||
T* ptr()
|
||||
{
|
||||
MOZ_ASSERT(mIsSome);
|
||||
return &ref();
|
||||
}
|
||||
|
||||
const T* ptr() const
|
||||
{
|
||||
MOZ_ASSERT(mIsSome);
|
||||
return &ref();
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the contents of this Maybe<T> by pointer. If |isNothing()|,
|
||||
|
@ -299,12 +312,30 @@ public:
|
|||
return aFunc();
|
||||
}
|
||||
|
||||
T* operator->();
|
||||
const T* operator->() const;
|
||||
T* operator->()
|
||||
{
|
||||
MOZ_ASSERT(mIsSome);
|
||||
return ptr();
|
||||
}
|
||||
|
||||
const T* operator->() const
|
||||
{
|
||||
MOZ_ASSERT(mIsSome);
|
||||
return ptr();
|
||||
}
|
||||
|
||||
/* Returns the contents of this Maybe<T> by ref. Unsafe unless |isSome()|. */
|
||||
T& ref();
|
||||
const T& ref() const;
|
||||
T& ref()
|
||||
{
|
||||
MOZ_ASSERT(mIsSome);
|
||||
return *static_cast<T*>(data());
|
||||
}
|
||||
|
||||
const T& ref() const
|
||||
{
|
||||
MOZ_ASSERT(mIsSome);
|
||||
return *static_cast<const T*>(data());
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the contents of this Maybe<T> by ref. If |isNothing()|, returns
|
||||
|
@ -348,8 +379,17 @@ public:
|
|||
return aFunc();
|
||||
}
|
||||
|
||||
T& operator*();
|
||||
const T& operator*() const;
|
||||
T& operator*()
|
||||
{
|
||||
MOZ_ASSERT(mIsSome);
|
||||
return ref();
|
||||
}
|
||||
|
||||
const T& operator*() const
|
||||
{
|
||||
MOZ_ASSERT(mIsSome);
|
||||
return ref();
|
||||
}
|
||||
|
||||
/* If |isSome()|, runs the provided function or functor on the contents of
|
||||
* this Maybe. */
|
||||
|
@ -413,7 +453,12 @@ public:
|
|||
* arguments to |emplace()| are the parameters to T's constructor.
|
||||
*/
|
||||
template<typename... Args>
|
||||
void emplace(Args&&... aArgs);
|
||||
void emplace(Args&&... aArgs)
|
||||
{
|
||||
MOZ_ASSERT(!mIsSome);
|
||||
::new (KnownNotNull, data()) T(Forward<Args>(aArgs)...);
|
||||
mIsSome = true;
|
||||
}
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& aStream, const Maybe<T>& aMaybe)
|
||||
|
@ -427,88 +472,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T
|
||||
Maybe<T>::value() const
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(mIsSome);
|
||||
return ref();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T*
|
||||
Maybe<T>::ptr()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(mIsSome);
|
||||
return &ref();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T*
|
||||
Maybe<T>::ptr() const
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(mIsSome);
|
||||
return &ref();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T*
|
||||
Maybe<T>::operator->()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(mIsSome);
|
||||
return ptr();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T*
|
||||
Maybe<T>::operator->() const
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(mIsSome);
|
||||
return ptr();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T&
|
||||
Maybe<T>::ref()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(mIsSome);
|
||||
return *static_cast<T*>(data());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T&
|
||||
Maybe<T>::ref() const
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(mIsSome);
|
||||
return *static_cast<const T*>(data());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T&
|
||||
Maybe<T>::operator*()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(mIsSome);
|
||||
return ref();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T&
|
||||
Maybe<T>::operator*() const
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(mIsSome);
|
||||
return ref();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename... Args>
|
||||
void
|
||||
Maybe<T>::emplace(Args&&... aArgs)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!mIsSome);
|
||||
::new (KnownNotNull, data()) T(Forward<Args>(aArgs)...);
|
||||
mIsSome = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some() creates a Maybe<T> value containing the provided T value. If T has a
|
||||
* move constructor, it's used to make this as efficient as possible.
|
||||
|
|
|
@ -3133,8 +3133,8 @@ pref("layout.display-list.dump-content", false);
|
|||
pref("layout.display-list.dump-parent", false);
|
||||
|
||||
// Toggle retaining display lists between paints
|
||||
#ifdef ANDROID
|
||||
pref("layout.display-list.retain", false);
|
||||
#if !defined(ANDROID) && defined(NIGHTLY_BUILD)
|
||||
pref("layout.display-list.retain", true);
|
||||
#else
|
||||
pref("layout.display-list.retain", false);
|
||||
#endif
|
||||
|
|
|
@ -548,7 +548,9 @@ Connection::Connection(Service *aService,
|
|||
|
||||
Connection::~Connection()
|
||||
{
|
||||
Unused << Close();
|
||||
// Failsafe Close() occurs in our custom Release method because of
|
||||
// complications related to Close() potentially invoking AsyncClose() which
|
||||
// will increment our refcount.
|
||||
MOZ_ASSERT(!mAsyncExecutionThread,
|
||||
"The async thread has not been shutdown properly!");
|
||||
}
|
||||
|
@ -572,8 +574,55 @@ NS_IMETHODIMP_(MozExternalRefCountType) Connection::Release(void)
|
|||
if (1 == count) {
|
||||
// If the refcount is 1, the single reference must be from
|
||||
// gService->mConnections (in class |Service|). Which means we can
|
||||
// unregister it safely.
|
||||
mStorageService->unregisterConnection(this);
|
||||
// perform our failsafe Close() and unregister...
|
||||
//
|
||||
// HOWEVER, there is an edge-case where our failsafe Close() may trigger
|
||||
// a call to AsyncClose() which obtains a strong reference. This reference
|
||||
// will be released via NS_ReleaseOnMainThreadSystemGroup() before Close()
|
||||
// returns, which can potentially result in reentrancy into this method and
|
||||
// this branch a second time. (It may also be deferred if we're not in
|
||||
// that event target ourselves.) To avoid reentrancy madness, we explicitly
|
||||
// bump our refcount up to 2 without going through AddRef().
|
||||
++mRefCnt;
|
||||
// Okay, now our refcount is 2, we trigger Close().
|
||||
Unused << Close();
|
||||
// Now our refcount should either be at 2 (because nothing happened, or the
|
||||
// addref and release pair happened due to SpinningSynchronousClose) or
|
||||
// 3 (because SpinningSynchronousClose happened but didn't release yet).
|
||||
//
|
||||
// We *really* want to avoid re-entrancy, and we have potentially two strong
|
||||
// references remaining that will invoke Release() and potentially trigger
|
||||
// a transition to 1 again. Since the second reference would be just a
|
||||
// proxy release of an already-closed connection, it's not a big deal for us
|
||||
// to unregister the connection now. We do need to take care to avoid a
|
||||
// strong refcount transition to 1 from 2 because that would induce
|
||||
// reentrancy. Note that we do not have any concerns about other threads
|
||||
// being involved here; we MUST be the main thread if AsyncClose() is
|
||||
// involved.
|
||||
//
|
||||
// Note: While Close() potentially spins the nested event loop, it is
|
||||
// conceivable that Service::CollectReports or Service::minimizeMemory might
|
||||
// be invoked. These call Service::getConnections() and will perform
|
||||
// matching AddRef and Release calls but will definitely not retain any
|
||||
// references. (Because connectionReady() will return false so both loops
|
||||
// will immediately "continue" to bypass the connection in question.)
|
||||
// Because our refcount is at least 2 at the lowest point, these do not pose
|
||||
// a problem.
|
||||
if (mRefCnt == 3) {
|
||||
// pending proxy release, strong release to 2
|
||||
mStorageService->unregisterConnection(this);
|
||||
// now weak release to 1, the outstanding refcount will strong release to
|
||||
// 0 and result in destruction later.
|
||||
--mRefCnt;
|
||||
} else if (mRefCnt == 2) {
|
||||
// weak release to 1
|
||||
--mRefCnt;
|
||||
// strong release to 0, destruction will happen, we must NOT touch
|
||||
// `this` after this point.
|
||||
mStorageService->unregisterConnection(this);
|
||||
} else {
|
||||
MOZ_ASSERT(false, "Connection refcount invariant violated.");
|
||||
}
|
||||
} else if (0 == count) {
|
||||
mRefCnt = 1; /* stabilize */
|
||||
#if 0 /* enable this to find non-threadsafe destructors: */
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/* 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/. */
|
||||
|
||||
/*
|
||||
* This file tests edge-cases related to mozStorageService::unregisterConnection
|
||||
* in the face of failsafe closing at destruction time which results in
|
||||
* SpinningSynchronousClose being invoked which can "resurrect" the connection
|
||||
* and result in a second call to unregisterConnection.
|
||||
*
|
||||
* See https://bugzilla.mozilla.org/show_bug.cgi?id=1413501 for more context.
|
||||
*/
|
||||
|
||||
add_task(async function test_failsafe_close_of_async_connection() {
|
||||
// get the db
|
||||
let db = getOpenedDatabase();
|
||||
|
||||
// do something async
|
||||
let callbackInvoked = new Promise((resolve) => {
|
||||
db.executeSimpleSQLAsync("CREATE TABLE test (id INTEGER)",
|
||||
{ handleCompletion: resolve });
|
||||
});
|
||||
|
||||
// drop our reference and force a GC so the only live reference is owned by
|
||||
// the async statement.
|
||||
db = gDBConn = null;
|
||||
// (we don't need to cycle collect)
|
||||
Components.utils.forceGC();
|
||||
|
||||
// now we need to wait for that callback to have completed.
|
||||
await callbackInvoked;
|
||||
|
||||
Assert.ok(true, "if we shutdown cleanly and do not crash, then we succeeded");
|
||||
});
|
|
@ -18,6 +18,10 @@ fail-if = os == "android"
|
|||
[test_connection_asyncClose.js]
|
||||
[test_connection_executeAsync.js]
|
||||
[test_connection_executeSimpleSQLAsync.js]
|
||||
[test_connection_failsafe_close.js]
|
||||
# The failsafe close mechanism asserts when performing SpinningSynchronousClose
|
||||
# on debug builds, so we can only test on non-debug builds.
|
||||
skip-if = debug
|
||||
[test_connection_interrupt.js]
|
||||
[test_js_helpers.js]
|
||||
[test_levenshtein.js]
|
||||
|
|
|
@ -31,7 +31,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetters(this, {
|
||||
gAddonPolicyService: ["@mozilla.org/addons/policy-service;1", "nsIAddonPolicyService"],
|
||||
aomStartup: ["@mozilla.org/addons/addon-manager-startup;1", "amIAddonManagerStartup"],
|
||||
});
|
||||
|
||||
|
@ -1478,8 +1477,6 @@ StartupCache = {
|
|||
},
|
||||
};
|
||||
|
||||
// void StartupCache.dataPromise;
|
||||
|
||||
Services.obs.addObserver(StartupCache, "startupcache-invalidate");
|
||||
|
||||
class CacheStore {
|
||||
|
|
Загрузка…
Ссылка в новой задаче