/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Foundation code. * * The Initial Developer of the Original Code is Mozilla Foundation. * Portions created by the Initial Developer are Copyright (C) 2008 * the Initial Developer. All Rights Reserved. * * Contributor(s): * John Daggett * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef GFX_USER_FONT_SET_H #define GFX_USER_FONT_SET_H #include "gfxTypes.h" #include "gfxFont.h" #include "gfxFontUtils.h" #include "nsRefPtrHashtable.h" #include "nsAutoPtr.h" #include "nsCOMPtr.h" #include "nsIURI.h" #include "nsIFile.h" #include "nsISupportsImpl.h" #include "nsIScriptError.h" class nsIURI; class gfxMixedFontFamily; class nsFontFaceLoader; // parsed CSS @font-face rule information // lifetime: from when @font-face rule processed until font is loaded struct gfxFontFaceSrc { bool mIsLocal; // url or local // if url, whether to use the origin principal or not bool mUseOriginPrincipal; // format hint flags, union of all possible formats // (e.g. TrueType, EOT, SVG, etc.) // see FLAG_FORMAT_* enum values below PRUint32 mFormatFlags; nsString mLocalName; // full font name if local nsCOMPtr mURI; // uri if url nsCOMPtr mReferrer; // referrer url if url nsCOMPtr mOriginPrincipal; // principal if url }; // Subclassed to store platform-specific code cleaned out when font entry is // deleted. // Lifetime: from when platform font is created until it is deactivated. // If the platform does not need to add any platform-specific code/data here, // then the gfxUserFontSet will allocate a base gfxUserFontData and attach // to the entry to track the basic user font info fields here. class gfxUserFontData { public: gfxUserFontData() : mSrcIndex(0), mFormat(0), mMetaOrigLen(0) { } virtual ~gfxUserFontData() { } nsTArray mMetadata; // woff metadata block (compressed), if any nsCOMPtr mURI; // URI of the source, if it was url() nsString mLocalName; // font name used for the source, if local() nsString mRealName; // original fullname from the font resource PRUint32 mSrcIndex; // index in the rule's source list PRUint32 mFormat; // format hint for the source used, if any PRUint32 mMetaOrigLen; // length needed to decompress metadata }; // initially contains a set of proxy font entry objects, replaced with // platform/user fonts as downloaded class gfxMixedFontFamily : public gfxFontFamily { public: friend class gfxUserFontSet; gfxMixedFontFamily(const nsAString& aName) : gfxFontFamily(aName) { } virtual ~gfxMixedFontFamily() { } void AddFontEntry(gfxFontEntry *aFontEntry) { nsRefPtr fe = aFontEntry; mAvailableFonts.AppendElement(fe); aFontEntry->SetFamily(this); ResetCharacterMap(); } void ReplaceFontEntry(gfxFontEntry *aOldFontEntry, gfxFontEntry *aNewFontEntry) { PRUint32 numFonts = mAvailableFonts.Length(); for (PRUint32 i = 0; i < numFonts; i++) { gfxFontEntry *fe = mAvailableFonts[i]; if (fe == aOldFontEntry) { aOldFontEntry->SetFamily(nsnull); // note that this may delete aOldFontEntry, if there's no // other reference to it except from its family mAvailableFonts[i] = aNewFontEntry; aNewFontEntry->SetFamily(this); break; } } ResetCharacterMap(); } void RemoveFontEntry(gfxFontEntry *aFontEntry) { PRUint32 numFonts = mAvailableFonts.Length(); for (PRUint32 i = 0; i < numFonts; i++) { gfxFontEntry *fe = mAvailableFonts[i]; if (fe == aFontEntry) { aFontEntry->SetFamily(nsnull); mAvailableFonts.RemoveElementAt(i); break; } } ResetCharacterMap(); } // clear family pointer for all entries and remove them from the family; // we need to do this explicitly before inserting the entries into a new // family, in case the old one is not actually deleted until later void DetachFontEntries() { PRUint32 i = mAvailableFonts.Length(); while (i--) { gfxFontEntry *fe = mAvailableFonts[i]; if (fe) { fe->SetFamily(nsnull); } } mAvailableFonts.Clear(); } // temp method to determine if all proxies are loaded bool AllLoaded() { PRUint32 numFonts = mAvailableFonts.Length(); for (PRUint32 i = 0; i < numFonts; i++) { gfxFontEntry *fe = mAvailableFonts[i]; if (fe->mIsProxy) return false; } return true; } }; class gfxProxyFontEntry; class THEBES_API gfxUserFontSet { public: NS_INLINE_DECL_REFCOUNTING(gfxUserFontSet) gfxUserFontSet(); virtual ~gfxUserFontSet(); enum { // no flags ==> no hint set // unknown ==> unknown format hint set FLAG_FORMAT_UNKNOWN = 1, FLAG_FORMAT_OPENTYPE = 1 << 1, FLAG_FORMAT_TRUETYPE = 1 << 2, FLAG_FORMAT_TRUETYPE_AAT = 1 << 3, FLAG_FORMAT_EOT = 1 << 4, FLAG_FORMAT_SVG = 1 << 5, FLAG_FORMAT_WOFF = 1 << 6, // mask of all unused bits, update when adding new formats FLAG_FORMAT_NOT_USED = ~((1 << 7)-1) }; enum LoadStatus { STATUS_LOADING = 0, STATUS_LOADED, STATUS_FORMAT_NOT_SUPPORTED, STATUS_ERROR, STATUS_END_OF_LIST }; // add in a font face // weight, stretch - 0 == unknown, [1, 9] otherwise // italic style = constants in gfxFontConstants.h, e.g. NS_FONT_STYLE_NORMAL // TODO: support for unicode ranges not yet implemented gfxFontEntry *AddFontFace(const nsAString& aFamilyName, const nsTArray& aFontFaceSrcList, PRUint32 aWeight, PRUint32 aStretch, PRUint32 aItalicStyle, const nsTArray& aFeatureSettings, const nsString& aLanguageOverride, gfxSparseBitSet *aUnicodeRanges = nsnull); // add in a font face for which we have the gfxFontEntry already void AddFontFace(const nsAString& aFamilyName, gfxFontEntry* aFontEntry); // Whether there is a face with this family name bool HasFamily(const nsAString& aFamilyName) const { return GetFamily(aFamilyName) != nsnull; } // lookup a font entry for a given style, returns null if not loaded gfxFontEntry *FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle, bool& aFoundFamily, bool& aNeedsBold, bool& aWaitForUserFont); // initialize the process that loads external font data, which upon // completion will call OnLoadComplete method virtual nsresult StartLoad(gfxProxyFontEntry *aProxy, const gfxFontFaceSrc *aFontFaceSrc) = 0; // when download has been completed, pass back data here // aDownloadStatus == NS_OK ==> download succeeded, error otherwise // returns true if platform font creation sucessful (or local() // reference was next in line) // Ownership of aFontData is passed in here; the font set must // ensure that it is eventually deleted with NS_Free(). bool OnLoadComplete(gfxProxyFontEntry *aProxy, const PRUint8 *aFontData, PRUint32 aLength, nsresult aDownloadStatus); // Replace a proxy with a real fontEntry; this is implemented in // nsUserFontSet in order to keep track of the entry corresponding // to each @font-face rule. virtual void ReplaceFontEntry(gfxProxyFontEntry *aProxy, gfxFontEntry *aFontEntry) = 0; // generation - each time a face is loaded, generation is // incremented so that the change can be recognized PRUint64 GetGeneration() { return mGeneration; } // increment the generation on font load void IncrementGeneration(); protected: // for a given proxy font entry, attempt to load the next resource // in the src list LoadStatus LoadNext(gfxProxyFontEntry *aProxyEntry); // helper method for creating a platform font // returns font entry if platform font creation successful // Ownership of aFontData is passed in here; the font set must // ensure that it is eventually deleted with NS_Free(). gfxFontEntry* LoadFont(gfxProxyFontEntry *aProxy, const PRUint8 *aFontData, PRUint32 &aLength); // parse data for a data URL virtual nsresult SyncLoadFontData(gfxProxyFontEntry *aFontToLoad, const gfxFontFaceSrc *aFontFaceSrc, PRUint8* &aBuffer, PRUint32 &aBufferLength) { // implemented in nsUserFontSet return NS_ERROR_NOT_IMPLEMENTED; } gfxMixedFontFamily *GetFamily(const nsAString& aName) const; // report a problem of some kind (implemented in nsUserFontSet) virtual nsresult LogMessage(gfxProxyFontEntry *aProxy, const char *aMessage, PRUint32 aFlags = nsIScriptError::errorFlag, nsresult aStatus = 0) = 0; // font families defined by @font-face rules nsRefPtrHashtable mFontFamilies; PRUint64 mGeneration; static PRLogModuleInfo *sUserFontsLog; private: static void CopyWOFFMetadata(const PRUint8* aFontData, PRUint32 aLength, nsTArray* aMetadata, PRUint32* aMetaOrigLen); }; // acts a placeholder until the real font is downloaded class gfxProxyFontEntry : public gfxFontEntry { friend class gfxUserFontSet; public: gfxProxyFontEntry(const nsTArray& aFontFaceSrcList, gfxMixedFontFamily *aFamily, PRUint32 aWeight, PRUint32 aStretch, PRUint32 aItalicStyle, const nsTArray& aFeatureSettings, PRUint32 aLanguageOverride, gfxSparseBitSet *aUnicodeRanges); virtual ~gfxProxyFontEntry(); virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold); // note that code depends on the ordering of these values! enum LoadingState { NOT_LOADING = 0, // not started to load any font resources yet LOADING_STARTED, // loading has started; hide fallback font LOADING_ALMOST_DONE, // timeout happened but we're nearly done, // so keep hiding fallback font LOADING_SLOWLY, // timeout happened and we're not nearly done, // so use the fallback font LOADING_FAILED // failed to load any source: use fallback }; LoadingState mLoadingState; bool mUnsupportedFormat; nsTArray mSrcList; PRUint32 mSrcIndex; // index of loading src item nsFontFaceLoader *mLoader; // current loader for this entry, if any }; #endif /* GFX_USER_FONT_SET_H */