1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Foundation code.
16 : *
17 : * The Initial Developer of the Original Code is Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2008
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * John Daggett <jdaggett@mozilla.com>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #ifndef GFX_USER_FONT_SET_H
39 : #define GFX_USER_FONT_SET_H
40 :
41 : #include "gfxTypes.h"
42 : #include "gfxFont.h"
43 : #include "gfxFontUtils.h"
44 : #include "nsRefPtrHashtable.h"
45 : #include "nsAutoPtr.h"
46 : #include "nsCOMPtr.h"
47 : #include "nsIURI.h"
48 : #include "nsIFile.h"
49 : #include "nsISupportsImpl.h"
50 : #include "nsIScriptError.h"
51 :
52 : class nsIURI;
53 : class gfxMixedFontFamily;
54 :
55 : // parsed CSS @font-face rule information
56 : // lifetime: from when @font-face rule processed until font is loaded
57 0 : struct gfxFontFaceSrc {
58 : bool mIsLocal; // url or local
59 :
60 : // if url, whether to use the origin principal or not
61 : bool mUseOriginPrincipal;
62 :
63 : // format hint flags, union of all possible formats
64 : // (e.g. TrueType, EOT, SVG, etc.)
65 : // see FLAG_FORMAT_* enum values below
66 : PRUint32 mFormatFlags;
67 :
68 : nsString mLocalName; // full font name if local
69 : nsCOMPtr<nsIURI> mURI; // uri if url
70 : nsCOMPtr<nsIURI> mReferrer; // referrer url if url
71 : nsCOMPtr<nsISupports> mOriginPrincipal; // principal if url
72 :
73 : };
74 :
75 : // Subclassed to store platform-specific code cleaned out when font entry is
76 : // deleted.
77 : // Lifetime: from when platform font is created until it is deactivated.
78 : // If the platform does not need to add any platform-specific code/data here,
79 : // then the gfxUserFontSet will allocate a base gfxUserFontData and attach
80 : // to the entry to track the basic user font info fields here.
81 : class gfxUserFontData {
82 : public:
83 0 : gfxUserFontData()
84 0 : : mSrcIndex(0), mFormat(0), mMetaOrigLen(0)
85 0 : { }
86 0 : virtual ~gfxUserFontData() { }
87 :
88 : nsTArray<PRUint8> mMetadata; // woff metadata block (compressed), if any
89 : nsCOMPtr<nsIURI> mURI; // URI of the source, if it was url()
90 : nsString mLocalName; // font name used for the source, if local()
91 : nsString mRealName; // original fullname from the font resource
92 : PRUint32 mSrcIndex; // index in the rule's source list
93 : PRUint32 mFormat; // format hint for the source used, if any
94 : PRUint32 mMetaOrigLen; // length needed to decompress metadata
95 : };
96 :
97 : // initially contains a set of proxy font entry objects, replaced with
98 : // platform/user fonts as downloaded
99 :
100 : class gfxMixedFontFamily : public gfxFontFamily {
101 : public:
102 : friend class gfxUserFontSet;
103 :
104 0 : gfxMixedFontFamily(const nsAString& aName)
105 0 : : gfxFontFamily(aName) { }
106 :
107 0 : virtual ~gfxMixedFontFamily() { }
108 :
109 0 : void AddFontEntry(gfxFontEntry *aFontEntry) {
110 0 : nsRefPtr<gfxFontEntry> fe = aFontEntry;
111 0 : mAvailableFonts.AppendElement(fe);
112 0 : aFontEntry->SetFamily(this);
113 0 : ResetCharacterMap();
114 0 : }
115 :
116 : void ReplaceFontEntry(gfxFontEntry *aOldFontEntry,
117 : gfxFontEntry *aNewFontEntry) {
118 : PRUint32 numFonts = mAvailableFonts.Length();
119 : for (PRUint32 i = 0; i < numFonts; i++) {
120 : gfxFontEntry *fe = mAvailableFonts[i];
121 : if (fe == aOldFontEntry) {
122 : aOldFontEntry->SetFamily(nsnull);
123 : // note that this may delete aOldFontEntry, if there's no
124 : // other reference to it except from its family
125 : mAvailableFonts[i] = aNewFontEntry;
126 : aNewFontEntry->SetFamily(this);
127 : break;
128 : }
129 : }
130 : ResetCharacterMap();
131 : }
132 :
133 : void RemoveFontEntry(gfxFontEntry *aFontEntry) {
134 : PRUint32 numFonts = mAvailableFonts.Length();
135 : for (PRUint32 i = 0; i < numFonts; i++) {
136 : gfxFontEntry *fe = mAvailableFonts[i];
137 : if (fe == aFontEntry) {
138 : aFontEntry->SetFamily(nsnull);
139 : mAvailableFonts.RemoveElementAt(i);
140 : break;
141 : }
142 : }
143 : ResetCharacterMap();
144 : }
145 :
146 : // clear family pointer for all entries and remove them from the family;
147 : // we need to do this explicitly before inserting the entries into a new
148 : // family, in case the old one is not actually deleted until later
149 : void DetachFontEntries() {
150 : PRUint32 i = mAvailableFonts.Length();
151 : while (i--) {
152 : gfxFontEntry *fe = mAvailableFonts[i];
153 : if (fe) {
154 : fe->SetFamily(nsnull);
155 : }
156 : }
157 : mAvailableFonts.Clear();
158 : }
159 :
160 : // temp method to determine if all proxies are loaded
161 : bool AllLoaded()
162 : {
163 : PRUint32 numFonts = mAvailableFonts.Length();
164 : for (PRUint32 i = 0; i < numFonts; i++) {
165 : gfxFontEntry *fe = mAvailableFonts[i];
166 : if (fe->mIsProxy)
167 : return false;
168 : }
169 : return true;
170 : }
171 : };
172 :
173 : class gfxProxyFontEntry;
174 :
175 : class THEBES_API gfxUserFontSet {
176 :
177 : public:
178 :
179 0 : NS_INLINE_DECL_REFCOUNTING(gfxUserFontSet)
180 :
181 : gfxUserFontSet();
182 : virtual ~gfxUserFontSet();
183 :
184 : enum {
185 : // no flags ==> no hint set
186 : // unknown ==> unknown format hint set
187 : FLAG_FORMAT_UNKNOWN = 1,
188 : FLAG_FORMAT_OPENTYPE = 1 << 1,
189 : FLAG_FORMAT_TRUETYPE = 1 << 2,
190 : FLAG_FORMAT_TRUETYPE_AAT = 1 << 3,
191 : FLAG_FORMAT_EOT = 1 << 4,
192 : FLAG_FORMAT_SVG = 1 << 5,
193 : FLAG_FORMAT_WOFF = 1 << 6,
194 :
195 : // mask of all unused bits, update when adding new formats
196 : FLAG_FORMAT_NOT_USED = ~((1 << 7)-1)
197 : };
198 :
199 : enum LoadStatus {
200 : STATUS_LOADING = 0,
201 : STATUS_LOADED,
202 : STATUS_FORMAT_NOT_SUPPORTED,
203 : STATUS_ERROR,
204 : STATUS_END_OF_LIST
205 : };
206 :
207 :
208 : // add in a font face
209 : // weight, stretch - 0 == unknown, [1, 9] otherwise
210 : // italic style = constants in gfxFontConstants.h, e.g. NS_FONT_STYLE_NORMAL
211 : // TODO: support for unicode ranges not yet implemented
212 : gfxFontEntry *AddFontFace(const nsAString& aFamilyName,
213 : const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
214 : PRUint32 aWeight,
215 : PRUint32 aStretch,
216 : PRUint32 aItalicStyle,
217 : const nsString& aFeatureSettings,
218 : const nsString& aLanguageOverride,
219 : gfxSparseBitSet *aUnicodeRanges = nsnull);
220 :
221 : // add in a font face for which we have the gfxFontEntry already
222 : void AddFontFace(const nsAString& aFamilyName, gfxFontEntry* aFontEntry);
223 :
224 : // Whether there is a face with this family name
225 0 : bool HasFamily(const nsAString& aFamilyName) const
226 : {
227 0 : return GetFamily(aFamilyName) != nsnull;
228 : }
229 :
230 : // lookup a font entry for a given style, returns null if not loaded
231 : gfxFontEntry *FindFontEntry(const nsAString& aName,
232 : const gfxFontStyle& aFontStyle,
233 : bool& aFoundFamily,
234 : bool& aNeedsBold,
235 : bool& aWaitForUserFont);
236 :
237 : // initialize the process that loads external font data, which upon
238 : // completion will call OnLoadComplete method
239 : virtual nsresult StartLoad(gfxProxyFontEntry *aProxy,
240 : const gfxFontFaceSrc *aFontFaceSrc) = 0;
241 :
242 : // when download has been completed, pass back data here
243 : // aDownloadStatus == NS_OK ==> download succeeded, error otherwise
244 : // returns true if platform font creation sucessful (or local()
245 : // reference was next in line)
246 : // Ownership of aFontData is passed in here; the font set must
247 : // ensure that it is eventually deleted with NS_Free().
248 : bool OnLoadComplete(gfxProxyFontEntry *aProxy,
249 : const PRUint8 *aFontData, PRUint32 aLength,
250 : nsresult aDownloadStatus);
251 :
252 : // Replace a proxy with a real fontEntry; this is implemented in
253 : // nsUserFontSet in order to keep track of the entry corresponding
254 : // to each @font-face rule.
255 : virtual void ReplaceFontEntry(gfxProxyFontEntry *aProxy,
256 : gfxFontEntry *aFontEntry) = 0;
257 :
258 : // generation - each time a face is loaded, generation is
259 : // incremented so that the change can be recognized
260 0 : PRUint64 GetGeneration() { return mGeneration; }
261 :
262 : // increment the generation on font load
263 : void IncrementGeneration();
264 :
265 : protected:
266 : // for a given proxy font entry, attempt to load the next resource
267 : // in the src list
268 : LoadStatus LoadNext(gfxProxyFontEntry *aProxyEntry);
269 :
270 : gfxMixedFontFamily *GetFamily(const nsAString& aName) const;
271 :
272 : // report a problem of some kind (implemented in nsUserFontSet)
273 : virtual nsresult LogMessage(gfxProxyFontEntry *aProxy,
274 : const char *aMessage,
275 : PRUint32 aFlags = nsIScriptError::errorFlag,
276 : nsresult aStatus = 0) = 0;
277 :
278 : // font families defined by @font-face rules
279 : nsRefPtrHashtable<nsStringHashKey, gfxMixedFontFamily> mFontFamilies;
280 :
281 : PRUint64 mGeneration;
282 :
283 : static PRLogModuleInfo *sUserFontsLog;
284 :
285 : private:
286 : static void CopyWOFFMetadata(const PRUint8* aFontData,
287 : PRUint32 aLength,
288 : nsTArray<PRUint8>* aMetadata,
289 : PRUint32* aMetaOrigLen);
290 : };
291 :
292 : // acts a placeholder until the real font is downloaded
293 :
294 : class gfxProxyFontEntry : public gfxFontEntry {
295 : friend class gfxUserFontSet;
296 :
297 : public:
298 : gfxProxyFontEntry(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
299 : gfxMixedFontFamily *aFamily,
300 : PRUint32 aWeight,
301 : PRUint32 aStretch,
302 : PRUint32 aItalicStyle,
303 : const nsTArray<gfxFontFeature>& aFeatureSettings,
304 : PRUint32 aLanguageOverride,
305 : gfxSparseBitSet *aUnicodeRanges);
306 :
307 : virtual ~gfxProxyFontEntry();
308 :
309 : virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold);
310 :
311 : // note that code depends on the ordering of these values!
312 : enum LoadingState {
313 : NOT_LOADING = 0, // not started to load any font resources yet
314 : LOADING_STARTED, // loading has started; hide fallback font
315 : LOADING_ALMOST_DONE, // timeout happened but we're nearly done,
316 : // so keep hiding fallback font
317 : LOADING_SLOWLY, // timeout happened and we're not nearly done,
318 : // so use the fallback font
319 : LOADING_FAILED // failed to load any source: use fallback
320 : };
321 : LoadingState mLoadingState;
322 : bool mUnsupportedFormat;
323 :
324 : nsTArray<gfxFontFaceSrc> mSrcList;
325 : PRUint32 mSrcIndex; // index of loading src item
326 : };
327 :
328 :
329 : #endif /* GFX_USER_FONT_SET_H */
|