1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef GFX_FONT_INFO_LOADER_H
7 #define GFX_FONT_INFO_LOADER_H
8 
9 #include "nsCOMPtr.h"
10 #include "nsIObserver.h"
11 #include "nsITimer.h"
12 #include "nsIThread.h"
13 #include "nsRefPtrHashtable.h"
14 #include "nsString.h"
15 #include "gfxFont.h"
16 #include "nsIRunnable.h"
17 #include "mozilla/Atomics.h"
18 #include "mozilla/TimeStamp.h"
19 #include "nsISupportsImpl.h"
20 
21 // data retrieved for a given face
22 
23 struct FontFaceData {
FontFaceDataFontFaceData24     FontFaceData() : mUVSOffset(0), mSymbolFont(false) {}
25 
FontFaceDataFontFaceData26     FontFaceData(const FontFaceData& aFontFaceData) {
27         mFullName = aFontFaceData.mFullName;
28         mPostscriptName = aFontFaceData.mPostscriptName;
29         mCharacterMap = aFontFaceData.mCharacterMap;
30         mUVSOffset = aFontFaceData.mUVSOffset;
31         mSymbolFont = aFontFaceData.mSymbolFont;
32     }
33 
34     nsString mFullName;
35     nsString mPostscriptName;
36     RefPtr<gfxCharacterMap> mCharacterMap;
37     uint32_t mUVSOffset;
38     bool mSymbolFont;
39 };
40 
41 // base class used to contain cached system-wide font info.
42 // methods in this class are called on off-main threads so
43 // all methods use only static methods or other thread-safe
44 // font data access API's. specifically, no use is made of
45 // gfxPlatformFontList, gfxFontFamily, gfxFamily or any
46 // harfbuzz API methods within FontInfoData subclasses.
47 
48 class FontInfoData {
49 public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FontInfoData)50     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FontInfoData)
51 
52     FontInfoData(bool aLoadOtherNames,
53                  bool aLoadFaceNames,
54                  bool aLoadCmaps) :
55         mCanceled(false),
56         mLoadOtherNames(aLoadOtherNames),
57         mLoadFaceNames(aLoadFaceNames),
58         mLoadCmaps(aLoadCmaps)
59     {
60         MOZ_COUNT_CTOR(FontInfoData);
61     }
62 
63 protected:
64     // Protected destructor, to discourage deletion outside of Release():
~FontInfoData()65     virtual ~FontInfoData() {
66         MOZ_COUNT_DTOR(FontInfoData);
67     }
68 
69 public:
70     virtual void Load();
71 
72     // loads font data for all fonts of a given family
73     // (called on async thread)
74     virtual void LoadFontFamilyData(const nsAString& aFamilyName) = 0;
75 
76     // -- methods overriden by platform-specific versions --
77 
78     // fetches cmap data for a particular font from cached font data
79     virtual already_AddRefed<gfxCharacterMap>
GetCMAP(const nsAString & aFontName,uint32_t & aUVSOffset,bool & aSymbolFont)80     GetCMAP(const nsAString& aFontName,
81             uint32_t& aUVSOffset,
82             bool& aSymbolFont)
83     {
84         FontFaceData faceData;
85         if (!mFontFaceData.Get(aFontName, &faceData) ||
86             !faceData.mCharacterMap) {
87             return nullptr;
88         }
89 
90         aUVSOffset = faceData.mUVSOffset;
91         aSymbolFont = faceData.mSymbolFont;
92         RefPtr<gfxCharacterMap> cmap = faceData.mCharacterMap;
93         return cmap.forget();
94     }
95 
96     // fetches fullname/postscript names from cached font data
GetFaceNames(const nsAString & aFontName,nsAString & aFullName,nsAString & aPostscriptName)97     virtual void GetFaceNames(const nsAString& aFontName,
98                               nsAString& aFullName,
99                               nsAString& aPostscriptName)
100     {
101         FontFaceData faceData;
102         if (!mFontFaceData.Get(aFontName, &faceData)) {
103             return;
104         }
105 
106         aFullName = faceData.mFullName;
107         aPostscriptName = faceData.mPostscriptName;
108     }
109 
110     // fetches localized family name data from cached font data
GetOtherFamilyNames(const nsAString & aFamilyName,nsTArray<nsString> & aOtherFamilyNames)111     virtual bool GetOtherFamilyNames(const nsAString& aFamilyName,
112                                      nsTArray<nsString>& aOtherFamilyNames)
113     {
114         return mOtherFamilyNames.Get(aFamilyName, &aOtherFamilyNames);
115     }
116 
117     nsTArray<nsString> mFontFamiliesToLoad;
118 
119     // currently non-issue but beware,
120     // this is also set during cleanup after finishing
121     mozilla::Atomic<bool> mCanceled;
122 
123     // time spent on the loader thread
124     mozilla::TimeDuration mLoadTime;
125 
126     struct FontCounts {
127         uint32_t families;
128         uint32_t fonts;
129         uint32_t cmaps;
130         uint32_t facenames;
131         uint32_t othernames;
132     };
133 
134     FontCounts mLoadStats;
135 
136     bool mLoadOtherNames;
137     bool mLoadFaceNames;
138     bool mLoadCmaps;
139 
140     // face name ==> per-face data
141     nsDataHashtable<nsStringHashKey, FontFaceData> mFontFaceData;
142 
143     // canonical family name ==> array of localized family names
144     nsDataHashtable<nsStringHashKey, nsTArray<nsString> > mOtherFamilyNames;
145 };
146 
147 // gfxFontInfoLoader - helper class for loading font info on async thread
148 // For large, "all fonts on system" data, data needed on a given platform
149 // (e.g. localized names, face names, cmaps) are loaded async.
150 
151 // helper class for loading in font info on a separate async thread
152 // once async thread completes, completion process is run on regular
153 // intervals to prevent tying up the main thread
154 
155 class gfxFontInfoLoader {
156 public:
157 
158     // state transitions:
159     //   initial ---StartLoader with delay---> timer on delay
160     //   initial ---StartLoader without delay---> timer on interval
161     //   timer on delay ---LoaderTimerFire---> timer on interval
162     //   timer on delay ---CancelLoader---> timer off
163     //   timer on interval ---CancelLoader---> timer off
164     //   timer off ---StartLoader with delay---> timer on delay
165     //   timer off ---StartLoader without delay---> timer on interval
166     typedef enum {
167         stateInitial,
168         stateTimerOnDelay,
169         stateAsyncLoad,
170         stateTimerOnInterval,
171         stateTimerOff
172     } TimerState;
173 
gfxFontInfoLoader()174     gfxFontInfoLoader() :
175         mInterval(0), mState(stateInitial)
176     {
177         MOZ_COUNT_CTOR(gfxFontInfoLoader);
178     }
179 
180     virtual ~gfxFontInfoLoader();
181 
182     // start timer with an initial delay, then call Run method at regular intervals
183     void StartLoader(uint32_t aDelay, uint32_t aInterval);
184 
185     // Finalize - async load complete, transfer data (on intervals if necessary)
186     virtual void FinalizeLoader(FontInfoData *aFontInfo);
187 
188     // cancel the timer and cleanup
189     void CancelLoader();
190 
GetInterval()191     uint32_t GetInterval() { return mInterval; }
192 
193 protected:
194     class ShutdownObserver : public nsIObserver
195     {
196     public:
197         NS_DECL_ISUPPORTS
198         NS_DECL_NSIOBSERVER
199 
ShutdownObserver(gfxFontInfoLoader * aLoader)200         explicit ShutdownObserver(gfxFontInfoLoader *aLoader)
201             : mLoader(aLoader)
202         { }
203 
204     protected:
~ShutdownObserver()205         virtual ~ShutdownObserver()
206         { }
207 
208         gfxFontInfoLoader *mLoader;
209     };
210 
211     // CreateFontInfo - create platform-specific object used
212     //                  to load system-wide font info
CreateFontInfoData()213     virtual already_AddRefed<FontInfoData> CreateFontInfoData() {
214         return nullptr;
215     }
216 
217     // Init - initialization before async loader thread runs
218     virtual void InitLoader() = 0;
219 
220     // LoadFontInfo - transfer font info data within a time limit, return
221     //                true when done
222     virtual bool LoadFontInfo() = 0;
223 
224     // Cleanup - finish and cleanup after done, including possible reflows
CleanupLoader()225     virtual void CleanupLoader() {
226         mFontInfo = nullptr;
227     }
228 
229     // Timer interval callbacks
LoadFontInfoCallback(nsITimer * aTimer,void * aThis)230     static void LoadFontInfoCallback(nsITimer *aTimer, void *aThis) {
231         gfxFontInfoLoader *loader = static_cast<gfxFontInfoLoader*>(aThis);
232         loader->LoadFontInfoTimerFire();
233     }
234 
DelayedStartCallback(nsITimer * aTimer,void * aThis)235     static void DelayedStartCallback(nsITimer *aTimer, void *aThis) {
236         gfxFontInfoLoader *loader = static_cast<gfxFontInfoLoader*>(aThis);
237         loader->StartLoader(0, loader->GetInterval());
238     }
239 
240     void LoadFontInfoTimerFire();
241 
242     void AddShutdownObserver();
243     void RemoveShutdownObserver();
244 
245     nsCOMPtr<nsITimer> mTimer;
246     nsCOMPtr<nsIObserver> mObserver;
247     nsCOMPtr<nsIThread> mFontLoaderThread;
248     uint32_t mInterval;
249     TimerState mState;
250 
251     // after async font loader completes, data is stored here
252     RefPtr<FontInfoData> mFontInfo;
253 
254     // time spent on the loader thread
255     mozilla::TimeDuration mLoadTime;
256 };
257 
258 #endif /* GFX_FONT_INFO_LOADER_H */
259