Bug 493280: restructure Windows font management based on cross-platform font-list classes. r=jdaggett sr=roc

This commit is contained in:
Jonathan Kew 2009-10-07 15:13:40 +01:00
parent cf2eca0586
commit 27f23b384f
18 changed files with 2029 additions and 1950 deletions

View File

@ -204,12 +204,12 @@ protected: // new functions
PRBool mEnableKerning;
void GetPrefFonts(const char *aLangGroup,
nsTArray<nsRefPtr<FontEntry> >& aFontEntryList);
void GetCJKPrefFonts(nsTArray<nsRefPtr<FontEntry> >& aFontEntryList);
nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList);
void GetCJKPrefFonts(nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList);
void FamilyListToArrayList(const nsString& aFamilies,
const nsCString& aLangGroup,
nsTArray<nsRefPtr<FontEntry> > *aFontEntryList);
already_AddRefed<gfxFT2Font> WhichFontSupportsChar(const nsTArray<nsRefPtr<FontEntry> >& aFontEntryList,
nsTArray<nsRefPtr<gfxFontEntry> > *aFontEntryList);
already_AddRefed<gfxFT2Font> WhichFontSupportsChar(const nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList,
PRUint32 aCh);
already_AddRefed<gfxFont> WhichPrefFontSupportsChar(PRUint32 aCh);
already_AddRefed<gfxFont> WhichSystemFontSupportsChar(PRUint32 aCh);

View File

@ -165,6 +165,7 @@ public:
mIsProxy(PR_FALSE), mIsValid(PR_TRUE),
mIsBadUnderlineFont(PR_FALSE), mIsUserFont(PR_FALSE),
mStandardFace(aIsStandardFace),
mSymbolFont(PR_FALSE),
mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
mCmapInitialized(PR_FALSE), mUserFontData(nsnull),
mFamily(aFamily)
@ -176,6 +177,7 @@ public:
mIsValid(aEntry.mIsValid), mIsBadUnderlineFont(aEntry.mIsBadUnderlineFont),
mIsUserFont(aEntry.mIsUserFont),
mStandardFace(aEntry.mStandardFace),
mSymbolFont(aEntry.mSymbolFont),
mWeight(aEntry.mWeight), mCmapInitialized(aEntry.mCmapInitialized),
mCharacterMap(aEntry.mCharacterMap), mUserFontData(aEntry.mUserFontData),
mFamily(aEntry.mFamily)
@ -186,13 +188,14 @@ public:
// unique name for the face, *not* the family
const nsString& Name() const { return mName; }
PRUint16 Weight() { return mWeight; }
PRInt16 Stretch() { return mStretch; }
PRUint16 Weight() const { return mWeight; }
PRInt16 Stretch() const { return mStretch; }
PRBool IsUserFont() { return mIsUserFont; }
PRBool IsFixedPitch() { return mFixedPitch; }
PRBool IsItalic() { return mItalic; }
PRBool IsBold() { return mWeight >= 600; } // bold == weights 600 and above
PRBool IsUserFont() const { return mIsUserFont; }
PRBool IsFixedPitch() const { return mFixedPitch; }
PRBool IsItalic() const { return mItalic; }
PRBool IsBold() const { return mWeight >= 600; } // bold == weights 600 and above
PRBool IsSymbolFont() const { return mSymbolFont; }
inline PRBool HasCharacter(PRUint32 ch) {
if (mCharacterMap.test(ch))
@ -204,6 +207,13 @@ public:
virtual PRBool TestCharacterMap(PRUint32 aCh);
virtual nsresult ReadCMAP();
virtual PRBool MatchesGenericFamily(const nsACString& aGeneric) const {
return PR_TRUE;
}
virtual PRBool SupportsLangGroup(const nsACString& aLangGroup) const {
return PR_TRUE;
}
const nsString& FamilyName();
nsString mName;
@ -215,6 +225,7 @@ public:
PRPackedBool mIsBadUnderlineFont : 1;
PRPackedBool mIsUserFont : 1;
PRPackedBool mStandardFace : 1;
PRPackedBool mSymbolFont : 1;
PRUint16 mWeight;
PRInt16 mStretch;
@ -235,6 +246,7 @@ protected:
mIsBadUnderlineFont(PR_FALSE),
mIsUserFont(PR_FALSE),
mStandardFace(PR_FALSE),
mSymbolFont(PR_FALSE),
mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
mCmapInitialized(PR_FALSE),
mUserFontData(nsnull),

View File

@ -57,246 +57,7 @@
// exceptions. use gfxSparseBitSet instead?
#include <bitset>
/**
* List of different types of fonts we support on Windows.
* These can generally be lumped in to 3 categories where we have to
* do special things: Really old fonts bitmap and vector fonts (device
* and raster), Type 1 fonts, and TrueType/OpenType fonts.
*
* This list is sorted in order from least prefered to most prefered.
* We prefer Type1 fonts over OpenType fonts to avoid falling back to
* things like Arial (opentype) when you ask for Helvetica (type1)
**/
enum gfxWindowsFontType {
GFX_FONT_TYPE_UNKNOWN = 0,
GFX_FONT_TYPE_DEVICE,
GFX_FONT_TYPE_RASTER,
GFX_FONT_TYPE_TRUETYPE,
GFX_FONT_TYPE_PS_OPENTYPE,
GFX_FONT_TYPE_TT_OPENTYPE,
GFX_FONT_TYPE_TYPE1
};
/**
* FontFamily is a class that describes one of the fonts on the users system. It holds
* each FontEntry (maps more directly to a font face) which holds font type, charset info
* and character map info.
*/
class FontEntry;
class FontFamily : public gfxFontFamily
{
public:
FontFamily(const nsAString& aName) :
gfxFontFamily(aName), mIsBadUnderlineFontFamily(PR_FALSE) { }
FontEntry *FindFontEntry(const gfxFontStyle& aFontStyle);
private:
friend class gfxWindowsPlatform;
void FindStyleVariations();
static int CALLBACK FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
const NEWTEXTMETRICEXW *nmetrics,
DWORD fontType, LPARAM data);
protected:
PRBool FindWeightsForStyle(gfxFontEntry* aFontsForWeights[],
PRBool anItalic, PRInt16 aStretch);
public:
PRPackedBool mIsBadUnderlineFontFamily;
};
class FontEntry : public gfxFontEntry
{
public:
FontEntry(const nsAString& aFaceName, gfxWindowsFontType aFontType,
PRBool aItalic, PRUint16 aWeight, gfxUserFontData *aUserFontData) :
gfxFontEntry(aFaceName), mFontType(aFontType),
mForceGDI(PR_FALSE), mUnknownCMAP(PR_FALSE),
mUnicodeFont(PR_FALSE), mSymbolFont(PR_FALSE),
mCharset(), mUnicodeRanges()
{
mUserFontData = aUserFontData;
mItalic = aItalic;
mWeight = aWeight;
if (IsType1())
mForceGDI = PR_TRUE;
mIsUserFont = aUserFontData != nsnull;
}
FontEntry(const FontEntry& aFontEntry) :
gfxFontEntry(aFontEntry),
mWindowsFamily(aFontEntry.mWindowsFamily),
mWindowsPitch(aFontEntry.mWindowsPitch),
mFontType(aFontEntry.mFontType),
mForceGDI(aFontEntry.mForceGDI),
mUnknownCMAP(aFontEntry.mUnknownCMAP),
mUnicodeFont(aFontEntry.mUnicodeFont),
mSymbolFont(aFontEntry.mSymbolFont),
mCharset(aFontEntry.mCharset),
mUnicodeRanges(aFontEntry.mUnicodeRanges)
{
}
static void InitializeFontEmbeddingProcs();
// create a font entry from downloaded font data
static FontEntry* LoadFont(const gfxProxyFontEntry &aProxyEntry,
const PRUint8 *aFontData,
PRUint32 aLength);
// create a font entry for a font with a given name
static FontEntry* CreateFontEntry(const nsAString& aName,
gfxWindowsFontType aFontType,
PRBool aItalic, PRUint16 aWeight,
gfxUserFontData* aUserFontData,
HDC hdc = 0, LOGFONTW *aLogFont = nsnull);
// create a font entry for a font referenced by its fullname
static FontEntry* LoadLocalFont(const gfxProxyFontEntry &aProxyEntry,
const nsAString& aFullname);
static void FillLogFont(LOGFONTW *aLogFont, const nsAString& aName,
gfxWindowsFontType aFontType, PRBool aItalic,
PRUint16 aWeight, gfxFloat aSize);
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);
}
PRBool IsTrueType() const {
return (mFontType == GFX_FONT_TYPE_TRUETYPE ||
mFontType == GFX_FONT_TYPE_PS_OPENTYPE ||
mFontType == GFX_FONT_TYPE_TT_OPENTYPE);
}
PRBool IsCrappyFont() const {
/* return if it is a bitmap not a unicode font */
return (!mUnicodeFont || mSymbolFont || IsType1());
}
PRBool MatchesGenericFamily(const nsACString& aGeneric) const {
if (aGeneric.IsEmpty())
return PR_TRUE;
// Japanese 'Mincho' fonts do not belong to FF_MODERN even if
// they are fixed pitch because they have variable stroke width.
if (mWindowsFamily == FF_ROMAN && mWindowsPitch & FIXED_PITCH) {
return aGeneric.EqualsLiteral("monospace");
}
// Japanese 'Gothic' fonts do not belong to FF_SWISS even if
// they are variable pitch because they have constant stroke width.
if (mWindowsFamily == FF_MODERN && mWindowsPitch & VARIABLE_PITCH) {
return aGeneric.EqualsLiteral("sans-serif");
}
// All other fonts will be grouped correctly using family...
switch (mWindowsFamily) {
case FF_DONTCARE:
return PR_TRUE;
case FF_ROMAN:
return aGeneric.EqualsLiteral("serif");
case FF_SWISS:
return aGeneric.EqualsLiteral("sans-serif");
case FF_MODERN:
return aGeneric.EqualsLiteral("monospace");
case FF_SCRIPT:
return aGeneric.EqualsLiteral("cursive");
case FF_DECORATIVE:
return aGeneric.EqualsLiteral("fantasy");
}
return PR_FALSE;
}
PRBool SupportsLangGroup(const nsACString& aLangGroup) const {
if (aLangGroup.IsEmpty())
return PR_TRUE;
PRInt16 bit = -1;
/* map our langgroup names in to Windows charset bits */
if (aLangGroup.EqualsLiteral("x-western")) {
bit = ANSI_CHARSET;
} else if (aLangGroup.EqualsLiteral("ja")) {
bit = SHIFTJIS_CHARSET;
} else if (aLangGroup.EqualsLiteral("ko")) {
bit = HANGEUL_CHARSET;
} else if (aLangGroup.EqualsLiteral("ko-XXX")) {
bit = JOHAB_CHARSET;
} else if (aLangGroup.EqualsLiteral("zh-CN")) {
bit = GB2312_CHARSET;
} else if (aLangGroup.EqualsLiteral("zh-TW")) {
bit = CHINESEBIG5_CHARSET;
} else if (aLangGroup.EqualsLiteral("el")) {
bit = GREEK_CHARSET;
} else if (aLangGroup.EqualsLiteral("tr")) {
bit = TURKISH_CHARSET;
} else if (aLangGroup.EqualsLiteral("he")) {
bit = HEBREW_CHARSET;
} else if (aLangGroup.EqualsLiteral("ar")) {
bit = ARABIC_CHARSET;
} else if (aLangGroup.EqualsLiteral("x-baltic")) {
bit = BALTIC_CHARSET;
} else if (aLangGroup.EqualsLiteral("x-cyrillic")) {
bit = RUSSIAN_CHARSET;
} else if (aLangGroup.EqualsLiteral("th")) {
bit = THAI_CHARSET;
} else if (aLangGroup.EqualsLiteral("x-central-euro")) {
bit = EASTEUROPE_CHARSET;
} else if (aLangGroup.EqualsLiteral("x-symbol")) {
bit = SYMBOL_CHARSET;
}
if (bit != -1)
return mCharset[bit];
return PR_FALSE;
}
PRBool SupportsRange(PRUint8 range) {
return mUnicodeRanges[range];
}
PRBool TestCharacterMap(PRUint32 aCh);
PRUint8 mWindowsFamily;
PRUint8 mWindowsPitch;
gfxWindowsFontType mFontType;
PRPackedBool mForceGDI : 1;
PRPackedBool mUnknownCMAP : 1;
PRPackedBool mUnicodeFont : 1;
PRPackedBool mSymbolFont : 1;
std::bitset<256> mCharset;
std::bitset<128> mUnicodeRanges;
};
class GDIFontEntry;
/**********************************************************************
*
@ -306,7 +67,7 @@ public:
class gfxWindowsFont : public gfxFont {
public:
gfxWindowsFont(FontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
gfxWindowsFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
cairo_antialias_t anAntialiasOption = CAIRO_ANTIALIAS_DEFAULT);
virtual ~gfxWindowsFont();
@ -336,10 +97,10 @@ public:
};
PRBool IsValid() { GetMetrics(); return mIsValid; }
FontEntry *GetFontEntry();
GDIFontEntry *GetFontEntry();
static already_AddRefed<gfxWindowsFont>
GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle,
GetOrMakeFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aStyle,
PRBool aNeedsBold = PR_FALSE);
protected:
@ -390,28 +151,26 @@ public:
return mGenericFamily;
}
const nsTArray<nsRefPtr<FontEntry> >& GetFontList() const {
return mFontEntries;
}
PRUint32 FontListLength() const {
return mFontEntries.Length();
}
FontEntry *GetFontEntryAt(PRInt32 i) {
return mFontEntries[i];
}
virtual gfxWindowsFont *GetFontAt(PRInt32 i);
void GroupFamilyListToArrayList(nsTArray<nsRefPtr<FontEntry> > *list,
void GroupFamilyListToArrayList(nsTArray<nsRefPtr<gfxFontEntry> > *list,
nsTArray<PRPackedBool> *aNeedsBold);
void FamilyListToArrayList(const nsString& aFamilies,
const nsCString& aLangGroup,
nsTArray<nsRefPtr<FontEntry> > *list);
nsTArray<nsRefPtr<gfxFontEntry> > *list);
void UpdateFontList();
virtual void UpdateFontList();
virtual gfxFloat GetUnderlineOffset();
gfxWindowsFont* GetFontAt(PRInt32 aFontIndex) {
// If it turns out to be hard for all clients that cache font
// groups to call UpdateFontList at appropriate times, we could
// instead consider just calling UpdateFontList from someplace
// more central (such as here).
NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(),
"Whoever was caching this font group should have "
"called UpdateFontList on it");
return static_cast<gfxWindowsFont*>(static_cast<gfxFont*>(mFonts[aFontIndex]));
}
protected:
void InitFontList();
@ -423,14 +182,19 @@ protected:
already_AddRefed<gfxFont> WhichPrefFontSupportsChar(PRUint32 aCh);
already_AddRefed<gfxFont> WhichSystemFontSupportsChar(PRUint32 aCh);
already_AddRefed<gfxWindowsFont> WhichFontSupportsChar(const nsTArray<nsRefPtr<FontEntry> >& fonts, PRUint32 ch);
void GetPrefFonts(const char *aLangGroup, nsTArray<nsRefPtr<FontEntry> >& array);
void GetCJKPrefFonts(nsTArray<nsRefPtr<FontEntry> >& array);
already_AddRefed<gfxWindowsFont> WhichFontSupportsChar(const nsTArray<nsRefPtr<gfxFontEntry> >& fonts, PRUint32 ch);
void GetPrefFonts(const char *aLangGroup, nsTArray<nsRefPtr<gfxFontEntry> >& array);
void GetCJKPrefFonts(nsTArray<nsRefPtr<gfxFontEntry> >& array);
static PRBool FindWindowsFont(const nsAString& aName,
const nsACString& aGenericName,
void *closure);
PRBool HasFont(gfxFontEntry *aFontEntry);
private:
nsCString mGenericFamily;
nsTArray<nsRefPtr<FontEntry> > mFontEntries;
nsTArray<PRPackedBool> mFontNeedsBold;
const char *mItemLangGroup; // used by pref-lang handling code

View File

@ -61,7 +61,7 @@ typedef struct FT_LibraryRec_ *FT_Library;
#include <windows.h>
class THEBES_API gfxWindowsPlatform : public gfxPlatform, private gfxFontInfoLoader {
class THEBES_API gfxWindowsPlatform : public gfxPlatform {
public:
gfxWindowsPlatform();
virtual ~gfxWindowsPlatform();
@ -69,6 +69,8 @@ public:
return (gfxWindowsPlatform*) gfxPlatform::GetPlatform();
}
virtual gfxPlatformFontList* CreatePlatformFontList();
already_AddRefed<gfxASurface> CreateOffscreenSurface(const gfxIntSize& size,
gfxASurface::gfxImageFormat imageFormat);
@ -104,8 +106,6 @@ public:
nsresult UpdateFontList();
void GetFontFamilyList(nsTArray<nsRefPtr<FontFamily> >& aFamilyArray);
nsresult ResolveFontName(const nsAString& aFontName,
FontResolverCallback aCallback,
void *aClosure, PRBool& aAborted);
@ -134,32 +134,17 @@ public:
*/
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
*
* this involves looking at the fonts on your machine and seeing which
* code points they support as well as looking at things like the font
* family, style, weight, etc.
*/
already_AddRefed<gfxFont>
FindFontForChar(PRUint32 aCh, gfxFont *aFont);
/* Find a FontFamily/FontEntry object that represents a font on your system given a name */
FontFamily *FindFontFamily(const nsAString& aName);
FontEntry *FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle);
gfxFontFamily *FindFontFamily(const nsAString& aName);
gfxFontEntry *FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle);
PRBool GetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<FontEntry> > *array);
void SetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<FontEntry> >& array);
PRBool GetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<gfxFontEntry> > *array);
void SetPrefFontEntries(const nsCString& aLangGroup, nsTArray<nsRefPtr<gfxFontEntry> >& array);
void ClearPrefFonts() { mPrefFonts.Clear(); }
typedef nsDataHashtable<nsStringHashKey, nsRefPtr<FontFamily> > FontTable;
#ifdef MOZ_FT2_FONTS
FT_Library GetFTLibrary();
private:
void AppendFacesFromFontFile(const PRUnichar *aFileName);
void FindFonts();
#endif
protected:
@ -170,59 +155,10 @@ protected:
private:
void Init();
void InitBadUnderlineList();
static int CALLBACK FontEnumProc(const ENUMLOGFONTEXW *lpelfe,
const NEWTEXTMETRICEXW *metrics,
DWORD fontType, LPARAM data);
static int CALLBACK FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
const NEWTEXTMETRICEXW *nmetrics,
DWORD fontType, LPARAM data);
static PLDHashOperator FontGetStylesProc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontFamily>& aFontFamily,
void* userArg);
static PLDHashOperator FontGetCMapDataProc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontFamily>& aFontFamily,
void* userArg);
static int CALLBACK FontResolveProc(const ENUMLOGFONTEXW *lpelfe,
const NEWTEXTMETRICEXW *metrics,
DWORD fontType, LPARAM data);
static PLDHashOperator HashEnumFunc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontFamily>& aData,
void* userArg);
static PLDHashOperator FindFontForCharProc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontFamily>& aFontFamily,
void* userArg);
virtual qcms_profile* GetPlatformCMSOutputProfile();
static int PrefChangedCallback(const char*, void*);
// gfxFontInfoLoader overrides, used to load in font cmaps
virtual void InitLoader();
virtual PRBool RunLoader();
virtual void FinishLoader();
FontTable mFonts;
FontTable mFontAliases;
FontTable mFontSubstitutes;
nsTArray<nsString> mNonExistingFonts;
// when system-wide font lookup fails for a character, cache it to skip future searches
gfxSparseBitSet mCodepointsWithNoFonts;
nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<FontEntry> > > mPrefFonts;
// data used as part of the font cmap loading process
nsTArray<nsRefPtr<FontFamily> > mFontFamilies;
PRUint32 mStartIndex;
PRUint32 mIncrement;
PRUint32 mNumFamilies;
// TODO: unify this with mPrefFonts (NB: holds families, not fonts) in gfxPlatformFontList
nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<gfxFontEntry> > > mPrefFonts;
};
#endif /* GFX_WINDOWS_PLATFORM_H */

View File

@ -56,10 +56,13 @@ CPPSRCS += gfxFT2Fonts.cpp \
gfxFT2FontBase.cpp \
gfxFT2Utils.cpp \
gfxDDrawSurface.cpp \
gfxFT2FontList.cpp \
$(NULL)
EXTRA_DSO_LDOPTS += ddraw.lib
else
CPPSRCS += gfxWindowsFonts.cpp
CPPSRCS += gfxWindowsFonts.cpp \
gfxGDIFontList.cpp \
$(NULL)
endif
CPPSRCS += gfxPDFSurface.cpp

View File

@ -0,0 +1,286 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Corporation code.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <stuart@mozilla.com>
* Masayuki Nakano <masayuki@d-toybox.com>
* Mats Palmgren <mats.palmgren@bredband.net>
* John Daggett <jdaggett@mozilla.com>
* Jonathan Kew <jfkthame@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "gfxFT2FontList.h"
#include "gfxUserFontSet.h"
#include "gfxFontUtils.h"
#include "ft2build.h"
#include FT_FREETYPE_H
#include "gfxFT2Fonts.h"
#include "nsIPref.h" // for pref changes callback notification
#include "nsServiceManagerUtils.h"
#include "nsTArray.h"
#include "nsUnicharUtils.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsISimpleEnumerator.h"
#include "nsIWindowsRegKey.h"
#ifdef XP_WIN
#include <windows.h>
#endif
#define ROUND(x) floor((x) + 0.5)
#ifdef PR_LOGGING
static PRLogModuleInfo *gFontInfoLog = PR_NewLogModule("fontInfoLog");
#endif /* PR_LOGGING */
#define LOG(args) PR_LOG(gFontInfoLog, PR_LOG_DEBUG, args)
#define LOG_ENABLED() PR_LOG_TEST(gFontInfoLog, PR_LOG_DEBUG)
static __inline void
BuildKeyNameFromFontName(nsAString &aName)
{
if (aName.Length() >= LF_FACESIZE)
aName.Truncate(LF_FACESIZE - 1);
ToLowerCase(aName);
}
/***************************************************************
*
* gfxFT2FontList
*
*/
// For Mobile, we use gfxFT2Fonts, and we build the font list by directly scanning
// the system's Fonts directory for OpenType and TrueType files.
//
// FontEntry is currently defined in gfxFT2Fonts.h, but will probably be moved here
// as part of the Freetype/Linux font restructuring for Harfbuzz integration.
//
// TODO: investigate startup performance - we might be able to improve by avoiding
// the creation of FT_Faces here, and just reading names directly from the file;
// or even consider caching a mapping from font family name to (list of) filenames,
// so that we don't have to scan all the files before we can do any font lookups.
gfxFT2FontList::gfxFT2FontList()
{
}
void
gfxFT2FontList::AppendFacesFromFontFile(const PRUnichar *aFileName)
{
char fileName[MAX_PATH];
WideCharToMultiByte(CP_ACP, 0, aFileName, -1, fileName, MAX_PATH, NULL, NULL);
FT_Library ftLibrary = gfxWindowsPlatform::GetPlatform()->GetFTLibrary();
FT_Face dummy;
if (FT_Err_Ok == FT_New_Face(ftLibrary, fileName, -1, &dummy)) {
for (FT_Long i = 0; i < dummy->num_faces; i++) {
FT_Face face;
if (FT_Err_Ok != FT_New_Face(ftLibrary, fileName, i, &face))
continue;
FontEntry* fe = FontEntry::CreateFontEntryFromFace(face);
if (fe) {
NS_ConvertUTF8toUTF16 name(face->family_name);
BuildKeyNameFromFontName(name);
gfxFontFamily *family = mFontFamilies.GetWeak(name);
if (!family) {
family = new gfxFontFamily(name);
mFontFamilies.Put(name, family);
}
family->AddFontEntry(fe);
family->SetHasStyles(PR_TRUE);
#ifdef PR_LOGGING
if (LOG_ENABLED()) {
LOG(("(fontinit) added (%s) to family (%s)"
" with style: %s weight: %d stretch: %d",
NS_ConvertUTF16toUTF8(fe->Name()).get(),
NS_ConvertUTF16toUTF8(family->Name()).get(),
fe->IsItalic() ? "italic" : "normal",
fe->Weight(), fe->Stretch()));
}
#endif
}
}
FT_Done_Face(dummy);
}
}
void
gfxFT2FontList::FindFonts()
{
nsTArray<nsString> searchPaths(3);
nsTArray<nsString> fontPatterns(3);
fontPatterns.AppendElement(NS_LITERAL_STRING("\\*.ttf"));
fontPatterns.AppendElement(NS_LITERAL_STRING("\\*.ttc"));
fontPatterns.AppendElement(NS_LITERAL_STRING("\\*.otf"));
wchar_t pathBuf[256];
SHGetSpecialFolderPathW(0, pathBuf, CSIDL_WINDOWS, 0);
searchPaths.AppendElement(pathBuf);
SHGetSpecialFolderPathW(0, pathBuf, CSIDL_FONTS, 0);
searchPaths.AppendElement(pathBuf);
nsCOMPtr<nsIFile> resDir;
NS_GetSpecialDirectory(NS_APP_RES_DIR, getter_AddRefs(resDir));
if (resDir) {
resDir->Append(NS_LITERAL_STRING("fonts"));
nsAutoString resPath;
resDir->GetPath(resPath);
searchPaths.AppendElement(resPath);
}
WIN32_FIND_DATAW results;
for (PRUint32 i = 0; i < searchPaths.Length(); i++) {
const nsString& path(searchPaths[i]);
for (PRUint32 j = 0; j < fontPatterns.Length(); j++) {
nsAutoString pattern(path);
pattern.Append(fontPatterns[j]);
HANDLE handle = FindFirstFileExW(pattern.get(),
FindExInfoStandard,
&results,
FindExSearchNameMatch,
NULL,
0);
PRBool moreFiles = handle != INVALID_HANDLE_VALUE;
while (moreFiles) {
nsAutoString filePath(path);
filePath.AppendLiteral("\\");
filePath.Append(results.cFileName);
AppendFacesFromFontFile(static_cast<const PRUnichar*>(filePath.get()));
moreFiles = FindNextFile(handle, &results);
}
if (handle != INVALID_HANDLE_VALUE)
FindClose(handle);
}
}
}
void
gfxFT2FontList::InitFontList()
{
mFontFamilies.Clear();
mOtherFamilyNames.Clear();
mOtherFamilyNamesInitialized = PR_FALSE;
mPrefFonts.Clear();
CancelLoader();
// initialize ranges of characters for which system-wide font search should be skipped
mCodepointsWithNoFonts.reset();
mCodepointsWithNoFonts.SetRange(0,0x1f); // C0 controls
mCodepointsWithNoFonts.SetRange(0x7f,0x9f); // C1 controls
FindFonts();
InitBadUnderlineList();
}
struct FullFontNameSearch {
FullFontNameSearch(const nsAString& aFullName)
: mFullName(aFullName), mFontEntry(nsnull)
{ }
nsString mFullName;
gfxFontEntry *mFontEntry;
};
// callback called for each family name, based on the assumption that the
// first part of the full name is the family name
static PLDHashOperator
FindFullName(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& 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)) {
nsTArray<nsRefPtr<gfxFontEntry> >& fontList = aFontFamily->GetFontList();
int index, len = fontList.Length();
for (index = 0; index < len; index++) {
if (fontList[index]->Name().Equals(data->mFullName)) {
data->mFontEntry = fontList[index];
return PL_DHASH_STOP;
}
}
}
return PL_DHASH_NEXT;
}
gfxFontEntry*
gfxFT2FontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
const nsAString& aFontName)
{
// walk over list of names
FullFontNameSearch data(aFontName);
mFontFamilies.Enumerate(FindFullName, &data);
return data.mFontEntry;
}
gfxFontEntry*
gfxFT2FontList::GetDefaultFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold)
{
#ifdef XP_WIN
HGDIOBJ hGDI = ::GetStockObject(SYSTEM_FONT);
LOGFONTW logFont;
if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont)) {
nsAutoString resolvedName;
if (ResolveFontName(nsDependentString(logFont.lfFaceName), resolvedName)) {
return FindFontForFamily(resolvedName, aStyle, aNeedsBold);
}
}
#endif
/* TODO: what about Qt or other platforms that may use this? */
return nsnull;
}
gfxFontEntry*
gfxFT2FontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
const PRUint8 *aFontData,
PRUint32 aLength)
{
// The FT2 font needs the font data to persist, so we do NOT free it here
// but instead pass ownership to the font entry.
// Deallocation will happen later, when the font face is destroyed.
return FontEntry::CreateFontEntry(*aProxyEntry, aFontData, aLength);
}

View File

@ -0,0 +1,72 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Corporation code.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <stuart@mozilla.com>
* Masayuki Nakano <masayuki@d-toybox.com>
* John Daggett <jdaggett@mozilla.com>
* Jonathan Kew <jfkthame@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef GFX_FT2FONTLIST_H
#define GFX_FT2FONTLIST_H
#include "gfxWindowsPlatform.h"
#include "gfxPlatformFontList.h"
#include <windows.h>
#include <bitset>
class gfxFT2FontList : public gfxPlatformFontList
{
public:
gfxFT2FontList();
virtual gfxFontEntry* GetDefaultFont(const gfxFontStyle* aStyle,
PRBool& aNeedsBold);
virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
const nsAString& aFontName);
virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
const PRUint8 *aFontData,
PRUint32 aLength);
protected:
virtual void InitFontList();
void AppendFacesFromFontFile(const PRUnichar *aFileName);
void FindFonts();
};
#endif /* GFX_FT2FONTLIST_H */

View File

@ -47,6 +47,7 @@
#endif
#include "gfxWindowsPlatform.h"
#define gfxToolkitPlatform gfxWindowsPlatform
#include "gfxFT2FontList.h"
#endif
#include "gfxTypes.h"
#include "gfxFT2Fonts.h"
@ -485,7 +486,7 @@ AddFontNameToArray(const nsAString& aName,
void
gfxFT2FontGroup::FamilyListToArrayList(const nsString& aFamilies,
const nsCString& aLangGroup,
nsTArray<nsRefPtr<FontEntry> > *aFontEntryList)
nsTArray<nsRefPtr<gfxFontEntry> > *aFontEntryList)
{
nsAutoTArray<nsString, 15> fonts;
ForEachFont(aFamilies, aLangGroup, AddFontNameToArray, &fonts);
@ -493,15 +494,15 @@ gfxFT2FontGroup::FamilyListToArrayList(const nsString& aFamilies,
PRUint32 len = fonts.Length();
for (PRUint32 i = 0; i < len; ++i) {
const nsString& str = fonts[i];
nsRefPtr<FontEntry> fe = gfxToolkitPlatform::GetPlatform()->FindFontEntry(str, mStyle);
nsRefPtr<gfxFontEntry> fe = (gfxToolkitPlatform::GetPlatform()->FindFontEntry(str, mStyle));
aFontEntryList->AppendElement(fe);
}
}
void gfxFT2FontGroup::GetPrefFonts(const char *aLangGroup, nsTArray<nsRefPtr<FontEntry> >& aFontEntryList) {
void gfxFT2FontGroup::GetPrefFonts(const char *aLangGroup, nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList) {
NS_ASSERTION(aLangGroup, "aLangGroup is null");
gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform();
nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts;
nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts;
/* this lookup has to depend on weight and style */
nsCAutoString key(aLangGroup);
key.Append("-");
@ -532,7 +533,7 @@ static PRInt32 GetCJKLangGroupIndex(const char *aLangGroup) {
}
// this function assigns to the array passed in.
void gfxFT2FontGroup::GetCJKPrefFonts(nsTArray<nsRefPtr<FontEntry> >& aFontEntryList) {
void gfxFT2FontGroup::GetCJKPrefFonts(nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList) {
gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform();
nsCAutoString key("x-internal-cjk-");
@ -622,13 +623,13 @@ void gfxFT2FontGroup::GetCJKPrefFonts(nsTArray<nsRefPtr<FontEntry> >& aFontEntry
}
already_AddRefed<gfxFT2Font>
gfxFT2FontGroup::WhichFontSupportsChar(const nsTArray<nsRefPtr<FontEntry> >& aFontEntryList, PRUint32 aCh)
gfxFT2FontGroup::WhichFontSupportsChar(const nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList, PRUint32 aCh)
{
for (PRUint32 i = 0; i < aFontEntryList.Length(); i++) {
nsRefPtr<FontEntry> fe = aFontEntryList[i];
gfxFontEntry *fe = aFontEntryList[i].get();
if (fe->HasCharacter(aCh)) {
nsRefPtr<gfxFT2Font> font =
gfxFT2Font::GetOrMakeFont(fe, &mStyle);
gfxFT2Font::GetOrMakeFont(static_cast<FontEntry*>(fe), &mStyle);
return font.forget();
}
}
@ -644,7 +645,7 @@ gfxFT2FontGroup::WhichPrefFontSupportsChar(PRUint32 aCh)
nsRefPtr<gfxFT2Font> selectedFont;
// check out the style's language group
nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts;
nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts;
GetPrefFonts(mStyle.langGroup.get(), fonts);
selectedFont = WhichFontSupportsChar(fonts, aCh);
@ -658,7 +659,7 @@ gfxFT2FontGroup::WhichPrefFontSupportsChar(PRUint32 aCh)
PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Trying to find fonts for: CJK"));
}
nsAutoTArray<nsRefPtr<FontEntry>, 15> fonts;
nsAutoTArray<nsRefPtr<gfxFontEntry>, 15> fonts;
GetCJKPrefFonts(fonts);
selectedFont = WhichFontSupportsChar(fonts, aCh);
} else {
@ -666,7 +667,7 @@ gfxFT2FontGroup::WhichPrefFontSupportsChar(PRUint32 aCh)
if (langGroup) {
PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Trying to find fonts for: %s", langGroup));
nsAutoTArray<nsRefPtr<FontEntry>, 5> fonts;
nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts;
GetPrefFonts(langGroup, fonts);
selectedFont = WhichFontSupportsChar(fonts, aCh);
}
@ -684,12 +685,22 @@ gfxFT2FontGroup::WhichPrefFontSupportsChar(PRUint32 aCh)
already_AddRefed<gfxFont>
gfxFT2FontGroup::WhichSystemFontSupportsChar(PRUint32 aCh)
{
#ifdef XP_WIN
FontEntry *fe = static_cast<FontEntry*>
(gfxPlatformFontList::PlatformFontList()->FindFontForChar(aCh, GetFontAt(0)));
if (fe) {
nsRefPtr<gfxFT2Font> f = gfxFT2Font::GetOrMakeFont(fe, &mStyle);
nsRefPtr<gfxFont> font = f.get();
return font.forget();
}
#else
nsRefPtr<gfxFont> selectedFont;
nsRefPtr<gfxFT2Font> refFont = GetFontAt(0);
gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform();
selectedFont = platform->FindFontForChar(aCh, refFont);
if (selectedFont)
return selectedFont.forget();
#endif
return nsnull;
}
@ -881,7 +892,8 @@ CreateScaledFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle)
already_AddRefed<gfxFT2Font>
gfxFT2Font::GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle)
{
FontEntry *fe = gfxToolkitPlatform::GetPlatform()->FindFontEntry(aName, *aStyle);
FontEntry *fe = static_cast<FontEntry*>
(gfxToolkitPlatform::GetPlatform()->FindFontEntry(aName, *aStyle));
if (!fe) {
NS_WARNING("Failed to find font entry for font!");
return nsnull;

View File

@ -0,0 +1,961 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Corporation code.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <stuart@mozilla.com>
* Masayuki Nakano <masayuki@d-toybox.com>
* Mats Palmgren <mats.palmgren@bredband.net>
* John Daggett <jdaggett@mozilla.com>
* Jonathan Kew <jfkthame@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "gfxGDIFontList.h"
#include "gfxWindowsPlatform.h"
#include "gfxUserFontSet.h"
#include "gfxFontUtils.h"
#include "gfxWindowsFonts.h"
#include "nsIPref.h" // for pref changes callback notification
#include "nsServiceManagerUtils.h"
#include "nsTArray.h"
#include "nsUnicharUtils.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsISimpleEnumerator.h"
#include "nsIWindowsRegKey.h"
#define ROUND(x) floor((x) + 0.5)
#ifdef PR_LOGGING
static PRLogModuleInfo *gFontInfoLog = PR_NewLogModule("fontInfoLog");
#endif /* PR_LOGGING */
#define LOG(args) PR_LOG(gFontInfoLog, PR_LOG_DEBUG, args)
#define LOG_ENABLED() PR_LOG_TEST(gFontInfoLog, PR_LOG_DEBUG)
// font info loader constants
static const PRUint32 kDelayBeforeLoadingFonts = 8 * 1000; // 8secs
static const PRUint32 kIntervalBetweenLoadingFonts = 150; // 150ms
static __inline void
BuildKeyNameFromFontName(nsAString &aName)
{
if (aName.Length() >= LF_FACESIZE)
aName.Truncate(LF_FACESIZE - 1);
ToLowerCase(aName);
}
// Implementation of gfxPlatformFontList for Win32 GDI,
// using GDI font enumeration APIs to get the list of fonts
// 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
(
HANDLE* phFontReference, // on completion, contains handle to identify embedded font installed
// on system
ULONG ulFlags, // flags specifying the request
ULONG* pulPrivStatus, // on completion, contains the embedding status
ULONG ulPrivs, // allows for the reduction of licensing privileges
ULONG* pulStatus, // on completion, may contain status flags for request
READEMBEDPROC lpfnReadFromStream, // callback function for doc/disk reads
LPVOID lpvReadStream, // the input stream tokin
LPWSTR szWinFamilyName, // the new 16 bit windows family name can be NULL
LPSTR szMacFamilyName, // the new 8 bit mac family name can be NULL
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;
class WinUserFontData : public gfxUserFontData {
public:
WinUserFontData(HANDLE aFontRef, PRBool aIsCFF)
: mFontRef(aFontRef), mIsCFF(aIsCFF)
{ }
virtual ~WinUserFontData()
{
if (mIsCFF) {
RemoveFontMemResourceEx(mFontRef);
} else {
ULONG pulStatus;
TTDeleteEmbeddedFontPtr(mFontRef, 0, &pulStatus);
}
}
HANDLE mFontRef;
PRPackedBool mIsCFF;
};
BYTE
FontTypeToOutPrecision(PRUint8 fontType)
{
BYTE ret;
switch (fontType) {
case GFX_FONT_TYPE_TT_OPENTYPE:
case GFX_FONT_TYPE_TRUETYPE:
ret = OUT_TT_ONLY_PRECIS;
break;
case GFX_FONT_TYPE_PS_OPENTYPE:
ret = OUT_PS_ONLY_PRECIS;
break;
case GFX_FONT_TYPE_TYPE1:
ret = OUT_OUTLINE_PRECIS;
break;
case GFX_FONT_TYPE_RASTER:
ret = OUT_RASTER_PRECIS;
break;
case GFX_FONT_TYPE_DEVICE:
ret = OUT_DEVICE_PRECIS;
break;
default:
ret = OUT_DEFAULT_PRECIS;
}
return ret;
}
/***************************************************************
*
* GDIFontEntry
*
*/
GDIFontEntry::GDIFontEntry(const nsAString& aFaceName, gfxWindowsFontType aFontType,
PRBool aItalic, PRUint16 aWeight, gfxUserFontData *aUserFontData) :
gfxFontEntry(aFaceName), mFontType(aFontType),
mForceGDI(PR_FALSE), mUnknownCMAP(PR_FALSE),
mUnicodeFont(PR_FALSE),
mCharset(), mUnicodeRanges()
{
mUserFontData = aUserFontData;
mItalic = aItalic;
mWeight = aWeight;
if (IsType1())
mForceGDI = PR_TRUE;
mIsUserFont = aUserFontData != nsnull;
InitLogFont(aFaceName, aFontType);
}
nsresult
GDIFontEntry::ReadCMAP()
{
// attempt this once, if errors occur leave a blank cmap
if (mCmapInitialized)
return NS_OK;
mCmapInitialized = PR_TRUE;
const PRUint32 kCmapTag = TRUETYPE_TAG('c','m','a','p');
nsAutoTArray<PRUint8,16384> buffer;
if (GetFontTable(kCmapTag, buffer) != NS_OK)
return NS_ERROR_FAILURE;
PRUint8 *cmap = buffer.Elements();
PRPackedBool unicodeFont = PR_FALSE, symbolFont = PR_FALSE;
nsresult rv = gfxFontUtils::ReadCMAP(cmap, buffer.Length(),
mCharacterMap, unicodeFont, symbolFont);
mUnicodeFont = unicodeFont;
mSymbolFont = symbolFont;
PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit-cmap) psname: %s, size: %d\n",
NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.GetSize()));
return rv;
}
nsresult
GDIFontEntry::GetFontTable(PRUint32 aTableTag, nsTArray<PRUint8>& aBuffer)
{
AutoDC dc;
AutoSelectFont font(dc.GetDC(), &mLogFont);
if (font.IsValid()) {
PRInt32 tableSize = ::GetFontData(dc.GetDC(), NS_SWAP32(aTableTag), 0, NULL, NULL);
if (tableSize != GDI_ERROR) {
if (aBuffer.SetLength(tableSize)) {
::GetFontData(dc.GetDC(), NS_SWAP32(aTableTag), 0, aBuffer.Elements(), tableSize);
return NS_OK;
}
return NS_ERROR_OUT_OF_MEMORY;
}
}
return NS_ERROR_FAILURE;
}
void
GDIFontEntry::FillLogFont(LOGFONTW *aLogFont, PRBool aItalic,
PRUint16 aWeight, gfxFloat aSize)
{
memcpy(aLogFont, &mLogFont, sizeof(LOGFONTW));
aLogFont->lfHeight = (LONG)-ROUND(aSize);
if (aLogFont->lfHeight == 0)
aLogFont->lfHeight = -1;
// 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 = aWeight;
}
PRBool
GDIFontEntry::TestCharacterMap(PRUint32 aCh)
{
if (ReadCMAP() != NS_OK) {
// Type1 fonts aren't necessarily Unicode but
// this is the best guess we can make here
mUnicodeFont = IsType1();
// For fonts where we failed to read the character map,
// we can take a slow path to look up glyphs character by character
mUnknownCMAP = PR_TRUE;
}
if (mUnknownCMAP) {
if (aCh > 0xFFFF)
return PR_FALSE;
// previous code was using the group style
gfxFontStyle fakeStyle;
if (mItalic)
fakeStyle.style = FONT_STYLE_ITALIC;
fakeStyle.weight = mWeight * 100;
nsRefPtr<gfxWindowsFont> font =
gfxWindowsFont::GetOrMakeFont(this, &fakeStyle);
if (!font->IsValid())
return PR_FALSE;
HDC dc = GetDC((HWND)nsnull);
SetGraphicsMode(dc, GM_ADVANCED);
HFONT hfont = font->GetHFONT();
HFONT oldFont = (HFONT)SelectObject(dc, hfont);
PRUnichar str[1] = { (PRUnichar)aCh };
WORD glyph[1];
PRBool hasGlyph = PR_FALSE;
if (IsType1()) {
// Type1 fonts and uniscribe APIs don't get along. ScriptGetCMap will return E_HANDLE
DWORD ret = GetGlyphIndicesW(dc, str, 1, glyph, GGI_MARK_NONEXISTING_GLYPHS);
if (ret != GDI_ERROR && glyph[0] != 0xFFFF)
hasGlyph = PR_TRUE;
} else {
// ScriptGetCMap works better than GetGlyphIndicesW for things like bitmap/vector fonts
HRESULT rv = ScriptGetCMap(dc, font->ScriptCache(), str, 1, 0, glyph);
if (rv == S_OK)
hasGlyph = PR_TRUE;
}
SelectObject(dc, oldFont);
ReleaseDC(NULL, dc);
if (hasGlyph) {
mCharacterMap.set(aCh);
return PR_TRUE;
}
} else {
// font had a cmap so simply check that
return mCharacterMap.test(aCh);
}
return PR_FALSE;
}
void
GDIFontEntry::InitLogFont(const nsAString& aName,
gfxWindowsFontType aFontType)
{
#define CLIP_TURNOFF_FONTASSOCIATION 0x40
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(aFontType);
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 = mItalic;
mLogFont.lfWeight = mWeight;
int len = PR_MIN(aName.Length(), LF_FACESIZE - 1);
memcpy(&mLogFont.lfFaceName, nsPromiseFlatString(aName).get(), len * 2);
mLogFont.lfFaceName[len] = '\0';
}
GDIFontEntry*
GDIFontEntry::CreateFontEntry(const nsAString& aName, gfxWindowsFontType aFontType,
PRBool aItalic, PRUint16 aWeight,
gfxUserFontData* aUserFontData)
{
// jtdfix - need to set charset, unicode ranges, pitch/family
GDIFontEntry *fe = new GDIFontEntry(aName, aFontType, aItalic, aWeight,
aUserFontData);
// ReadCMAP may change the values of mUnicodeFont and mSymbolFont
if (NS_FAILED(fe->ReadCMAP())) {
// 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;
}
return fe;
}
/***************************************************************
*
* GDIFontFamily
*
*/
int CALLBACK
GDIFontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
const NEWTEXTMETRICEXW *nmetrics,
DWORD fontType, LPARAM data)
{
const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
LOGFONTW logFont = lpelfe->elfLogFont;
GDIFontFamily *ff = reinterpret_cast<GDIFontFamily*>(data);
// 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 = GDIFontEntry::DetermineFontType(metrics, fontType);
GDIFontEntry *fe = nsnull;
for (PRUint32 i = 0; i < ff->mAvailableFonts.Length(); ++i) {
fe = static_cast<GDIFontEntry*>(ff->mAvailableFonts[i].get());
if (feType > fe->mFontType) {
// if the new type is better than the old one, remove the old entries
ff->mAvailableFonts.RemoveElementAt(i);
--i;
} else if (feType < fe->mFontType) {
// otherwise if the new type is worse, skip it
return 1;
}
}
for (PRUint32 i = 0; i < ff->mAvailableFonts.Length(); ++i) {
fe = static_cast<GDIFontEntry*>(ff->mAvailableFonts[i].get());
// check if we already know about this face
if (fe->mWeight == logFont.lfWeight &&
fe->mItalic == (logFont.lfItalic == 0xFF)) {
// update the charset bit here since this could be different
fe->mCharset[metrics.tmCharSet] = 1;
return 1;
}
}
fe = GDIFontEntry::CreateFontEntry(ff->mName, feType, (logFont.lfItalic == 0xFF),
(PRUint16) (logFont.lfWeight), nsnull);
if (!fe)
return 1;
ff->mAvailableFonts.AppendElement(fe);
// mark the charset bit
fe->mCharset[metrics.tmCharSet] = 1;
fe->mWindowsFamily = logFont.lfPitchAndFamily & 0xF0;
fe->mWindowsPitch = logFont.lfPitchAndFamily & 0x0F;
if (nmetrics->ntmFontSig.fsUsb[0] != 0x00000000 &&
nmetrics->ntmFontSig.fsUsb[1] != 0x00000000 &&
nmetrics->ntmFontSig.fsUsb[2] != 0x00000000 &&
nmetrics->ntmFontSig.fsUsb[3] != 0x00000000) {
// set the unicode ranges
PRUint32 x = 0;
for (PRUint32 i = 0; i < 4; ++i) {
DWORD range = nmetrics->ntmFontSig.fsUsb[i];
for (PRUint32 k = 0; k < 32; ++k) {
fe->mUnicodeRanges[x++] = (range & (1 << k)) != 0;
}
}
}
#ifdef PR_LOGGING
if (LOG_ENABLED()) {
LOG(("(fontinit) added (%s) to family (%s)"
" with style: %s weight: %d stretch: %d",
NS_ConvertUTF16toUTF8(fe->Name()).get(),
NS_ConvertUTF16toUTF8(ff->Name()).get(),
(logFont.lfItalic == 0xff) ? "italic" : "normal",
logFont.lfWeight, fe->Stretch()));
}
#endif
return 1;
}
void
GDIFontFamily::FindStyleVariations()
{
if (mHasStyles)
return;
mHasStyles = PR_TRUE;
HDC hdc = GetDC(nsnull);
SetGraphicsMode(hdc, GM_ADVANCED);
LOGFONTW logFont;
memset(&logFont, 0, sizeof(LOGFONTW));
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfPitchAndFamily = 0;
PRUint32 l = PR_MIN(mName.Length(), LF_FACESIZE - 1);
memcpy(logFont.lfFaceName,
nsPromiseFlatString(mName).get(),
l * sizeof(PRUnichar));
logFont.lfFaceName[l] = 0;
EnumFontFamiliesExW(hdc, &logFont,
(FONTENUMPROCW)GDIFontFamily::FamilyAddStylesProc,
(LPARAM)this, 0);
#ifdef DEBUG
if (mAvailableFonts.Length() == 0) {
char msgBuf[256];
(void)sprintf(msgBuf, "no styles available in family \"%s\"",
NS_ConvertUTF16toUTF8(mName).get());
NS_ASSERTION(mAvailableFonts.Length() != 0, msgBuf);
}
#endif
ReleaseDC(nsnull, hdc);
if (mIsBadUnderlineFamily)
SetBadUnderlineFonts();
}
/***************************************************************
*
* gfxGDIFontList
*
*/
gfxGDIFontList::gfxGDIFontList()
{
mFontSubstitutes.Init(50);
InitializeFontEmbeddingProcs();
}
static void
RemoveCharsetFromFontSubstitute(nsAString &aName)
{
PRInt32 comma = aName.FindChar(PRUnichar(','));
if (comma >= 0)
aName.Truncate(comma);
}
nsresult
gfxGDIFontList::GetFontSubstitutes()
{
// Create the list of FontSubstitutes
nsCOMPtr<nsIWindowsRegKey> regKey = do_CreateInstance("@mozilla.org/windows-registry-key;1");
if (!regKey)
return NS_ERROR_FAILURE;
NS_NAMED_LITERAL_STRING(kFontSubstitutesKey, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes");
nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
kFontSubstitutesKey, nsIWindowsRegKey::ACCESS_READ);
if (NS_FAILED(rv))
return rv;
PRUint32 count;
rv = regKey->GetValueCount(&count);
if (NS_FAILED(rv) || count == 0)
return rv;
for (PRUint32 i = 0; i < count; i++) {
nsAutoString substituteName;
rv = regKey->GetValueName(i, substituteName);
if (NS_FAILED(rv) || substituteName.IsEmpty() || substituteName.CharAt(1) == PRUnichar('@'))
continue;
PRUint32 valueType;
rv = regKey->GetValueType(substituteName, &valueType);
if (NS_FAILED(rv) || valueType != nsIWindowsRegKey::TYPE_STRING)
continue;
nsAutoString actualFontName;
rv = regKey->ReadStringValue(substituteName, actualFontName);
if (NS_FAILED(rv))
continue;
RemoveCharsetFromFontSubstitute(substituteName);
BuildKeyNameFromFontName(substituteName);
RemoveCharsetFromFontSubstitute(actualFontName);
BuildKeyNameFromFontName(actualFontName);
gfxFontFamily *ff;
if (!actualFontName.IsEmpty() && (ff = mFontFamilies.GetWeak(actualFontName))) {
mFontSubstitutes.Put(substituteName, ff);
} else {
mNonExistingFonts.AppendElement(substituteName);
}
}
return NS_OK;
}
void
gfxGDIFontList::InitFontList()
{
gfxFontCache *fc = gfxFontCache::GetCache();
if (fc)
fc->AgeAllGenerations();
mFontFamilies.Clear();
mOtherFamilyNames.Clear();
mOtherFamilyNamesInitialized = PR_FALSE;
mPrefFonts.Clear();
mFontSubstitutes.Clear();
mNonExistingFonts.Clear();
CancelLoader();
// initialize ranges of characters for which system-wide font search should be skipped
mCodepointsWithNoFonts.reset();
mCodepointsWithNoFonts.SetRange(0,0x1f); // C0 controls
mCodepointsWithNoFonts.SetRange(0x7f,0x9f); // C1 controls
// iterate over available families
LOGFONTW logfont;
memset(&logfont, 0, sizeof(logfont));
logfont.lfCharSet = DEFAULT_CHARSET;
AutoDC hdc;
int result = EnumFontFamiliesExW(hdc.GetDC(), &logfont,
(FONTENUMPROCW)&EnumFontFamExProc,
0, 0);
GetFontSubstitutes();
InitBadUnderlineList();
StartLoader(kDelayBeforeLoadingFonts, kIntervalBetweenLoadingFonts);
}
int CALLBACK
gfxGDIFontList::EnumFontFamExProc(ENUMLOGFONTEXW *lpelfe,
NEWTEXTMETRICEXW *lpntme,
DWORD fontType,
LPARAM lParam)
{
const LOGFONTW& lf = lpelfe->elfLogFont;
if (lf.lfFaceName[0] == '@') {
return 1;
}
nsAutoString name(lf.lfFaceName);
BuildKeyNameFromFontName(name);
gfxGDIFontList *fontList = PlatformFontList();
if (!fontList->mFontFamilies.GetWeak(name)) {
nsRefPtr<gfxFontFamily> family = new GDIFontFamily(nsDependentString(lf.lfFaceName));
fontList->mFontFamilies.Put(name, family);
}
return 1;
}
gfxFontEntry*
gfxGDIFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
const nsAString& aFullname)
{
LOGFONTW logFont;
memset(&logFont, 0, sizeof(LOGFONTW));
logFont.lfCharSet = DEFAULT_CHARSET;
PRUint32 namelen = PR_MIN(aFullname.Length(), LF_FACESIZE - 1);
::memcpy(logFont.lfFaceName,
nsPromiseFlatString(aFullname).get(),
namelen * sizeof(PRUnichar));
logFont.lfFaceName[namelen] = 0;
AutoDC dc;
::SetGraphicsMode(dc.GetDC(), GM_ADVANCED);
AutoSelectFont font(dc.GetDC(), &logFont);
if (!font.IsValid())
return nsnull;
// fetch fullname from name table (Windows takes swapped tag order)
const PRUint32 kNameTag = NS_SWAP32(TRUETYPE_TAG('n','a','m','e'));
nsAutoString fullName;
{
DWORD len = ::GetFontData(dc.GetDC(), kNameTag, 0, nsnull, 0);
if (len == GDI_ERROR || len == 0) // not a truetype font --
return nsnull; // so just ignore
nsAutoTArray<PRUint8,1024> nameData;
if (!nameData.AppendElements(len))
return nsnull;
PRUint8 *nameTable = nameData.Elements();
DWORD newLen = ::GetFontData(dc.GetDC(), kNameTag, 0, nameTable, len);
if (newLen != len)
return nsnull;
nsresult rv;
rv = gfxFontUtils::ReadCanonicalName(nameData,
gfxFontUtils::NAME_ID_FULL,
fullName);
if (NS_FAILED(rv))
return nsnull;
}
// reject if different from canonical fullname
if (!aFullname.Equals(fullName))
return nsnull;
// create a new font entry
PRUint16 w = (aProxyEntry->mWeight == 0 ? 400 : aProxyEntry->mWeight);
PRBool isCFF = PR_FALSE; // jtdfix -- need to determine this
gfxFontEntry *fe = GDIFontEntry::CreateFontEntry(aFullname,
gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/,
PRUint32(aProxyEntry->mItalic ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL),
w, nsnull);
if (!fe)
return fe;
fe->mIsUserFont = PR_TRUE;
return fe;
}
void gfxGDIFontList::InitializeFontEmbeddingProcs()
{
HMODULE fontlib = LoadLibraryW(L"t2embed.dll");
if (!fontlib)
return;
TTLoadEmbeddedFontPtr = (TTLoadEmbeddedFontProc) GetProcAddress(fontlib, "TTLoadEmbeddedFont");
TTDeleteEmbeddedFontPtr = (TTDeleteEmbeddedFontProc) GetProcAddress(fontlib, "TTDeleteEmbeddedFont");
}
// used to control stream read by Windows TTLoadEmbeddedFont API
class EOTFontStreamReader {
public:
EOTFontStreamReader(const PRUint8 *aFontData, PRUint32 aLength, PRUint8 *aEOTHeader,
PRUint32 aEOTHeaderLen, FontDataOverlay *aNameOverlay)
: mCurrentChunk(0), mChunkOffset(0)
{
NS_ASSERTION(aFontData, "null font data ptr passed in");
NS_ASSERTION(aEOTHeader, "null EOT header ptr passed in");
NS_ASSERTION(aNameOverlay, "null name overlay struct passed in");
if (aNameOverlay->overlaySrc) {
mNumChunks = 4;
// 0 : EOT header
mDataChunks[0].mData = aEOTHeader;
mDataChunks[0].mLength = aEOTHeaderLen;
// 1 : start of font data to overlayDest
mDataChunks[1].mData = aFontData;
mDataChunks[1].mLength = aNameOverlay->overlayDest;
// 2 : overlay data
mDataChunks[2].mData = aFontData + aNameOverlay->overlaySrc;
mDataChunks[2].mLength = aNameOverlay->overlaySrcLen;
// 3 : rest of font data
mDataChunks[3].mData = aFontData + aNameOverlay->overlayDest + aNameOverlay->overlaySrcLen;
mDataChunks[3].mLength = aLength - aNameOverlay->overlayDest - aNameOverlay->overlaySrcLen;
} else {
mNumChunks = 2;
// 0 : EOT header
mDataChunks[0].mData = aEOTHeader;
mDataChunks[0].mLength = aEOTHeaderLen;
// 1 : font data
mDataChunks[1].mData = aFontData;
mDataChunks[1].mLength = aLength;
}
}
~EOTFontStreamReader()
{
}
struct FontDataChunk {
const PRUint8 *mData;
PRUint32 mLength;
};
PRUint32 mNumChunks;
FontDataChunk mDataChunks[4];
PRUint32 mCurrentChunk;
PRUint32 mChunkOffset;
unsigned long Read(void *outBuffer, const unsigned long aBytesToRead)
{
PRUint32 bytesLeft = aBytesToRead; // bytes left in the out buffer
PRUint8 *out = static_cast<PRUint8*> (outBuffer);
while (mCurrentChunk < mNumChunks && bytesLeft) {
FontDataChunk& currentChunk = mDataChunks[mCurrentChunk];
PRUint32 bytesToCopy = PR_MIN(bytesLeft,
currentChunk.mLength - mChunkOffset);
memcpy(out, currentChunk.mData + mChunkOffset, bytesToCopy);
bytesLeft -= bytesToCopy;
mChunkOffset += bytesToCopy;
out += bytesToCopy;
NS_ASSERTION(mChunkOffset <= currentChunk.mLength, "oops, buffer overrun");
if (mChunkOffset == currentChunk.mLength) {
mCurrentChunk++;
mChunkOffset = 0;
}
}
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*
gfxGDIFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
const PRUint8 *aFontData,
PRUint32 aLength)
{
// MakePlatformFont is responsible for deleting the font data with NS_Free
// so we set up a stack object to ensure it is freed even if we take an
// early exit
struct FontDataDeleter {
FontDataDeleter(const PRUint8 *aFontData)
: mFontData(aFontData) { }
~FontDataDeleter() { NS_Free((void*)mFontData); }
const PRUint8 *mFontData;
};
FontDataDeleter autoDelete(aFontData);
// if calls aren't available, bail
if (!TTLoadEmbeddedFontPtr || !TTDeleteEmbeddedFontPtr)
return nsnull;
PRBool isCFF = gfxFontUtils::IsCffFont(aFontData);
nsresult rv;
HANDLE fontRef = nsnull;
PRBool isEmbedded = PR_FALSE;
nsAutoString uniqueName;
rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName);
if (NS_FAILED(rv))
return nsnull;
// for TTF fonts, first try using the t2embed library
if (!isCFF) {
// TrueType-style glyphs, use EOT library
nsAutoTArray<PRUint8,2048> eotHeader;
PRUint8 *buffer;
PRUint32 eotlen;
isEmbedded = PR_TRUE;
PRUint32 nameLen = PR_MIN(uniqueName.Length(), LF_FACESIZE - 1);
nsPromiseFlatString fontName(Substring(uniqueName, 0, nameLen));
FontDataOverlay overlayNameData = {0, 0, 0};
rv = gfxFontUtils::MakeEOTHeader(aFontData, aLength, &eotHeader,
&overlayNameData);
if (NS_FAILED(rv))
return nsnull;
// load in embedded font data
eotlen = eotHeader.Length();
buffer = reinterpret_cast<PRUint8*> (eotHeader.Elements());
PRInt32 ret;
ULONG privStatus, pulStatus;
EOTFontStreamReader eotReader(aFontData, aLength, buffer, eotlen,
&overlayNameData);
ret = TTLoadEmbeddedFontPtr(&fontRef, TTLOAD_PRIVATE, &privStatus,
LICENSE_PREVIEWPRINT, &pulStatus,
EOTFontStreamReader::ReadEOTStream,
&eotReader, (PRUnichar*)(fontName.get()), 0, 0);
if (ret != E_NONE)
fontRef = nsnull;
}
// load CFF fonts or fonts that failed with t2embed loader
if (fontRef == nsnull) {
// Postscript-style glyphs, swizzle name table, load directly
nsTArray<PRUint8> newFontData;
isEmbedded = PR_FALSE;
rv = gfxFontUtils::RenameFont(uniqueName, aFontData, aLength, &newFontData);
if (NS_FAILED(rv))
return nsnull;
DWORD numFonts = 0;
PRUint8 *fontData = reinterpret_cast<PRUint8*> (newFontData.Elements());
PRUint32 fontLength = newFontData.Length();
NS_ASSERTION(fontData, "null font data after renaming");
// http://msdn.microsoft.com/en-us/library/ms533942(VS.85).aspx
// "A font that is added by AddFontMemResourceEx is always private
// to the process that made the call and is not enumerable."
fontRef = AddFontMemResourceEx(fontData, fontLength,
0 /* reserved */, &numFonts);
if (!fontRef)
return nsnull;
// only load fonts with a single face contained in the data
if (fontRef && numFonts != 1) {
RemoveFontMemResourceEx(fontRef);
return nsnull;
}
}
// make a new font entry using the unique name
WinUserFontData *winUserFontData = new WinUserFontData(fontRef, isCFF);
PRUint16 w = (aProxyEntry->mWeight == 0 ? 400 : aProxyEntry->mWeight);
GDIFontEntry *fe = GDIFontEntry::CreateFontEntry(uniqueName,
gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/,
PRUint32(aProxyEntry->mItalic ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL),
w, winUserFontData);
if (!fe)
return fe;
fe->mIsUserFont = PR_TRUE;
// Uniscribe doesn't place CFF fonts loaded privately via AddFontMemResourceEx
if (isCFF)
fe->mForceGDI = PR_TRUE;
return fe;
}
gfxFontEntry*
gfxGDIFontList::GetDefaultFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold)
{
// this really shouldn't fail to find a font....
HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT);
LOGFONTW logFont;
if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont)) {
nsAutoString resolvedName;
if (ResolveFontName(nsDependentString(logFont.lfFaceName), resolvedName)) {
return FindFontForFamily(resolvedName, aStyle, aNeedsBold);
}
}
// ...but just in case, try another approach as well
NONCLIENTMETRICSW ncm;
ncm.cbSize = sizeof(ncm);
BOOL status = ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
sizeof(ncm), &ncm, 0);
if (status) {
nsAutoString resolvedName;
if (ResolveFontName(nsDependentString(ncm.lfMessageFont.lfFaceName), resolvedName)) {
return FindFontForFamily(resolvedName, aStyle, aNeedsBold);
}
}
return nsnull;
}
PRBool
gfxGDIFontList::ResolveFontName(const nsAString& aFontName, nsAString& aResolvedFontName)
{
nsAutoString keyName(aFontName);
BuildKeyNameFromFontName(keyName);
nsRefPtr<gfxFontFamily> ff;
if (mFontSubstitutes.Get(keyName, &ff)) {
aResolvedFontName = ff->Name();
return PR_TRUE;
}
if (mNonExistingFonts.Contains(keyName))
return PR_FALSE;
if (gfxPlatformFontList::ResolveFontName(aFontName, aResolvedFontName))
return PR_TRUE;
return PR_FALSE;
}

View File

@ -0,0 +1,353 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Corporation code.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <stuart@mozilla.com>
* Masayuki Nakano <masayuki@d-toybox.com>
* John Daggett <jdaggett@mozilla.com>
* Jonathan Kew <jfkthame@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef GFX_GDIFONTLIST_H
#define GFX_GDIFONTLIST_H
#include "gfxWindowsPlatform.h"
#include "gfxPlatformFontList.h"
#include <windows.h>
#include <bitset>
class AutoDC // get the global device context, and auto-release it on destruction
{
public:
AutoDC() {
mDC = ::GetDC(NULL);
}
~AutoDC() {
::ReleaseDC(NULL, mDC);
}
HDC GetDC() {
return mDC;
}
private:
HDC mDC;
};
class AutoSelectFont // select a font into the given DC, and auto-restore
{
public:
AutoSelectFont(HDC aDC, LOGFONTW *aLogFont) {
mFont = ::CreateFontIndirectW(aLogFont);
if (mFont) {
mDC = aDC;
mOldFont = (HFONT)::SelectObject(aDC, mFont);
} else {
mOldFont = NULL;
}
}
AutoSelectFont(HDC aDC, HFONT aFont) {
mDC = aDC;
mFont = aFont;
mOldFont = (HFONT)::SelectObject(aDC, aFont);
}
~AutoSelectFont() {
if (mOldFont) {
::SelectObject(mDC, mOldFont);
}
}
PRBool IsValid() const {
return mFont != NULL;
}
HFONT GetFont() const {
return mFont;
}
private:
HDC mDC;
HFONT mFont;
HFONT mOldFont;
};
/**
* List of different types of fonts we support on Windows.
* These can generally be lumped in to 3 categories where we have to
* do special things: Really old fonts bitmap and vector fonts (device
* and raster), Type 1 fonts, and TrueType/OpenType fonts.
*
* This list is sorted in order from least prefered to most prefered.
* We prefer Type1 fonts over OpenType fonts to avoid falling back to
* things like Arial (opentype) when you ask for Helvetica (type1)
**/
enum gfxWindowsFontType {
GFX_FONT_TYPE_UNKNOWN = 0,
GFX_FONT_TYPE_DEVICE,
GFX_FONT_TYPE_RASTER,
GFX_FONT_TYPE_TRUETYPE,
GFX_FONT_TYPE_PS_OPENTYPE,
GFX_FONT_TYPE_TT_OPENTYPE,
GFX_FONT_TYPE_TYPE1
};
// A single member of a font family (i.e. a single face, such as Times Italic)
// represented as a LOGFONT that will resolve to the correct face.
// This replaces FontEntry from gfxWindowsFonts.h/cpp.
class GDIFontEntry : public gfxFontEntry
{
public:
LPLOGFONTW GetLogFont() { return &mLogFont; }
nsresult ReadCMAP();
void FillLogFont(LOGFONTW *aLogFont, PRBool aItalic,
PRUint16 aWeight, gfxFloat aSize);
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);
}
PRBool IsTrueType() const {
return (mFontType == GFX_FONT_TYPE_TRUETYPE ||
mFontType == GFX_FONT_TYPE_PS_OPENTYPE ||
mFontType == GFX_FONT_TYPE_TT_OPENTYPE);
}
PRBool IsCrappyFont() const {
/* return if it is a bitmap not a unicode font */
return (!mUnicodeFont || IsSymbolFont() || IsType1());
}
PRBool MatchesGenericFamily(const nsACString& aGeneric) const {
if (aGeneric.IsEmpty())
return PR_TRUE;
// Japanese 'Mincho' fonts do not belong to FF_MODERN even if
// they are fixed pitch because they have variable stroke width.
if (mWindowsFamily == FF_ROMAN && mWindowsPitch & FIXED_PITCH) {
return aGeneric.EqualsLiteral("monospace");
}
// Japanese 'Gothic' fonts do not belong to FF_SWISS even if
// they are variable pitch because they have constant stroke width.
if (mWindowsFamily == FF_MODERN && mWindowsPitch & VARIABLE_PITCH) {
return aGeneric.EqualsLiteral("sans-serif");
}
// All other fonts will be grouped correctly using family...
switch (mWindowsFamily) {
case FF_DONTCARE:
return PR_TRUE;
case FF_ROMAN:
return aGeneric.EqualsLiteral("serif");
case FF_SWISS:
return aGeneric.EqualsLiteral("sans-serif");
case FF_MODERN:
return aGeneric.EqualsLiteral("monospace");
case FF_SCRIPT:
return aGeneric.EqualsLiteral("cursive");
case FF_DECORATIVE:
return aGeneric.EqualsLiteral("fantasy");
}
return PR_FALSE;
}
PRBool SupportsLangGroup(const nsACString& aLangGroup) const {
if (aLangGroup.IsEmpty())
return PR_TRUE;
PRInt16 bit = -1;
/* map our langgroup names in to Windows charset bits */
if (aLangGroup.EqualsLiteral("x-western")) {
bit = ANSI_CHARSET;
} else if (aLangGroup.EqualsLiteral("ja")) {
bit = SHIFTJIS_CHARSET;
} else if (aLangGroup.EqualsLiteral("ko")) {
bit = HANGEUL_CHARSET;
} else if (aLangGroup.EqualsLiteral("ko-XXX")) {
bit = JOHAB_CHARSET;
} else if (aLangGroup.EqualsLiteral("zh-CN")) {
bit = GB2312_CHARSET;
} else if (aLangGroup.EqualsLiteral("zh-TW")) {
bit = CHINESEBIG5_CHARSET;
} else if (aLangGroup.EqualsLiteral("el")) {
bit = GREEK_CHARSET;
} else if (aLangGroup.EqualsLiteral("tr")) {
bit = TURKISH_CHARSET;
} else if (aLangGroup.EqualsLiteral("he")) {
bit = HEBREW_CHARSET;
} else if (aLangGroup.EqualsLiteral("ar")) {
bit = ARABIC_CHARSET;
} else if (aLangGroup.EqualsLiteral("x-baltic")) {
bit = BALTIC_CHARSET;
} else if (aLangGroup.EqualsLiteral("x-cyrillic")) {
bit = RUSSIAN_CHARSET;
} else if (aLangGroup.EqualsLiteral("th")) {
bit = THAI_CHARSET;
} else if (aLangGroup.EqualsLiteral("x-central-euro")) {
bit = EASTEUROPE_CHARSET;
} else if (aLangGroup.EqualsLiteral("x-symbol")) {
bit = SYMBOL_CHARSET;
}
if (bit != -1)
return mCharset[bit];
return PR_FALSE;
}
PRBool SupportsRange(PRUint8 range) {
return mUnicodeRanges[range];
}
PRBool TestCharacterMap(PRUint32 aCh);
// create a font entry for a font with a given name
static GDIFontEntry* CreateFontEntry(const nsAString& aName,
gfxWindowsFontType aFontType,
PRBool aItalic, PRUint16 aWeight,
gfxUserFontData* aUserFontData);
// create a font entry for a font referenced by its fullname
static GDIFontEntry* LoadLocalFont(const gfxProxyFontEntry &aProxyEntry,
const nsAString& aFullname);
PRUint8 mWindowsFamily;
PRUint8 mWindowsPitch;
gfxWindowsFontType mFontType;
PRPackedBool mForceGDI : 1;
PRPackedBool mUnknownCMAP : 1;
PRPackedBool mUnicodeFont : 1;
std::bitset<256> mCharset;
std::bitset<128> mUnicodeRanges;
protected:
friend class gfxWindowsFont;
GDIFontEntry(const nsAString& aFaceName, gfxWindowsFontType aFontType,
PRBool aItalic, PRUint16 aWeight, gfxUserFontData *aUserFontData);
void InitLogFont(const nsAString& aName, gfxWindowsFontType aFontType);
virtual nsresult GetFontTable(PRUint32 aTableTag, nsTArray<PRUint8>& aBuffer);
LOGFONTW mLogFont;
};
// a single font family, referencing one or more faces
class GDIFontFamily : public gfxFontFamily
{
public:
GDIFontFamily(nsAString &aName) :
gfxFontFamily(aName) {}
virtual void FindStyleVariations();
private:
static int CALLBACK FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe,
const NEWTEXTMETRICEXW *nmetrics,
DWORD fontType, LPARAM data);
};
class gfxGDIFontList : public gfxPlatformFontList {
public:
static gfxGDIFontList* PlatformFontList() {
return static_cast<gfxGDIFontList*>(sPlatformFontList);
}
virtual gfxFontEntry* GetDefaultFont(const gfxFontStyle* aStyle, PRBool& aNeedsBold);
virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
const nsAString& aFontName);
virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
const PRUint8 *aFontData, PRUint32 aLength);
virtual PRBool ResolveFontName(const nsAString& aFontName,
nsAString& aResolvedFontName);
private:
friend class gfxWindowsPlatform;
gfxGDIFontList();
void InitializeFontEmbeddingProcs();
// initialize font lists
virtual void InitFontList();
nsresult GetFontSubstitutes();
static int CALLBACK EnumFontFamExProc(ENUMLOGFONTEXW *lpelfe,
NEWTEXTMETRICEXW *lpntme,
DWORD fontType,
LPARAM lParam);
typedef nsDataHashtable<nsStringHashKey, nsRefPtr<gfxFontFamily> > FontTable;
FontTable mFontSubstitutes;
nsTArray<nsString> mNonExistingFonts;
};
#endif /* GFX_GDIFONTLIST_H */

View File

@ -92,7 +92,7 @@ protected:
class gfxMacPlatformFontList : public gfxPlatformFontList {
public:
static gfxMacPlatformFontList* PlatformFontList() {
return (gfxMacPlatformFontList*)sPlatformFontList;
return static_cast<gfxMacPlatformFontList*>(sPlatformFontList);
}
static PRInt32 AppleWeightToCSSWeight(PRInt32 aAppleWeight);
@ -104,7 +104,7 @@ public:
virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
const nsAString& aFontName);
virtual gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry,
virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
const PRUint8 *aFontData, PRUint32 aLength);
void ClearPrefFonts() { mPrefFonts.Clear(); }

View File

@ -106,7 +106,12 @@ static NSString* GetNSStringForString(const nsAString& aSrc)
length:aSrc.Length()];
}
#ifdef PR_LOGGING
static PRLogModuleInfo *gFontInfoLog = PR_NewLogModule("fontInfoLog");
#endif /* PR_LOGGING */
#define LOG(args) PR_LOG(gFontInfoLog, PR_LOG_DEBUG, args)
#define LOG_ENABLED() PR_LOG_TEST(gFontInfoLog, PR_LOG_DEBUG)
/* MacOSFontEntry */
#pragma mark-
@ -394,9 +399,6 @@ gfxMacFontFamily::FindStyleVariations()
PRInt32 cssWeight = gfxMacPlatformFontList::AppleWeightToCSSWeight(appKitWeight) * 100;
PR_LOG(gFontInfoLog, PR_LOG_DEBUG, ("(fontinit) family: %s, psname: %s, face: %s, apple-weight: %d, css-weight: %d, macTraits: %8.8x\n",
[family UTF8String], [psname UTF8String], [facename UTF8String], appKitWeight, cssWeight, macTraits));
// make a nsString
nsAutoString postscriptFontName;
GetStringForNSString(psname, postscriptFontName);
@ -429,6 +431,19 @@ gfxMacFontFamily::FindStyleVariations()
fontEntry->mFixedPitch = PR_TRUE;
}
#ifdef PR_LOGGING
if (LOG_ENABLED()) {
LOG(("(fontinit) added (%s) to family (%s)"
" with style: %s weight: %d stretch: %d"
" (apple-weight: %d macTraits: %8.8x)",
NS_ConvertUTF16toUTF8(fontEntry->Name()).get(),
NS_ConvertUTF16toUTF8(Name()).get(),
fontEntry->IsItalic() ? "italic" : "normal",
cssWeight, fontEntry->Stretch(),
appKitWeight, macTraits));
}
#endif
// insert into font entry array of family
AddFontEntry(fontEntry);
}
@ -578,9 +593,13 @@ gfxMacPlatformFontList::InitFontList()
mOtherFamilyNames.Clear();
mOtherFamilyNamesInitialized = PR_FALSE;
mPrefFonts.Clear();
mCodepointsWithNoFonts.reset();
CancelLoader();
// initialize ranges of characters for which system-wide font search should be skipped
mCodepointsWithNoFonts.reset();
mCodepointsWithNoFonts.SetRange(0,0x1f); // C0 controls
mCodepointsWithNoFonts.SetRange(0x7f,0x9f); // C1 controls
// iterate over available families
NSEnumerator *families = [[sFontManager availableFontFamilies]
objectEnumerator]; // returns "canonical", non-localized family name
@ -622,15 +641,10 @@ gfxMacPlatformFontList::InitFontList()
SetFixedPitch(NS_LITERAL_STRING("Monaco"));
}
// initialize ranges of characters for which system-wide font search should be skipped
mCodepointsWithNoFonts.SetRange(0,0x1f); // C0 controls
mCodepointsWithNoFonts.SetRange(0x7f,0x9f); // C1 controls
InitBadUnderlineList();
// start the delayed cmap loader
StartLoader(kDelayBeforeLoadingCmaps, kIntervalBetweenLoadingCmaps);
}
void
@ -754,7 +768,7 @@ gfxMacPlatformFontList::AppleWeightToCSSWeight(PRInt32 aAppleWeight)
gfxFontEntry*
gfxMacPlatformFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
const nsAString& aFontName)
const nsAString& aFontName)
{
NSString *faceName = GetNSStringForString(aFontName);
@ -817,7 +831,7 @@ public:
};
gfxFontEntry*
gfxMacPlatformFontList::MakePlatformFont(const gfxFontEntry *aProxyEntry,
gfxMacPlatformFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
const PRUint8 *aFontData,
PRUint32 aLength)
{
@ -825,6 +839,17 @@ gfxMacPlatformFontList::MakePlatformFont(const gfxFontEntry *aProxyEntry,
NS_ASSERTION(aFontData, "MakePlatformFont called with null data");
// MakePlatformFont is responsible for deleting the font data with NS_Free
// so we set up a stack object to ensure it is freed even if we take an
// early exit
struct FontDataDeleter {
FontDataDeleter(const PRUint8 *aFontData)
: mFontData(aFontData) { }
~FontDataDeleter() { NS_Free((void*)mFontData); }
const PRUint8 *mFontData;
};
FontDataDeleter autoDelete(aFontData);
ATSFontRef fontRef;
ATSFontContainerRef containerRef;
@ -844,11 +869,9 @@ gfxMacPlatformFontList::MakePlatformFont(const gfxFontEntry *aProxyEntry,
if (err != noErr) {
#if DEBUG
char warnBuf[1024];
const gfxProxyFontEntry *proxyEntry =
static_cast<const gfxProxyFontEntry*> (aProxyEntry);
sprintf(warnBuf, "downloaded font error, ATSFontActivateFromMemory err: %d for (%s)",
PRInt32(err),
NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get());
NS_WARNING(warnBuf);
#endif
return nsnull;
@ -860,11 +883,9 @@ gfxMacPlatformFontList::MakePlatformFont(const gfxFontEntry *aProxyEntry,
if (err != noErr) {
#if DEBUG
char warnBuf[1024];
const gfxProxyFontEntry *proxyEntry =
static_cast<const gfxProxyFontEntry*> (aProxyEntry);
sprintf(warnBuf, "downloaded font error, ATSFontFindFromContainer err: %d for (%s)",
PRInt32(err),
NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get());
NS_WARNING(warnBuf);
#endif
::ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
@ -880,10 +901,8 @@ gfxMacPlatformFontList::MakePlatformFont(const gfxFontEntry *aProxyEntry,
} else {
#ifdef DEBUG
char warnBuf[1024];
const gfxProxyFontEntry *proxyEntry =
static_cast<const gfxProxyFontEntry*> (aProxyEntry);
sprintf(warnBuf, "ATSFontGetPostScriptName err = %d for (%s), retries = %d", (PRInt32)err,
NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get(), retryCount);
NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get(), retryCount);
NS_WARNING(warnBuf);
#endif
::ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault);
@ -932,10 +951,8 @@ gfxMacPlatformFontList::MakePlatformFont(const gfxFontEntry *aProxyEntry,
// if something is funky about this font, delete immediately
#if DEBUG
char warnBuf[1024];
const gfxProxyFontEntry *proxyEntry =
static_cast<const gfxProxyFontEntry*> (aProxyEntry);
sprintf(warnBuf, "downloaded font not loaded properly, removed face for (%s)",
NS_ConvertUTF16toUTF8(proxyEntry->mFamily->Name()).get());
NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get());
NS_WARNING(warnBuf);
#endif
delete newFontEntry;

View File

@ -70,6 +70,7 @@
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
#include "nsIPrefBranch2.h"
#include "nsCRT.h"
gfxPlatform *gPlatform = nsnull;
@ -186,7 +187,7 @@ gfxPlatform::Init()
nsresult rv;
#if defined(XP_MACOSX) // temporary, until this is implemented on others
#if defined(XP_MACOSX) || defined(XP_WIN) // temporary, until this is implemented on others
rv = gfxPlatformFontList::Init();
if (NS_FAILED(rv)) {
NS_ERROR("Could not initialize gfxPlatformFontList");
@ -236,7 +237,7 @@ gfxPlatform::Shutdown()
gfxTextRunCache::Shutdown();
gfxTextRunWordCache::Shutdown();
gfxFontCache::Shutdown();
#if defined(XP_MACOSX) // temporary, until this is implemented on others
#if defined(XP_MACOSX) || defined(XP_WIN) // temporary, until this is implemented on others
gfxPlatformFontList::Shutdown();
#endif
@ -440,8 +441,27 @@ PRBool gfxPlatform::ForEachPrefFont(eFontPrefLang aLangArray[], PRUint32 aLangAr
prefName.Append(genericDotLang);
rv = prefs->GetCharPref(prefName.get(), getter_Copies(nameListValue));
if (NS_SUCCEEDED(rv) && !nameListValue.Equals(nameValue)) {
if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(nameListValue), aClosure))
return PR_FALSE;
const char kComma = ',';
const char *p, *p_end;
nsCAutoString list(nameListValue);
list.BeginReading(p);
list.EndReading(p_end);
while (p < p_end) {
while (nsCRT::IsAsciiSpace(*p)) {
if (++p == p_end)
break;
}
if (p == p_end)
break;
const char *start = p;
while (++p != p_end && *p != kComma)
/* nothing */ ;
nsCAutoString fontName(Substring(start, p));
fontName.CompressWhitespace(PR_FALSE, PR_TRUE);
if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(fontName), aClosure))
return PR_FALSE;
p++;
}
}
}

View File

@ -247,9 +247,28 @@ gfxPlatformFontList::HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
{
FontListData *data = static_cast<FontListData*>(aUserArg);
nsAutoString localizedFamilyName;
aFamilyEntry->LocalizedName(localizedFamilyName);
data->mListOfFonts.AppendElement(localizedFamilyName);
// use the first variation for now. This data should be the same
// for all the variations and should probably be moved up to
// the Family
gfxFontStyle style;
style.langGroup = data->mLangGroup;
PRBool needsBold;
nsRefPtr<gfxFontEntry> aFontEntry = aFamilyEntry->FindFontForStyle(style, needsBold);
NS_ASSERTION(aFontEntry, "couldn't find any font entry in family");
if (!aFontEntry)
return PL_DHASH_NEXT;
/* skip symbol fonts */
if (aFontEntry->IsSymbolFont())
return PL_DHASH_NEXT;
if (aFontEntry->SupportsLangGroup(data->mLangGroup) &&
aFontEntry->MatchesGenericFamily(data->mGenericFamily)) {
nsAutoString localizedFamilyName;
aFamilyEntry->LocalizedName(localizedFamilyName);
data->mListOfFonts.AppendElement(localizedFamilyName);
}
return PL_DHASH_NEXT;
}
@ -417,6 +436,14 @@ gfxPlatformFontList::AddOtherFamilyName(gfxFontFamily *aFamilyEntry, nsAString&
}
}
PRBool
gfxPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
{
aFamilyName.Truncate();
ResolveFontName(aFontName, aFamilyName);
return !aFamilyName.IsEmpty();
}
void
gfxPlatformFontList::InitLoader()
{
@ -460,4 +487,3 @@ gfxPlatformFontList::FinishLoader()
mFontFamiliesToLoad.Clear();
mNumFamilies = 0;
}

View File

@ -109,12 +109,13 @@ public:
// create a new platform font from downloaded data (@font-face)
// this method is responsible to ensure aFontData is NS_Free()'d
virtual gfxFontEntry* MakePlatformFont(const gfxFontEntry *aProxyEntry,
virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
const PRUint8 *aFontData,
PRUint32 aLength) = 0;
// get the standard family name on the platform for a given font name
virtual PRBool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) = 0;
// (platforms may override, eg Mac)
virtual PRBool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
protected:
gfxPlatformFontList();

View File

@ -189,14 +189,12 @@ gfxFontEntry*
gfxPlatformMac::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
const PRUint8 *aFontData, PRUint32 aLength)
{
// Ownership of aFontData is passed in here.
// After activating the font via ATS, we can discard the data.
gfxFontEntry *fe =
gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry,
aFontData,
aLength);
NS_Free((void*)aFontData);
return fe;
// Ownership of aFontData is received here, and passed on to
// gfxPlatformFontList::MakePlatformFont(), which must ensure the data
// is released with NS_Free when no longer needed
return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry,
aFontData,
aLength);
}
PRBool

File diff suppressed because it is too large Load Diff

View File

@ -60,8 +60,10 @@
#include "gfxFT2Fonts.h"
#include "cairo-ft.h"
#include "nsAppDirectoryServiceDefs.h"
#include "gfxFT2FontList.h"
#else
#include "gfxWindowsFonts.h"
#include "gfxGDIFontList.h"
#endif
/*XXX to get CAIRO_HAS_DDRAW_SURFACE */
@ -83,11 +85,6 @@
static FT_Library gPlatformFTLibrary = NULL;
#endif
// font info loader constants
static const PRUint32 kDelayBeforeLoadingCmaps = 8 * 1000; // 8secs
static const PRUint32 kIntervalBetweenLoadingCmaps = 150; // 150ms
static const PRUint32 kNumFontsPerSlice = 10; // read in info 10 fonts at a time
static __inline void
BuildKeyNameFromFontName(nsAString &aName)
{
@ -96,54 +93,14 @@ BuildKeyNameFromFontName(nsAString &aName)
ToLowerCase(aName);
}
class gfxWindowsPlatformPrefObserver : public nsIObserver {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
};
NS_IMPL_ISUPPORTS1(gfxWindowsPlatformPrefObserver, nsIObserver)
NS_IMETHODIMP
gfxWindowsPlatformPrefObserver::Observe(nsISupports *aSubject,
const char *aTopic,
const PRUnichar *aData)
{
NS_ASSERTION(!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID), "invalid topic");
// XXX this could be made to only clear out the cache for the prefs that were changed
// but it probably isn't that big a deal.
gfxWindowsPlatform::GetPlatform()->ClearPrefFonts();
return NS_OK;
}
gfxWindowsPlatform::gfxWindowsPlatform()
: mStartIndex(0), mIncrement(kNumFontsPerSlice), mNumFamilies(0)
{
mFonts.Init(200);
mFontAliases.Init(20);
mFontSubstitutes.Init(50);
mPrefFonts.Init(10);
mPrefFonts.Init(50);
#ifdef MOZ_FT2_FONTS
FT_Init_FreeType(&gPlatformFTLibrary);
#else
FontEntry::InitializeFontEmbeddingProcs();
#endif
UpdateFontList();
nsCOMPtr<nsIPrefBranch2> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (pref) {
gfxWindowsPlatformPrefObserver *observer = new gfxWindowsPlatformPrefObserver();
if (observer) {
pref->AddObserver("font.", observer, PR_FALSE);
pref->AddObserver("font.name-list.", observer, PR_FALSE);
pref->AddObserver("intl.accept_languages", observer, PR_FALSE);
// don't bother unregistering. We'll get shutdown after the pref service
}
}
/* Pick the default render mode differently between
* desktop, Windows Mobile, and Windows CE.
*/
@ -155,6 +112,8 @@ gfxWindowsPlatform::gfxWindowsPlatform()
mRenderMode = RENDER_GDI;
#endif
nsCOMPtr<nsIPrefBranch2> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);
PRInt32 rmode;
if (NS_SUCCEEDED(pref->GetIntPref("mozilla.widget.render-mode", &rmode))) {
if (rmode >= 0 || rmode < RENDER_MODE_MAX) {
@ -173,6 +132,16 @@ gfxWindowsPlatform::~gfxWindowsPlatform()
// these FT_Faces. See bug 458169.
}
gfxPlatformFontList*
gfxWindowsPlatform::CreatePlatformFontList()
{
#ifdef MOZ_FT2_FONTS
return new gfxFT2FontList();
#else
return new gfxGDIFontList();
#endif
}
already_AddRefed<gfxASurface>
gfxWindowsPlatform::CreateOffscreenSurface(const gfxIntSize& size,
gfxASurface::gfxImageFormat imageFormat)
@ -197,85 +166,12 @@ gfxWindowsPlatform::CreateOffscreenSurface(const gfxIntSize& size,
return surf;
}
int CALLBACK
gfxWindowsPlatform::FontEnumProc(const ENUMLOGFONTEXW *lpelfe,
const NEWTEXTMETRICEXW *nmetrics,
DWORD fontType, LPARAM data)
{
FontTable *ht = reinterpret_cast<FontTable*>(data);
const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
const LOGFONTW& logFont = lpelfe->elfLogFont;
// Ignore vertical fonts
if (logFont.lfFaceName[0] == L'@')
return 1;
nsAutoString name(logFont.lfFaceName);
BuildKeyNameFromFontName(name);
nsRefPtr<FontFamily> ff;
if (!ht->Get(name, &ff)) {
ff = new FontFamily(nsDependentString(logFont.lfFaceName));
ht->Put(name, ff);
}
return 1;
}
// general cmap reading routines moved to gfxFontUtils.cpp
struct FontListData {
FontListData(const nsACString& aLangGroup, const nsACString& aGenericFamily, nsTArray<nsString>& aListOfFonts) :
mLangGroup(aLangGroup), mGenericFamily(aGenericFamily), mStringArray(aListOfFonts) {}
const nsACString& mLangGroup;
const nsACString& mGenericFamily;
nsTArray<nsString>& mStringArray;
};
PLDHashOperator
gfxWindowsPlatform::HashEnumFunc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontFamily>& aFontFamily,
void* userArg)
{
FontListData *data = (FontListData*)userArg;
// use the first variation for now. This data should be the same
// for all the variations and should probably be moved up to
// the Family
gfxFontStyle style;
style.langGroup = data->mLangGroup;
nsRefPtr<FontEntry> aFontEntry = aFontFamily->FindFontEntry(style);
NS_ASSERTION(aFontEntry, "couldn't find any font entry in family");
if (!aFontEntry)
return PL_DHASH_NEXT;
#ifndef MOZ_FT2_FONTS
/* skip symbol fonts */
if (aFontEntry->mSymbolFont)
return PL_DHASH_NEXT;
if (aFontEntry->SupportsLangGroup(data->mLangGroup) &&
aFontEntry->MatchesGenericFamily(data->mGenericFamily))
#endif
data->mStringArray.AppendElement(aFontFamily->Name());
return PL_DHASH_NEXT;
}
nsresult
gfxWindowsPlatform::GetFontList(const nsACString& aLangGroup,
const nsACString& aGenericFamily,
nsTArray<nsString>& aListOfFonts)
{
FontListData data(aLangGroup, aGenericFamily, aListOfFonts);
mFonts.Enumerate(gfxWindowsPlatform::HashEnumFunc, &data);
aListOfFonts.Sort();
aListOfFonts.Compact();
gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, aGenericFamily, aListOfFonts);
return NS_OK;
}
@ -288,225 +184,15 @@ RemoveCharsetFromFontSubstitute(nsAString &aName)
aName.Truncate(comma);
}
#ifdef MOZ_FT2_FONTS
void gfxWindowsPlatform::AppendFacesFromFontFile(const PRUnichar *aFileName) {
char fileName[MAX_PATH];
WideCharToMultiByte(CP_ACP, 0, aFileName, -1, fileName, MAX_PATH, NULL, NULL);
FT_Face dummy;
if (FT_Err_Ok == FT_New_Face(GetFTLibrary(), fileName, -1, &dummy)) {
for (FT_Long i = 0; i < dummy->num_faces; i++) {
FT_Face face;
if (FT_Err_Ok != FT_New_Face(GetFTLibrary(), fileName,
i, &face))
continue;
FontEntry* fe = FontEntry::CreateFontEntryFromFace(face);
if (fe) {
NS_ConvertUTF8toUTF16 name(face->family_name);
BuildKeyNameFromFontName(name);
nsRefPtr<FontFamily> ff;
if (!mFonts.Get(name, &ff)) {
ff = new FontFamily(name);
mFonts.Put(name, ff);
}
ff->AddFontEntry(fe);
ff->SetHasStyles(PR_TRUE);
}
}
FT_Done_Face(dummy);
}
}
void
gfxWindowsPlatform::FindFonts()
{
nsTArray<nsString> searchPaths(3);
nsTArray<nsString> fontPatterns(3);
fontPatterns.AppendElement(NS_LITERAL_STRING("\\*.ttf"));
fontPatterns.AppendElement(NS_LITERAL_STRING("\\*.ttc"));
fontPatterns.AppendElement(NS_LITERAL_STRING("\\*.otf"));
wchar_t pathBuf[256];
SHGetSpecialFolderPathW(0, pathBuf, CSIDL_WINDOWS, 0);
searchPaths.AppendElement(pathBuf);
SHGetSpecialFolderPathW(0, pathBuf, CSIDL_FONTS, 0);
searchPaths.AppendElement(pathBuf);
nsCOMPtr<nsIFile> resDir;
NS_GetSpecialDirectory(NS_APP_RES_DIR, getter_AddRefs(resDir));
if (resDir) {
resDir->Append(NS_LITERAL_STRING("fonts"));
nsAutoString resPath;
resDir->GetPath(resPath);
searchPaths.AppendElement(resPath);
}
WIN32_FIND_DATAW results;
for (PRUint32 i = 0; i < searchPaths.Length(); i++) {
const nsString& path(searchPaths[i]);
for (PRUint32 j = 0; j < fontPatterns.Length(); j++) {
nsAutoString pattern(path);
pattern.Append(fontPatterns[j]);
HANDLE handle = FindFirstFileExW(pattern.get(),
FindExInfoStandard,
&results,
FindExSearchNameMatch,
NULL,
0);
PRBool moreFiles = handle != INVALID_HANDLE_VALUE;
while (moreFiles) {
nsAutoString filePath(path);
filePath.AppendLiteral("\\");
filePath.Append(results.cFileName);
AppendFacesFromFontFile(static_cast<const PRUnichar*>(filePath.get()));
moreFiles = FindNextFile(handle, &results);
}
if (handle != INVALID_HANDLE_VALUE)
FindClose(handle);
}
}
}
#endif
nsresult
gfxWindowsPlatform::UpdateFontList()
{
gfxFontCache *fc = gfxFontCache::GetCache();
if (fc)
fc->AgeAllGenerations();
mFonts.Clear();
mFontAliases.Clear();
mNonExistingFonts.Clear();
mFontSubstitutes.Clear();
mPrefFonts.Clear();
mCodepointsWithNoFonts.reset();
CancelLoader();
#ifdef MOZ_FT2_FONTS
FindFonts();
#else
LOGFONTW logFont;
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfFaceName[0] = 0;
logFont.lfPitchAndFamily = 0;
// Use the screen DC here.. should we use something else for printing?
HDC dc = ::GetDC(nsnull);
EnumFontFamiliesExW(dc, &logFont, (FONTENUMPROCW)gfxWindowsPlatform::FontEnumProc, (LPARAM)&mFonts, 0);
::ReleaseDC(nsnull, dc);
#endif
// initialize the cmap loading process after font list has been initialized
StartLoader(kDelayBeforeLoadingCmaps, kIntervalBetweenLoadingCmaps);
// Create the list of FontSubstitutes
nsCOMPtr<nsIWindowsRegKey> regKey = do_CreateInstance("@mozilla.org/windows-registry-key;1");
if (!regKey)
return NS_ERROR_FAILURE;
NS_NAMED_LITERAL_STRING(kFontSubstitutesKey, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes");
nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
kFontSubstitutesKey, nsIWindowsRegKey::ACCESS_READ);
if (NS_FAILED(rv))
return rv;
PRUint32 count;
rv = regKey->GetValueCount(&count);
if (NS_FAILED(rv) || count == 0)
return rv;
for (PRUint32 i = 0; i < count; i++) {
nsAutoString substituteName;
rv = regKey->GetValueName(i, substituteName);
if (NS_FAILED(rv) || substituteName.IsEmpty() ||
substituteName.CharAt(1) == PRUnichar('@'))
continue;
PRUint32 valueType;
rv = regKey->GetValueType(substituteName, &valueType);
if (NS_FAILED(rv) || valueType != nsIWindowsRegKey::TYPE_STRING)
continue;
nsAutoString actualFontName;
rv = regKey->ReadStringValue(substituteName, actualFontName);
if (NS_FAILED(rv))
continue;
RemoveCharsetFromFontSubstitute(substituteName);
BuildKeyNameFromFontName(substituteName);
RemoveCharsetFromFontSubstitute(actualFontName);
BuildKeyNameFromFontName(actualFontName);
nsRefPtr<FontFamily> ff;
if (!actualFontName.IsEmpty() && mFonts.Get(actualFontName, &ff))
mFontSubstitutes.Put(substituteName, ff);
else
mNonExistingFonts.AppendElement(substituteName);
}
// initialize ranges of characters for which system-wide font search should be skipped
mCodepointsWithNoFonts.SetRange(0,0x1f); // C0 controls
mCodepointsWithNoFonts.SetRange(0x7f,0x9f); // C1 controls
InitBadUnderlineList();
gfxPlatformFontList::PlatformFontList()->UpdateFontList();
return NS_OK;
}
struct FontFamilyListData {
FontFamilyListData(nsTArray<nsRefPtr<FontFamily> >& aFamilyArray)
: mFamilyArray(aFamilyArray)
{}
static PLDHashOperator AppendFamily(nsStringHashKey::KeyType aKey,
nsRefPtr<FontFamily>& aFamilyEntry,
void *aUserArg)
{
FontFamilyListData *data = (FontFamilyListData*)aUserArg;
data->mFamilyArray.AppendElement(aFamilyEntry);
return PL_DHASH_NEXT;
}
nsTArray<nsRefPtr<FontFamily> >& mFamilyArray;
};
void
gfxWindowsPlatform::GetFontFamilyList(nsTArray<nsRefPtr<FontFamily> >& aFamilyArray)
{
FontFamilyListData data(aFamilyArray);
mFonts.Enumerate(FontFamilyListData::AppendFamily, &data);
}
static PRBool SimpleResolverCallback(const nsAString& aName, void* aClosure)
{
nsString *result = static_cast<nsString*>(aClosure);
result->Assign(aName);
return PR_FALSE;
}
void
gfxWindowsPlatform::InitBadUnderlineList()
{
// Only windows fonts have mIsBadUnderlineFontFamily flag
#ifndef MOZ_FT2_FONTS
nsAutoTArray<nsString, 10> blacklist;
gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset", blacklist);
PRUint32 numFonts = blacklist.Length();
for (PRUint32 i = 0; i < numFonts; i++) {
PRBool aborted;
nsAutoString resolved;
ResolveFontName(blacklist[i], SimpleResolverCallback, &resolved, aborted);
if (resolved.IsEmpty())
continue;
FontFamily *ff = FindFontFamily(resolved);
if (!ff)
continue;
ff->mIsBadUnderlineFontFamily = 1;
}
#endif
}
nsresult
gfxWindowsPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
{
aFamilyName.Truncate();
PRBool aborted;
return ResolveFontName(aFontName, SimpleResolverCallback, &aFamilyName, aborted);
}
struct ResolveData {
ResolveData(gfxPlatform::FontResolverCallback aCallback,
gfxWindowsPlatform *aCaller, const nsAString *aFontName,
@ -523,186 +209,23 @@ struct ResolveData {
nsresult
gfxWindowsPlatform::ResolveFontName(const nsAString& aFontName,
FontResolverCallback aCallback,
void *aClosure,
PRBool& aAborted)
void *aClosure, PRBool& aAborted)
{
if (aFontName.IsEmpty())
return NS_ERROR_FAILURE;
nsAutoString keyName(aFontName);
BuildKeyNameFromFontName(keyName);
nsRefPtr<FontFamily> ff;
if (mFonts.Get(keyName, &ff) ||
mFontSubstitutes.Get(keyName, &ff) ||
mFontAliases.Get(keyName, &ff)) {
aAborted = !(*aCallback)(ff->Name(), aClosure);
// XXX If the font has font link, we should add the linked font.
return NS_OK;
}
if (mNonExistingFonts.Contains(keyName)) {
nsAutoString resolvedName;
if (!gfxPlatformFontList::PlatformFontList()->
ResolveFontName(aFontName, resolvedName)) {
aAborted = PR_FALSE;
return NS_OK;
}
LOGFONTW logFont;
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfPitchAndFamily = 0;
PRInt32 len = aFontName.Length();
if (len >= LF_FACESIZE)
len = LF_FACESIZE - 1;
memcpy(logFont.lfFaceName,
nsPromiseFlatString(aFontName).get(), len * sizeof(PRUnichar));
logFont.lfFaceName[len] = 0;
HDC dc = ::GetDC(nsnull);
ResolveData data(aCallback, this, &keyName, aClosure);
aAborted = !EnumFontFamiliesExW(dc, &logFont,
(FONTENUMPROCW)gfxWindowsPlatform::FontResolveProc,
(LPARAM)&data, 0);
if (data.mFoundCount == 0)
mNonExistingFonts.AppendElement(keyName);
::ReleaseDC(nsnull, dc);
aAborted = !(*aCallback)(resolvedName, aClosure);
return NS_OK;
}
int CALLBACK
gfxWindowsPlatform::FontResolveProc(const ENUMLOGFONTEXW *lpelfe,
const NEWTEXTMETRICEXW *nmetrics,
DWORD fontType, LPARAM data)
nsresult
gfxWindowsPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
{
const LOGFONTW& logFont = lpelfe->elfLogFont;
// Ignore vertical fonts
if (logFont.lfFaceName[0] == L'@' || logFont.lfFaceName[0] == 0)
return 1;
ResolveData *rData = reinterpret_cast<ResolveData*>(data);
nsAutoString name(logFont.lfFaceName);
// Save the alias name to cache
nsRefPtr<FontFamily> ff;
nsAutoString keyName(name);
BuildKeyNameFromFontName(keyName);
if (!rData->mCaller->mFonts.Get(keyName, &ff)) {
// This case only occurs on failing to build
// the list of font substitue. In this case, the user should
// reboot the Windows. Probably, we don't have the good way for
// resolving in this time.
NS_WARNING("Cannot find actual font");
return 1;
}
rData->mFoundCount++;
rData->mCaller->mFontAliases.Put(*(rData->mFontName), ff);
return (rData->mCallback)(name, rData->mClosure);
// XXX If the font has font link, we should add the linked font.
}
PLDHashOperator
gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey,
nsRefPtr<FontFamily>& aFontFamily,
void* userArg)
{
FontSearch *data = (FontSearch*)userArg;
#ifdef MOZ_FT2_FONTS
aFontFamily->FindFontForChar(data);
#else
const PRUint32 ch = data->mCh;
nsRefPtr<FontEntry> fe = aFontFamily->FindFontEntry(*data->mFontToMatch->GetStyle());
NS_ASSERTION(fe, "couldn't find any font entry in family");
if (!fe)
return PL_DHASH_NEXT;
// initialize rank to 1 so that any match is better than the initial
// value of data->mMatchRank (zero); therefore the first font that
// passes the mCharacterMap.test() will become the mBestMatch until
// a better entry is found
PRInt32 rank = 1;
// skip over non-unicode and bitmap fonts and fonts that don't have
// the code point we're looking for
if (fe->IsCrappyFont() || !fe->mCharacterMap.test(ch))
return PL_DHASH_NEXT;
// fonts that claim to support the range are more
// likely to be "better fonts" than ones that don't... (in theory)
if (fe->SupportsRange(gfxFontUtils::CharRangeBit(ch)))
rank += 1;
if (fe->SupportsLangGroup(data->mFontToMatch->GetStyle()->langGroup))
rank += 2;
FontEntry* mfe = static_cast<FontEntry*>(data->mFontToMatch->GetFontEntry());
if (fe->mWindowsFamily == mfe->mWindowsFamily)
rank += 3;
if (fe->mWindowsPitch == mfe->mWindowsPitch)
rank += 3;
/* italic */
const PRBool italic = (data->mFontToMatch->GetStyle()->style != FONT_STYLE_NORMAL);
if (fe->mItalic != italic)
rank += 3;
/* weight */
PRInt8 baseWeight, weightDistance;
data->mFontToMatch->GetStyle()->ComputeWeightAndOffset(&baseWeight, &weightDistance);
if (fe->mWeight == (baseWeight * 100) + (weightDistance * 100))
rank += 2;
else if (fe->mWeight == data->mFontToMatch->GetFontEntry()->mWeight)
rank += 1;
if (rank > data->mMatchRank ||
(rank == data->mMatchRank && Compare(fe->Name(), data->mBestMatch->Name()) > 0)) {
data->mBestMatch = fe;
data->mMatchRank = rank;
}
#endif
return PL_DHASH_NEXT;
}
already_AddRefed<gfxFont>
gfxWindowsPlatform::FindFontForChar(PRUint32 aCh, gfxFont *aFont)
{
// is codepoint with no matching font? return null immediately
if (mCodepointsWithNoFonts.test(aCh)) {
return nsnull;
}
FontSearch data(aCh, aFont);
// find fonts that support the character
mFonts.Enumerate(gfxWindowsPlatform::FindFontForCharProc, &data);
if (data.mBestMatch) {
#ifdef MOZ_FT2_FONTS
nsRefPtr<gfxFT2Font> font =
gfxFT2Font::GetOrMakeFont(static_cast<FontEntry*>(data.mBestMatch.get()),
aFont->GetStyle());
gfxFont* ret = font.forget().get();
return already_AddRefed<gfxFont>(ret);
#else
nsRefPtr<gfxWindowsFont> font =
gfxWindowsFont::GetOrMakeFont(static_cast<FontEntry*>(data.mBestMatch.get()),
aFont->GetStyle());
if (font->IsValid()) {
gfxFont* ret = font.forget().get();
return already_AddRefed<gfxFont>(ret);
}
#endif
return nsnull;
}
// no match? add to set of non-matching codepoints
mCodepointsWithNoFonts.set(aCh);
return nsnull;
gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName);
return NS_OK;
}
gfxFontGroup *
@ -717,143 +240,21 @@ gfxWindowsPlatform::CreateFontGroup(const nsAString &aFamilies,
#endif
}
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;
};
#ifndef MOZ_FT2_FONTS
// 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
}
#endif
// callback called for each family name, based on the assumption that the
// first part of the full name is the family name
static PLDHashOperator
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)) {
#ifdef MOZ_FT2_FONTS
int len = aFontFamily->GetFontList().Length();
int index = 0;
for (; index < len &&
!aFontFamily->GetFontList()[index]->Name().Equals(data->mFullName); index++);
if (index < len) {
data->mFound = PR_TRUE;
data->mFontEntry = aFontFamily->GetFontList()[index];
}
#else
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);
#endif
}
if (data->mFound)
return PL_DHASH_STOP;
return PL_DHASH_NEXT;
}
gfxFontEntry*
gfxWindowsPlatform::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
const nsAString& aFontName)
{
#ifdef MOZ_FT2_FONTS
// 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;
#else
return FontEntry::LoadLocalFont(*aProxyEntry, aFontName);
#endif
return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry,
aFontName);
}
gfxFontEntry*
gfxWindowsPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
const PRUint8 *aFontData, PRUint32 aLength)
{
#ifdef MOZ_FT2_FONTS
// The FT2 font needs the font data to persist, so we do NOT free it here
// but instead pass ownership to the font entry.
// Deallocation will happen later, when the font face is destroyed.
return FontEntry::CreateFontEntry(*aProxyEntry, aFontData, aLength);
#else
// With GDI, we can free the downloaded data after activating the font
gfxFontEntry *fe = FontEntry::LoadFont(*aProxyEntry, aFontData, aLength);
NS_Free((void*)aFontData);
return fe;
#endif
return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry,
aFontData,
aLength);
}
PRBool
@ -879,29 +280,21 @@ gfxWindowsPlatform::IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlag
return PR_TRUE;
}
FontFamily *
gfxFontFamily *
gfxWindowsPlatform::FindFontFamily(const nsAString& aName)
{
nsAutoString name(aName);
BuildKeyNameFromFontName(name);
nsRefPtr<FontFamily> ff;
if (!mFonts.Get(name, &ff) &&
!mFontSubstitutes.Get(name, &ff) &&
!mFontAliases.Get(name, &ff)) {
return nsnull;
}
return ff.get();
return gfxPlatformFontList::PlatformFontList()->FindFamily(aName);
}
FontEntry *
gfxFontEntry *
gfxWindowsPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle)
{
nsRefPtr<FontFamily> ff = FindFontFamily(aName);
nsRefPtr<gfxFontFamily> ff = FindFontFamily(aName);
if (!ff)
return nsnull;
return ff->FindFontEntry(aFontStyle);
PRBool aNeedsBold;
return ff->FindFontForStyle(aFontStyle, aNeedsBold);
}
qcms_profile*
@ -938,50 +331,17 @@ gfxWindowsPlatform::GetPlatformCMSOutputProfile()
}
PRBool
gfxWindowsPlatform::GetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<FontEntry> > *array)
gfxWindowsPlatform::GetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<gfxFontEntry> > *array)
{
return mPrefFonts.Get(aKey, array);
}
void
gfxWindowsPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<FontEntry> >& array)
gfxWindowsPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<gfxFontEntry> >& array)
{
mPrefFonts.Put(aKey, array);
}
void
gfxWindowsPlatform::InitLoader()
{
GetFontFamilyList(mFontFamilies);
mStartIndex = 0;
mNumFamilies = mFontFamilies.Length();
}
PRBool
gfxWindowsPlatform::RunLoader()
{
PRUint32 i, endIndex = ( mStartIndex + mIncrement < mNumFamilies ? mStartIndex + mIncrement : mNumFamilies );
#ifndef MOZ_FT2_FONTS
// for each font family, load in various font info
for (i = mStartIndex; i < endIndex; i++) {
// load the cmaps for all variations
mFontFamilies[i]->FindStyleVariations();
}
#endif
mStartIndex += mIncrement;
if (mStartIndex < mNumFamilies)
return PR_FALSE;
return PR_TRUE;
}
void
gfxWindowsPlatform::FinishLoader()
{
mFontFamilies.Clear();
mNumFamilies = 0;
}
#ifdef MOZ_FT2_FONTS
FT_Library
gfxWindowsPlatform::GetFTLibrary()