Bug 441473. Implement user font set object. r+sr=roc

This commit is contained in:
John Daggett 2008-10-01 12:01:53 +09:00
parent 4fc0ecadda
commit c5d2a8ddfd
46 changed files with 1966 additions and 265 deletions

View File

@ -1975,7 +1975,7 @@ nsCanvasRenderingContext2D::SetFont(const nsAString& font)
fontStyle->mFont.systemFont,
fontStyle->mFont.familyNameQuirks);
CurrentState().fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(fontStyle->mFont.name, &style);
CurrentState().fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(fontStyle->mFont.name, &style, presShell->GetPresContext()->GetUserFontSet());
NS_ASSERTION(CurrentState().fontGroup, "Could not get font group");
CurrentState().font = font;
return NS_OK;

View File

@ -61,7 +61,7 @@ public:
virtual nsresult Init(nsIDeviceContext* aContext);
virtual nsresult GetDeviceContext(nsIDeviceContext *&aContext) const;
virtual nsresult GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
nsIFontMetrics *&aMetrics);
nsIFontMetrics *&aMetrics, gfxUserFontSet *aUserFontSet = nsnull);
nsresult FontMetricsDeleted(const nsIFontMetrics* aFontMetrics);
nsresult Compact();
@ -100,8 +100,9 @@ public:
NS_IMETHOD CreateRenderingContextInstance(nsIRenderingContext *&aContext);
NS_IMETHOD GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
nsIFontMetrics*& aMetrics);
NS_IMETHOD GetMetricsFor(const nsFont& aFont, nsIFontMetrics*& aMetrics);
nsIFontMetrics*& aMetrics, gfxUserFontSet *aUserFontSet = nsnull);
NS_IMETHOD GetMetricsFor(const nsFont& aFont, nsIFontMetrics*& aMetrics,
gfxUserFontSet *aUserFontSet = nsnull);
NS_IMETHOD FirstExistingFont(const nsFont& aFont, nsString& aFaceName);

View File

@ -52,6 +52,7 @@ class nsIFontMetrics;
class nsIWidget;
class nsIDeviceContextSpec;
class nsIAtom;
class gfxUserFontSet;
struct nsFont;
@ -330,19 +331,23 @@ public:
* @param aFont font description to obtain metrics for
* @param aLangGroup the language group of the document
* @param aMetrics out parameter for font metrics
* @param aUserFontSet user font set
* @return error status
*/
NS_IMETHOD GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
nsIFontMetrics*& aMetrics) = 0;
nsIFontMetrics*& aMetrics,
gfxUserFontSet *aUserFontSet = nsnull) = 0;
/**
* Get the nsIFontMetrics that describe the properties of
* an nsFont.
* @param aFont font description to obtain metrics for
* @param aMetrics out parameter for font metrics
* @param aUserFontSet user font set
* @return error status
*/
NS_IMETHOD GetMetricsFor(const nsFont& aFont, nsIFontMetrics*& aMetrics) = 0;
NS_IMETHOD GetMetricsFor(const nsFont& aFont, nsIFontMetrics*& aMetrics,
gfxUserFontSet *aUserFontSet = nsnull) = 0;
/**
* Check to see if a particular named font exists.

View File

@ -45,6 +45,7 @@
class nsString;
class nsIDeviceContext;
class nsIAtom;
class gfxUserFontSet;
// IID for the nsIFontMetrics interface
#define NS_IFONT_METRICS_IID \
@ -87,7 +88,7 @@ public:
* @see nsIDeviceContext#GetMetricsFor()
*/
NS_IMETHOD Init(const nsFont& aFont, nsIAtom* aLangGroup,
nsIDeviceContext *aContext) = 0;
nsIDeviceContext *aContext, gfxUserFontSet *aUserFontSet = nsnull) = 0;
/**
* Destroy this font metrics. This breaks the association between

View File

@ -50,6 +50,7 @@
#include "nsUnicharUtils.h"
#include "nsCRT.h"
#include "nsIRenderingContext.h"
#include "gfxUserFontSet.h"
NS_IMPL_ISUPPORTS3(DeviceContextImpl, nsIDeviceContext, nsIObserver, nsISupportsWeakReference)
@ -213,7 +214,7 @@ DeviceContextImpl::GetLocaleLangGroup(void)
}
NS_IMETHODIMP DeviceContextImpl::GetMetricsFor(const nsFont& aFont,
nsIAtom* aLangGroup, nsIFontMetrics*& aMetrics)
nsIAtom* aLangGroup, nsIFontMetrics*& aMetrics, gfxUserFontSet *aUserFontSet)
{
if (nsnull == mFontCache) {
nsresult rv = CreateFontCache();
@ -230,10 +231,12 @@ NS_IMETHODIMP DeviceContextImpl::GetMetricsFor(const nsFont& aFont,
aLangGroup = mLocaleLangGroup;
}
return mFontCache->GetMetricsFor(aFont, aLangGroup, aMetrics);
return mFontCache->GetMetricsFor(aFont, aLangGroup, aMetrics, aUserFontSet);
}
NS_IMETHODIMP DeviceContextImpl::GetMetricsFor(const nsFont& aFont, nsIFontMetrics*& aMetrics)
NS_IMETHODIMP DeviceContextImpl::GetMetricsFor(const nsFont& aFont,
nsIFontMetrics*& aMetrics,
gfxUserFontSet *aUserFontSet)
{
if (nsnull == mFontCache) {
nsresult rv = CreateFontCache();
@ -244,7 +247,8 @@ NS_IMETHODIMP DeviceContextImpl::GetMetricsFor(const nsFont& aFont, nsIFontMetri
// XXX temporary fix for performance problem -- erik
GetLocaleLangGroup();
}
return mFontCache->GetMetricsFor(aFont, mLocaleLangGroup, aMetrics);
return mFontCache->GetMetricsFor(aFont, mLocaleLangGroup,
aMetrics, aUserFontSet);
}
NS_IMETHODIMP DeviceContextImpl::GetDepth(PRUint32& aDepth)
@ -469,7 +473,7 @@ nsFontCache::GetDeviceContext(nsIDeviceContext *&aContext) const
nsresult
nsFontCache::GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
nsIFontMetrics *&aMetrics)
nsIFontMetrics *&aMetrics, gfxUserFontSet *aUserFontSet)
{
// First check our cache
// start from the end, which is where we put the most-recent-used element
@ -497,7 +501,7 @@ nsFontCache::GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
aMetrics = nsnull;
nsresult rv = CreateFontMetricsInstance(&fm);
if (NS_FAILED(rv)) return rv;
rv = fm->Init(aFont, aLangGroup, mContext);
rv = fm->Init(aFont, aLangGroup, mContext, aUserFontSet);
if (NS_SUCCEEDED(rv)) {
// the mFontMetrics list has the "head" at the end, because append is
// cheaper than insert
@ -516,7 +520,7 @@ nsFontCache::GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
Compact();
rv = CreateFontMetricsInstance(&fm);
if (NS_FAILED(rv)) return rv;
rv = fm->Init(aFont, aLangGroup, mContext);
rv = fm->Init(aFont, aLangGroup, mContext, aUserFontSet);
if (NS_SUCCEEDED(rv)) {
mFontMetrics.AppendElement(fm);
aMetrics = fm;

View File

@ -44,6 +44,7 @@
#include "gfxTextRunCache.h"
#include "gfxPlatform.h"
#include "gfxUserFontSet.h"
NS_IMPL_ISUPPORTS1(nsThebesFontMetrics, nsIFontMetrics)
@ -63,7 +64,8 @@ nsThebesFontMetrics::~nsThebesFontMetrics()
NS_IMETHODIMP
nsThebesFontMetrics::Init(const nsFont& aFont, nsIAtom* aLangGroup,
nsIDeviceContext *aContext)
nsIDeviceContext *aContext,
gfxUserFontSet *aUserFontSet)
{
mFont = aFont;
mLangGroup = aLangGroup;
@ -86,7 +88,8 @@ nsThebesFontMetrics::Init(const nsFont& aFont, nsIAtom* aLangGroup,
aFont.familyNameQuirks);
mFontGroup =
gfxPlatform::GetPlatform()->CreateFontGroup(aFont.name, mFontStyle);
gfxPlatform::GetPlatform()->CreateFontGroup(aFont.name, mFontStyle,
aUserFontSet);
return NS_OK;
}

View File

@ -57,7 +57,8 @@ public:
NS_DECL_ISUPPORTS
NS_IMETHOD Init(const nsFont& aFont, nsIAtom* aLangGroup,
nsIDeviceContext *aContext);
nsIDeviceContext *aContext,
gfxUserFontSet *aUserFontSet = nsnull);
NS_IMETHOD Destroy();
NS_IMETHOD GetXHeight(nscoord& aResult);
NS_IMETHOD GetSuperscriptOffset(nscoord& aResult);

View File

@ -31,6 +31,7 @@ EXPORTS = gfxASurface.h \
gfxTextRunCache.h \
gfxTextRunWordCache.h \
gfxUtils.h \
gfxUserFontSet.h \
$(NULL)
EXPORTS += gfxFontTest.h

View File

@ -113,7 +113,8 @@ protected:
class THEBES_API gfxAtsuiFontGroup : public gfxFontGroup {
public:
gfxAtsuiFontGroup(const nsAString& families,
const gfxFontStyle *aStyle);
const gfxFontStyle *aStyle,
gfxUserFontSet *aUserFontSet);
virtual ~gfxAtsuiFontGroup() {};
virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
@ -137,7 +138,9 @@ public:
PRBool HasFont(ATSUFontID fid);
inline gfxAtsuiFont* WhichFontSupportsChar(nsTArray< nsRefPtr<gfxFont> >& aFontList, PRUint32 aCh) {
inline gfxAtsuiFont* WhichFontSupportsChar(nsTArray< nsRefPtr<gfxFont> >& aFontList,
PRUint32 aCh)
{
PRUint32 len = aFontList.Length();
for (PRUint32 i = 0; i < len; i++) {
gfxAtsuiFont* font = static_cast<gfxAtsuiFont*>(aFontList.ElementAt(i).get());
@ -147,10 +150,12 @@ public:
return nsnull;
}
// search through pref fonts for a character, return nsnull if no matching pref font
already_AddRefed<gfxFont> WhichPrefFontSupportsChar(PRUint32 aCh);
already_AddRefed<gfxFont> WhichSystemFontSupportsChar(PRUint32 aCh);
// search through pref fonts for a character, return nsnull if no matching pref font
already_AddRefed<gfxFont> WhichPrefFontSupportsChar(PRUint32 aCh);
already_AddRefed<gfxFont> WhichSystemFontSupportsChar(PRUint32 aCh);
void UpdateFontList();
protected:
static PRBool FindATSUFont(const nsAString& aName,

View File

@ -51,8 +51,6 @@
#include "gfxSkipChars.h"
#include "gfxRect.h"
#include "nsExpirationTracker.h"
#include "nsMathUtils.h"
#include "nsBidiUtils.h"
#ifdef DEBUG
#include <stdio.h>
@ -63,6 +61,8 @@ class gfxTextRun;
class nsIAtom;
class gfxFont;
class gfxFontGroup;
class gfxUserFontSet;
class gfxUserFontData;
#define FONT_STYLE_NORMAL 0
#define FONT_STYLE_ITALIC 1
@ -140,20 +140,24 @@ struct THEBES_API gfxFontStyle {
}
};
class gfxFontEntry {
public:
THEBES_INLINE_DECL_REFCOUNTING(gfxFontEntry)
gfxFontEntry(const nsAString& aName) :
mName(aName), mCmapInitialized(PR_FALSE)
mName(aName), mIsProxy(PR_FALSE), mIsValid(PR_TRUE),
mIsBadUnderlineFont(PR_FALSE),
mCmapInitialized(PR_FALSE), mUserFontData(nsnull)
{ }
gfxFontEntry(const gfxFontEntry& aEntry) :
mName(aEntry.mName), mItalic(aEntry.mItalic), mFixedPitch(aEntry.mFixedPitch),
mUnicodeFont(aEntry.mUnicodeFont), mSymbolFont(aEntry.mSymbolFont), mTrueType(aEntry.mTrueType),
mIsType1(aEntry.mIsType1), mWeight(aEntry.mWeight), mCmapInitialized(aEntry.mCmapInitialized),
mCharacterMap(aEntry.mCharacterMap)
mName(aEntry.mName), mItalic(aEntry.mItalic),
mFixedPitch(aEntry.mFixedPitch), mUnicodeFont(aEntry.mUnicodeFont),
mSymbolFont(aEntry.mSymbolFont), mTrueType(aEntry.mTrueType),
mIsType1(aEntry.mIsType1), mIsProxy(aEntry.mIsProxy),
mIsValid(aEntry.mIsValid), mIsBadUnderlineFont(aEntry.mIsBadUnderlineFont),
mWeight(aEntry.mWeight), mCmapInitialized(aEntry.mCmapInitialized),
mCharacterMap(aEntry.mCharacterMap), mUserFontData(aEntry.mUserFontData)
{ }
virtual ~gfxFontEntry();
@ -165,7 +169,7 @@ public:
PRBool IsFixedPitch() { return mFixedPitch; }
PRBool IsItalic() { return mItalic; }
PRBool IsBold() { return mWeight >= 6; } // bold == weights 600 and above
PRBool IsBold() { return mWeight >= 600; } // bold == weights 600 and above
inline PRBool HasCharacter(PRUint32 ch) {
if (mCharacterMap.test(ch))
@ -177,7 +181,7 @@ public:
virtual PRBool TestCharacterMap(PRUint32 aCh);
virtual nsresult ReadCMAP() { return 0; }
nsString mName;
nsString mName;
PRPackedBool mItalic : 1;
PRPackedBool mFixedPitch : 1;
@ -186,11 +190,23 @@ public:
PRPackedBool mSymbolFont : 1;
PRPackedBool mTrueType : 1;
PRPackedBool mIsType1 : 1;
PRPackedBool mIsProxy : 1;
PRPackedBool mIsValid : 1;
PRPackedBool mIsBadUnderlineFont : 1;
PRUint16 mWeight;
PRUint16 mStretch;
PRPackedBool mCmapInitialized;
gfxSparseBitSet mCharacterMap;
gfxUserFontData* mUserFontData;
protected:
gfxFontEntry() :
mIsProxy(PR_FALSE), mIsValid(PR_TRUE),
mCmapInitialized(PR_FALSE), mUserFontData(nsnull)
{ }
};
@ -205,12 +221,17 @@ public:
const nsString& Name() { return mName; }
// choose a specific face to match a style using CSS font matching rules (weight matching occurs here)
gfxFontEntry *FindFontForStyle(const gfxFontStyle& aFontStyle, PRBool& aNeedsBold);
// choose a specific face to match a style using CSS font matching
// rules (weight matching occurs here)
gfxFontEntry *FindFontForStyle(const gfxFontStyle& aFontStyle,
PRBool& aNeedsBold);
protected:
// fills in an array with weights of faces that match style, returns number of weights in array
virtual PRBool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], const gfxFontStyle& aFontStyle) { return PR_FALSE; }
// fills in an array with weights of faces that match style, returns
// number of weights in array
virtual PRBool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[],
const gfxFontStyle& aFontStyle)
{ return PR_FALSE; }
nsString mName;
};
@ -351,7 +372,7 @@ public:
PRUint16 GetContainedGlyphWidthAppUnits(PRUint32 aGlyphID) const {
return mContainedGlyphWidths.Get(aGlyphID);
}
PRBool IsGlyphKnown(PRUint32 aGlyphID) const {
return mContainedGlyphWidths.Get(aGlyphID) != INVALID_WIDTH ||
mTightGlyphExtents.GetEntry(aGlyphID) != nsnull;
@ -638,7 +659,7 @@ public:
PRBool IsSyntheticBold() { return mSyntheticBoldOffset != 0; }
PRUint32 GetSyntheticBoldOffset() { return mSyntheticBoldOffset; }
gfxFontEntry *GetFontEntry() { return mFontEntry.get(); }
PRBool HasCharacter(PRUint32 ch) {
if (!mIsValid)
@ -675,7 +696,7 @@ public:
PLATFORM_TEXT_FLAGS = 0x0000F000,
TEXTRUN_TEXT_FLAGS = 0x00000FFF,
SETTABLE_FLAGS = CACHE_TEXT_FLAGS | USER_TEXT_FLAGS,
/**
* When set, the text string pointer used to create the text run
* is guaranteed to be available during the lifetime of the text run.
@ -1385,6 +1406,9 @@ public:
PRPackedBool mClipBeforePart;
PRPackedBool mClipAfterPart;
};
// user font set generation when text run was created
PRUint64 GetUserFontSetGeneration() { return mUserFontSetGeneration; }
#ifdef DEBUG
// number of entries referencing this textrun in the gfxTextRunWordCache
@ -1488,16 +1512,15 @@ private:
PRUint32 mFlags;
PRUint32 mCharacterCount;
PRUint32 mHashCode;
PRUint64 mUserFontSetGeneration; // user font set generation when text run created
};
class THEBES_API gfxFontGroup : public gfxTextRunFactory {
protected:
gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle);
gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle, gfxUserFontSet *aUserFontSet = nsnull);
public:
virtual ~gfxFontGroup() {
mFonts.Clear();
}
virtual ~gfxFontGroup();
virtual gfxFont *GetFontAt(PRInt32 i) {
return static_cast<gfxFont*>(mFonts[i]);
@ -1519,20 +1542,8 @@ public:
* The listed characters should not be passed in to MakeTextRun and should
* be treated as invisible and zero-width.
*/
static PRBool IsInvalidChar(PRUnichar ch) {
if (ch >= 32) {
return ch == 0x0085/*NEL*/ ||
((ch & 0xFF00) == 0x2000 /* Unicode control character */ &&
(ch == 0x200B/*ZWSP*/ || ch == 0x2028/*LSEP*/ || ch == 0x2029/*PSEP*/ ||
IS_BIDI_CONTROL_CHAR(ch)));
}
// We could just blacklist all control characters, but it seems better
// to only blacklist the ones we know cause problems for native font
// engines.
return ch == 0x0B || ch == '\t' || ch == '\r' || ch == '\n' || ch == '\f' ||
(ch >= 0x1c && ch <= 0x1f);
}
static PRBool IsInvalidChar(PRUnichar ch);
/**
* Make a textrun for an empty string. This is fast; if you call it,
* don't bother caching the result.
@ -1567,7 +1578,7 @@ public:
typedef PRBool (*FontCreationCallback) (const nsAString& aName,
const nsACString& aGenericName,
void *closure);
static PRBool ForEachFont(const nsAString& aFamilies,
/*static*/ PRBool ForEachFont(const nsAString& aFamilies,
const nsACString& aLangGroup,
FontCreationCallback fc,
void *closure);
@ -1595,6 +1606,16 @@ public:
void ComputeRanges(nsTArray<gfxTextRange>& mRanges, const PRUnichar *aString, PRUint32 begin, PRUint32 end);
gfxUserFontSet* GetUserFontSet();
void SetUserFontSet(gfxUserFontSet *aUserFontSet);
// With downloadable fonts, the composition of the font group can change as fonts are downloaded
// for each change in state of the user font set, the generation value is bumped to avoid picking up
// previously created text runs in the text run word cache. For font groups based on stylesheets
// with no @font-face rule, this always returns 0.
PRUint64 GetGeneration();
virtual void UpdateFontList() { }
protected:
nsString mFamilies;
@ -1602,6 +1623,9 @@ protected:
nsTArray< nsRefPtr<gfxFont> > mFonts;
gfxFloat mUnderlineOffset;
gfxUserFontSet* mUserFontSet;
PRUint64 mCurrGeneration; // track the current user font set generation, rebuild font list if needed
// Init this font group's font metrics. If there no bad fonts, you don't need to call this.
// But if there are one or more bad fonts which have bad underline offset,
// you should call this with the *first* bad font.
@ -1615,7 +1639,7 @@ protected:
* family name in aFamilies (after resolving CSS/Gecko generic family names
* if aResolveGeneric).
*/
static PRBool ForEachFontInternal(const nsAString& aFamilies,
/*static*/ PRBool ForEachFontInternal(const nsAString& aFamilies,
const nsACString& aLangGroup,
PRBool aResolveGeneric,
PRBool aResolveFontName,

View File

@ -44,6 +44,7 @@
#include "cairo.h"
#include "gfxFont.h"
#include "gfxUserFontSet.h"
struct THEBES_API gfxFontTestItem {
gfxFontTestItem(const nsCString& fontName,

View File

@ -312,18 +312,32 @@ public:
static inline PRUint32
ReadLongAt(const PRUint8 *aBuf, PRUint32 aIndex)
{
return ((aBuf[aIndex] << 24) | (aBuf[aIndex + 1] << 16) | (aBuf[aIndex + 2] << 8) | (aBuf[aIndex + 3]));
return ((aBuf[aIndex] << 24) | (aBuf[aIndex + 1] << 16) |
(aBuf[aIndex + 2] << 8) | (aBuf[aIndex + 3]));
}
static nsresult
ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap);
ReadCMAPTableFormat12(PRUint8 *aBuf, PRInt32 aLength,
gfxSparseBitSet& aCharacterMap);
static nsresult
ReadCMAPTableFormat4(PRUint8 *aBuf, PRInt32 aLength, gfxSparseBitSet& aCharacterMap);
ReadCMAPTableFormat4(PRUint8 *aBuf, PRInt32 aLength,
gfxSparseBitSet& aCharacterMap);
static nsresult
ReadCMAP(PRUint8 *aBuf, PRUint32 aBufLength, gfxSparseBitSet& aCharacterMap,
PRPackedBool& aUnicodeFont, PRPackedBool& aSymbolFont);
#ifdef XP_WIN
// given a TrueType/OpenType data file, produce a EOT-format header
// for use with Windows T2Embed API AddFontResource type API's
// effectively hide existing fonts with matching names aHeaderLen is
// the size of the header buffer on input, the actual size of the
// EOT header on output aIsCFF returns whether the font has PS style
// glyphs or not (as opposed to TrueType glyphs)
static nsresult
MakeEOTHeader(nsIFile *aFontData, nsTArray<PRUint8> *aHeader, PRBool *aIsCFF);
#endif
static inline bool IsJoiner(PRUint32 ch) {
return (ch == 0x200C ||
@ -338,7 +352,8 @@ public:
static PRUint8 CharRangeBit(PRUint32 ch);
// for a given font list pref name, set up a list of font names
static void GetPrefsFontList(const char *aPrefName, nsTArray<nsString>& aFontList);
static void GetPrefsFontList(const char *aPrefName,
nsTArray<nsString>& aFontList);
};
@ -400,7 +415,8 @@ public:
InitLoader();
// start timer
mTimer->InitWithFuncCallback(LoaderTimerCallback, this, aDelay, nsITimer::TYPE_REPEATING_SLACK);
mTimer->InitWithFuncCallback(LoaderTimerCallback, this, aDelay,
nsITimer::TYPE_REPEATING_SLACK);
}
// cancel the timer and cleanup

View File

@ -95,7 +95,7 @@ private:
class THEBES_API gfxOS2FontGroup : public gfxFontGroup {
public:
gfxOS2FontGroup(const nsAString& aFamilies, const gfxFontStyle* aStyle);
gfxOS2FontGroup(const nsAString& aFamilies, const gfxFontStyle* aStyle, gfxUserFontSet *aUserFontSet);
virtual ~gfxOS2FontGroup();
virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);

View File

@ -71,7 +71,8 @@ public:
nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
const gfxFontStyle *aStyle);
const gfxFontStyle *aStyle
gfxUserFontSet *aUserFontSet);
// Given a string and a font we already have, find the font that
// supports the most code points and most closely resembles aFont.

View File

@ -73,7 +73,8 @@ public:
class THEBES_API gfxPangoFontGroup : public gfxFontGroup {
public:
gfxPangoFontGroup (const nsAString& families,
const gfxFontStyle *aStyle);
const gfxFontStyle *aStyle,
gfxUserFontSet *aUserFontSet);
virtual ~gfxPangoFontGroup ();
virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);

View File

@ -59,6 +59,10 @@ class gfxImageSurface;
class gfxFont;
class gfxFontGroup;
struct gfxFontStyle;
class gfxUserFontSet;
struct gfxDownloadedFontData;
class gfxFontEntry;
class nsIURI;
// pref lang id's for font prefs
// !!! needs to match the list of pref font.default.xx entries listed in all.js !!!
@ -184,7 +188,30 @@ public:
* Create the appropriate platform font group
*/
virtual gfxFontGroup *CreateFontGroup(const nsAString& aFamilies,
const gfxFontStyle *aStyle) = 0;
const gfxFontStyle *aStyle,
gfxUserFontSet *aUserFontSet) = 0;
/**
* Look up a local platform font using the full font face name (needed to support @font-face src local() )
*/
virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName) { return nsnull; }
/**
* Activate a platform font (needed to support @font-face src url() )
*
* Note: MakePlatformFont implementation is responsible for removing font file data, since data may need to
* persist beyond this call.
*/
virtual gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry, const gfxDownloadedFontData* aFontData) { return nsnull; }
/**
* Whether to allow downloadable fonts via @font-face rules
*/
virtual PRBool DownloadableFontsEnabled();
// check whether format is supported on a platform or not (if unclear, returns true)
virtual PRBool IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags) { return PR_FALSE; }
void GetPrefFonts(const char *aLangGroup, nsString& array, PRBool aAppendUnicode = PR_TRUE);

View File

@ -79,7 +79,8 @@ public:
nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
const gfxFontStyle *aStyle);
const gfxFontStyle *aStyle,
gfxUserFontSet *aUserFontSet);
#ifndef MOZ_PANGO
FontFamily *FindFontFamily(const nsAString& aName);

View File

@ -66,7 +66,14 @@ public:
nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
const gfxFontStyle *aStyle);
const gfxFontStyle *aStyle,
gfxUserFontSet *aUserFontSet);
gfxFontEntry* LookupLocalFont(const nsAString& aFontName);
gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry, const gfxDownloadedFontData* aFontData);
PRBool IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags);
nsresult GetFontList(const nsACString& aLangGroup,
const nsACString& aGenericFamily,

View File

@ -83,7 +83,7 @@ class FontFamily : public gfxFontFamily
{
public:
FontFamily(const nsAString& aName) :
gfxFontFamily(aName), mHasStyles(PR_FALSE), mIsBadUnderlineFont(PR_FALSE) { }
gfxFontFamily(aName), mIsBadUnderlineFontFamily(PR_FALSE), mHasStyles(PR_FALSE) { }
FontEntry *FindFontEntry(const gfxFontStyle& aFontStyle);
@ -101,18 +101,18 @@ protected:
public:
nsTArray<nsRefPtr<FontEntry> > mVariations;
PRPackedBool mIsBadUnderlineFont;
PRPackedBool mIsBadUnderlineFontFamily;
private:
PRBool mHasStyles;
PRPackedBool mHasStyles;
};
class FontEntry : public gfxFontEntry
{
public:
FontEntry(const nsString& aFaceName) :
FontEntry(const nsAString& aFaceName) :
gfxFontEntry(aFaceName), mFontType(GFX_FONT_TYPE_UNKNOWN),
mIsBadUnderlineFont(PR_FALSE), mForceGDI(PR_FALSE), mUnknownCMAP(PR_FALSE),
mForceGDI(PR_FALSE), mUnknownCMAP(PR_FALSE),
mCharset(0), mUnicodeRanges(0)
{
mUnicodeFont = PR_FALSE;
@ -124,7 +124,6 @@ public:
mWindowsFamily(aFontEntry.mWindowsFamily),
mWindowsPitch(aFontEntry.mWindowsPitch),
mFontType(aFontEntry.mFontType),
mIsBadUnderlineFont(aFontEntry.mIsBadUnderlineFont),
mForceGDI(aFontEntry.mForceGDI),
mUnknownCMAP(aFontEntry.mUnknownCMAP),
mCharset(aFontEntry.mCharset),
@ -133,6 +132,31 @@ public:
}
static FontEntry* CreateFontEntry(const nsAString& aName, gfxWindowsFontType aFontType, PRBool aItalic, PRUint16 aWeight, gfxUserFontData* aUserFontData, HDC hdc = 0, LOGFONTW *aLogFont = nsnull);
static void FillLogFont(LOGFONTW *aLogFont, FontEntry *aFontEntry, gfxFloat aSize, PRBool aItalic);
static gfxWindowsFontType DetermineFontType(const NEWTEXTMETRICW& metrics, DWORD fontType)
{
gfxWindowsFontType feType;
if (metrics.ntmFlags & NTM_TYPE1)
feType = GFX_FONT_TYPE_TYPE1;
else if (metrics.ntmFlags & NTM_PS_OPENTYPE)
feType = GFX_FONT_TYPE_PS_OPENTYPE;
else if (metrics.ntmFlags & NTM_TT_OPENTYPE)
feType = GFX_FONT_TYPE_TT_OPENTYPE;
else if (fontType == TRUETYPE_FONTTYPE)
feType = GFX_FONT_TYPE_TRUETYPE;
else if (fontType == RASTER_FONTTYPE)
feType = GFX_FONT_TYPE_RASTER;
else if (fontType == DEVICE_FONTTYPE)
feType = GFX_FONT_TYPE_DEVICE;
else
feType = GFX_FONT_TYPE_UNKNOWN;
return feType;
}
PRBool IsType1() const {
return (mFontType == GFX_FONT_TYPE_TYPE1);
}
@ -232,16 +256,12 @@ public:
return mUnicodeRanges[range];
}
// whether this font family is in "bad" underline offset blacklist.
PRBool IsBadUnderlineFont() { return mIsBadUnderlineFont != 0; }
PRBool TestCharacterMap(PRUint32 aCh);
PRUint8 mWindowsFamily;
PRUint8 mWindowsPitch;
gfxWindowsFontType mFontType;
PRPackedBool mIsBadUnderlineFont : 1;
PRPackedBool mForceGDI : 1;
PRPackedBool mUnknownCMAP : 1;
@ -317,7 +337,7 @@ private:
class THEBES_API gfxWindowsFontGroup : public gfxFontGroup {
public:
gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFontStyle* aStyle);
gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFontStyle* aStyle, gfxUserFontSet *aUserFontSet);
virtual ~gfxWindowsFontGroup();
virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
@ -349,8 +369,10 @@ public:
const nsCString& aLangGroup,
nsTArray<nsRefPtr<FontEntry> > *list);
void UpdateFontList();
protected:
void InitFontList();
void InitTextRunGDI(gfxContext *aContext, gfxTextRun *aRun, const char *aString, PRUint32 aLength);
void InitTextRunGDI(gfxContext *aContext, gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength);

View File

@ -75,7 +75,23 @@ public:
nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
gfxFontGroup *CreateFontGroup(const nsAString &aFamilies,
const gfxFontStyle *aStyle);
const gfxFontStyle *aStyle,
gfxUserFontSet *aUserFontSet);
/**
* Look up a local platform font using the full font face name (needed to support @font-face src local() )
*/
virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName);
/**
* Activate a platform font (needed to support @font-face src url() )
*/
virtual gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry, const gfxDownloadedFontData* aFontData);
/**
* Check whether format is supported on a platform or not (if unclear, returns true)
*/
virtual PRBool IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags);
/* Given a string and a font we already have find the font that
* supports the most code points and most closely resembles aFont

View File

@ -38,6 +38,7 @@ CPPSRCS = \
gfxSkipChars.cpp \
gfxTextRunCache.cpp \
gfxTextRunWordCache.cpp \
gfxUserFontSet.cpp \
$(NULL)
EXTRA_DSO_LDOPTS += \

View File

@ -58,6 +58,7 @@
#include "gfxQuartzSurface.h"
#include "gfxQuartzFontCache.h"
#include "gfxUserFontSet.h"
#include "nsUnicodeRange.h"
@ -322,7 +323,7 @@ gfxAtsuiFont::InitMetrics(ATSUFontID aFontID, ATSFontRef aFontRef)
if (glyphID == 0) // no zero in this font
mMetrics.zeroOrAveCharWidth = mMetrics.aveCharWidth;
SanitizeMetrics(&mMetrics, GetFontEntry()->FamilyEntry()->IsBadUnderlineFontFamily());
SanitizeMetrics(&mMetrics, GetFontEntry()->mIsBadUnderlineFont);
#if 0
fprintf (stderr, "Font: %p size: %f (fixed: %d)", this, size, gfxQuartzFontCache::SharedFontCache()->IsFixedPitch(aFontID));
@ -501,9 +502,11 @@ GetOrMakeFont(MacOSFontEntry *aFontEntry, const gfxFontStyle *aStyle, PRBool aNe
return static_cast<gfxAtsuiFont *>(f);
}
gfxAtsuiFontGroup::gfxAtsuiFontGroup(const nsAString& families,
const gfxFontStyle *aStyle)
: gfxFontGroup(families, aStyle)
const gfxFontStyle *aStyle,
gfxUserFontSet *aUserFontSet)
: gfxFontGroup(families, aStyle, aUserFontSet)
{
ForEachFont(FindATSUFont, this);
@ -536,7 +539,7 @@ gfxAtsuiFontGroup::gfxAtsuiFontGroup(const nsAString& families,
if (!mStyle.systemFont) {
for (PRUint32 i = 0; i < mFonts.Length(); ++i) {
gfxAtsuiFont* font = static_cast<gfxAtsuiFont*>(mFonts[i].get());
if (font->GetFontEntry()->FamilyEntry()->IsBadUnderlineFontFamily()) {
if (font->GetFontEntry()->mIsBadUnderlineFont) {
gfxFloat first = mFonts[0]->GetMetrics().underlineOffset;
gfxFloat bad = font->GetMetrics().underlineOffset;
mUnderlineOffset = PR_MIN(first, bad);
@ -554,10 +557,23 @@ gfxAtsuiFontGroup::FindATSUFont(const nsAString& aName,
gfxAtsuiFontGroup *fontGroup = (gfxAtsuiFontGroup*) closure;
const gfxFontStyle *fontStyle = fontGroup->GetStyle();
gfxQuartzFontCache *fc = gfxQuartzFontCache::SharedFontCache();
PRBool needsBold;
MacOSFontEntry *fe = fc->FindFontForFamily(aName, fontStyle, needsBold);
MacOSFontEntry *fe = nsnull;
// first, look up in the user font set
gfxUserFontSet *fs = fontGroup->GetUserFontSet();
gfxFontEntry *gfe;
if (fs && (gfe = fs->FindFontEntry(aName, *fontStyle, needsBold))) {
// assume for now platform font if not SVG
fe = static_cast<MacOSFontEntry*> (gfe);
}
// nothing in the user font set ==> check system fonts
if (!fe) {
gfxQuartzFontCache *fc = gfxQuartzFontCache::SharedFontCache();
fe = fc->FindFontForFamily(aName, fontStyle, needsBold);
}
if (fe && !fontGroup->HasFont(fe->GetFontID())) {
nsRefPtr<gfxAtsuiFont> font = GetOrMakeFont(fe, fontStyle, needsBold);
@ -572,7 +588,7 @@ gfxAtsuiFontGroup::FindATSUFont(const nsAString& aName,
gfxFontGroup *
gfxAtsuiFontGroup::Copy(const gfxFontStyle *aStyle)
{
return new gfxAtsuiFontGroup(mFamilies, aStyle);
return new gfxAtsuiFontGroup(mFamilies, aStyle, mUserFontSet);
}
static void
@ -933,6 +949,19 @@ gfxAtsuiFontGroup::WhichSystemFontSupportsChar(PRUint32 aCh)
return nsnull;
}
void
gfxAtsuiFontGroup::UpdateFontList()
{
// if user font set is set, check to see if font list needs updating
if (mUserFontSet && mCurrGeneration != GetGeneration()) {
// xxx - can probably improve this to detect when all fonts were found, so no need to update list
mFonts.Clear();
ForEachFont(FindATSUFont, this);
mCurrGeneration = GetGeneration();
}
}
/**
* Simple wrapper for ATSU "direct data arrays"
*/
@ -1392,8 +1421,8 @@ gfxAtsuiFontGroup::InitTextRun(gfxTextRun *aRun,
("InitTextRun %p fontgroup %p (%s) lang: %s len %d TEXTRUN \"%s\" ENDTEXTRUN\n",
aRun, this, families.get(), mStyle.langGroup.get(), aLengthInTextRun, str.get()) );
PR_LOG(gAtsuiTextRunLog, PR_LOG_DEBUG,
("InitTextRun font: %s\n",
NS_ConvertUTF16toUTF8(firstFont->GetUniqueName()).get()) );
("InitTextRun font: %s user font set: %p (%8.8x)\n",
NS_ConvertUTF16toUTF8(firstFont->GetUniqueName()).get(), mUserFontSet, PRUint32(mCurrGeneration)) );
#endif
if (aRun->GetFlags() & TEXT_DISABLE_OPTIONAL_LIGATURES) {

View File

@ -49,7 +49,9 @@
#include "gfxTypes.h"
#include "gfxContext.h"
#include "gfxFontMissingGlyphs.h"
#include "gfxUserFontSet.h"
#include "nsMathUtils.h"
#include "nsBidiUtils.h"
#include "cairo.h"
#include "gfxFontTest.h"
@ -74,8 +76,10 @@ static PRUint32 gGlyphExtentsSetupLazyTight = 0;
static PRUint32 gGlyphExtentsSetupFallBackToTight = 0;
#endif
gfxFontEntry::~gfxFontEntry() {
gfxFontEntry::~gfxFontEntry()
{
if (mUserFontData)
delete mUserFontData;
}
@ -91,7 +95,9 @@ gfxFontEntry *gfxFontFamily::FindFontForStyle(const gfxFontStyle& aFontStyle, PR
aNeedsBold = PR_FALSE;
FindWeightsForStyle(weightList, aFontStyle);
PRBool foundWeights = FindWeightsForStyle(weightList, aFontStyle);
if (!foundWeights)
return nsnull;
PRInt8 baseWeight, weightDistance;
aFontStyle.ComputeWeightAndOffset(&baseWeight, &weightDistance);
@ -856,10 +862,32 @@ gfxGlyphExtents::SetTightGlyphExtents(PRUint32 aGlyphID, const gfxRect& aExtents
entry->height = aExtentsAppUnits.size.height;
}
gfxFontGroup::gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle)
gfxFontGroup::gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle, gfxUserFontSet *aUserFontSet)
: mFamilies(aFamilies), mStyle(*aStyle), mUnderlineOffset(UNDERLINE_OFFSET_NOT_SET)
{
mUserFontSet = nsnull;
SetUserFontSet(aUserFontSet);
}
gfxFontGroup::~gfxFontGroup() {
mFonts.Clear();
SetUserFontSet(nsnull);
}
PRBool
gfxFontGroup::IsInvalidChar(PRUnichar ch) {
if (ch >= 32) {
return ch == 0x0085/*NEL*/ ||
((ch & 0xFF00) == 0x2000 /* Unicode control character */ &&
(ch == 0x200B/*ZWSP*/ || ch == 0x2028/*LSEP*/ || ch == 0x2029/*PSEP*/ ||
IS_BIDI_CONTROL_CHAR(ch)));
}
// We could just blacklist all control characters, but it seems better
// to only blacklist the ones we know cause problems for native font
// engines.
return ch == 0x0B || ch == '\t' || ch == '\r' || ch == '\n' || ch == '\f' ||
(ch >= 0x1c && ch <= 0x1f);
}
PRBool
@ -989,11 +1017,18 @@ gfxFontGroup::ForEachFontInternal(const nsAString& aFamilies,
NS_LossyConvertUTF16toASCII gf(genericFamily);
if (aResolveFontName) {
ResolveData data(fc, gf, closure);
PRBool aborted;
gfxPlatform *pf = gfxPlatform::GetPlatform();
nsresult rv = pf->ResolveFontName(family,
PRBool aborted, needsBold;
nsresult rv;
if (mUserFontSet && mUserFontSet->FindFontEntry(family, mStyle, needsBold)) {
gfxFontGroup::FontResolverProc(family, &data);
rv = NS_OK;
} else {
gfxPlatform *pf = gfxPlatform::GetPlatform();
rv = pf->ResolveFontName(family,
gfxFontGroup::FontResolverProc,
&data, aborted);
}
if (NS_FAILED(rv) || aborted)
return PR_FALSE;
}
@ -1089,7 +1124,7 @@ gfxFontGroup::FindFontForChar(PRUint32 aCh, PRUint32 aPrevCh, PRUint32 aNextCh,
// if match, return
if (selectedFont)
return selectedFont.forget();
// if character is in Private Use Area, don't do matching against pref or system fonts
if ((aCh >= 0xE000 && aCh <= 0xF8FF) || (aCh >= 0xF0000 && aCh <= 0x10FFFD))
return nsnull;
@ -1169,6 +1204,29 @@ void gfxFontGroup::ComputeRanges(nsTArray<gfxTextRange>& aRanges, const PRUnicha
aRanges[aRanges.Length()-1].end = len;
}
gfxUserFontSet*
gfxFontGroup::GetUserFontSet()
{
return mUserFontSet;
}
void
gfxFontGroup::SetUserFontSet(gfxUserFontSet *aUserFontSet)
{
NS_IF_RELEASE(mUserFontSet);
mUserFontSet = aUserFontSet;
NS_IF_ADDREF(mUserFontSet);
mCurrGeneration = GetGeneration();
}
PRUint64
gfxFontGroup::GetGeneration()
{
if (!mUserFontSet)
return 0;
return mUserFontSet->GetGeneration();
}
#define DEFAULT_PIXEL_FONT_SIZE 16.0f
@ -1331,6 +1389,8 @@ gfxTextRun::gfxTextRun(const gfxTextRunFactory::Parameters *aParams, const void
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
AccountStorageForTextRun(this, 1);
#endif
mUserFontSetGeneration = mFontGroup->GetGeneration();
}
gfxTextRun::~gfxTextRun()

View File

@ -45,6 +45,8 @@
#include "nsIPrefService.h"
#include "nsIPrefLocalizedString.h"
#include "nsISupportsPrimitives.h"
#include "nsIStreamBufferAccess.h"
#include "nsILocalFile.h"
#define NO_RANGE_FOUND 126 // bit 126 in the font unicode ranges is required to be 0
@ -469,4 +471,558 @@ void gfxFontUtils::GetPrefsFontList(const char *aPrefName, nsTArray<nsString>& a
}
// for now, this is only needed on Windows
#ifdef XP_WIN
// TrueType/OpenType table handling code
// need byte aligned structs
#pragma pack(1)
struct AutoSwap_PRUint16 {
operator PRUint16() { return NS_SWAP16(value); }
operator PRUint32() { return NS_SWAP16(value); }
PRUint16 value;
};
struct AutoSwap_PRInt16 {
operator PRInt16() { return NS_SWAP16(value); }
operator PRUint32() { return NS_SWAP16(value); }
PRInt16 value;
};
struct AutoSwap_PRUint32 {
operator PRUint32() { return NS_SWAP32(value); }
PRUint32 value;
};
struct AutoSwap_PRUint64 {
operator PRUint64() { return NS_SWAP64(value); }
PRUint64 value;
};
struct SFNTHeader {
AutoSwap_PRUint32 sfntVersion; // Fixed, 0x00010000 for version 1.0.
AutoSwap_PRUint16 numTables; // Number of tables.
AutoSwap_PRUint16 searchRange; // (Maximum power of 2 <= numTables) x 16.
AutoSwap_PRUint16 entrySelector; // Log2(maximum power of 2 <= numTables).
AutoSwap_PRUint16 rangeShift; // NumTables x 16-searchRange.
};
struct TableDirEntry {
AutoSwap_PRUint32 tag; // 4 -byte identifier.
AutoSwap_PRUint32 checkSum; // CheckSum for this table.
AutoSwap_PRUint32 offset; // Offset from beginning of TrueType font file.
AutoSwap_PRUint32 length; // Length of this table.
};
struct HeadTable {
enum {
HEAD_MAGIC_NUMBER = 0x5F0F3CF5
};
AutoSwap_PRUint32 tableVersionNumber; // Fixed, 0x00010000 for version 1.0.
AutoSwap_PRUint32 fontRevision; // Set by font manufacturer.
AutoSwap_PRUint32 checkSumAdjustment; // To compute: set it to 0, sum the entire font as ULONG, then store 0xB1B0AFBA - sum.
AutoSwap_PRUint32 magicNumber; // Set to 0x5F0F3CF5.
AutoSwap_PRUint16 flags;
AutoSwap_PRUint16 unitsPerEm; // Valid range is from 16 to 16384. This value should be a power of 2 for fonts that have TrueType outlines.
AutoSwap_PRUint64 created; // Number of seconds since 12:00 midnight, January 1, 1904. 64-bit integer
AutoSwap_PRUint64 modified; // Number of seconds since 12:00 midnight, January 1, 1904. 64-bit integer
AutoSwap_PRInt16 xMin; // For all glyph bounding boxes.
AutoSwap_PRInt16 yMin; // For all glyph bounding boxes.
AutoSwap_PRInt16 xMax; // For all glyph bounding boxes.
AutoSwap_PRInt16 yMax; // For all glyph bounding boxes.
AutoSwap_PRUint16 macStyle; // Bit 0: Bold (if set to 1);
AutoSwap_PRUint16 lowestRecPPEM; // Smallest readable size in pixels.
AutoSwap_PRInt16 fontDirectionHint;
AutoSwap_PRInt16 indexToLocFormat;
AutoSwap_PRInt16 glyphDataFormat;
};
// name table has a header, followed by name records, followed by string data
struct NameHeader {
AutoSwap_PRUint16 format; // Format selector (=0).
AutoSwap_PRUint16 count; // Number of name records.
AutoSwap_PRUint16 stringOffset; // Offset to start of string storage (from start of table)
};
struct NameRecord {
AutoSwap_PRUint16 platformID; // Platform ID
AutoSwap_PRUint16 encodingID; // Platform-specific encoding ID
AutoSwap_PRUint16 languageID; // Language ID
AutoSwap_PRUint16 nameID; // Name ID.
AutoSwap_PRUint16 length; // String length (in bytes).
AutoSwap_PRUint16 offset; // String offset from start of storage area (in bytes).
enum {
NAME_ID_FAMILY = 1,
NAME_ID_STYLE = 2,
NAME_ID_FULL = 4,
NAME_ID_VERSION = 5,
PLATFORM_ID_UNICODE = 0, // Mac OS uses this typically
PLATFORM_ID_MICROSOFT = 3,
ENCODING_ID_MICROSOFT_UNICODEBMP = 1, // with Microsoft platformID, BMP-only Unicode encoding
LANG_ID_MICROSOFT_EN_US = 0x0409 // with Microsoft platformID, EN US lang code
};
};
struct OS2Table {
AutoSwap_PRUint16 version; // 0004 = OpenType 1.5
AutoSwap_PRInt16 xAvgCharWidth;
AutoSwap_PRUint16 usWeightClass;
AutoSwap_PRUint16 usWidthClass;
AutoSwap_PRUint16 fsType;
AutoSwap_PRInt16 ySubscriptXSize;
AutoSwap_PRInt16 ySubscriptYSize;
AutoSwap_PRInt16 ySubscriptXOffset;
AutoSwap_PRInt16 ySubscriptYOffset;
AutoSwap_PRInt16 ySuperscriptXSize;
AutoSwap_PRInt16 ySuperscriptYSize;
AutoSwap_PRInt16 ySuperscriptXOffset;
AutoSwap_PRInt16 ySuperscriptYOffset;
AutoSwap_PRInt16 yStrikeoutSize;
AutoSwap_PRInt16 yStrikeoutPosition;
AutoSwap_PRInt16 sFamilyClass;
PRUint8 panose[10];
AutoSwap_PRUint32 unicodeRange1;
AutoSwap_PRUint32 unicodeRange2;
AutoSwap_PRUint32 unicodeRange3;
AutoSwap_PRUint32 unicodeRange4;
PRUint8 achVendID[4];
AutoSwap_PRUint16 fsSelection;
AutoSwap_PRUint16 usFirstCharIndex;
AutoSwap_PRUint16 usLastCharIndex;
AutoSwap_PRInt16 sTypoAscender;
AutoSwap_PRInt16 sTypoDescender;
AutoSwap_PRInt16 sTypoLineGap;
AutoSwap_PRUint16 usWinAscent;
AutoSwap_PRUint16 usWinDescent;
AutoSwap_PRUint32 codePageRange1;
AutoSwap_PRUint32 codePageRange2;
AutoSwap_PRInt16 sxHeight;
AutoSwap_PRInt16 sCapHeight;
AutoSwap_PRUint16 usDefaultChar;
AutoSwap_PRUint16 usBreakChar;
AutoSwap_PRUint16 usMaxContext;
};
// Embedded OpenType (EOT) handling
// needed for dealing with downloadable fonts on Windows
//
// EOT version 0x00020001
// based on http://www.w3.org/Submission/2008/SUBM-EOT-20080305/
//
// EOT header consists of a fixed-size portion containing general font
// info, followed by a variable-sized portion containing name data,
// followed by the actual TT/OT font data (non-byte values are always
// stored in big-endian format)
//
// EOT header is stored in *little* endian order!!
struct EOTFixedHeader {
PRUint32 eotSize; // Total structure length in PRUint8s (including string and font data)
PRUint32 fontDataSize; // Length of the OpenType font (FontData) in PRUint8s
PRUint32 version; // Version number of this format - 0x00010000
PRUint32 flags; // Processing Flags
PRUint8 panose[10]; // The PANOSE value for this font - See http://www.microsoft.com/typography/otspec/os2.htm#pan
PRUint8 charset; // In Windows this is derived from TEXTMETRIC.tmCharSet. This value specifies the character set of the font. DEFAULT_CHARSET (0x01) indicates no preference. - See http://msdn2.microsoft.com/en-us/library/ms534202.aspx
PRUint8 italic; // If the bit for ITALIC is set in OS/2.fsSelection, the value will be 0x01 - See http://www.microsoft.com/typography/otspec/os2.htm#fss
PRUint32 weight; // The weight value for this font - See http://www.microsoft.com/typography/otspec/os2.htm#wtc
PRUint16 fsType; // Type flags that provide information about embedding permissions - See http://www.microsoft.com/typography/otspec/os2.htm#fst
PRUint16 magicNumber; // Magic number for EOT file - 0x504C. Used to check for data corruption.
PRUint32 unicodeRange1; // OS/2.UnicodeRange1 (bits 0-31) - See http://www.microsoft.com/typography/otspec/os2.htm#ur
PRUint32 unicodeRange2; // OS/2.UnicodeRange2 (bits 32-63) - See http://www.microsoft.com/typography/otspec/os2.htm#ur
PRUint32 unicodeRange3; // OS/2.UnicodeRange3 (bits 64-95) - See http://www.microsoft.com/typography/otspec/os2.htm#ur
PRUint32 unicodeRange4; // OS/2.UnicodeRange4 (bits 96-127) - See http://www.microsoft.com/typography/otspec/os2.htm#ur
PRUint32 codePageRange1; // CodePageRange1 (bits 0-31) - See http://www.microsoft.com/typography/otspec/os2.htm#cpr
PRUint32 codePageRange2; // CodePageRange2 (bits 32-63) - See http://www.microsoft.com/typography/otspec/os2.htm#cpr
PRUint32 checkSumAdjustment; // head.CheckSumAdjustment - See http://www.microsoft.com/typography/otspec/head.htm
PRUint32 reserved[4]; // Reserved - must be 0
PRUint16 padding1; // Padding to maintain long alignment. Padding value must always be set to 0x0000.
enum {
EOT_VERSION = 0x00020001,
EOT_MAGIC_NUMBER = 0x504c,
EOT_DEFAULT_CHARSET = 0x01,
EOT_EMBED_PRINT_PREVIEW = 0x0004,
EOT_FAMILY_NAME_INDEX = 0, // order of names in variable portion of EOT header
EOT_STYLE_NAME_INDEX = 1,
EOT_VERSION_NAME_INDEX = 2,
EOT_FULL_NAME_INDEX = 3,
EOT_NUM_NAMES = 4
};
};
// EOT variable-sized header (version 0x00020001 - contains 4 name
// fields, each with the structure):
//
// // number of bytes in the name array
// PRUint16 size;
// // array of UTF-16 chars, total length = <size> bytes
// // note: english version of name record string
// PRUint8 name[size];
//
// This structure is used for the following names, each separated by two
// bytes of padding (always 0 with no padding after the rootString):
//
// familyName - based on name ID = 1
// styleName - based on name ID = 2
// versionName - based on name ID = 5
// fullName - based on name ID = 4
// rootString - used to restrict font usage to a specific domain
//
class AutoCloseFile {
public:
AutoCloseFile(PRFileDesc *aFileDesc)
: mFile(aFileDesc) { }
~AutoCloseFile() { PR_Close(mFile); }
PRFileDesc *mFile;
};
static PRFileDesc *
OpenFontFile(nsIFile *aFontData)
{
// open up the font file
nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(aFontData);
if (!localFile)
return nsnull;
PRFileDesc *fd;
nsresult rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
if (NS_FAILED(rv) || !fd)
return nsnull;
return fd;
}
static PRBool
IsValidVersion(PRUint32 version)
{
// normally 0x00010000, CFF-style OT fonts == 'OTTO' and Apple TT fonts = 'true'
return version == 0x10000 || version == 'OTTO' || version == 'true';
}
// copy and swap UTF-16 values, assume no surrogate pairs, can be in place
static void
CopySwapUTF16(PRUint16 *aInBuf, PRUint16 *aOutBuf, PRUint32 aLen)
{
PRUint16 *end = aInBuf + aLen;
while (aInBuf < end) {
PRUint16 value = *aInBuf;
*aOutBuf = (value >> 8) | (value & 0xff) << 8;
aOutBuf++;
aInBuf++;
}
}
// name table stores set of name record structures, followed by
// large block containing all the strings. name record offset and length
// indicates the offset and length within that block.
// http://www.microsoft.com/typography/otspec/name.htm
struct NameRecordData {
PRUint32 offset;
PRUint32 length;
};
#if DEBUG
static void DumpEOTHeader(PRUint8 *aHeader, PRUint32 aHeaderLen)
{
PRUint32 offset = 0;
PRUint8 *ch = aHeader;
printf("\n\nlen == %d\n\n", aHeaderLen);
while (offset < aHeaderLen) {
printf("%7.7x ", offset);
int i;
for (i = 0; i < 16; i++) {
printf("%2.2x ", *ch++);
}
printf("\n");
offset += 16;
}
}
#endif
nsresult
gfxFontUtils::MakeEOTHeader(nsIFile *aFontData, nsTArray<PRUint8> *aHeader,
PRBool *aIsCFF)
{
PRInt32 bytesRead;
// assume TrueType
*aIsCFF = PR_FALSE;
NS_ASSERTION(aHeader, "null header");
NS_ASSERTION(aHeader->Length() == 0, "non-empty header passed in");
NS_ASSERTION(aIsCFF, "null boolean ptr");
if (!aHeader->AppendElements(sizeof(EOTFixedHeader)))
return NS_ERROR_OUT_OF_MEMORY;
EOTFixedHeader *eotHeader = reinterpret_cast<EOTFixedHeader*> (aHeader->Elements());
memset(eotHeader, 0, sizeof(EOTFixedHeader));
// open the font file
PRFileDesc *fd = OpenFontFile(aFontData);
if (!fd)
return NS_ERROR_FAILURE;
AutoCloseFile autoCloseFile(fd);
PRFileInfo64 fileInfo;
if (PR_GetOpenFileInfo64(fd, &fileInfo) != PR_SUCCESS
|| fileInfo.size > PRInt64(0xFFFFFFFF))
return NS_ERROR_FAILURE;
PRUint32 fontDataSize = PRUint32(fileInfo.size);
// set up header fields
eotHeader->fontDataSize = fontDataSize;
eotHeader->version = EOTFixedHeader::EOT_VERSION;
eotHeader->flags = 0; // don't specify any special processing
eotHeader->charset = EOTFixedHeader::EOT_DEFAULT_CHARSET;
eotHeader->fsType = EOTFixedHeader::EOT_EMBED_PRINT_PREVIEW;
eotHeader->magicNumber = EOTFixedHeader::EOT_MAGIC_NUMBER;
// read in the sfnt header
SFNTHeader sfntHeader;
bytesRead = PR_Read(fd, &sfntHeader, sizeof(SFNTHeader));
if (bytesRead != sizeof(SFNTHeader) || !IsValidVersion(sfntHeader.sfntVersion))
return NS_ERROR_FAILURE;
// iterate through the table headers to find the head, name and OS/2 tables
PRBool foundHead = PR_FALSE, foundOS2 = PR_FALSE, foundName = PR_FALSE, foundGlyphs = PR_FALSE;
PRUint32 headOffset, headLen, nameOffset, nameLen, os2Offset, os2Len;
PRUint32 i, numTables;
numTables = sfntHeader.numTables;
for (i = 0; i < numTables; i++) {
TableDirEntry dirEntry;
bytesRead = PR_Read(fd, &dirEntry, sizeof(TableDirEntry));
if (bytesRead != sizeof(TableDirEntry))
return NS_ERROR_FAILURE;
switch (dirEntry.tag) {
case 'head':
foundHead = PR_TRUE;
headOffset = dirEntry.offset;
headLen = dirEntry.length;
if (headLen < sizeof(HeadTable))
return NS_ERROR_FAILURE;
break;
case 'name':
foundName = PR_TRUE;
nameOffset = dirEntry.offset;
nameLen = dirEntry.length;
break;
case 'OS/2':
foundOS2 = PR_TRUE;
os2Offset = dirEntry.offset;
os2Len = dirEntry.length;
break;
case 'glyf': // TrueType-style quadratic glyph table
foundGlyphs = PR_TRUE;
break;
case 'CFF ': // PS-style cubic glyph table
foundGlyphs = PR_TRUE;
*aIsCFF = PR_TRUE;
break;
default:
break;
}
if (foundHead && foundName && foundOS2 && foundGlyphs)
break;
}
// require these three tables on Windows
if (!foundHead || !foundName || !foundOS2)
return NS_ERROR_FAILURE;
// read in the data from those tables
PROffset64 offset;
// -- head table data
HeadTable headData;
offset = PR_Seek64(fd, PROffset64(headOffset), PR_SEEK_SET);
if (offset == -1)
return NS_ERROR_FAILURE;
bytesRead = PR_Read(fd, &headData, sizeof(HeadTable));
if (bytesRead != sizeof(HeadTable) || headData.magicNumber != HeadTable::HEAD_MAGIC_NUMBER)
return NS_ERROR_FAILURE;
eotHeader->checkSumAdjustment = headData.checkSumAdjustment;
// -- name table data
// -- first, read name table header
NameHeader nameHeader;
offset = PR_Seek64(fd, PROffset64(nameOffset), PR_SEEK_SET);
if (offset == -1)
return NS_ERROR_FAILURE;
bytesRead = PR_Read(fd, &nameHeader, sizeof(NameHeader));
if (bytesRead != sizeof(NameHeader))
return NS_ERROR_FAILURE;
// -- seek point is now at the start of name records
// -- iterate through name records, look for specific name ids with
// matching platform/encoding/etc. and store offset/lengths
NameRecordData names[EOTFixedHeader::EOT_NUM_NAMES] = {0};
PRUint32 nameCount = nameHeader.count;
for (i = 0; i < nameCount; i++) {
NameRecord nameRecord;
bytesRead = PR_Read(fd, &nameRecord, sizeof(NameRecord));
if (bytesRead != sizeof(NameRecord))
return NS_ERROR_FAILURE;
// looking for Microsoft English US name strings, skip others
if (PRUint32(nameRecord.platformID) != NameRecord::PLATFORM_ID_MICROSOFT ||
PRUint32(nameRecord.encodingID) != NameRecord::ENCODING_ID_MICROSOFT_UNICODEBMP ||
PRUint32(nameRecord.languageID) != NameRecord::LANG_ID_MICROSOFT_EN_US)
continue;
switch ((PRUint32)nameRecord.nameID) {
case NameRecord::NAME_ID_FAMILY:
names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].offset = nameRecord.offset;
names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].length = nameRecord.length;
break;
case NameRecord::NAME_ID_STYLE:
names[EOTFixedHeader::EOT_STYLE_NAME_INDEX].offset = nameRecord.offset;
names[EOTFixedHeader::EOT_STYLE_NAME_INDEX].length = nameRecord.length;
break;
case NameRecord::NAME_ID_FULL:
names[EOTFixedHeader::EOT_FULL_NAME_INDEX].offset = nameRecord.offset;
names[EOTFixedHeader::EOT_FULL_NAME_INDEX].length = nameRecord.length;
break;
case NameRecord::NAME_ID_VERSION:
names[EOTFixedHeader::EOT_VERSION_NAME_INDEX].offset = nameRecord.offset;
names[EOTFixedHeader::EOT_VERSION_NAME_INDEX].length = nameRecord.length;
break;
default:
break;
}
if (names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].length &&
names[EOTFixedHeader::EOT_STYLE_NAME_INDEX].length &&
names[EOTFixedHeader::EOT_FULL_NAME_INDEX].length &&
names[EOTFixedHeader::EOT_VERSION_NAME_INDEX].length)
break;
}
if (!(names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].length &&
names[EOTFixedHeader::EOT_STYLE_NAME_INDEX].length &&
names[EOTFixedHeader::EOT_FULL_NAME_INDEX].length &&
names[EOTFixedHeader::EOT_VERSION_NAME_INDEX].length))
{
return NS_ERROR_FAILURE;
}
// -- expand buffer if needed to include variable-length portion
PRUint32 eotVariableLength = 0;
eotVariableLength = (names[EOTFixedHeader::EOT_FAMILY_NAME_INDEX].length & (~1)) +
(names[EOTFixedHeader::EOT_STYLE_NAME_INDEX].length & (~1)) +
(names[EOTFixedHeader::EOT_FULL_NAME_INDEX].length & (~1)) +
(names[EOTFixedHeader::EOT_VERSION_NAME_INDEX].length & (~1)) +
EOTFixedHeader::EOT_NUM_NAMES * (2 /* size */
+ 2 /* padding */) +
2 /* null root string size */;
if (!aHeader->AppendElements(eotVariableLength))
return NS_ERROR_OUT_OF_MEMORY;
// append the string data to the end of the EOT header
PRUint8 *eotEnd = aHeader->Elements() + sizeof(EOTFixedHeader);
PROffset64 strOffset;
PRUint32 strLen;
for (i = 0; i < EOTFixedHeader::EOT_NUM_NAMES; i++) {
PRUint32 namelen = names[i].length;
PRUint32 nameoff = names[i].offset; // offset from base of string storage
strOffset = nameOffset + PRUint32(nameHeader.stringOffset) + nameoff;
offset = PR_Seek64(fd, strOffset, PR_SEEK_SET);
if (offset == -1)
return NS_ERROR_FAILURE;
// output 2-byte str size
strLen = namelen & (~1); // UTF-16 string len must be even
*((PRUint16*) eotEnd) = PRUint16(strLen);
eotEnd += 2;
// read in actual string and swap bytes from big-endian
// (TrueType/OpenType) to little-endian (EOT)
bytesRead = PR_Read(fd, eotEnd, strLen);
if (PRUint32(bytesRead) != strLen)
return NS_ERROR_FAILURE;
// length is number of UTF-16 chars, not bytes
CopySwapUTF16(reinterpret_cast<PRUint16*>(eotEnd),
reinterpret_cast<PRUint16*>(eotEnd),
(strLen >> 1));
eotEnd += strLen;
// add 2-byte zero padding to the end of each string
*eotEnd++ = 0;
*eotEnd++ = 0;
// Note: Microsoft's WEFT tool produces name strings which
// include an extra null at the end of each string, in addition
// to the 2-byte zero padding that separates the string fields.
// Don't think this is important to imitate...
}
// append null root string size
*eotEnd++ = 0;
*eotEnd++ = 0;
NS_ASSERTION(eotEnd == aHeader->Elements() + aHeader->Length(),
"header length calculation incorrect");
// -- OS/2 table data
OS2Table os2Data;
offset = PR_Seek64(fd, PROffset64(os2Offset), PR_SEEK_SET);
if (offset == -1)
return NS_ERROR_FAILURE;
bytesRead = PR_Read(fd, &os2Data, sizeof(OS2Table));
if (bytesRead != sizeof(OS2Table))
return NS_ERROR_FAILURE;
memcpy(eotHeader->panose, os2Data.panose, sizeof(eotHeader->panose));
eotHeader->italic = (PRUint16) os2Data.fsSelection & 0x01;
eotHeader->weight = os2Data.usWeightClass;
eotHeader->unicodeRange1 = os2Data.unicodeRange1;
eotHeader->unicodeRange2 = os2Data.unicodeRange2;
eotHeader->unicodeRange3 = os2Data.unicodeRange3;
eotHeader->unicodeRange4 = os2Data.unicodeRange4;
eotHeader->codePageRange1 = os2Data.codePageRange1;
eotHeader->codePageRange2 = os2Data.codePageRange2;
eotHeader->eotSize = aHeader->Length() + fontDataSize;
// DumpEOTHeader(aHeader->Elements(), aHeader->Length());
return NS_OK;
}
#endif

View File

@ -457,8 +457,9 @@ already_AddRefed<gfxOS2Font> gfxOS2Font::GetOrMakeFont(const nsAString& aName,
**********************************************************************/
gfxOS2FontGroup::gfxOS2FontGroup(const nsAString& aFamilies,
const gfxFontStyle* aStyle)
: gfxFontGroup(aFamilies, aStyle)
const gfxFontStyle* aStyle,
gfxUserFontSet *aUserFontSet)
: gfxFontGroup(aFamilies, aStyle, aUserFontSet)
{
#ifdef DEBUG_thebes_2
printf("gfxOS2FontGroup[%#x]::gfxOS2FontGroup(\"%s\", %#x)\n",
@ -510,7 +511,7 @@ gfxOS2FontGroup::~gfxOS2FontGroup()
gfxFontGroup *gfxOS2FontGroup::Copy(const gfxFontStyle *aStyle)
{
return new gfxOS2FontGroup(mFamilies, aStyle);
return new gfxOS2FontGroup(mFamilies, aStyle, mUserFontSet);
}
/**

View File

@ -164,9 +164,10 @@ gfxOS2Platform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFa
gfxFontGroup *
gfxOS2Platform::CreateFontGroup(const nsAString &aFamilies,
const gfxFontStyle *aStyle)
const gfxFontStyle *aStyle,
gfxUserFontSet *aUserFontSet)
{
return new gfxOS2FontGroup(aFamilies, aStyle);
return new gfxOS2FontGroup(aFamilies, aStyle, aUserFontSet);
}
already_AddRefed<gfxOS2Font>

View File

@ -784,8 +784,9 @@ FontCallback (const nsAString& fontName, const nsACString& genericName,
}
gfxPangoFontGroup::gfxPangoFontGroup (const nsAString& families,
const gfxFontStyle *aStyle)
: gfxFontGroup(families, aStyle),
const gfxFontStyle *aStyle,
gfxUserFontSet *aUserFontSet)
: gfxFontGroup(families, aStyle, aUserFontSet),
mBasePangoFont(nsnull), mAdjustedSize(0)
{
mFonts.AppendElements(1);
@ -800,7 +801,7 @@ gfxPangoFontGroup::~gfxPangoFontGroup()
gfxFontGroup *
gfxPangoFontGroup::Copy(const gfxFontStyle *aStyle)
{
return new gfxPangoFontGroup(mFamilies, aStyle);
return new gfxPangoFontGroup(mFamilies, aStyle, mUserFontSet);
}
// A string of family names suitable for fontconfig

View File

@ -56,6 +56,7 @@
#include "gfxImageSurface.h"
#include "gfxTextRunCache.h"
#include "gfxTextRunWordCache.h"
#include "gfxUserFontSet.h"
#include "nsIPref.h"
#include "nsServiceManagerUtils.h"
@ -304,6 +305,29 @@ gfxPlatform::UpdateFontList()
return NS_ERROR_NOT_IMPLEMENTED;
}
#define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
PRBool
gfxPlatform::DownloadableFontsEnabled()
{
static PRBool initialized = PR_FALSE;
static PRBool allowDownloadableFonts = PR_FALSE;
if (initialized == PR_FALSE) {
initialized = PR_TRUE;
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (prefs) {
PRBool allow;
nsresult rv = prefs->GetBoolPref(GFX_DOWNLOADABLE_FONTS_ENABLED, &allow);
if (NS_SUCCEEDED(rv))
allowDownloadableFonts = allow;
}
}
return allowDownloadableFonts;
}
static void
AppendGenericFontFromPref(nsString& aFonts, const char *aLangGroup, const char *aGenericName)
{

View File

@ -267,9 +267,10 @@ gfxPlatformGtk::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFa
gfxFontGroup *
gfxPlatformGtk::CreateFontGroup(const nsAString &aFamilies,
const gfxFontStyle *aStyle)
const gfxFontStyle *aStyle,
gfxUserFontSet *aUserFontSet)
{
return new gfxPangoFontGroup(aFamilies, aStyle);
return new gfxPangoFontGroup(aFamilies, aStyle, aUserFontSet);
}
#else

View File

@ -44,6 +44,7 @@
#include "gfxQuartzFontCache.h"
#include "gfxAtsuiFonts.h"
#include "gfxUserFontSet.h"
#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
@ -115,9 +116,36 @@ gfxPlatformMac::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFa
gfxFontGroup *
gfxPlatformMac::CreateFontGroup(const nsAString &aFamilies,
const gfxFontStyle *aStyle)
const gfxFontStyle *aStyle,
gfxUserFontSet *aUserFontSet)
{
return new gfxAtsuiFontGroup(aFamilies, aStyle);
return new gfxAtsuiFontGroup(aFamilies, aStyle, aUserFontSet);
}
gfxFontEntry*
gfxPlatformMac::LookupLocalFont(const nsAString& aFontName)
{
return gfxQuartzFontCache::SharedFontCache()->LookupLocalFont(aFontName);
}
gfxFontEntry*
gfxPlatformMac::MakePlatformFont(const gfxFontEntry *aProxyEntry, const gfxDownloadedFontData* aFontData)
{
return gfxQuartzFontCache::SharedFontCache()->MakePlatformFont(aProxyEntry, aFontData);
}
PRBool
gfxPlatformMac::IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags)
{
// reject based on format flags
if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_EOT | gfxUserFontSet::FLAG_FORMAT_SVG)) {
return PR_FALSE;
}
// reject based on filetype in URI
// otherwise, return true
return PR_TRUE;
}
nsresult

View File

@ -83,13 +83,15 @@ public:
ATSUFontID GetFontID();
nsresult ReadCMAP();
MacOSFamilyEntry* FamilyEntry() { return mFamily; }
protected:
// for use with data fonts
MacOSFontEntry(ATSUFontID aFontID, PRUint16 aWeight, PRUint16 aStretch, PRUint32 aItalicStyle, gfxUserFontData *aUserFontData);
PRUint32 mTraits;
MacOSFamilyEntry *mFamily;
PRPackedBool mATSUIDInitialized;
ATSUFontID mATSUFontID;
PRPackedBool mATSUIDInitialized;
};
// helper class for adding other family names back into font cache
@ -103,9 +105,8 @@ public:
friend class gfxQuartzFontCache;
// name is canonical font family name returned from NSFontManager
MacOSFamilyEntry(nsString &aName) :
gfxFontFamily(aName), mOtherFamilyNamesInitialized(PR_FALSE), mHasOtherFamilyNames(PR_FALSE),
mIsBadUnderlineFontFamily(PR_FALSE)
MacOSFamilyEntry(nsAString &aName) :
gfxFontFamily(aName), mOtherFamilyNamesInitialized(PR_FALSE), mHasOtherFamilyNames(PR_FALSE)
{}
virtual ~MacOSFamilyEntry() {}
@ -132,7 +133,7 @@ public:
virtual void ReadOtherFamilyNames(AddOtherFamilyNameFunctor& aOtherFamilyFunctor);
// search for a specific face using the Postscript name
MacOSFontEntry* FindFont(const nsString& aPostscriptName);
MacOSFontEntry* FindFont(const nsAString& aPostscriptName);
// read in cmaps for all the faces
void ReadCMAP() {
@ -141,9 +142,12 @@ public:
mAvailableFonts[i]->ReadCMAP();
}
// whether this font family is in "bad" underline offset blacklist.
PRBool IsBadUnderlineFontFamily() { return mIsBadUnderlineFontFamily != 0; }
// set whether this font family is in "bad" underline offset blacklist.
void SetBadUnderlineFont(PRBool aIsBadUnderlineFont) {
PRUint32 i, numFonts = mAvailableFonts.Length();
for (i = 0; i < numFonts; i++)
mAvailableFonts[i]->mIsBadUnderlineFont = aIsBadUnderlineFont;
}
protected:
@ -158,14 +162,13 @@ protected:
nsTArray<nsRefPtr<MacOSFontEntry> > mAvailableFonts;
PRPackedBool mOtherFamilyNamesInitialized;
PRPackedBool mHasOtherFamilyNames;
PRPackedBool mIsBadUnderlineFontFamily;
};
// special-case situation where specific faces need to be treated as separate font family
class SingleFaceFamily : public MacOSFamilyEntry
{
public:
SingleFaceFamily(nsString &aName) :
SingleFaceFamily(nsAString &aName) :
MacOSFamilyEntry(aName)
{}
@ -222,6 +225,10 @@ public:
void AddOtherFamilyName(MacOSFamilyEntry *aFamilyEntry, nsAString& aOtherFamilyName);
gfxFontEntry* LookupLocalFont(const nsAString& aFontName);
gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry, const gfxDownloadedFontData* aFontData);
private:
static PLDHashOperator PR_CALLBACK FindFontForCharProc(nsStringHashKey::KeyType aKey,
nsRefPtr<MacOSFamilyEntry>& aFamilyEntry,
@ -244,7 +251,7 @@ private:
// commonly used fonts for which the name table should be loaded at startup
void PreloadNamesList();
// initialize the MacOSFamilyEntry::mIsBadUnderlineFontFamily from pref.
// initialize the bad underline blacklist from pref.
void InitBadUnderlineList();
// eliminate faces which have the same ATSUI id
@ -293,6 +300,13 @@ private:
PRUint32 mStartIndex;
PRUint32 mIncrement;
PRUint32 mNumFamilies;
// keep track of ATS generation to prevent unneeded updates when loading downloaded fonts
PRUint32 mATSGeneration;
enum {
kATSGenerationInitial = -1
};
};
#endif /* GFXQUARTZFONTCACHE_H_ */

View File

@ -44,10 +44,18 @@
#include "gfxPlatformMac.h"
#include "gfxQuartzFontCache.h"
#include "gfxAtsuiFonts.h"
#include "gfxUserFontSet.h"
#include "nsIPref.h" // for pref changes callback notification
#include "nsServiceManagerUtils.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsISimpleEnumerator.h"
#include <unistd.h>
#include <time.h>
// _atsFontID is private; add it in our new category to NSFont
@interface NSFont (MozillaCategory)
- (ATSUFontID)_atsFontID;
@ -113,12 +121,47 @@ MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
: gfxFontEntry(aPostscriptName), mTraits(aTraits), mFamily(aFamily), mATSUFontID(0),
mATSUIDInitialized(0)
{
mWeight = gfxQuartzFontCache::AppleWeightToCSSWeight(aAppleWeight);
mWeight = gfxQuartzFontCache::AppleWeightToCSSWeight(aAppleWeight) * 100;
mItalic = (mTraits & NSItalicFontMask ? 1 : 0);
mFixedPitch = (mTraits & NSFixedPitchFontMask ? 1 : 0);
}
MacOSFontEntry::MacOSFontEntry(ATSUFontID aFontID, PRUint16 aWeight, PRUint16 aStretch, PRUint32 aItalicStyle, gfxUserFontData *aUserFontData)
{
// xxx - stretch is basically ignored for now
mATSUIDInitialized = PR_TRUE;
mATSUFontID = aFontID;
mUserFontData = aUserFontData;
mWeight = aWeight;
mStretch = aStretch;
mFixedPitch = PR_FALSE; // xxx - do we need this for downloaded fonts?
mItalic = (aItalicStyle & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
mTraits = (mItalic ? NSItalicFontMask : NSUnitalicFontMask) |
(mFixedPitch ? NSFixedPitchFontMask : 0) |
(mWeight >= 600 ? NSBoldFontMask : NSUnboldFontMask);
// get the postscript name
OSStatus err;
NSString *psname = NULL;
// now lookup the Postscript name
err = ATSFontGetPostScriptName((ATSFontRef) aFontID, kATSOptionFlagsDefault, (CFStringRef*) (&psname));
if (err == noErr) {
GetStringForNSString(psname, mName);
[psname release];
} else {
mIsValid = PR_FALSE;
#if DEBUG
char warnBuf[1024];
sprintf(warnBuf, "ATSFontGetPostScriptName err = %d", (PRInt32)err);
NS_WARNING(warnBuf);
#endif
}
}
const nsString&
MacOSFontEntry::FamilyName()
{
@ -174,7 +217,14 @@ MacOSFontEntry::ReadCMAP()
status = ATSFontGetTable(fontID, 'cmap', 0, 0, 0, &size);
cmapSize = size;
//printf( "cmap size: %s %d\n", NS_ConvertUTF16toUTF8(mName).get(), size );
//printf( "cmap size: %s %d", NS_ConvertUTF16toUTF8(mName).get(), size );
#if DEBUG
if (status != noErr) {
char warnBuf[1024];
sprintf(warnBuf, "ATSFontGetTable returned %d for (%s)", (PRInt32)status, NS_ConvertUTF16toUTF8(mName).get());
NS_WARNING(warnBuf);
}
#endif
NS_ENSURE_TRUE(status == noErr, NS_ERROR_FAILURE);
nsAutoTArray<PRUint8,16384> buffer;
@ -298,7 +348,7 @@ MacOSFamilyEntry::FindFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold)
}
MacOSFontEntry*
MacOSFamilyEntry::FindFont(const nsString& aPostscriptName)
MacOSFamilyEntry::FindFont(const nsAString& aPostscriptName)
{
// find the font using a simple linear search
PRUint32 numFonts = mAvailableFonts.Length();
@ -339,7 +389,7 @@ MacOSFamilyEntry::FindFontForChar(FontSearch *aMatchData)
// italics
if (fe->IsItalic() &&
(style->style == FONT_STYLE_ITALIC || style->style == FONT_STYLE_ITALIC)) {
(style->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0) {
rank += 5;
}
@ -351,7 +401,7 @@ MacOSFamilyEntry::FindFontForChar(FontSearch *aMatchData)
// the "next bolder/lighter face"
PRUint32 targetWeight = (baseWeight * 100) + (weightDistance * 100);
PRUint32 entryWeight = fe->Weight() * 100;
PRUint32 entryWeight = fe->Weight();
if (entryWeight == targetWeight) {
rank += 5;
} else {
@ -393,7 +443,8 @@ MacOSFamilyEntry::FindFontsWithTraits(gfxFontEntry* aFontsForWeights[], PRUint32
// aPosTraitsMask == 0 ==> match all
if ((!aPosTraitsMask || (traits & aPosTraitsMask)) && !(traits & aNegTraitsMask)) {
PRInt32 weight = fe->Weight();
PRInt32 weight = fe->Weight() / 100;
NS_ASSERTION(weight >= 1 && weight <= 9, "bogus font weight value!");
// always prefer the first font for a given weight, helps deal a bit with
// families with lots of faces (e.g. Minion Pro)
@ -412,13 +463,14 @@ MacOSFamilyEntry::FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], const gf
// short-circuit the single face per family case
if (mAvailableFonts.Length() == 1) {
MacOSFontEntry *fe = mAvailableFonts[0];
PRUint32 weight = fe->Weight();
PRUint32 weight = fe->Weight() / 100;
NS_ASSERTION(weight >= 1 && weight <= 9, "bogus font weight value!");
aFontsForWeights[weight] = fe;
return PR_TRUE;
}
PRBool found = PR_FALSE;
PRBool isItalic = (aFontStyle.style == FONT_STYLE_ITALIC || aFontStyle.style == FONT_STYLE_OBLIQUE);
PRBool isItalic = (aFontStyle.style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0;
// match italic faces
if (isItalic) {
@ -629,6 +681,8 @@ gfxQuartzFontCache *gfxQuartzFontCache::sSharedFontCache = nsnull;
gfxQuartzFontCache::gfxQuartzFontCache()
: mStartIndex(0), mIncrement(kNumFontsPerSlice), mNumFamilies(0)
{
mATSGeneration = PRUint32(kATSGenerationInitial);
mFontFamilies.Init(100);
mOtherFamilyNames.Init(30);
mOtherFamilyNamesInitialized = PR_FALSE;
@ -652,6 +706,15 @@ const PRUint32 kNonNormalTraits = NSItalicFontMask | NSBoldFontMask | NSNarrowFo
void
gfxQuartzFontCache::InitFontList()
{
ATSGeneration currentGeneration = ATSGeneration();
// need to ignore notifications after adding each font
if (mATSGeneration == currentGeneration)
return;
mATSGeneration = currentGeneration;
PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit) updating to generation: %d", mATSGeneration));
mFontFamilies.Clear();
mOtherFamilyNames.Clear();
mOtherFamilyNamesInitialized = PR_FALSE;
@ -918,7 +981,7 @@ gfxQuartzFontCache::InitBadUnderlineList()
MacOSFamilyEntry *familyEntry = mFontFamilies.GetWeak(key, &found);
if (familyEntry)
familyEntry->mIsBadUnderlineFontFamily = 1;
familyEntry->SetBadUnderlineFont(PR_TRUE);
}
}
@ -1205,6 +1268,158 @@ gfxQuartzFontCache::AddOtherFamilyName(MacOSFamilyEntry *aFamilyEntry, nsAString
}
}
gfxFontEntry*
gfxQuartzFontCache::LookupLocalFont(const nsAString& aFontName)
{
NSString *faceName = GetNSStringForString(aFontName);
NSFont *font = [NSFont fontWithName:faceName size:0.0];
if (font) {
nsAutoString availableFamilyName;
NSString *availableFamily = [font familyName];
GetStringForNSString(availableFamily, availableFamilyName);
MacOSFamilyEntry *familyEntry = FindFamily(availableFamilyName);
if (familyEntry) {
MacOSFontEntry *fontEntry = familyEntry->FindFont(aFontName);
return fontEntry;
}
}
// didn't find the font
return nsnull;
}
// grumble, another non-publised Apple API dependency (found in Webkit code)
// activated with this value, font will not be found via system lookup routines
// it can only be used via the created ATSUFontID
// needed to prevent one doc from finding a font used in a separate doc
enum {
kPrivateATSFontContextPrivate = 3
};
class MacOSUserFontData : public gfxUserFontData {
public:
MacOSUserFontData(ATSFontContainerRef aContainerRef, nsIFile *aFontFile,
nsISupports *aDownloader)
: mContainerRef(aContainerRef), mFontFile(aFontFile),
mDownloader(aDownloader)
{ }
virtual ~MacOSUserFontData()
{
// deactivate font
if (mContainerRef)
ATSFontDeactivate(mContainerRef, NULL, kATSOptionFlagsDefault);
if (mFontFile) {
mFontFile->Remove(PR_FALSE); // ignore errors
}
}
ATSFontContainerRef mContainerRef;
nsCOMPtr<nsIFile> mFontFile;
// maintaining a ref to this keeps temp file around or cache file pinned
nsCOMPtr<nsISupports> mDownloader;
};
static OSStatus
MakeFSSpec(FSSpec *aFSSpec, NSString *path)
{
FSRef fsref;
OSStatus err = FSPathMakeRef((UInt8*)([path fileSystemRepresentation]), &fsref, NULL);
if (err == noErr)
err = FSGetCatalogInfo(&fsref, kFSCatInfoNone, NULL, NULL, aFSSpec, NULL);
return err;
}
gfxFontEntry*
gfxQuartzFontCache::MakePlatformFont(const gfxFontEntry *aProxyEntry,
const gfxDownloadedFontData* aFontData)
{
OSStatus err;
FSSpec spec;
nsAutoString filePath;
NS_ASSERTION(aFontData && aFontData->mFontFile,
"MakePlatformFont called with null file ptr");
if (!aFontData->mFontFile)
return nsnull;
aFontData->mFontFile->GetPath(filePath);
NSString *path = GetNSStringForString(filePath);
if (!path)
return nsnull;
// assumption: filename is already in the form xxx.ttf, otherwise
// ATS will reject
err = MakeFSSpec(&spec, path);
if (err != noErr)
return nsnull;
ATSUFontID fontID;
ATSFontContainerRef containerRef;
err = ATSFontActivateFromFileSpecification(&spec,
kPrivateATSFontContextPrivate,
kATSFontFormatUnspecified,
NULL,
kATSOptionFlagsDoNotNotify,
&containerRef);
if (err != noErr)
return nsnull;
mATSGeneration = ATSGeneration();
// ignoring containers with multiple fonts, use the first face only for now
err = ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1,
(ATSFontRef*)&fontID, NULL);
if (err != noErr)
return nsnull;
// font entry will own this
MacOSUserFontData *userFontData = new MacOSUserFontData(containerRef,
aFontData->mFontFile,
aFontData->mDownloader);
if (!userFontData)
return nsnull;
PRUint16 w = aProxyEntry->mWeight;
NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!");
MacOSFontEntry *newFontEntry =
new MacOSFontEntry(fontID, w, aProxyEntry->mStretch,
(PRUint32(aProxyEntry->mItalic) ?
FONT_STYLE_ITALIC :
FONT_STYLE_NORMAL),
userFontData);
// if something is funky about this font, delete immediately
if (newFontEntry && !newFontEntry->mIsValid) {
#if DEBUG
char warnBuf[1024];
const gfxProxyFontEntry *proxyEntry =
static_cast<const gfxProxyFontEntry*> (aProxyEntry);
sprintf(warnBuf, "downloaded font not loaded properly, removed (%s) for (%s)",
[path UTF8String],
NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
NS_WARNING(warnBuf);
#endif
delete newFontEntry;
return nsnull;
}
return newFontEntry;
}
void
gfxQuartzFontCache::InitLoader()
{

View File

@ -113,6 +113,7 @@ protected:
PRUint32 mLength;
PRUint32 mAppUnitsPerDevUnit;
PRUint32 mStringHash;
PRUint64 mUserFontSetGeneration;
PRPackedBool mIsDoubleByteText;
PRPackedBool mIsRTL;
PRPackedBool mEnabledOptionalLigatures;
@ -124,6 +125,7 @@ protected:
mLength(aLength),
mAppUnitsPerDevUnit(aBaseTextRun->GetAppUnitsPerDevUnit()),
mStringHash(aHash),
mUserFontSetGeneration(aBaseTextRun->GetUserFontSetGeneration()),
mIsDoubleByteText((aBaseTextRun->GetFlags() & gfxTextRunFactory::TEXT_IS_8BIT) == 0),
mIsRTL(aBaseTextRun->IsRightToLeft()),
mEnabledOptionalLigatures((aBaseTextRun->GetFlags() & gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES) == 0),
@ -197,14 +199,17 @@ HashMix(PRUint32 aHash, PRUnichar aCh)
// If the substring of the textrun is rendered entirely in the first font
// of the textrun's fontgroup, then return that font. Otherwise return the
// fontgroup.
// fontgroup. When a user font set is in use, always return the font group.
static void *GetWordFontOrGroup(gfxTextRun *aTextRun, PRUint32 aOffset,
PRUint32 aLength)
{
gfxFontGroup *fontGroup = aTextRun->GetFontGroup();
if (fontGroup->GetUserFontSet() != nsnull)
return fontGroup;
PRUint32 glyphRunCount;
const gfxTextRun::GlyphRun *glyphRuns = aTextRun->GetGlyphRuns(&glyphRunCount);
PRUint32 glyphRunIndex = aTextRun->FindFirstGlyphRunContaining(aOffset);
gfxFontGroup *fontGroup = aTextRun->GetFontGroup();
gfxFont *firstFont = fontGroup->GetFontAt(0);
if (glyphRuns[glyphRunIndex].mFont != firstFont)
return fontGroup;
@ -260,8 +265,11 @@ TextRunWordCache::LookupWord(gfxTextRun *aTextRun, gfxFont *aFirstFont,
{
if (aEnd <= aStart)
return PR_TRUE;
gfxFontGroup *fontGroup = aTextRun->GetFontGroup();
CacheHashKey key(aTextRun, aFirstFont, aStart, aEnd - aStart, aHash);
PRBool useFontGroup = (fontGroup->GetUserFontSet() != nsnull);
CacheHashKey key(aTextRun, (useFontGroup ? (void*)fontGroup : (void*)aFirstFont), aStart, aEnd - aStart, aHash);
CacheHashEntry *fontEntry = mCache.PutEntry(key);
if (!fontEntry)
return PR_FALSE;
@ -269,7 +277,10 @@ TextRunWordCache::LookupWord(gfxTextRun *aTextRun, gfxFont *aFirstFont,
if (fontEntry->mTextRun) {
existingEntry = fontEntry;
} else if (useFontGroup) {
PR_LOG(gWordCacheLog, PR_LOG_DEBUG, ("%p(%d-%d,%d): added using font group", aTextRun, aStart, aEnd - aStart, aHash));
} else {
// test to see if this can be found using the font group instead
PR_LOG(gWordCacheLog, PR_LOG_DEBUG, ("%p(%d-%d,%d): added using font", aTextRun, aStart, aEnd - aStart, aHash));
key.mFontOrGroup = aTextRun->GetFontGroup();
CacheHashEntry *groupEntry = mCache.GetEntry(key);
@ -304,7 +315,8 @@ TextRunWordCache::LookupWord(gfxTextRun *aTextRun, gfxFont *aFirstFont,
// entry, we'll copy within our own textrun
fontEntry->mTextRun = aTextRun;
fontEntry->mWordOffset = aStart;
fontEntry->mHashedByFont = PR_TRUE;
if (!useFontGroup)
fontEntry->mHashedByFont = PR_TRUE;
return PR_FALSE;
}
@ -331,6 +343,11 @@ TextRunWordCache::FinishTextRun(gfxTextRun *aTextRun, gfxTextRun *aNewRun,
PRUint32 i;
gfxFontGroup *fontGroup = aTextRun->GetFontGroup();
gfxFont *font = fontGroup->GetFontAt(0);
// need to use the font group when user font set is around, since
// the first font may change as the result of a font download
PRBool useFontGroup = (fontGroup->GetUserFontSet() != nsnull);
// copy deferred words from various sources into destination textrun
for (i = 0; i < aDeferredWords.Length(); ++i) {
const DeferredWord *word = &aDeferredWords[i];
@ -350,11 +367,11 @@ TextRunWordCache::FinishTextRun(gfxTextRun *aTextRun, gfxTextRun *aNewRun,
// we need to remove that cache entry and replace it with an entry
// keyed off the fontgroup.
PRBool rekeyWithFontGroup =
GetWordFontOrGroup(aNewRun, word->mSourceOffset, word->mLength) != font;
GetWordFontOrGroup(aNewRun, word->mSourceOffset, word->mLength) != font && !useFontGroup;
if (!aSuccessful || rekeyWithFontGroup ||
wordStartsInsideCluster || wordStartsInsideLigature) {
// We need to remove the current placeholder cache entry
CacheHashKey key(aTextRun, font, word->mDestOffset, word->mLength,
CacheHashKey key(aTextRun, (useFontGroup ? (void*)fontGroup : (void*)font), word->mDestOffset, word->mLength,
word->mHash);
NS_ASSERTION(mCache.GetEntry(key),
"This entry should have been added previously!");
@ -459,6 +476,9 @@ TextRunWordCache::MakeTextRun(const PRUnichar *aText, PRUint32 aLength,
const gfxFontGroup::Parameters *aParams,
PRUint32 aFlags)
{
// update font list when using user fonts (assures generation is current)
aFontGroup->UpdateFontList();
if (aFontGroup->GetStyle()->size == 0) {
// Short-circuit for size-0 fonts, as Windows and ATSUI can't handle
// them, and always create at least size 1 fonts, i.e. they still
@ -530,7 +550,7 @@ TextRunWordCache::MakeTextRun(const PRUnichar *aText, PRUint32 aLength,
nsAutoPtr<gfxTextRun> newRun;
newRun = aFontGroup->MakeTextRun(tempString.Elements(), tempString.Length(),
&params, aFlags | gfxTextRunFactory::TEXT_IS_PERSISTENT);
FinishTextRun(textRun, newRun, aParams, deferredWords, newRun != nsnull);
return textRun.forget();
}
@ -541,6 +561,9 @@ TextRunWordCache::MakeTextRun(const PRUint8 *aText, PRUint32 aLength,
const gfxFontGroup::Parameters *aParams,
PRUint32 aFlags)
{
// update font list when using user fonts (assures generation is current)
aFontGroup->UpdateFontList();
if (aFontGroup->GetStyle()->size == 0) {
// Short-circuit for size-0 fonts, as Windows and ATSUI can't handle
// them, and always create at least size 1 fonts, i.e. they still
@ -628,6 +651,7 @@ TextRunWordCache::RemoveWord(gfxTextRun *aTextRun, PRUint32 aStart,
PRUint32 length = aEnd - aStart;
CacheHashKey key(aTextRun, GetWordFontOrGroup(aTextRun, aStart, length),
aStart, length, aHash);
CacheHashEntry *entry = mCache.GetEntry(key);
if (entry && entry->mTextRun == aTextRun) {
// XXX would like to use RawRemoveEntry here plus some extra method
@ -710,7 +734,8 @@ TextRunWordCache::CacheHashEntry::KeyEquals(const KeyTypePointer aKey) const
aKey->mAppUnitsPerDevUnit != mTextRun->GetAppUnitsPerDevUnit() ||
aKey->mIsRTL != mTextRun->IsRightToLeft() ||
aKey->mEnabledOptionalLigatures != ((mTextRun->GetFlags() & gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES) == 0) ||
aKey->mOptimizeSpeed != ((mTextRun->GetFlags() & gfxTextRunFactory::TEXT_OPTIMIZE_SPEED) != 0))
aKey->mOptimizeSpeed != ((mTextRun->GetFlags() & gfxTextRunFactory::TEXT_OPTIMIZE_SPEED) != 0) ||
aKey->mUserFontSetGeneration != (mTextRun->GetUserFontSetGeneration()))
return PR_FALSE;
if (mTextRun->GetFlags() & gfxFontGroup::TEXT_IS_8BIT) {
@ -731,7 +756,12 @@ TextRunWordCache::CacheHashEntry::KeyEquals(const KeyTypePointer aKey) const
PLDHashNumber
TextRunWordCache::CacheHashEntry::HashKey(const KeyTypePointer aKey)
{
return aKey->mStringHash + (long)aKey->mFontOrGroup + aKey->mAppUnitsPerDevUnit +
// only use lower 32 bits of generation counter in hash key,
// since these vary the most
PRUint32 fontSetGen;
LL_L2UI(fontSetGen, aKey->mUserFontSetGeneration);
return aKey->mStringHash + fontSetGen + (long)aKey->mFontOrGroup + aKey->mAppUnitsPerDevUnit +
aKey->mIsDoubleByteText + aKey->mIsRTL*2 + aKey->mEnabledOptionalLigatures*4 +
aKey->mOptimizeSpeed*8;
}

View File

@ -192,21 +192,8 @@ FontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
// Some fonts claim to support things > 900, but we don't so clamp the sizes
logFont.lfWeight = PR_MAX(PR_MIN(logFont.lfWeight, 900), 100);
gfxWindowsFontType feType;
if (metrics.ntmFlags & NTM_TYPE1)
feType = GFX_FONT_TYPE_TYPE1;
else if (metrics.ntmFlags & (NTM_PS_OPENTYPE))
feType = GFX_FONT_TYPE_PS_OPENTYPE;
else if (metrics.ntmFlags & (NTM_TT_OPENTYPE))
feType = GFX_FONT_TYPE_TT_OPENTYPE;
else if (fontType == TRUETYPE_FONTTYPE)
feType = GFX_FONT_TYPE_TRUETYPE;
else if (fontType == RASTER_FONTTYPE)
feType = GFX_FONT_TYPE_RASTER;
else if (fontType == DEVICE_FONTTYPE)
feType = GFX_FONT_TYPE_DEVICE;
else
feType = GFX_FONT_TYPE_UNKNOWN;
gfxWindowsFontType feType = FontEntry::DetermineFontType(metrics, fontType);
FontEntry *fe = nsnull;
for (PRUint32 i = 0; i < ff->mVariations.Length(); ++i) {
@ -232,15 +219,14 @@ FontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
}
}
fe = new FontEntry(ff->mName);
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfOutPrecision = FontTypeToOutPrecision(feType);
fe = FontEntry::CreateFontEntry(ff->mName, feType, (logFont.lfItalic == 0xFF), (PRUint16) (logFont.lfWeight), nsnull, hdc, &logFont);
if (!fe)
return 1;
ff->mVariations.AppendElement(fe);
fe->mFontType = feType;
fe->mItalic = (logFont.lfItalic == 0xFF);
fe->mWeight = logFont.lfWeight;
if (fe->IsType1())
fe->mForceGDI = PR_TRUE;
// mark the charset bit
fe->mCharset[metrics.tmCharSet] = 1;
@ -263,39 +249,7 @@ FontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
}
}
fe->mIsBadUnderlineFont = ff->mIsBadUnderlineFont;
// read in the character map
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfOutPrecision = FontTypeToOutPrecision(fe->mFontType);
HFONT font = CreateFontIndirectW(&logFont);
NS_ASSERTION(font, "This font creation should never ever ever fail");
if (font) {
HFONT oldFont = (HFONT)SelectObject(hdc, font);
// ReadCMAP may change the values of mUnicodeFont and mSymbolFont
if (NS_FAILED(ReadCMAP(hdc, fe))) {
// Type1 fonts aren't necessarily Unicode but
// this is the best guess we can make here
if (fe->IsType1())
fe->mUnicodeFont = PR_TRUE;
else
fe->mUnicodeFont = PR_FALSE;
// For fonts where we failed to read the character map,
// we can take a slow path to look up glyphs character by character
fe->mUnknownCMAP = PR_TRUE;
//printf("(fontinit-cmap) %s failed to get cmap, type1:%d \n", NS_ConvertUTF16toUTF8(fe->mFaceName).get(), (PRUint32)(fe->mIsType1));
} else {
//printf("(fontinit-cmap) %s cmap loaded, italic:%d, weight:%d\n", NS_ConvertUTF16toUTF8(fe->mFaceName).get(), (PRUint32)(fe->mItalic), (PRUint32)(fe->mWeight));
}
SelectObject(hdc, oldFont);
DeleteObject(font);
}
fe->mIsBadUnderlineFont = ff->mIsBadUnderlineFontFamily;
return 1;
}
@ -393,6 +347,102 @@ FontFamily::FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], const gfxFontS
return matchesSomething;
}
FontEntry*
FontEntry::CreateFontEntry(const nsAString& aName, gfxWindowsFontType aFontType, PRBool aItalic, PRUint16 aWeight, gfxUserFontData* aUserFontData, HDC hdc, LOGFONTW *aLogFont)
{
LOGFONTW logFont;
PRBool needRelease = PR_FALSE;
// jtdfix - need to set charset, unicode ranges, pitch/family
FontEntry *fe;
fe = new FontEntry(aName);
fe->mFontType = aFontType;
fe->mUserFontData = aUserFontData;
fe->mItalic = aItalic;
fe->mWeight = aWeight;
if (fe->IsType1())
fe->mForceGDI = PR_TRUE;
if (!aLogFont) {
aLogFont = &logFont;
FontEntry::FillLogFont(aLogFont, fe, 0, aItalic);
}
if (!hdc) {
hdc = GetDC(nsnull);
SetGraphicsMode(hdc, GM_ADVANCED);
needRelease = PR_TRUE;
}
HFONT font = CreateFontIndirectW(aLogFont);
if (font) {
HFONT oldFont = (HFONT)SelectObject(hdc, font);
// ReadCMAP may change the values of mUnicodeFont and mSymbolFont
if (NS_FAILED(::ReadCMAP(hdc, fe))) {
// Type1 fonts aren't necessarily Unicode but
// this is the best guess we can make here
if (fe->IsType1())
fe->mUnicodeFont = PR_TRUE;
else
fe->mUnicodeFont = PR_FALSE;
// For fonts where we failed to read the character map,
// we can take a slow path to look up glyphs character by character
fe->mUnknownCMAP = PR_TRUE;
}
SelectObject(hdc, oldFont);
DeleteObject(font);
}
if (needRelease)
ReleaseDC(nsnull, hdc);
return fe;
}
void
FontEntry::FillLogFont(LOGFONTW *aLogFont, FontEntry *aFontEntry, gfxFloat aSize, PRBool aItalic)
{
#define CLIP_TURNOFF_FONTASSOCIATION 0x40
aLogFont->lfHeight = (LONG)-ROUND(aSize);
if (aLogFont->lfHeight == 0)
aLogFont->lfHeight = -1;
// Fill in logFont structure
aLogFont->lfWidth = 0;
aLogFont->lfEscapement = 0;
aLogFont->lfOrientation = 0;
aLogFont->lfUnderline = FALSE;
aLogFont->lfStrikeOut = FALSE;
aLogFont->lfCharSet = DEFAULT_CHARSET;
aLogFont->lfOutPrecision = FontTypeToOutPrecision(aFontEntry->mFontType);
aLogFont->lfClipPrecision = CLIP_TURNOFF_FONTASSOCIATION;
aLogFont->lfQuality = DEFAULT_QUALITY;
aLogFont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
// always force lfItalic if we want it. Font selection code will
// do its best to give us an italic font entry, but if no face exists
// it may give us a regular one based on weight. Windows should
// do fake italic for us in that case.
aLogFont->lfItalic = aItalic;
aLogFont->lfWeight = aFontEntry->mWeight;
int len = PR_MIN(aFontEntry->Name().Length(), LF_FACESIZE - 1);
memcpy(aLogFont->lfFaceName, nsPromiseFlatString(aFontEntry->Name()).get(), len * 2);
aLogFont->lfFaceName[len] = '\0';
}
PRBool
FontEntry::TestCharacterMap(PRUint32 aCh)
{
@ -664,40 +714,13 @@ gfxWindowsFont::ComputeMetrics()
ReleaseDC((HWND)nsnull, dc);
SanitizeMetrics(mMetrics, GetFontEntry()->IsBadUnderlineFont());
SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont);
}
void
gfxWindowsFont::FillLogFont(gfxFloat aSize)
{
#define CLIP_TURNOFF_FONTASSOCIATION 0x40
mLogFont.lfHeight = (LONG)-ROUND(aSize);
if (mLogFont.lfHeight == 0)
mLogFont.lfHeight = -1;
// Fill in logFont structure
mLogFont.lfWidth = 0;
mLogFont.lfEscapement = 0;
mLogFont.lfOrientation = 0;
mLogFont.lfUnderline = FALSE;
mLogFont.lfStrikeOut = FALSE;
mLogFont.lfCharSet = DEFAULT_CHARSET;
mLogFont.lfOutPrecision = FontTypeToOutPrecision(GetFontEntry()->mFontType);
mLogFont.lfClipPrecision = CLIP_TURNOFF_FONTASSOCIATION;
mLogFont.lfQuality = DEFAULT_QUALITY;
mLogFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
// always force lfItalic if we want it. Font selection code will
// do its best to give us an italic font entry, but if no face exists
// it may give us a regular one based on weight. Windows should
// do fake italic for us in that case.
mLogFont.lfItalic = (GetStyle()->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) ? TRUE : FALSE;
mLogFont.lfWeight = GetFontEntry()->mWeight;
int len = PR_MIN(GetName().Length(), LF_FACESIZE - 1);
memcpy(mLogFont.lfFaceName, nsPromiseFlatString(mFontEntry->Name()).get(), len * 2);
mLogFont.lfFaceName[len] = '\0';
FontEntry::FillLogFont(&mLogFont, GetFontEntry(), aSize, (GetStyle()->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)));
}
@ -806,6 +829,7 @@ AddFontNameToArray(const nsAString& aName,
return PR_TRUE;
}
void
gfxWindowsFontGroup::GroupFamilyListToArrayList(nsTArray<nsRefPtr<FontEntry> > *list)
{
@ -814,8 +838,25 @@ gfxWindowsFontGroup::GroupFamilyListToArrayList(nsTArray<nsRefPtr<FontEntry> > *
PRUint32 len = fonts.Length();
for (PRUint32 i = 0; i < len; ++i) {
nsRefPtr<FontEntry> fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(fonts[i], mStyle);
list->AppendElement(fe);
nsRefPtr<FontEntry> fe;
// first, look up in the user font set
gfxFontEntry *gfe;
PRBool needsBold;
if (mUserFontSet && (gfe = mUserFontSet->FindFontEntry(fonts[i], mStyle, needsBold))) {
// assume for now platform font if not SVG
fe = static_cast<FontEntry*> (gfe);
}
// nothing in the user font set ==> check system fonts
if (!fe) {
fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(fonts[i], mStyle);
}
// if found, add to the list
if (fe) {
list->AppendElement(fe);
}
}
}
@ -835,8 +876,50 @@ gfxWindowsFontGroup::FamilyListToArrayList(const nsString& aFamilies,
}
}
gfxWindowsFontGroup::gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle)
: gfxFontGroup(aFamilies, aStyle)
gfxWindowsFontGroup::gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle, gfxUserFontSet *aUserFontSet)
: gfxFontGroup(aFamilies, aStyle, aUserFontSet)
{
InitFontList();
}
gfxWindowsFontGroup::~gfxWindowsFontGroup()
{
}
gfxWindowsFont *
gfxWindowsFontGroup::GetFontAt(PRInt32 i)
{
if (!mFonts[i]) {
nsRefPtr<gfxWindowsFont> font =
gfxWindowsFont::GetOrMakeFont(mFontEntries[i], &mStyle);
mFonts[i] = font;
}
return static_cast<gfxWindowsFont*>(mFonts[i].get());
}
gfxFontGroup *
gfxWindowsFontGroup::Copy(const gfxFontStyle *aStyle)
{
return new gfxWindowsFontGroup(mFamilies, aStyle, mUserFontSet);
}
void
gfxWindowsFontGroup::UpdateFontList()
{
// if user font set is set, check to see if font list needs updating
if (mUserFontSet && mCurrGeneration != GetGeneration()) {
// xxx - can probably improve this to detect when all fonts were found, so no need to update list
mFonts.Clear();
mFontEntries.Clear();
InitFontList();
mCurrGeneration = GetGeneration();
}
}
void
gfxWindowsFontGroup::InitFontList()
{
GroupFamilyListToArrayList(&mFontEntries);
@ -892,7 +975,7 @@ gfxWindowsFontGroup::gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFo
if (!mStyle.systemFont) {
for (PRUint32 i = 0; i < mFontEntries.Length(); ++i) {
if (mFontEntries[i]->IsBadUnderlineFont()) {
if (mFontEntries[i]->mIsBadUnderlineFont) {
gfxFloat first = GetFontAt(0)->GetMetrics().underlineOffset;
gfxFloat bad = GetFontAt(i)->GetMetrics().underlineOffset;
mUnderlineOffset = PR_MIN(first, bad);
@ -900,28 +983,7 @@ gfxWindowsFontGroup::gfxWindowsFontGroup(const nsAString& aFamilies, const gfxFo
}
}
}
}
gfxWindowsFontGroup::~gfxWindowsFontGroup()
{
}
gfxWindowsFont *
gfxWindowsFontGroup::GetFontAt(PRInt32 i)
{
if (!mFonts[i]) {
nsRefPtr<gfxWindowsFont> font =
gfxWindowsFont::GetOrMakeFont(mFontEntries[i], &mStyle);
mFonts[i] = font;
}
return static_cast<gfxWindowsFont*>(mFonts[i].get());
}
gfxFontGroup *
gfxWindowsFontGroup::Copy(const gfxFontStyle *aStyle)
{
return new gfxWindowsFontGroup(mFamilies, aStyle);
}
static PRBool

View File

@ -49,14 +49,18 @@
#include "nsServiceManagerUtils.h"
#include "nsIWindowsRegKey.h"
#include "nsILocalFile.h"
#include "plbase64.h"
#include "gfxWindowsFonts.h"
#include "gfxUserFontSet.h"
#include <string>
#include <time.h>
#include "lcms.h"
//#define DEBUG_CMAP_SIZE 1
static void InitializeFontEmbeddingProcs();
// font info loader constants
static const PRUint32 kDelayBeforeLoadingCmaps = 8 * 1000; // 8secs
@ -96,6 +100,8 @@ gfxWindowsPlatform::gfxWindowsPlatform()
pref->RegisterCallback("font.name-list.", PrefChangedCallback, this);
pref->RegisterCallback("intl.accept_languages", PrefChangedCallback, this);
// don't bother unregistering. We'll get shutdown after the pref service
InitializeFontEmbeddingProcs();
}
gfxWindowsPlatform::~gfxWindowsPlatform()
@ -319,7 +325,7 @@ gfxWindowsPlatform::InitBadUnderlineList()
FontFamily *ff = FindFontFamily(resolved);
if (!ff)
continue;
ff->mIsBadUnderlineFont = 1;
ff->mIsBadUnderlineFontFamily = 1;
}
}
@ -517,9 +523,364 @@ gfxWindowsPlatform::FindFontForChar(PRUint32 aCh, gfxWindowsFont *aFont)
gfxFontGroup *
gfxWindowsPlatform::CreateFontGroup(const nsAString &aFamilies,
const gfxFontStyle *aStyle)
const gfxFontStyle *aStyle,
gfxUserFontSet *aUserFontSet)
{
return new gfxWindowsFontGroup(aFamilies, aStyle);
return new gfxWindowsFontGroup(aFamilies, aStyle, aUserFontSet);
}
struct FullFontNameSearch {
FullFontNameSearch(const nsAString& aFullName)
: mFound(PR_FALSE), mFullName(aFullName), mDC(nsnull), mFontEntry(nsnull)
{ }
PRPackedBool mFound;
nsString mFullName;
nsString mFamilyName;
HDC mDC;
gfxFontEntry *mFontEntry;
};
// callback called for each face within a single family
// match against elfFullName
static int CALLBACK
FindFullNameForFace(const ENUMLOGFONTEXW *lpelfe,
const NEWTEXTMETRICEXW *nmetrics,
DWORD fontType, LPARAM userArg)
{
FullFontNameSearch *data = reinterpret_cast<FullFontNameSearch*>(userArg);
// does the full name match?
if (!data->mFullName.Equals(nsDependentString(lpelfe->elfFullName)))
return 1; // continue
// found match, create a new font entry
data->mFound = PR_TRUE;
const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
LOGFONTW logFont = lpelfe->elfLogFont;
// Some fonts claim to support things > 900, but we don't so clamp the sizes
logFont.lfWeight = PR_MAX(PR_MIN(logFont.lfWeight, 900), 100);
gfxWindowsFontType feType = FontEntry::DetermineFontType(metrics, fontType);
data->mFontEntry = FontEntry::CreateFontEntry(data->mFamilyName, feType, (logFont.lfItalic == 0xFF), (PRUint16) (logFont.lfWeight), nsnull, data->mDC, &logFont);
return 0; // stop iteration
}
// callback called for each family name, based on the assumption that the
// first part of the full name is the family name
static PLDHashOperator PR_CALLBACK
FindFullName(nsStringHashKey::KeyType aKey,
nsRefPtr<FontFamily>& aFontFamily,
void* userArg)
{
FullFontNameSearch *data = reinterpret_cast<FullFontNameSearch*>(userArg);
// does the family name match up to the length of the family name?
const nsString& family = aFontFamily->Name();
nsString fullNameFamily;
data->mFullName.Left(fullNameFamily, family.Length());
// if so, iterate over faces in this family to see if there is a match
if (family.Equals(fullNameFamily)) {
HDC hdc;
if (!data->mDC) {
data->mDC= GetDC(nsnull);
SetGraphicsMode(data->mDC, GM_ADVANCED);
}
hdc = data->mDC;
LOGFONTW logFont;
memset(&logFont, 0, sizeof(LOGFONTW));
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfPitchAndFamily = 0;
PRUint32 l = PR_MIN(family.Length(), LF_FACESIZE - 1);
memcpy(logFont.lfFaceName,
nsPromiseFlatString(family).get(),
l * sizeof(PRUnichar));
logFont.lfFaceName[l] = 0;
data->mFamilyName.Assign(family);
EnumFontFamiliesExW(hdc, &logFont, (FONTENUMPROCW)FindFullNameForFace, (LPARAM)data, 0);
}
if (data->mFound)
return PL_DHASH_STOP;
return PL_DHASH_NEXT;
}
gfxFontEntry*
gfxWindowsPlatform::LookupLocalFont(const nsAString& aFontName)
{
// walk over list of names
FullFontNameSearch data(aFontName);
// find fonts that support the character
mFonts.Enumerate(FindFullName, &data);
if (data.mDC)
ReleaseDC(nsnull, data.mDC);
return data.mFontEntry;
}
// make a unique font name, limited on Windows to 31 two-byte characters
static void MakeUniqueFontName(PRUnichar aName[LF_FACESIZE])
{
static PRUint32 fontCount = 0;
++fontCount;
PRUint32 time = (PRUint32) _time32(nsnull);
char buf[LF_FACESIZE];
sprintf(buf, "mozfont%8.8x%8.8x", time, fontCount); // slightly retarded, figure something better later...
nsCAutoString fontName(buf);
PRUint32 nameLen = PR_MIN(fontName.Length(), LF_FACESIZE - 1);
memcpy(aName, nsPromiseFlatString(NS_ConvertUTF8toUTF16(fontName)).get(), nameLen * 2);
aName[nameLen] = 0;
}
// from t2embapi.h, included in Platform SDK 6.1 but not 6.0
#ifndef __t2embapi__
#define TTLOAD_PRIVATE 0x00000001
#define LICENSE_PREVIEWPRINT 0x0004
#define E_NONE 0x0000L
typedef unsigned long( WINAPIV *READEMBEDPROC ) ( void*, void*, const unsigned long );
typedef struct
{
unsigned short usStructSize; // size in bytes of structure client should set to sizeof(TTLOADINFO)
unsigned short usRefStrSize; // size in wide characters of pusRefStr including NULL terminator
unsigned short *pusRefStr; // reference or actual string.
}TTLOADINFO;
LONG WINAPI TTLoadEmbeddedFont
(
__out HANDLE* phFontReference, // on completion, contains handle to identify embedded font installed
// on system
__in ULONG ulFlags, // flags specifying the request
__out ULONG* pulPrivStatus, // on completion, contains the embedding status
__in ULONG ulPrivs, // allows for the reduction of licensing privileges
__out ULONG* pulStatus, // on completion, may contain status flags for request
__in READEMBEDPROC lpfnReadFromStream, // callback function for doc/disk reads
__in LPVOID lpvReadStream, // the input stream tokin
__in_opt LPWSTR szWinFamilyName, // the new 16 bit windows family name can be NULL
__in_opt LPSTR szMacFamilyName, // the new 8 bit mac family name can be NULL
__in_opt TTLOADINFO* pTTLoadInfo // optional security
);
#endif // __t2embapi__
typedef LONG( WINAPI *TTLoadEmbeddedFontProc ) (HANDLE* phFontReference, ULONG ulFlags, ULONG* pulPrivStatus, ULONG ulPrivs, ULONG* pulStatus,
READEMBEDPROC lpfnReadFromStream, LPVOID lpvReadStream, LPWSTR szWinFamilyName,
LPSTR szMacFamilyName, TTLOADINFO* pTTLoadInfo);
typedef LONG( WINAPI *TTDeleteEmbeddedFontProc ) (HANDLE hFontReference, ULONG ulFlags, ULONG* pulStatus);
static TTLoadEmbeddedFontProc TTLoadEmbeddedFontPtr = nsnull;
static TTDeleteEmbeddedFontProc TTDeleteEmbeddedFontPtr = nsnull;
static void InitializeFontEmbeddingProcs()
{
HMODULE fontlib = LoadLibrary("t2embed.dll");
if (!fontlib)
return;
TTLoadEmbeddedFontPtr = (TTLoadEmbeddedFontProc) GetProcAddress(fontlib, "TTLoadEmbeddedFont");
TTDeleteEmbeddedFontPtr = (TTDeleteEmbeddedFontProc) GetProcAddress(fontlib, "TTDeleteEmbeddedFont");
}
class WinUserFontData : public gfxUserFontData {
public:
WinUserFontData(HANDLE aFontRef)
: mFontRef(aFontRef)
{ }
virtual ~WinUserFontData()
{
ULONG pulStatus;
TTDeleteEmbeddedFontPtr(mFontRef, 0, &pulStatus);
}
HANDLE mFontRef;
};
// used to control stream read by Windows TTLoadEmbeddedFont API
class EOTFontStreamReader {
public:
EOTFontStreamReader(nsILocalFile *aFontFile, PRUint8 *aEOTHeader,
PRUint32 aEOTHeaderLen)
: mFontFile(aFontFile), mFd(nsnull), mOpenError(PR_FALSE),
mInHeader(PR_TRUE), mHeaderOffset(0), mEOTHeader(aEOTHeader),
mEOTHeaderLen(aEOTHeaderLen)
{
}
~EOTFontStreamReader()
{
if (mFd) {
PR_Close(mFd);
}
mFontFile->Remove(PR_FALSE);
}
nsCOMPtr<nsILocalFile> mFontFile;
PRFileDesc *mFd;
PRPackedBool mOpenError;
PRPackedBool mInHeader;
PRUint32 mHeaderOffset;
PRUint8 *mEOTHeader;
PRUint32 mEOTHeaderLen;
PRBool OpenFontFile()
{
nsresult rv;
rv = mFontFile->OpenNSPRFileDesc(PR_RDONLY, 0, &mFd);
if (NS_FAILED(rv) || !mFd)
return PR_FALSE;
return PR_TRUE;
}
unsigned long Read(void *outBuffer, const unsigned long aBytesToRead)
{
PRUint32 bytesLeft = aBytesToRead;
PRUint8 *out = static_cast<PRUint8*> (outBuffer);
if (mOpenError)
return 0;
if (!mFd) {
if (!OpenFontFile()) {
mOpenError = PR_TRUE;
return 0;
}
}
// read from EOT header
if (mInHeader) {
PRUint32 toCopy = PR_MIN(aBytesToRead, mEOTHeaderLen - mHeaderOffset);
memcpy(out, mEOTHeader + mHeaderOffset, toCopy);
bytesLeft -= toCopy;
mHeaderOffset += toCopy;
out += toCopy;
if (mHeaderOffset == mEOTHeaderLen)
mInHeader = PR_FALSE;
}
if (bytesLeft) {
PRInt32 bytesRead = PR_Read(mFd, out, bytesLeft);
if (bytesRead > 0)
bytesLeft -= bytesRead;
}
return aBytesToRead - bytesLeft;
}
static unsigned long ReadEOTStream(void *aReadStream, void *outBuffer,
const unsigned long aBytesToRead)
{
EOTFontStreamReader *eotReader =
static_cast<EOTFontStreamReader*> (aReadStream);
return eotReader->Read(outBuffer, aBytesToRead);
}
};
gfxFontEntry*
gfxWindowsPlatform::MakePlatformFont(const gfxFontEntry *aProxyEntry,
const gfxDownloadedFontData* aFontData)
{
// if calls aren't available, bail
if (!TTLoadEmbeddedFontPtr || !TTDeleteEmbeddedFontPtr)
return nsnull;
// create an eot header
nsAutoTArray<PRUint8,2048> eotHeader;
PRUint8 *buffer;
PRUint32 eotlen;
PRUnichar fontName[LF_FACESIZE];
PRBool isCFF;
nsresult rv;
HANDLE fontRef;
PRInt32 ret;
{
nsCOMPtr<nsILocalFile> fontFile(do_QueryInterface(aFontData->mFontFile, &rv));
if (NS_FAILED(rv))
return nsnull;
rv = gfxFontUtils::MakeEOTHeader(fontFile, &eotHeader, &isCFF);
if (NS_FAILED(rv))
return nsnull;
// load in embedded font data
eotlen = eotHeader.Length();
buffer = reinterpret_cast<PRUint8*> (eotHeader.Elements());
ULONG privStatus, pulStatus;
MakeUniqueFontName(fontName);
EOTFontStreamReader eotReader(fontFile, buffer, eotlen);
ret = TTLoadEmbeddedFontPtr(&fontRef, TTLOAD_PRIVATE, &privStatus,
LICENSE_PREVIEWPRINT, &pulStatus,
EOTFontStreamReader::ReadEOTStream,
&eotReader, fontName, 0, 0);
}
if (ret != E_NONE)
return nsnull;
// make a new font entry using the unique name
WinUserFontData *winUserFontData = new WinUserFontData(fontRef);
PRUint16 w = (aProxyEntry->mWeight == 0 ? 400 : aProxyEntry->mWeight);
return FontEntry::CreateFontEntry(nsDependentString(fontName),
gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/,
PRUint32(aProxyEntry->mItalic ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL),
w, winUserFontData);
}
PRBool
gfxWindowsPlatform::IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags)
{
// reject based on format flags
if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_EOT | gfxUserFontSet::FLAG_FORMAT_SVG)) {
return PR_FALSE;
}
// exclude AAT fonts on platforms other than Mac OS X, this allows
// fonts for complex scripts which require AAT tables to be omitted
// on other platforms
if ((aFormatFlags & gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT)
&& !(aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_OPENTYPE | gfxUserFontSet::FLAG_FORMAT_TRUETYPE))) {
return PR_FALSE;
}
// reject based on filetype in URI
// otherwise, return true
return PR_TRUE;
}
FontFamily *

View File

@ -52,7 +52,9 @@ REQUIRES = \
cairo \
pref \
lcms \
necko \
unicharutil \
nspr \
$(NULL)
# All platforms

View File

@ -288,7 +288,7 @@ PRBool
RunTest (TestEntry *test, gfxContext *ctx) {
nsRefPtr<gfxFontGroup> fontGroup;
fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(NS_ConvertUTF8toUTF16(test->utf8FamilyString), &test->fontStyle);
fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(NS_ConvertUTF8toUTF16(test->utf8FamilyString), &test->fontStyle, nsnull);
nsAutoPtr<gfxTextRun> textRun;
gfxTextRunFactory::Parameters params = {

View File

@ -96,7 +96,7 @@ RunTest (TestEntry *test, gfxContext *ctx) {
0.0,
PR_FALSE, PR_FALSE);
fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(NS_ConvertUTF8toUTF16(test->mFamilies), &style_western_normal_16);
fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(NS_ConvertUTF8toUTF16(test->mFamilies), &style_western_normal_16, nsnull);
}
nsAutoPtr<gfxTextRun> textRun;

View File

@ -163,7 +163,7 @@ main (int argc, char **argv) {
PR_FALSE, PR_FALSE);
nsRefPtr<gfxFontGroup> fontGroup =
gfxPlatform::GetPlatform()->CreateFontGroup(NS_LITERAL_STRING("Geneva, MS Sans Serif, Helvetica,serif"), &style);
gfxPlatform::GetPlatform()->CreateFontGroup(NS_LITERAL_STRING("Geneva, MS Sans Serif, Helvetica,serif"), &style, nsnull);
gfxTextRunFactory::Parameters params = {
ctx, nsnull, nsnull, nsnull, 0, 60

View File

@ -78,6 +78,7 @@
#include "nsIWidget.h"
#include "gfxMatrix.h"
#include "gfxTypes.h"
#include "gfxUserFontSet.h"
#ifdef MOZ_SVG
#include "nsSVGUtils.h"
@ -1493,10 +1494,13 @@ nsresult
nsLayoutUtils::GetFontMetricsForStyleContext(nsStyleContext* aStyleContext,
nsIFontMetrics** aFontMetrics)
{
return aStyleContext->PresContext()->DeviceContext()->
GetMetricsFor(aStyleContext->GetStyleFont()->mFont,
// pass the user font set object into the device context to pass along to CreateFontGroup
gfxUserFontSet* fs = aStyleContext->PresContext()->GetUserFontSet();
return aStyleContext->PresContext()->DeviceContext()->GetMetricsFor(
aStyleContext->GetStyleFont()->mFont,
aStyleContext->GetStyleVisibility()->mLangGroup,
*aFontMetrics);
*aFontMetrics, fs);
}
nsIFrame*

View File

@ -83,6 +83,7 @@
#include "nsStyleChangeList.h"
#include "nsRuleNode.h"
#include "nsEventDispatcher.h"
#include "gfxUserFontSet.h"
#ifdef IBMBIDI
#include "nsBidiPresUtils.h"
@ -226,6 +227,7 @@ nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
mNeverAnimate = PR_FALSE;
}
NS_ASSERTION(mDocument, "Null document");
mUserFontSet = nsnull;
}
nsPresContext::~nsPresContext()
@ -283,6 +285,8 @@ nsPresContext::~nsPresContext()
NS_IF_RELEASE(mDeviceContext);
NS_IF_RELEASE(mLookAndFeel);
NS_IF_RELEASE(mLangGroup);
SetUserFontSet(nsnull);
}
NS_IMPL_CYCLE_COLLECTION_CLASS(nsPresContext)
@ -1576,6 +1580,19 @@ nsPresContext::HasAuthorSpecifiedRules(nsIFrame *aFrame, PRUint32 ruleTypeMask)
HasAuthorSpecifiedRules(aFrame->GetStyleContext(), ruleTypeMask);
}
gfxUserFontSet*
nsPresContext::GetUserFontSet() {
return mUserFontSet;
}
void
nsPresContext::SetUserFontSet(gfxUserFontSet *aUserFontSet)
{
NS_IF_RELEASE(mUserFontSet);
mUserFontSet = aUserFontSet;
NS_IF_ADDREF(mUserFontSet);
}
void
nsPresContext::FireDOMPaintEvent()
{

View File

@ -66,6 +66,7 @@
// This also pulls in gfxTypes.h, which we cannot include directly.
#include "gfxRect.h"
#include "nsRegion.h"
class nsImageLoader;
#ifdef IBMBIDI
class nsBidiPresUtils;
@ -91,6 +92,7 @@ class nsIAtom;
struct nsStyleBackground;
template <class T> class nsRunnableMethod;
class nsIRunnable;
class gfxUserFontSet;
#ifdef MOZ_REFLOW_PERF
class nsIRenderingContext;
@ -778,6 +780,9 @@ public:
}
PRBool SupressingResizeReflow() const { return mSupressResizeReflow; }
gfxUserFontSet* GetUserFontSet();
void SetUserFontSet(gfxUserFontSet *aUserFontSet);
void NotifyInvalidation(const nsRect& aRect, PRBool aIsCrossDoc);
void FireDOMPaintEvent();
@ -845,6 +850,9 @@ protected:
nsRegion mSameDocDirtyRegion;
nsRegion mCrossDocDirtyRegion;
// container for per-context fonts (downloadable, SVG, etc.)
gfxUserFontSet* mUserFontSet;
nsLanguageSpecificTransformType mLanguageSpecificTransformType;
PRInt32 mFontScaler;
nscoord mMinimumFontSize;

View File

@ -151,6 +151,7 @@ CPPSRCS = \
nsDOMCSSRGBColor.cpp \
nsDOMCSSRect.cpp \
nsDOMCSSValueList.cpp \
nsFontFaceLoader.cpp \
nsHTMLCSSStyleSheet.cpp \
nsHTMLStyleSheet.cpp \
nsInspectorCSSUtils.cpp \

View File

@ -82,6 +82,10 @@
#include "nsTArray.h"
#include "nsContentUtils.h"
#include "nsIMediaList.h"
#include "gfxPlatform.h"
#include "gfxUserFontSet.h"
#include "nsCSSRules.h"
#include "nsFontFaceLoader.h"
static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
static nsTArray< nsCOMPtr<nsIAtom> >* sSystemMetrics = 0;
@ -2292,6 +2296,129 @@ struct CascadeEnumData {
PLArenaPool& mArena;
};
static void
InsertFontFaceRule(nsICSSRule* aRule, gfxUserFontSet* fs)
{
nsCSSFontFaceRule *fontFace = static_cast<nsCSSFontFaceRule*> (aRule);
PRInt32 type;
NS_ASSERTION(NS_SUCCEEDED(aRule->GetType(type))
&& type == nsICSSRule::FONT_FACE_RULE,
"InsertFontFaceRule passed a non-fontface CSS rule");
// fontFace->List();
nsAutoString fontfamily, valueString;
nsCSSValue val;
PRUint32 unit;
PRUint32 weight = NS_STYLE_FONT_WEIGHT_NORMAL;
PRUint32 stretch = NS_STYLE_FONT_STRETCH_NORMAL;
PRUint32 italicStyle = FONT_STYLE_NORMAL;
// set up family name
fontFace->GetDesc(eCSSFontDesc_Family, val);
unit = val.GetUnit();
if (unit == eCSSUnit_String) {
val.GetStringValue(fontfamily);
fontfamily.Trim("\"");
} else {
NS_ASSERTION(unit == eCSSUnit_String,
"@font-face family name has non-string unit type");
return;
}
// set up weight
fontFace->GetDesc(eCSSFontDesc_Weight, val);
unit = val.GetUnit();
if (unit != eCSSUnit_Null) {
if (unit == eCSSUnit_Normal) {
weight = NS_STYLE_FONT_WEIGHT_NORMAL;
} else {
weight = val.GetIntValue();
}
}
// set up stretch
fontFace->GetDesc(eCSSFontDesc_Stretch, val);
unit = val.GetUnit();
if (unit != eCSSUnit_Null) {
if (unit == eCSSUnit_Normal) {
stretch = NS_STYLE_FONT_STRETCH_NORMAL;
} else {
stretch = val.GetIntValue();
}
}
// set up font style
fontFace->GetDesc(eCSSFontDesc_Style, val);
if (val.GetUnit() != eCSSUnit_Null) {
if (val.GetUnit() == eCSSUnit_Normal) {
italicStyle = FONT_STYLE_NORMAL;
} else {
italicStyle = val.GetIntValue();
}
}
// set up src array
nsTArray<gfxFontFaceSrc> srcArray;
fontFace->GetDesc(eCSSFontDesc_Src, val);
unit = val.GetUnit();
if (unit == eCSSUnit_Array) {
nsCSSValue::Array *srcArr = val.GetArrayValue();
PRUint32 i, numSrc = srcArr->Count(), faceIndex = 0;
for (i = 0; i < numSrc; i++) {
val = srcArr->Item(i);
unit = val.GetUnit();
gfxFontFaceSrc *face = srcArray.AppendElements(1);
if (!face)
return;
switch (unit) {
case eCSSUnit_Local_Font:
val.GetStringValue(face->mLocalName);
face->mIsLocal = PR_TRUE;
face->mURI = nsnull;
face->mFormatFlags = 0;
break;
case eCSSUnit_URL:
face->mIsLocal = PR_FALSE;
face->mURI = val.GetURLValue();
face->mLocalName.Truncate();
face->mFormatFlags = 0;
while (i + 1 < numSrc && (val = srcArr->Item(i+1),
val.GetUnit() == eCSSUnit_Font_Format)) {
nsDependentString valueString(val.GetStringBufferValue());
if (valueString.LowerCaseEqualsASCII("opentype")) {
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_OPENTYPE;
} else if (valueString.LowerCaseEqualsASCII("truetype")) {
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_TRUETYPE;
} else if (valueString.LowerCaseEqualsASCII("truetype-aat")) {
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT;
} else if (valueString.LowerCaseEqualsASCII("embedded-opentype")) {
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_EOT;
} else if (valueString.LowerCaseEqualsASCII("svg")) {
face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_SVG;
}
i++;
}
break;
default:
NS_ASSERTION(unit == eCSSUnit_Local_Font || unit == eCSSUnit_URL,
"strange unit type in font-face src array");
break;
}
}
}
if (!fontfamily.IsEmpty() && srcArray.Length() > 0) {
fs->AddFontFace(fontfamily, srcArray, weight, stretch, italicStyle);
}
}
static PRBool
InsertRuleByWeight(nsICSSRule* aRule, void* aData)
{
@ -2325,10 +2452,28 @@ InsertRuleByWeight(nsICSSRule* aRule, void* aData)
if (!groupRule->EnumerateRulesForwards(InsertRuleByWeight, aData))
return PR_FALSE;
}
else if (nsICSSRule::FONT_FACE_RULE == type
&& gfxPlatform::GetPlatform()->DownloadableFontsEnabled()) {
nsPresContext *presContext = data->mPresContext;
gfxUserFontSet *fs = presContext->GetUserFontSet();
if (!fs) {
nsFontFaceLoaderContext *loaderCtx = new nsFontFaceLoaderContext(presContext);
if (!loaderCtx)
return PR_FALSE;
fs = new gfxUserFontSet(loaderCtx); // user font set owns loader context
if (!fs) {
delete loaderCtx;
return PR_FALSE;
}
presContext->SetUserFontSet(fs);
}
InsertFontFaceRule(aRule, fs);
}
return PR_TRUE;
}
static PRBool
CascadeSheetRulesInto(nsICSSStyleSheet* aSheet, void* aData)
{

View File

@ -1253,7 +1253,7 @@ nsSVGGlyphFrame::EnsureTextRun(float *aDrawScale, float *aMetricsScale,
font.familyNameQuirks);
nsRefPtr<gfxFontGroup> fontGroup =
gfxPlatform::GetPlatform()->CreateFontGroup(font.name, &fontStyle);
gfxPlatform::GetPlatform()->CreateFontGroup(font.name, &fontStyle, presContext->GetUserFontSet());
PRUint32 flags = gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX |
nsLayoutUtils::GetTextRunFlagsForStyle(GetStyleContext(), GetStyleText(), GetStyleFont());

View File

@ -134,6 +134,9 @@ pref("gfx.color_management.mode", 2);
pref("gfx.color_management.display_profile", "");
pref("gfx.color_management.rendering_intent", 0);
pref("gfx.downloadable_fonts.enabled", true);
pref("gfx.downloadable_fonts.enforce_same_site_origin", true);
pref("accessibility.browsewithcaret", false);
pref("accessibility.warn_on_browsewithcaret", true);