Bug 962440 - async font info loader infrastructure with OSX implementation. r=bas

This commit is contained in:
John Daggett 2014-01-29 16:39:01 +09:00
Родитель 9df88fff38
Коммит 031132973a
14 изменённых файлов: 710 добавлений и 126 удалений

Просмотреть файл

@ -147,7 +147,7 @@ GetDirectWriteFaceName(IDWriteFont *aFont,
}
void
gfxDWriteFontFamily::FindStyleVariations()
gfxDWriteFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
{
HRESULT hr;
if (mHasStyles) {
@ -496,30 +496,38 @@ gfxDWriteFontEntry::GetFontTable(uint32_t aTag)
}
nsresult
gfxDWriteFontEntry::ReadCMAP()
gfxDWriteFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
{
nsresult rv;
// attempt this once, if errors occur leave a blank cmap
if (mCharacterMap) {
return NS_OK;
}
nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
nsRefPtr<gfxCharacterMap> charmap;
nsresult rv;
bool symbolFont;
uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
AutoTable cmapTable(this, kCMAP);
if (cmapTable) {
bool unicodeFont = false, symbolFont = false; // currently ignored
uint32_t cmapLen;
const uint8_t* cmapData =
reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable,
&cmapLen));
rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen,
*charmap, mUVSOffset,
unicodeFont, symbolFont);
if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData,
mUVSOffset,
symbolFont))) {
rv = NS_OK;
} else {
rv = NS_ERROR_NOT_AVAILABLE;
uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
charmap = new gfxCharacterMap();
AutoTable cmapTable(this, kCMAP);
if (cmapTable) {
bool unicodeFont = false, symbolFont = false; // currently ignored
uint32_t cmapLen;
const uint8_t* cmapData =
reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable,
&cmapLen));
rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen,
*charmap, mUVSOffset,
unicodeFont, symbolFont);
} else {
rv = NS_ERROR_NOT_AVAILABLE;
}
}
mHasCmapTable = NS_SUCCEEDED(rv);

Просмотреть файл

@ -43,7 +43,7 @@ public:
: gfxFontFamily(aName), mDWFamily(aFamily), mForceGDIClassic(false) {}
virtual ~gfxDWriteFontFamily();
virtual void FindStyleVariations();
virtual void FindStyleVariations(FontInfoData *aFontInfoData = nullptr);
virtual void LocalizedName(nsAString& aLocalizedName);
@ -149,7 +149,7 @@ public:
virtual hb_blob_t* GetFontTable(uint32_t aTableTag) MOZ_OVERRIDE;
nsresult ReadCMAP();
nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr);
bool IsCJKFont();

Просмотреть файл

@ -463,7 +463,7 @@ FT2FontEntry::CairoFontFace()
}
nsresult
FT2FontEntry::ReadCMAP()
FT2FontEntry::ReadCMAP(FontInfoData *aFontInfoData)
{
if (mCharacterMap) {
return NS_OK;

Просмотреть файл

@ -74,7 +74,7 @@ public:
// This may fail and return null, so caller must be prepared to handle this.
cairo_scaled_font_t *CreateScaledFont(const gfxFontStyle *aStyle);
nsresult ReadCMAP();
nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr);
virtual hb_blob_t* GetFontTable(uint32_t aTableTag) MOZ_OVERRIDE;

Просмотреть файл

@ -225,7 +225,7 @@ uint16_t gfxFontEntry::GetUVSGlyph(uint32_t aCh, uint32_t aVS)
return 0;
}
nsresult gfxFontEntry::ReadCMAP()
nsresult gfxFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
{
NS_ASSERTION(false, "using default no-op implementation of ReadCMAP");
mCharacterMap = new gfxCharacterMap();
@ -564,6 +564,18 @@ gfxFontEntry::GetTableFromFontData(const void* aFontData, uint32_t aTableTag)
return nullptr;
}
already_AddRefed<gfxCharacterMap>
gfxFontEntry::GetCMAPFromFontInfo(FontInfoData *aFontInfoData,
uint32_t& aUVSOffset,
bool& aSymbolFont)
{
if (!aFontInfoData || !aFontInfoData->mLoadCmaps) {
return nullptr;
}
return aFontInfoData->GetCMAP(mName, aUVSOffset, aSymbolFont);
}
hb_blob_t *
gfxFontEntry::GetFontTable(uint32_t aTag)
{
@ -905,6 +917,11 @@ gfxFontFamily::FindFontForStyle(const gfxFontStyle& aFontStyle,
void
gfxFontFamily::CheckForSimpleFamily()
{
// already checked this family
if (mIsSimpleFamily) {
return;
};
uint32_t count = mAvailableFonts.Length();
if (count > 4 || count == 0) {
return; // can't be "simple" if there are >4 faces;
@ -1266,18 +1283,46 @@ gfxFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList)
void
gfxFontFamily::ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
bool aNeedFullnamePostscriptNames)
bool aNeedFullnamePostscriptNames,
FontInfoData *aFontInfoData)
{
// if all needed names have already been read, skip
if (mOtherFamilyNamesInitialized &&
(mFaceNamesInitialized || !aNeedFullnamePostscriptNames))
return;
FindStyleVariations();
if (!mOtherFamilyNamesInitialized &&
aFontInfoData &&
aFontInfoData->mLoadOtherNames)
{
nsAutoTArray<nsString,4> otherFamilyNames;
bool foundOtherNames =
aFontInfoData->GetOtherFamilyNames(mName, otherFamilyNames);
if (foundOtherNames) {
uint32_t i, n = otherFamilyNames.Length();
for (i = 0; i < n; i++) {
aPlatformFontList->AddOtherFamilyName(this, otherFamilyNames[i]);
}
}
mOtherFamilyNamesInitialized = true;
}
// if all needed data has been initialized, return
if (mOtherFamilyNamesInitialized &&
(mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
return;
}
FindStyleVariations(aFontInfoData);
// check again, as style enumeration code may have loaded names
if (mOtherFamilyNamesInitialized &&
(mFaceNamesInitialized || !aNeedFullnamePostscriptNames)) {
return;
}
uint32_t i, numFonts = mAvailableFonts.Length();
const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e');
nsAutoString fullname, psname;
bool firstTime = true, readAllFaces = false;
for (i = 0; i < numFonts; ++i) {
@ -1285,11 +1330,35 @@ gfxFontFamily::ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
if (!fe) {
continue;
}
nsAutoString fullname, psname;
bool foundFaceNames = false;
if (!mFaceNamesInitialized &&
aNeedFullnamePostscriptNames &&
aFontInfoData &&
aFontInfoData->mLoadFaceNames) {
aFontInfoData->GetFaceNames(fe->Name(), fullname, psname);
if (!fullname.IsEmpty()) {
aPlatformFontList->AddFullname(fe, fullname);
}
if (!psname.IsEmpty()) {
aPlatformFontList->AddPostscriptName(fe, psname);
}
foundFaceNames = true;
// found everything needed? skip to next font
if (mOtherFamilyNamesInitialized) {
continue;
}
}
// load directly from the name table
gfxFontEntry::AutoTable nameTable(fe, kNAME);
if (!nameTable) {
continue;
}
if (aNeedFullnamePostscriptNames) {
if (aNeedFullnamePostscriptNames && !foundFaceNames) {
if (gfxFontUtils::ReadCanonicalName(
nameTable, gfxFontUtils::NAME_ID_FULL, fullname) == NS_OK)
{
@ -1341,8 +1410,10 @@ gfxFontFamily::FindFont(const nsAString& aPostscriptName)
}
void
gfxFontFamily::ReadAllCMAPs()
gfxFontFamily::ReadAllCMAPs(FontInfoData *aFontInfoData)
{
FindStyleVariations(aFontInfoData);
uint32_t i, numFonts = mAvailableFonts.Length();
for (i = 0; i < numFonts; i++) {
gfxFontEntry *fe = mAvailableFonts[i];
@ -1350,7 +1421,7 @@ gfxFontFamily::ReadAllCMAPs()
if (!fe || fe->mIsProxy) {
continue;
}
fe->ReadCMAP();
fe->ReadCMAP(aFontInfoData);
mFamilyCharacterMap.Union(*(fe->mCharacterMap));
}
mFamilyCharacterMap.Compact();

Просмотреть файл

@ -49,6 +49,7 @@ class gfxShapedText;
class gfxShapedWord;
class gfxSVGGlyphs;
class gfxTextContextPaint;
class FontInfoData;
class nsILanguageAtomService;
@ -299,7 +300,7 @@ public:
// ReadCMAP() must *always* set the mCharacterMap pointer to a valid
// gfxCharacterMap, even if empty, as other code assumes this pointer
// can be safely dereferenced.
virtual nsresult ReadCMAP();
virtual nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr);
bool TryGetSVGData(gfxFont* aFont);
bool HasSVGGlyph(uint32_t aGlyphId);
@ -491,6 +492,12 @@ protected:
// caller is responsible to do any sanitization/validation necessary.
hb_blob_t* GetTableFromFontData(const void* aFontData, uint32_t aTableTag);
// lookup the cmap in cached font data
virtual already_AddRefed<gfxCharacterMap>
GetCMAPFromFontInfo(FontInfoData *aFontInfoData,
uint32_t& aUVSOffset,
bool& aSymbolFont);
// Font's unitsPerEm from the 'head' table, if available (will be set to
// kInvalidUPEM for non-sfnt font formats)
uint16_t mUnitsPerEm;
@ -693,6 +700,7 @@ public:
}
// note that the styles for this family have been added
bool HasStyles() { return mHasStyles; }
void SetHasStyles(bool aHasStyles) { mHasStyles = aHasStyles; }
// choose a specific face to match a style using CSS font matching
@ -729,17 +737,18 @@ public:
// read in other localized family names, fullnames and Postscript names
// for all faces and append to lookup tables
virtual void ReadFaceNames(gfxPlatformFontList *aPlatformFontList,
bool aNeedFullnamePostscriptNames);
bool aNeedFullnamePostscriptNames,
FontInfoData *aFontInfoData = nullptr);
// find faces belonging to this family (platform implementations override this;
// should be made pure virtual once all subclasses have been updated)
virtual void FindStyleVariations() { }
virtual void FindStyleVariations(FontInfoData *aFontInfoData = nullptr) { }
// search for a specific face using the Postscript name
gfxFontEntry* FindFont(const nsAString& aPostscriptName);
// read in cmaps for all the faces
void ReadAllCMAPs();
void ReadAllCMAPs(FontInfoData *aFontInfoData = nullptr);
bool TestCharacterMap(uint32_t aCh) {
if (!mFamilyCharacterMapInitialized) {

Просмотреть файл

@ -6,10 +6,86 @@
#include "gfxFontInfoLoader.h"
#include "nsCRT.h"
#include "nsIObserverService.h"
#include "nsThreadUtils.h" // for nsRunnable
#include "gfxPlatformFontList.h"
using namespace mozilla;
using mozilla::services::GetObserverService;
void
FontInfoData::Load()
{
TimeStamp start = TimeStamp::Now();
uint32_t i, n = mFontFamiliesToLoad.Length();
mLoadStats.families = n;
for (i = 0; i < n; i++) {
LoadFontFamilyData(mFontFamiliesToLoad[i]);
}
mLoadTime = TimeStamp::Now() - start;
}
class FontInfoLoadCompleteEvent : public nsRunnable {
NS_DECL_THREADSAFE_ISUPPORTS
FontInfoLoadCompleteEvent(FontInfoData *aFontInfo) :
mFontInfo(aFontInfo)
{}
virtual ~FontInfoLoadCompleteEvent() {}
NS_IMETHOD Run();
nsRefPtr<FontInfoData> mFontInfo;
};
class AsyncFontInfoLoader : public nsRunnable {
NS_DECL_THREADSAFE_ISUPPORTS
AsyncFontInfoLoader(FontInfoData *aFontInfo) :
mFontInfo(aFontInfo)
{
mCompleteEvent = new FontInfoLoadCompleteEvent(aFontInfo);
}
virtual ~AsyncFontInfoLoader() {}
NS_IMETHOD Run();
nsRefPtr<FontInfoData> mFontInfo;
nsRefPtr<FontInfoLoadCompleteEvent> mCompleteEvent;
};
// runs on main thread after async font info loading is done
nsresult
FontInfoLoadCompleteEvent::Run()
{
gfxFontInfoLoader *loader =
static_cast<gfxFontInfoLoader*>(gfxPlatformFontList::PlatformFontList());
loader->FinalizeLoader(mFontInfo);
mFontInfo = nullptr;
return NS_OK;
}
NS_IMPL_ISUPPORTS1(FontInfoLoadCompleteEvent, nsIRunnable);
// runs on separate thread
nsresult
AsyncFontInfoLoader::Run()
{
// load platform-specific font info
mFontInfo->Load();
// post a completion event that transfer the data to the fontlist
NS_DispatchToMainThread(mCompleteEvent, NS_DISPATCH_NORMAL);
mFontInfo = nullptr;
return NS_OK;
}
NS_IMPL_ISUPPORTS1(AsyncFontInfoLoader, nsIRunnable);
NS_IMPL_ISUPPORTS1(gfxFontInfoLoader::ShutdownObserver, nsIObserver)
NS_IMETHODIMP
@ -31,7 +107,9 @@ gfxFontInfoLoader::StartLoader(uint32_t aDelay, uint32_t aInterval)
mInterval = aInterval;
// sanity check
if (mState != stateInitial && mState != stateTimerOff) {
if (mState != stateInitial &&
mState != stateTimerOff &&
mState != stateTimerOnDelay) {
CancelLoader();
}
@ -44,28 +122,55 @@ gfxFontInfoLoader::StartLoader(uint32_t aDelay, uint32_t aInterval)
}
}
// need an initial delay?
uint32_t timerInterval;
AddShutdownObserver();
// delay? ==> start async thread after a delay
if (aDelay) {
mState = stateTimerOnDelay;
timerInterval = aDelay;
} else {
mState = stateTimerOnInterval;
timerInterval = mInterval;
mTimer->InitWithFuncCallback(DelayedStartCallback, this, aDelay,
nsITimer::TYPE_ONE_SHOT);
return;
}
mFontInfo = CreateFontInfoData();
// initialize
InitLoader();
// start timer
mTimer->InitWithFuncCallback(LoaderTimerCallback, this, timerInterval,
nsITimer::TYPE_REPEATING_SLACK);
nsCOMPtr<nsIObserverService> obs = GetObserverService();
if (obs) {
mObserver = new ShutdownObserver(this);
obs->AddObserver(mObserver, "quit-application", false);
// start async load
mState = stateAsyncLoad;
nsresult rv = NS_NewNamedThread("Font Loader",
getter_AddRefs(mFontLoaderThread),
nullptr);
if (NS_FAILED(rv)) {
return;
}
nsCOMPtr<nsIRunnable> loadEvent = new AsyncFontInfoLoader(mFontInfo);
mFontLoaderThread->Dispatch(loadEvent, NS_DISPATCH_NORMAL);
}
void
gfxFontInfoLoader::FinalizeLoader(FontInfoData *aFontInfo)
{
// avoid loading data if loader has already been canceled
if (mState != stateAsyncLoad) {
return;
}
mLoadTime = mFontInfo->mLoadTime;
// try to load all font data immediately
if (LoadFontInfo()) {
CancelLoader();
return;
}
// not all work completed ==> run load on interval
mState = stateTimerOnInterval;
mTimer->InitWithFuncCallback(LoadFontInfoCallback, this, mInterval,
nsITimer::TYPE_REPEATING_SLACK);
}
void
@ -79,19 +184,23 @@ gfxFontInfoLoader::CancelLoader()
mTimer->Cancel();
mTimer = nullptr;
}
if (mFontLoaderThread) {
mFontLoaderThread->Shutdown();
mFontLoaderThread = nullptr;
}
RemoveShutdownObserver();
FinishLoader();
CleanupLoader();
}
void
gfxFontInfoLoader::LoaderTimerFire()
gfxFontInfoLoader::LoadFontInfoTimerFire()
{
if (mState == stateTimerOnDelay) {
mState = stateTimerOnInterval;
mTimer->SetDelay(mInterval);
}
bool done = RunLoader();
bool done = LoadFontInfo();
if (done) {
CancelLoader();
}
@ -102,6 +211,20 @@ gfxFontInfoLoader::~gfxFontInfoLoader()
RemoveShutdownObserver();
}
void
gfxFontInfoLoader::AddShutdownObserver()
{
if (mObserver) {
return;
}
nsCOMPtr<nsIObserverService> obs = GetObserverService();
if (obs) {
mObserver = new ShutdownObserver(this);
obs->AddObserver(mObserver, "quit-application", false);
}
}
void
gfxFontInfoLoader::RemoveShutdownObserver()
{

Просмотреть файл

@ -6,11 +6,143 @@
#ifndef GFX_FONT_INFO_LOADER_H
#define GFX_FONT_INFO_LOADER_H
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsIObserver.h"
#include "nsITimer.h"
#include "nsIThread.h"
#include "nsRefPtrHashtable.h"
#include "nsString.h"
#include "gfxFont.h"
#include "nsIRunnable.h"
#include "mozilla/TimeStamp.h"
#include "nsTraceRefcnt.h"
// helper class for loading in font info spaced out at regular intervals
// data retrieved for a given face
struct FontFaceData {
FontFaceData() : mUVSOffset(0), mSymbolFont(false) {}
FontFaceData(const FontFaceData& aFontFaceData) {
mFullName = aFontFaceData.mFullName;
mPostscriptName = aFontFaceData.mPostscriptName;
mCharacterMap = aFontFaceData.mCharacterMap;
mUVSOffset = aFontFaceData.mUVSOffset;
mSymbolFont = aFontFaceData.mSymbolFont;
}
nsString mFullName;
nsString mPostscriptName;
nsRefPtr<gfxCharacterMap> mCharacterMap;
uint32_t mUVSOffset;
bool mSymbolFont;
};
// base class used to contain cached system-wide font info.
// methods in this class are called on off-main threads so
// all methods use only static methods or other thread-safe
// font data access API's. specifically, no use is made of
// gfxPlatformFontList, gfxFontFamily, gfxFamily or any
// harfbuzz API methods within FontInfoData subclasses.
class FontInfoData {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FontInfoData)
FontInfoData(bool aLoadOtherNames,
bool aLoadFaceNames,
bool aLoadCmaps) :
mLoadOtherNames(aLoadOtherNames),
mLoadFaceNames(aLoadFaceNames),
mLoadCmaps(aLoadCmaps)
{
MOZ_COUNT_CTOR(FontInfoData);
}
virtual ~FontInfoData() {
MOZ_COUNT_DTOR(FontInfoData);
}
virtual void Load();
// loads font data for all fonts of a given family
// (called on async thread)
virtual void LoadFontFamilyData(const nsAString& aFamilyName) = 0;
// -- methods overriden by platform-specific versions --
// fetches cmap data for a particular font from cached font data
virtual already_AddRefed<gfxCharacterMap>
GetCMAP(const nsAString& aFontName,
uint32_t& aUVSOffset,
bool& aSymbolFont)
{
FontFaceData faceData;
if (!mFontFaceData.Get(aFontName, &faceData) ||
!faceData.mCharacterMap) {
return nullptr;
}
aUVSOffset = faceData.mUVSOffset;
aSymbolFont = faceData.mSymbolFont;
nsRefPtr<gfxCharacterMap> cmap = faceData.mCharacterMap;
return cmap.forget();
}
// fetches fullname/postscript names from cached font data
virtual void GetFaceNames(const nsAString& aFontName,
nsAString& aFullName,
nsAString& aPostscriptName)
{
FontFaceData faceData;
if (!mFontFaceData.Get(aFontName, &faceData)) {
return;
}
aFullName = faceData.mFullName;
aPostscriptName = faceData.mPostscriptName;
}
// fetches localized family name data from cached font data
virtual bool GetOtherFamilyNames(const nsAString& aFamilyName,
nsTArray<nsString>& aOtherFamilyNames)
{
return mOtherFamilyNames.Get(aFamilyName, &aOtherFamilyNames);
}
nsTArray<nsString> mFontFamiliesToLoad;
// time spent on the loader thread
mozilla::TimeDuration mLoadTime;
struct FontCounts {
uint32_t families;
uint32_t fonts;
uint32_t cmaps;
uint32_t facenames;
uint32_t othernames;
};
FontCounts mLoadStats;
bool mLoadOtherNames;
bool mLoadFaceNames;
bool mLoadCmaps;
// face name ==> per-face data
nsDataHashtable<nsStringHashKey, FontFaceData> mFontFaceData;
// canonical family name ==> array of localized family names
nsDataHashtable<nsStringHashKey, nsTArray<nsString> > mOtherFamilyNames;
};
// gfxFontInfoLoader - helper class for loading font info on async thread
// For large, "all fonts on system" data, data needed on a given platform
// (e.g. localized names, face names, cmaps) are loaded async.
// helper class for loading in font info on a separate async thread
// once async thread completes, completion process is run on regular
// intervals to prevent tying up the main thread
class gfxFontInfoLoader {
public:
@ -26,6 +158,7 @@ public:
typedef enum {
stateInitial,
stateTimerOnDelay,
stateAsyncLoad,
stateTimerOnInterval,
stateTimerOff
} TimerState;
@ -40,9 +173,14 @@ public:
// start timer with an initial delay, then call Run method at regular intervals
void StartLoader(uint32_t aDelay, uint32_t aInterval);
// Finalize - async load complete, transfer data (on intervals if necessary)
virtual void FinalizeLoader(FontInfoData *aFontInfo);
// cancel the timer and cleanup
void CancelLoader();
uint32_t GetInterval() { return mInterval; }
protected:
class ShutdownObserver : public nsIObserver
{
@ -61,29 +199,51 @@ protected:
gfxFontInfoLoader *mLoader;
};
// Init - initialization at start time after initial delay
virtual void InitLoader() = 0;
// Run - called at intervals, return true to indicate done
virtual bool RunLoader() = 0;
// Finish - cleanup after done
virtual void FinishLoader() = 0;
// Timer interval callbacks
static void LoaderTimerCallback(nsITimer *aTimer, void *aThis) {
gfxFontInfoLoader *loader = static_cast<gfxFontInfoLoader*>(aThis);
loader->LoaderTimerFire();
// CreateFontInfo - create platform-specific object used
// to load system-wide font info
virtual already_AddRefed<FontInfoData> CreateFontInfoData() {
return nullptr;
}
void LoaderTimerFire();
// Init - initialization before async loader thread runs
virtual void InitLoader() = 0;
// LoadFontInfo - transfer font info data within a time limit, return
// true when done
virtual bool LoadFontInfo() = 0;
// Cleanup - finish and cleanup after done, including possible reflows
virtual void CleanupLoader() {
mFontInfo = nullptr;
}
// Timer interval callbacks
static void LoadFontInfoCallback(nsITimer *aTimer, void *aThis) {
gfxFontInfoLoader *loader = static_cast<gfxFontInfoLoader*>(aThis);
loader->LoadFontInfoTimerFire();
}
static void DelayedStartCallback(nsITimer *aTimer, void *aThis) {
gfxFontInfoLoader *loader = static_cast<gfxFontInfoLoader*>(aThis);
loader->StartLoader(0, loader->GetInterval());
}
void LoadFontInfoTimerFire();
void AddShutdownObserver();
void RemoveShutdownObserver();
nsCOMPtr<nsITimer> mTimer;
nsCOMPtr<nsIObserver> mObserver;
nsCOMPtr<nsIThread> mFontLoaderThread;
uint32_t mInterval;
TimerState mState;
// after async font loader completes, data is stored here
nsRefPtr<FontInfoData> mFontInfo;
// time spent on the loader thread
mozilla::TimeDuration mLoadTime;
};
#endif /* GFX_FONT_INFO_LOADER_H */

Просмотреть файл

@ -146,7 +146,7 @@ GDIFontEntry::GDIFontEntry(const nsAString& aFaceName,
}
nsresult
GDIFontEntry::ReadCMAP()
GDIFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
{
// attempt this once, if errors occur leave a blank cmap
if (mCharacterMap) {
@ -163,22 +163,28 @@ GDIFontEntry::ReadCMAP()
return NS_ERROR_FAILURE;
}
nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
nsRefPtr<gfxCharacterMap> charmap;
nsresult rv;
bool unicodeFont = false, symbolFont = false;
AutoFallibleTArray<uint8_t,16384> cmap;
rv = CopyFontTable(kCMAP, cmap);
if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData,
mUVSOffset,
symbolFont))) {
mSymbolFont = symbolFont;
rv = NS_OK;
} else {
uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
charmap = new gfxCharacterMap();
AutoFallibleTArray<uint8_t,16384> cmap;
rv = CopyFontTable(kCMAP, cmap);
bool unicodeFont = false, symbolFont = false; // currently ignored
if (NS_SUCCEEDED(rv)) {
rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
*charmap, mUVSOffset,
unicodeFont, symbolFont);
if (NS_SUCCEEDED(rv)) {
rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(),
*charmap, mUVSOffset,
unicodeFont, symbolFont);
}
mSymbolFont = symbolFont;
}
mSymbolFont = symbolFont;
mHasCmapTable = NS_SUCCEEDED(rv);
if (mHasCmapTable) {
@ -512,7 +518,7 @@ GDIFontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
}
void
GDIFontFamily::FindStyleVariations()
GDIFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
{
if (mHasStyles)
return;

Просмотреть файл

@ -108,7 +108,7 @@ class GDIFontEntry : public gfxFontEntry
public:
LPLOGFONTW GetLogFont() { return &mLogFont; }
nsresult ReadCMAP();
nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr);
virtual bool IsSymbolFont();
@ -294,7 +294,7 @@ public:
GDIFontFamily(nsAString &aName) :
gfxFontFamily(aName) {}
virtual void FindStyleVariations();
virtual void FindStyleVariations(FontInfoData *aFontInfoData = nullptr);
private:
static int CALLBACK FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,

Просмотреть файл

@ -48,7 +48,7 @@ public:
virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
FontListSizes* aSizes) const;
nsresult ReadCMAP();
nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr);
bool RequiresAATLayout() const { return mRequiresAAT; }
@ -116,6 +116,8 @@ private:
virtual bool UsesSystemFallback() { return true; }
virtual already_AddRefed<FontInfoData> CreateFontInfoData();
enum {
kATSGenerationInitial = -1
};

Просмотреть файл

@ -222,30 +222,38 @@ SupportsScriptInGSUB(gfxFontEntry* aFontEntry, const hb_tag_t* aScriptTags)
}
nsresult
MacOSFontEntry::ReadCMAP()
MacOSFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
{
// attempt this once, if errors occur leave a blank cmap
if (mCharacterMap) {
return NS_OK;
}
nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
AutoTable cmapTable(this, kCMAP);
nsRefPtr<gfxCharacterMap> charmap;
nsresult rv;
bool symbolFont;
if (cmapTable) {
bool unicodeFont = false, symbolFont = false; // currently ignored
uint32_t cmapLen;
const char* cmapData = hb_blob_get_data(cmapTable, &cmapLen);
rv = gfxFontUtils::ReadCMAP((const uint8_t*)cmapData, cmapLen,
*charmap, mUVSOffset,
unicodeFont, symbolFont);
if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData,
mUVSOffset,
symbolFont))) {
rv = NS_OK;
} else {
rv = NS_ERROR_NOT_AVAILABLE;
uint32_t kCMAP = TRUETYPE_TAG('c','m','a','p');
charmap = new gfxCharacterMap();
AutoTable cmapTable(this, kCMAP);
if (cmapTable) {
bool unicodeFont = false, symbolFont = false; // currently ignored
uint32_t cmapLen;
const uint8_t* cmapData =
reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable,
&cmapLen));
rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen,
*charmap, mUVSOffset,
unicodeFont, symbolFont);
} else {
rv = NS_ERROR_NOT_AVAILABLE;
}
}
if (NS_SUCCEEDED(rv) && !HasGraphiteTables()) {
@ -446,7 +454,7 @@ public:
virtual void LocalizedName(nsAString& aLocalizedName);
virtual void FindStyleVariations();
virtual void FindStyleVariations(FontInfoData *aFontInfoData = nullptr);
};
void
@ -474,7 +482,7 @@ gfxMacFontFamily::LocalizedName(nsAString& aLocalizedName)
}
void
gfxMacFontFamily::FindStyleVariations()
gfxMacFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
{
if (mHasStyles)
return;
@ -1014,3 +1022,139 @@ gfxMacPlatformFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
return nullptr;
}
// used to load system-wide font info on off-main thread
class MacFontInfo : public FontInfoData {
public:
MacFontInfo(bool aLoadOtherNames,
bool aLoadFaceNames,
bool aLoadCmaps) :
FontInfoData(aLoadOtherNames, aLoadFaceNames, aLoadCmaps)
{}
virtual ~MacFontInfo() {}
virtual void Load() {
nsAutoreleasePool localPool;
FontInfoData::Load();
}
// loads font data for all members of a given family
virtual void LoadFontFamilyData(const nsAString& aFamilyName);
};
void
MacFontInfo::LoadFontFamilyData(const nsAString& aFamilyName)
{
// family name ==> CTFontDescriptor
NSString *famName = GetNSStringForString(aFamilyName);
CFStringRef family = CFStringRef(famName);
CFMutableDictionaryRef attr =
CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(attr, kCTFontFamilyNameAttribute, family);
CTFontDescriptorRef fd = CTFontDescriptorCreateWithAttributes(attr);
CFRelease(attr);
CFArrayRef matchingFonts =
CTFontDescriptorCreateMatchingFontDescriptors(fd, NULL);
CFRelease(fd);
if (!matchingFonts) {
return;
}
nsTArray<nsString> otherFamilyNames;
bool hasOtherFamilyNames = true;
// iterate over faces in the family
int f, numFaces = (int) CFArrayGetCount(matchingFonts);
for (f = 0; f < numFaces; f++) {
mLoadStats.fonts++;
CTFontDescriptorRef faceDesc =
(CTFontDescriptorRef)CFArrayGetValueAtIndex(matchingFonts, f);
if (!faceDesc) {
continue;
}
CTFontRef fontRef = CTFontCreateWithFontDescriptor(faceDesc,
0.0, nullptr);
if (mLoadCmaps) {
// face name
CFStringRef faceName = (CFStringRef)
CTFontDescriptorCopyAttribute(faceDesc, kCTFontNameAttribute);
nsAutoTArray<UniChar, 1024> buffer;
CFIndex len = CFStringGetLength(faceName);
buffer.SetLength(len+1);
CFStringGetCharacters(faceName, ::CFRangeMake(0, len),
buffer.Elements());
buffer[len] = 0;
nsAutoString fontName(reinterpret_cast<char16_t*>(buffer.Elements()),
len);
// load the cmap data
FontFaceData fontData;
CFDataRef cmapTable = CTFontCopyTable(fontRef, kCTFontTableCmap,
kCTFontTableOptionNoOptions);
if (cmapTable) {
bool unicodeFont = false, symbolFont = false; // ignored
const uint8_t *cmapData =
(const uint8_t*)CFDataGetBytePtr(cmapTable);
uint32_t cmapLen = CFDataGetLength(cmapTable);
nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
uint32_t offset;
nsresult rv;
rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen, *charmap, offset,
unicodeFont, symbolFont);
if (NS_SUCCEEDED(rv)) {
fontData.mCharacterMap = charmap;
fontData.mUVSOffset = offset;
fontData.mSymbolFont = symbolFont;
mLoadStats.cmaps++;
}
CFRelease(cmapTable);
}
mFontFaceData.Put(fontName, fontData);
CFRelease(faceName);
}
if (mLoadOtherNames && hasOtherFamilyNames) {
CFDataRef nameTable = CTFontCopyTable(fontRef, kCTFontTableName,
kCTFontTableOptionNoOptions);
if (nameTable) {
const char *nameData = (const char*)CFDataGetBytePtr(nameTable);
uint32_t nameLen = CFDataGetLength(nameTable);
gfxFontFamily::ReadOtherFamilyNamesForFace(aFamilyName,
nameData, nameLen,
otherFamilyNames,
false);
hasOtherFamilyNames = otherFamilyNames.Length() != 0;
CFRelease(nameTable);
}
}
CFRelease(fontRef);
}
CFRelease(matchingFonts);
// if found other names, insert them in the hash table
if (otherFamilyNames.Length() != 0) {
mOtherFamilyNames.Put(aFamilyName, otherFamilyNames);
mLoadStats.othernames += otherFamilyNames.Length();
}
}
already_AddRefed<FontInfoData>
gfxMacPlatformFontList::CreateFontInfoData()
{
bool loadCmaps = !UsesSystemFallback() ||
gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
nsRefPtr<MacFontInfo> fi =
new MacFontInfo(true, NeedFullnamePostscriptNames(), loadCmaps);
return fi.forget();
}

Просмотреть файл

@ -558,6 +558,25 @@ static void LogRegistryEvent(const wchar_t *msg)
}
#endif
gfxFontFamily*
gfxPlatformFontList::CheckFamily(gfxFontFamily *aFamily)
{
if (aFamily && !aFamily->HasStyles()) {
aFamily->FindStyleVariations();
aFamily->CheckForSimpleFamily();
}
if (aFamily && aFamily->GetFontList().Length() == 0) {
// failed to load any faces for this family, so discard it
nsAutoString key;
GenerateFontListKey(aFamily->Name(), key);
mFontFamilies.Remove(key);
return nullptr;
}
return aFamily;
}
gfxFontFamily*
gfxPlatformFontList::FindFamily(const nsAString& aFamily)
{
@ -569,12 +588,12 @@ gfxPlatformFontList::FindFamily(const nsAString& aFamily)
// lookup in canonical (i.e. English) family name list
if ((familyEntry = mFontFamilies.GetWeak(key))) {
return familyEntry;
return CheckFamily(familyEntry);
}
// lookup in other family names list (mostly localized names)
if ((familyEntry = mOtherFamilyNames.GetWeak(key)) != nullptr) {
return familyEntry;
return CheckFamily(familyEntry);
}
// name not found and other family names not yet fully initialized so
@ -585,7 +604,7 @@ gfxPlatformFontList::FindFamily(const nsAString& aFamily)
if (!mOtherFamilyNamesInitialized && !IsASCII(aFamily)) {
InitOtherFamilyNames();
if ((familyEntry = mOtherFamilyNames.GetWeak(key)) != nullptr) {
return familyEntry;
return CheckFamily(familyEntry);
}
}
@ -705,49 +724,59 @@ gfxPlatformFontList::RemoveCmap(const gfxCharacterMap* aCharMap)
}
}
static PLDHashOperator AppendFamilyToList(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void *aUserArg)
{
nsTArray<nsString> *familyNames = static_cast<nsTArray<nsString> *>(aUserArg);
familyNames->AppendElement(aFamilyEntry->Name());
return PL_DHASH_NEXT;
}
void
gfxPlatformFontList::GetFontFamilyNames(nsTArray<nsString>& aFontFamilyNames)
{
mFontFamilies.Enumerate(AppendFamilyToList, &aFontFamilyNames);
}
void
gfxPlatformFontList::InitLoader()
{
GetFontFamilyList(mFontFamiliesToLoad);
GetFontFamilyNames(mFontInfo->mFontFamiliesToLoad);
mStartIndex = 0;
mNumFamilies = mFontFamiliesToLoad.Length();
mNumFamilies = mFontInfo->mFontFamiliesToLoad.Length();
memset(&(mFontInfo->mLoadStats), 0, sizeof(mFontInfo->mLoadStats));
}
#define FONT_LOADER_MAX_TIMESLICE 100 // max time for one pass through RunLoader = 100ms
bool
gfxPlatformFontList::RunLoader()
gfxPlatformFontList::LoadFontInfo()
{
TimeStamp start = TimeStamp::Now();
uint32_t i, endIndex = (mStartIndex + mIncrement < mNumFamilies ? mStartIndex + mIncrement : mNumFamilies);
uint32_t i, endIndex = mNumFamilies;
bool loadCmaps = !UsesSystemFallback() ||
gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
// for each font family, load in various font info
for (i = mStartIndex; i < endIndex; i++) {
gfxFontFamily* familyEntry = mFontFamiliesToLoad[i];
nsAutoString key;
gfxFontFamily *familyEntry;
GenerateFontListKey(mFontInfo->mFontFamiliesToLoad[i], key);
// find all faces that are members of this family
familyEntry->FindStyleVariations();
if (familyEntry->GetFontList().Length() == 0) {
// failed to load any faces for this family, so discard it
nsAutoString key;
GenerateFontListKey(familyEntry->Name(), key);
mFontFamilies.Remove(key);
// lookup in canonical (i.e. English) family name list
if (!(familyEntry = mFontFamilies.GetWeak(key))) {
continue;
}
// read in face names
familyEntry->ReadFaceNames(this, NeedFullnamePostscriptNames(), mFontInfo);
// load the cmaps if needed
if (loadCmaps) {
familyEntry->ReadAllCMAPs();
familyEntry->ReadAllCMAPs(mFontInfo);
}
// read in face names
familyEntry->ReadFaceNames(this, NeedFullnamePostscriptNames());
// check whether the family can be considered "simple" for style matching
familyEntry->CheckForSimpleFamily();
// limit the time spent reading fonts in one pass
TimeDuration elapsed = TimeStamp::Now() - start;
if (elapsed.ToMilliseconds() > FONT_LOADER_MAX_TIMESLICE &&
@ -758,15 +787,42 @@ gfxPlatformFontList::RunLoader()
}
mStartIndex = endIndex;
bool done = mStartIndex >= mNumFamilies;
return (mStartIndex >= mNumFamilies);
#ifdef PR_LOGGING
if (LOG_FONTINIT_ENABLED()) {
TimeDuration elapsed = TimeStamp::Now() - start;
LOG_FONTINIT(("(fontinit) fontloader load pass %8.2f ms done %s\n",
elapsed.ToMilliseconds(), (done ? "true" : "false")));
}
#endif
return done;
}
void
gfxPlatformFontList::FinishLoader()
gfxPlatformFontList::CleanupLoader()
{
mFontFamiliesToLoad.Clear();
mNumFamilies = 0;
#ifdef PR_LOGGING
if (LOG_FONTINIT_ENABLED() && mFontInfo) {
LOG_FONTINIT(("(fontinit) fontloader load thread took %8.2f ms "
"%d families %d fonts %d cmaps "
"%d facenames %d othernames",
mLoadTime.ToMilliseconds(),
mFontInfo->mLoadStats.families,
mFontInfo->mLoadStats.fonts,
mFontInfo->mLoadStats.cmaps,
mFontInfo->mLoadStats.facenames,
mFontInfo->mLoadStats.othernames));
}
#endif
mOtherFamilyNamesInitialized = true;
mFaceNamesInitialized = true;
gfxFontInfoLoader::CleanupLoader();
}
void

Просмотреть файл

@ -82,7 +82,7 @@ struct FontListSizes {
uint32_t mCharMapsSize; // memory used for cmap coverage info
};
class gfxPlatformFontList : protected gfxFontInfoLoader
class gfxPlatformFontList : public gfxFontInfoLoader
{
public:
static gfxPlatformFontList* PlatformFontList() {
@ -211,6 +211,9 @@ protected:
// if system fallback is used, no need to load all cmaps
virtual bool UsesSystemFallback() { return false; }
// verifies that a family contains a non-zero font count
gfxFontFamily* CheckFamily(gfxFontFamily *aFamily);
// separate initialization for reading in name tables, since this is expensive
void InitOtherFamilyNames();
@ -241,10 +244,12 @@ protected:
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void* aUserArg);
virtual void GetFontFamilyNames(nsTArray<nsString>& aFontFamilyNames);
// gfxFontInfoLoader overrides, used to load in font cmaps
virtual void InitLoader();
virtual bool RunLoader();
virtual void FinishLoader();
virtual bool LoadFontInfo();
virtual void CleanupLoader();
// read the loader initialization prefs, and start it
void GetPrefsAndStartLoader();