Merge mozilla-central into electrolysis.

This commit is contained in:
Benjamin Smedberg 2010-01-08 10:42:46 -05:00
commit ec5b735597
34 changed files with 2473 additions and 2231 deletions

View File

@ -2,7 +2,7 @@
# Filenames that should be ignored wherever they appear
~$
\.pyc$
\.py(c|o)$
(^|/)TAGS$
(^|/)ID$
(^|/)\.DS_Store$

View File

@ -85,7 +85,7 @@ static const PRInt32 kIEnumVariantDisconnected = -1;
// construction
//-----------------------------------------------------
nsAccessibleWrap::nsAccessibleWrap(nsIDOMNode* aNode, nsIWeakReference *aShell):
nsAccessible(aNode, aShell), mEnumVARIANTPosition(0)
nsAccessible(aNode, aShell), mEnumVARIANTPosition(0), mTypeInfo(NULL)
{
}
@ -94,6 +94,8 @@ nsAccessibleWrap::nsAccessibleWrap(nsIDOMNode* aNode, nsIWeakReference *aShell):
//-----------------------------------------------------
nsAccessibleWrap::~nsAccessibleWrap()
{
if (mTypeInfo)
mTypeInfo->Release();
}
NS_IMPL_ISUPPORTS_INHERITED0(nsAccessibleWrap, nsAccessible);
@ -1589,38 +1591,63 @@ __try {
return E_FAIL;
}
// For IDispatch support
////////////////////////////////////////////////////////////////////////////////
// IDispatch
STDMETHODIMP
nsAccessibleWrap::GetTypeInfoCount(UINT *p)
nsAccessibleWrap::GetTypeInfoCount(UINT *pctinfo)
{
*p = 0;
return E_NOTIMPL;
*pctinfo = 1;
return S_OK;
}
// For IDispatch support
STDMETHODIMP nsAccessibleWrap::GetTypeInfo(UINT i, LCID lcid, ITypeInfo **ppti)
STDMETHODIMP
nsAccessibleWrap::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
{
*ppti = 0;
return E_NOTIMPL;
*ppTInfo = NULL;
if (iTInfo != 0)
return ResultFromScode(DISP_E_BADINDEX);
ITypeInfo * typeInfo = GetTI(lcid);
if (!typeInfo)
return E_FAIL;
typeInfo->AddRef();
*ppTInfo = typeInfo;
return S_OK;
}
// For IDispatch support
STDMETHODIMP
nsAccessibleWrap::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames,
UINT cNames, LCID lcid, DISPID *rgDispId)
UINT cNames, LCID lcid, DISPID *rgDispId)
{
return E_NOTIMPL;
ITypeInfo *typeInfo = GetTI(lcid);
if (!typeInfo)
return E_FAIL;
HRESULT hr = DispGetIDsOfNames(typeInfo, rgszNames, cNames, rgDispId);
return hr;
}
// For IDispatch support
STDMETHODIMP nsAccessibleWrap::Invoke(DISPID dispIdMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
STDMETHODIMP
nsAccessibleWrap::Invoke(DISPID dispIdMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
VARIANT *pVarResult, EXCEPINFO *pExcepInfo,
UINT *puArgErr)
{
return E_NOTIMPL;
ITypeInfo *typeInfo = GetTI(lcid);
if (!typeInfo)
return E_FAIL;
return typeInfo->Invoke(static_cast<IAccessible*>(this), dispIdMember,
wFlags, pDispParams, pVarResult, pExcepInfo,
puArgErr);
}
// nsIAccessible method
NS_IMETHODIMP nsAccessibleWrap::GetNativeInterface(void **aOutAccessible)
{
*aOutAccessible = static_cast<IAccessible*>(this);
@ -1935,3 +1962,23 @@ void nsAccessibleWrap::UpdateSystemCaret()
::DeleteObject(caretBitMap);
}
}
ITypeInfo*
nsAccessibleWrap::GetTI(LCID lcid)
{
if (mTypeInfo)
return mTypeInfo;
ITypeLib *typeLib = NULL;
HRESULT hr = LoadRegTypeLib(LIBID_Accessibility, 1, 0, lcid, &typeLib);
if (FAILED(hr))
return NULL;
hr = typeLib->GetTypeInfoOfGuid(IID_IAccessible, &mTypeInfo);
typeLib->Release();
if (FAILED(hr))
return NULL;
return mTypeInfo;
}

View File

@ -287,15 +287,24 @@ class nsAccessibleWrap : public nsAccessible,
/* [out] */ IEnumVARIANT __RPC_FAR *__RPC_FAR *ppEnum);
// ====== Methods for IDispatch - for VisualBasic bindings (not implemented) ======
// IDispatch (support of scripting languages like VB)
virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo);
STDMETHODIMP GetTypeInfoCount(UINT *p);
STDMETHODIMP GetTypeInfo(UINT i, LCID lcid, ITypeInfo **ppti);
STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames,
UINT cNames, LCID lcid, DISPID *rgDispId);
STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr);
virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid,
ITypeInfo **ppTInfo);
virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid,
LPOLESTR *rgszNames,
UINT cNames,
LCID lcid,
DISPID *rgDispId);
virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid,
LCID lcid, WORD wFlags,
DISPPARAMS *pDispParams,
VARIANT *pVarResult,
EXCEPINFO *pExcepInfo,
UINT *puArgErr);
// nsAccessible
virtual nsresult FireAccessibleEvent(nsIAccessibleEvent *aEvent);
@ -340,6 +349,14 @@ protected:
// nsIEnumVariant::Reset(), Skip() and Next().
PRInt32 mEnumVARIANTPosition;
/**
* Creates ITypeInfo for LIBID_Accessibility if it's needed and returns it.
*/
ITypeInfo *GetTI(LCID lcid);
ITypeInfo *mTypeInfo;
enum navRelations {
NAVRELATION_CONTROLLED_BY = 0x1000,
NAVRELATION_CONTROLLER_FOR = 0x1001,

View File

@ -301,7 +301,7 @@ pref("browser.search.update", true);
pref("browser.search.update.log", false);
// Check whether we need to perform engine updates every 6 hours
pref("browser.search.updateinterval", 6);
pref("browser.search.update.interval", 21600);
// Whether or not microsummary and generator updates are enabled
pref("browser.microsummary.enabled", true);

View File

@ -125,11 +125,13 @@ function uri(spec) {
function remove_all_bookmarks() {
var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
getService(Ci.nsINavBookmarksService);
// Clear all bookmarks
// Clear all bookmarks.
bs.removeFolderChildren(bs.bookmarksMenuFolder);
bs.removeFolderChildren(bs.toolbarFolder);
bs.removeFolderChildren(bs.unfiledBookmarksFolder);
// Check for correct cleanup
// Check for correct cleanup.
dump_table("moz_bookmarks");
check_no_bookmarks()
}
@ -148,7 +150,13 @@ function check_no_bookmarks() {
var result = hs.executeQuery(query, options);
var root = result.root;
root.containerOpen = true;
do_check_eq(root.childCount, 0);
var cc = root.childCount;
// Dump contents if found.
for (var i = 0; i < cc ; i++) {
var node = root.getChild(i);
print("Found unexpected child at " + i + ": " + node.title);
}
do_check_eq(cc, 0);
root.containerOpen = false;
}

View File

@ -106,6 +106,8 @@ function continue_test() {
let bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
getService(Ci.nsINavBookmarksService);
dump_table("moz_bookmarks");
// Check the custom bookmarks exist on menu.
let menuItemId = bs.getIdForItemAt(bs.bookmarksMenuFolder, 0);
do_check_neq(menuItemId, -1);

View File

@ -225,7 +225,8 @@ function next_test() {
// nsBrowserGlue stops observing topics after first notification,
// so we add back the observer to test additional runs.
os.addObserver(bg, TOPIC_PLACES_INIT_COMPLETE, false);
if (testIndex > 0)
os.addObserver(bg, TOPIC_PLACES_INIT_COMPLETE, false);
// Execute next test.
let test = tests.shift();

View File

@ -186,6 +186,11 @@ function countFolderChildren(aFolderItemId) {
var rootNode = hs.executeQuery(query, options).root;
rootNode.containerOpen = true;
var cc = rootNode.childCount;
// Dump contents.
for (var i = 0; i < cc ; i++) {
var node = rootNode.getChild(i);
print("Found child at " + i + ": " + node.title);
}
rootNode.containerOpen = false;
return cc;
}
@ -201,7 +206,8 @@ var testIndex = 0;
function next_test() {
// nsBrowserGlue stops observing topics after first notification,
// so we add back the observer to test additional runs.
os.addObserver(bg, TOPIC_PLACES_INIT_COMPLETE, false);
if (testIndex > 0)
os.addObserver(bg, TOPIC_PLACES_INIT_COMPLETE, false);
// Execute next test.
let test = tests.shift();
@ -210,9 +216,6 @@ function next_test() {
}
function run_test() {
// XXX disabled due to bug 510219
return;
// Clean up database from all bookmarks.
remove_all_bookmarks();

View File

@ -396,8 +396,8 @@ nsINode::GetSelectionRootContent(nsIPresShell* aPresShell)
if (!IsNodeOfType(eCONTENT))
return nsnull;
NS_ASSERTION(GetCurrentDoc() == aPresShell->GetDocument(),
"Wrong document somewhere");
NS_ENSURE_TRUE(GetCurrentDoc() == aPresShell->GetDocument(), nsnull);
nsIFrame* frame = static_cast<nsIContent*>(this)->GetPrimaryFrame();
if (frame && frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION) {
// This node should be a descendant of input/textarea editor.

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()

View File

@ -5958,8 +5958,7 @@ PresShell::GetFocusedDOMWindowInOurWindow()
nsCOMPtr<nsPIDOMWindow> rootWindow = window->GetPrivateRoot();
NS_ENSURE_TRUE(rootWindow, nsnull);
nsPIDOMWindow* focusedWindow;
nsIContent* content =
nsFocusManager::GetFocusedDescendant(rootWindow, PR_TRUE, &focusedWindow);
nsFocusManager::GetFocusedDescendant(rootWindow, PR_TRUE, &focusedWindow);
return focusedWindow;
}

View File

@ -167,7 +167,14 @@ nsSVGSwitchFrame::UpdateCoveredRegion()
{
static_cast<nsSVGSwitchElement*>(mContent)->UpdateActiveChild();
return nsSVGSwitchFrameBase::UpdateCoveredRegion();
nsIFrame *kid = GetActiveChildFrame();
if (kid) {
nsISVGChildFrame* child = do_QueryFrame(kid);
if (child) {
child->UpdateCoveredRegion();
}
}
return NS_OK;
}
NS_IMETHODIMP

View File

@ -70,8 +70,6 @@
#include "nsIPrefService.h"
#include "Helpers.h"
#include "mozilla/storage.h"
// For large favicons optimization.
#include "imgITools.h"
#include "imgIContainer.h"
@ -137,12 +135,12 @@ private:
class ExpireFaviconsStatementCallbackNotifier : public AsyncStatementCallback
{
public:
ExpireFaviconsStatementCallbackNotifier(bool *aFaviconsExpirationRunning);
ExpireFaviconsStatementCallbackNotifier(bool* aFaviconsExpirationRunning);
NS_DECL_ISUPPORTS
NS_DECL_ASYNCSTATEMENTCALLBACK
private:
bool *mFaviconsExpirationRunning;
bool* mFaviconsExpirationRunning;
};
PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsFaviconService, gFaviconService)
@ -165,31 +163,33 @@ namespace {
* loaded.
*/
already_AddRefed<nsIURI>
GetEffectivePageForFavicon(nsIURI *aPageURI,
nsIURI *aFaviconURI)
GetEffectivePageForFavicon(nsIURI* aPageURI, nsIURI* aFaviconURI)
{
NS_ASSERTION(aPageURI, "Must provide a pageURI!");
NS_ASSERTION(aFaviconURI, "Must provide a favicon URI!");
nsCOMPtr<nsIURI> pageURI(aPageURI);
nsNavHistory *history = nsNavHistory::GetHistoryService();
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, nsnull);
PRBool canAddToHistory;
nsresult rv = history->CanAddURI(pageURI, &canAddToHistory);
NS_ENSURE_TRUE(NS_SUCCEEDED(rv), nsnull);
if (NS_FAILED(rv))
return nsnull;
// If history is disabled or the page isn't addable to history, only load
// favicons if the page is bookmarked.
if (!canAddToHistory || history->IsHistoryDisabled()) {
nsNavBookmarks *bmSvc = nsNavBookmarks::GetBookmarksService();
nsNavBookmarks* bmSvc = nsNavBookmarks::GetBookmarksService();
NS_ENSURE_TRUE(bmSvc, nsnull);
// Check if the page is bookmarked.
nsCOMPtr<nsIURI> bookmarkedURI;
rv = bmSvc->GetBookmarkedURIFor(aPageURI, getter_AddRefs(bookmarkedURI));
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && bookmarkedURI, nsnull);
NS_ENSURE_SUCCESS(rv, nsnull);
if (!bookmarkedURI)
return nsnull;
// We always want to use the bookmark URI regardless of aPageURI.
pageURI = bookmarkedURI.forget();
@ -201,7 +201,9 @@ GetEffectivePageForFavicon(nsIURI *aPageURI,
// for now we just avoid that, for database size concerns.
PRBool pageEqualsFavicon;
rv = pageURI->Equals(aFaviconURI, &pageEqualsFavicon);
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && !pageEqualsFavicon, nsnull);
NS_ENSURE_SUCCESS(rv, nsnull);
if (pageEqualsFavicon)
return nsnull;
// We don't store favicons to error pages.
nsCOMPtr<nsIURI> errorPageFaviconURI;
@ -210,7 +212,9 @@ GetEffectivePageForFavicon(nsIURI *aPageURI,
NS_ENSURE_SUCCESS(rv, nsnull);
PRBool isErrorPage;
rv = aFaviconURI->Equals(errorPageFaviconURI, &isErrorPage);
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && !isErrorPage, nsnull);
NS_ENSURE_SUCCESS(rv, nsnull);
if (isErrorPage)
return nsnull;
// This favicon should load, so return the page's URI.
return pageURI.forget();
@ -225,8 +229,8 @@ class FaviconExpirationGetter : public AsyncStatementCallback
public:
NS_DECL_ISUPPORTS
FaviconExpirationGetter(nsIURI *aPageURI,
nsIURI *aFaviconURI,
FaviconExpirationGetter(nsIURI* aPageURI,
nsIURI* aFaviconURI,
bool aForceReload) :
mPageURI(aPageURI)
, mFaviconURI(aFaviconURI)
@ -240,8 +244,9 @@ public:
* Performs a lookup of the needed information asynchronously, and loads the
* icon if necessary.
*/
NS_IMETHOD checkAndLoad(mozIStorageStatement *aStatement)
NS_IMETHOD checkAndLoad(mozIStorageStatement* aStatement)
{
NS_ENSURE_STATE(aStatement);
mozStorageStatementScoper scoper(aStatement);
nsresult rv = BindStatementURI(aStatement, 0, mFaviconURI);
NS_ENSURE_SUCCESS(rv, rv);
@ -254,7 +259,7 @@ public:
return NS_OK;
}
NS_IMETHOD HandleResult(mozIStorageResultSet *aResultSet)
NS_IMETHOD HandleResult(mozIStorageResultSet* aResultSet)
{
nsCOMPtr<mozIStorageRow> row;
nsresult rv = aResultSet->GetNextRow(getter_AddRefs(row));
@ -282,7 +287,7 @@ public:
if (mHasData && PR_Now() < mExpiration && !mForceReload) {
// Our data is likely still valid, but we should check to make sure the
// URI has changed, otherwise there is no need to notify.
nsFaviconService *fs = nsFaviconService::GetFaviconService();
nsFaviconService* fs = nsFaviconService::GetFaviconService();
NS_ENSURE_TRUE(fs, NS_ERROR_OUT_OF_MEMORY);
fs->checkAndNotify(mPageURI, mFaviconURI);
return NS_OK;
@ -321,15 +326,18 @@ NS_IMPL_ISUPPORTS1(
} // anonymous namespace
nsFaviconService::nsFaviconService() : mFaviconsExpirationRunning(false)
, mOptimizedIconDimension(OPTIMIZED_FAVICON_DIMENSION)
, mFailedFaviconSerial(0)
nsFaviconService::nsFaviconService()
: mFaviconsExpirationRunning(false)
, mOptimizedIconDimension(OPTIMIZED_FAVICON_DIMENSION)
, mFailedFaviconSerial(0)
, mShuttingDown(false)
{
NS_ASSERTION(!gFaviconService,
"Attempting to create two instances of the service!");
gFaviconService = this;
}
nsFaviconService::~nsFaviconService()
{
NS_ASSERTION(gFaviconService == this,
@ -338,69 +346,98 @@ nsFaviconService::~nsFaviconService()
gFaviconService = nsnull;
}
nsresult
nsFaviconService::Init()
{
// creation of history service will call InitTables
// Creation of history service will call InitTables.
nsNavHistory* historyService = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(historyService, NS_ERROR_OUT_OF_MEMORY);
mDBConn = historyService->GetStorageConnection();
NS_ENSURE_TRUE(mDBConn, NS_ERROR_FAILURE);
nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT id, length(data), expiration FROM moz_favicons WHERE url = ?1"),
getter_AddRefs(mDBGetIconInfo));
NS_ENSURE_SUCCESS(rv, rv);
// We can avoid checking for duplicates in the unified table since an uri
// can only have one favicon associated. LIMIT 1 will ensure that we get
// only one result.
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT f.id, f.url, length(f.data), f.expiration "
"FROM ( "
"SELECT " MOZ_PLACES_COLUMNS " FROM moz_places_temp "
"WHERE url = ?1 "
"UNION ALL "
"SELECT " MOZ_PLACES_COLUMNS " FROM moz_places "
"WHERE url = ?1 "
") AS h JOIN moz_favicons f ON h.favicon_id = f.id "
"LIMIT 1"),
getter_AddRefs(mDBGetURL));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT f.data, f.mime_type FROM moz_favicons f WHERE url = ?1"),
getter_AddRefs(mDBGetData));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"INSERT INTO moz_favicons (url, data, mime_type, expiration) "
"VALUES (?1, ?2, ?3, ?4)"),
getter_AddRefs(mDBInsertIcon));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"UPDATE moz_favicons SET data = ?2, mime_type = ?3, expiration = ?4 "
"WHERE id = ?1"),
getter_AddRefs(mDBUpdateIcon));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"UPDATE moz_places_view SET favicon_id = ?2 WHERE id = ?1"),
getter_AddRefs(mDBSetPageFavicon));
NS_ENSURE_SUCCESS(rv, rv);
// failed favicon cache
if (! mFailedFavicons.Init(MAX_FAVICON_CACHE_SIZE))
// Init failed favicon cache.
if (!mFailedFavicons.Init(MAX_FAVICON_CACHE_SIZE))
return NS_ERROR_OUT_OF_MEMORY;
nsCOMPtr<nsIPrefBranch> pb = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (pb)
pb->GetIntPref("places.favicons.optimizeToDimension", &mOptimizedIconDimension);
if (pb) {
(void)pb->GetIntPref("places.favicons.optimizeToDimension",
&mOptimizedIconDimension);
}
return NS_OK;
}
mozIStorageStatement*
nsFaviconService::GetStatement(const nsCOMPtr<mozIStorageStatement>& aStmt)
{
#define RETURN_IF_STMT(_stmt, _sql) \
PR_BEGIN_MACRO \
if (address_of(_stmt) == address_of(aStmt)) { \
if (!_stmt) { \
nsresult rv = mDBConn->CreateStatement(_sql, getter_AddRefs(_stmt)); \
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && _stmt, nsnull); \
} \
return _stmt.get(); \
} \
PR_END_MACRO
if (mShuttingDown)
return nsnull;
RETURN_IF_STMT(mDBGetIconInfo, NS_LITERAL_CSTRING(
"SELECT id, length(data), expiration FROM moz_favicons WHERE url = ?1"));
RETURN_IF_STMT(mDBGetURL, NS_LITERAL_CSTRING(
"SELECT f.id, f.url, length(f.data), f.expiration "
"FROM ( "
"SELECT " MOZ_PLACES_COLUMNS " FROM moz_places_temp "
"WHERE url = ?1 "
"UNION ALL "
"SELECT " MOZ_PLACES_COLUMNS " FROM moz_places "
"WHERE url = ?1 "
") AS h JOIN moz_favicons f ON h.favicon_id = f.id "
"LIMIT 1"));
RETURN_IF_STMT(mDBGetData, NS_LITERAL_CSTRING(
"SELECT f.data, f.mime_type FROM moz_favicons f WHERE url = ?1"));
RETURN_IF_STMT(mDBInsertIcon, NS_LITERAL_CSTRING(
"INSERT INTO moz_favicons (url, data, mime_type, expiration) "
"VALUES (?1, ?2, ?3, ?4)"));
RETURN_IF_STMT(mDBUpdateIcon, NS_LITERAL_CSTRING(
"UPDATE moz_favicons SET data = ?2, mime_type = ?3, expiration = ?4 "
"WHERE id = ?1"));
RETURN_IF_STMT(mDBSetPageFavicon, NS_LITERAL_CSTRING(
"UPDATE moz_places_view SET favicon_id = ?2 WHERE id = ?1"));
RETURN_IF_STMT(mDBRemoveOnDiskReferences, NS_LITERAL_CSTRING(
"UPDATE moz_places "
"SET favicon_id = NULL "
"WHERE favicon_id NOT NULL"));
RETURN_IF_STMT(mDBRemoveTempReferences, NS_LITERAL_CSTRING(
"UPDATE moz_places_temp "
"SET favicon_id = NULL "
"WHERE favicon_id NOT NULL"));
RETURN_IF_STMT(mDBRemoveAllFavicons, NS_LITERAL_CSTRING(
"DELETE FROM moz_favicons WHERE id NOT IN ("
"SELECT favicon_id FROM moz_places_temp WHERE favicon_id NOT NULL "
"UNION ALL "
"SELECT favicon_id FROM moz_places WHERE favicon_id NOT NULL "
")"));
return nsnull;
#undef RETURN_IF_STMT
}
// nsFaviconService::InitTables
//
// Called by the history service to create the favicon table. The history
@ -413,66 +450,41 @@ nsFaviconService::InitTables(mozIStorageConnection* aDBConn)
nsresult rv;
PRBool exists = PR_FALSE;
aDBConn->TableExists(NS_LITERAL_CSTRING("moz_favicons"), &exists);
if (! exists) {
if (!exists) {
rv = aDBConn->ExecuteSimpleSQL(CREATE_MOZ_FAVICONS);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
NS_IMETHODIMP
nsFaviconService::ExpireAllFavicons()
{
mFaviconsExpirationRunning = true;
// Remove all references to favicons.
// We do this in 2 steps, first we null-out all favicons in the disk table,
// then we do the same in the temp table. This is because the view UPDATE
// trigger does not allow setting a NULL value to prevent dataloss.
nsCOMPtr<mozIStorageStatement> removeOnDiskReferences;
nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"UPDATE moz_places "
"SET favicon_id = NULL "
"WHERE favicon_id NOT NULL"
), getter_AddRefs(removeOnDiskReferences));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<mozIStorageStatement> removeTempReferences;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"UPDATE moz_places_temp "
"SET favicon_id = NULL "
"WHERE favicon_id NOT NULL"
), getter_AddRefs(removeTempReferences));
NS_ENSURE_SUCCESS(rv, rv);
// Remove all favicons.
// We run async, so be sure to not remove any favicon that could have been
// created in the meantime.
nsCOMPtr<mozIStorageStatement> removeFavicons;
rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"DELETE FROM moz_favicons WHERE id NOT IN ("
"SELECT favicon_id FROM moz_places_temp WHERE favicon_id NOT NULL "
"UNION ALL "
"SELECT favicon_id FROM moz_places WHERE favicon_id NOT NULL "
")"
), getter_AddRefs(removeFavicons));
NS_ENSURE_SUCCESS(rv, rv);
mozIStorageStatement *stmts[] = {
removeOnDiskReferences,
removeTempReferences,
removeFavicons
GetStatement(mDBRemoveOnDiskReferences),
GetStatement(mDBRemoveTempReferences),
GetStatement(mDBRemoveAllFavicons),
};
NS_ENSURE_STATE(stmts[0] && stmts[1] && stmts[2]);
nsCOMPtr<mozIStoragePendingStatement> ps;
nsCOMPtr<ExpireFaviconsStatementCallbackNotifier> callback =
new ExpireFaviconsStatementCallbackNotifier(&mFaviconsExpirationRunning);
rv = mDBConn->ExecuteAsync(stmts, NS_ARRAY_LENGTH(stmts), callback,
getter_AddRefs(ps));
nsresult rv = mDBConn->ExecuteAsync(stmts, NS_ARRAY_LENGTH(stmts), callback,
getter_AddRefs(ps));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
//// nsIFaviconService
@ -495,6 +507,7 @@ nsFaviconService::SetFaviconUrlForPage(nsIURI* aPageURI, nsIURI* aFaviconURI)
return NS_OK;
}
NS_IMETHODIMP
nsFaviconService::GetDefaultFavicon(nsIURI** _retval)
{
@ -509,6 +522,7 @@ nsFaviconService::GetDefaultFavicon(nsIURI** _retval)
return mDefaultIcon->Clone(_retval);
}
// nsFaviconService::SetFaviconUrlForPageInternal
//
// This creates a new entry in the favicon table if necessary and tells the
@ -540,19 +554,21 @@ nsFaviconService::SetFaviconUrlForPageInternal(nsIURI* aPageURI,
mozStorageTransaction transaction(mDBConn, PR_FALSE);
{
mozStorageStatementScoper scoper(mDBGetIconInfo);
rv = BindStatementURI(mDBGetIconInfo, 0, aFaviconURI);
mozIStorageStatement* stmt = GetStatement(mDBGetIconInfo);
NS_ENSURE_STATE(stmt);
mozStorageStatementScoper scoper(stmt);
rv = BindStatementURI(stmt, 0, aFaviconURI);
NS_ENSURE_SUCCESS(rv, rv);
PRBool hasResult = PR_FALSE;
if (NS_SUCCEEDED(mDBGetIconInfo->ExecuteStep(&hasResult)) && hasResult) {
if (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
// We already have an entry for this icon, just get the stats
rv = mDBGetIconInfo->GetInt64(0, &iconId);
rv = stmt->GetInt64(0, &iconId);
NS_ENSURE_SUCCESS(rv, rv);
// see if this icon has data already
PRInt32 dataSize;
rv = mDBGetIconInfo->GetInt32(1, &dataSize);
rv = stmt->GetInt32(1, &dataSize);
NS_ENSURE_SUCCESS(rv, rv);
if (dataSize > 0)
*aHasData = PR_TRUE;
@ -563,24 +579,28 @@ nsFaviconService::SetFaviconUrlForPageInternal(nsIURI* aPageURI,
// We did not find any entry, so create a new one
// not-binded params are automatically nullified by mozStorage
mozStorageStatementScoper scoper(mDBInsertIcon);
rv = BindStatementURI(mDBInsertIcon, 0, aFaviconURI);
mozIStorageStatement* stmt = GetStatement(mDBInsertIcon);
NS_ENSURE_STATE(stmt);
mozStorageStatementScoper scoper(stmt);
rv = BindStatementURI(stmt, 0, aFaviconURI);
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBInsertIcon->Execute();
rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv, rv);
{
mozStorageStatementScoper scoper(mDBGetIconInfo);
mozIStorageStatement* getInfoStmt = GetStatement(mDBGetIconInfo);
NS_ENSURE_STATE(getInfoStmt);
mozStorageStatementScoper scoper(getInfoStmt);
rv = BindStatementURI(mDBGetIconInfo, 0, aFaviconURI);
rv = BindStatementURI(getInfoStmt, 0, aFaviconURI);
NS_ENSURE_SUCCESS(rv, rv);
PRBool hasResult;
rv = mDBGetIconInfo->ExecuteStep(&hasResult);
rv = getInfoStmt->ExecuteStep(&hasResult);
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(hasResult, "hasResult is false but the call succeeded?");
iconId = mDBGetIconInfo->AsInt64(0);
iconId = getInfoStmt->AsInt64(0);
}
}
@ -589,12 +609,14 @@ nsFaviconService::SetFaviconUrlForPageInternal(nsIURI* aPageURI,
rv = historyService->GetUrlIdFor(aPageURI, &pageId, PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
mozStorageStatementScoper scoper(mDBSetPageFavicon);
rv = mDBSetPageFavicon->BindInt64Parameter(0, pageId);
mozIStorageStatement* stmt = GetStatement(mDBSetPageFavicon);
NS_ENSURE_STATE(stmt);
mozStorageStatementScoper scoper(stmt);
rv = stmt->BindInt64Parameter(0, pageId);
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBSetPageFavicon->BindInt64Parameter(1, iconId);
rv = stmt->BindInt64Parameter(1, iconId);
NS_ENSURE_SUCCESS(rv, rv);
rv = mDBSetPageFavicon->Execute();
rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv, rv);
rv = transaction.Commit();
@ -602,6 +624,7 @@ nsFaviconService::SetFaviconUrlForPageInternal(nsIURI* aPageURI,
return NS_OK;
}
// nsFaviconService::UpdateBookmarkRedirectFavicon
//
// It is not uncommon to have a bookmark (usually manually entered or
@ -649,6 +672,7 @@ nsFaviconService::UpdateBookmarkRedirectFavicon(nsIURI* aPageURI,
return NS_OK;
}
// nsFaviconService::SendFaviconNotifications
//
// Call to send out favicon changed notifications. Should only be called
@ -667,6 +691,7 @@ nsFaviconService::SendFaviconNotifications(nsIURI* aPageURI,
}
}
NS_IMETHODIMP
nsFaviconService::SetAndLoadFaviconForPage(nsIURI* aPageURI,
nsIURI* aFaviconURI,
@ -689,6 +714,7 @@ nsFaviconService::SetAndLoadFaviconForPage(nsIURI* aPageURI,
#endif
}
nsresult
nsFaviconService::DoSetAndLoadFaviconForPage(nsIURI* aPageURI,
nsIURI* aFaviconURI,
@ -718,13 +744,14 @@ nsFaviconService::DoSetAndLoadFaviconForPage(nsIURI* aPageURI,
new FaviconExpirationGetter(page, aFaviconURI, !!aForceReload);
NS_ENSURE_TRUE(dataGetter, NS_ERROR_OUT_OF_MEMORY);
rv = dataGetter->checkAndLoad(mDBGetIconInfo);
rv = dataGetter->checkAndLoad(GetStatement(mDBGetIconInfo));
NS_ENSURE_SUCCESS(rv, rv);
// DB will be updated and observers notified when data has finished loading.
return NS_OK;
}
// nsFaviconService::SetFaviconData
//
// See the IDL for this function for lots of info. Note from there: we don't
@ -767,24 +794,29 @@ nsFaviconService::SetFaviconData(nsIURI* aFaviconURI, const PRUint8* aData,
{
// this block forces the scoper to reset our statement: necessary for the
// next statement
mozStorageStatementScoper scoper(mDBGetIconInfo);
rv = BindStatementURI(mDBGetIconInfo, 0, aFaviconURI);
mozIStorageStatement* stmt = GetStatement(mDBGetIconInfo);
NS_ENSURE_STATE(stmt);
mozStorageStatementScoper scoper(stmt);
rv = BindStatementURI(stmt, 0, aFaviconURI);
NS_ENSURE_SUCCESS(rv, rv);
PRBool hasResult;
rv = mDBGetIconInfo->ExecuteStep(&hasResult);
rv = stmt->ExecuteStep(&hasResult);
NS_ENSURE_SUCCESS(rv, rv);
if (hasResult) {
// update old one (statement parameter 0 = ID)
PRInt64 id;
rv = mDBGetIconInfo->GetInt64(0, &id);
rv = stmt->GetInt64(0, &id);
NS_ENSURE_SUCCESS(rv, rv);
statement = mDBUpdateIcon;
statement = GetStatement(mDBUpdateIcon);
NS_ENSURE_STATE(statement);
rv = statement->BindInt64Parameter(0, id);
} else {
}
else {
// insert new one (statement parameter 0 = favicon URL)
statement = mDBInsertIcon;
statement = GetStatement(mDBInsertIcon);
NS_ENSURE_STATE(statement);
rv = BindStatementURI(statement, 0, aFaviconURI);
}
NS_ENSURE_SUCCESS(rv, rv);
@ -799,9 +831,13 @@ nsFaviconService::SetFaviconData(nsIURI* aFaviconURI, const PRUint8* aData,
NS_ENSURE_SUCCESS(rv, rv);
rv = statement->BindInt64Parameter(3, aExpiration);
NS_ENSURE_SUCCESS(rv, rv);
return statement->Execute();
rv = statement->Execute();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsFaviconService::SetFaviconDataFromDataURL(nsIURI* aFaviconURI,
const nsAString& aDataURL,
@ -861,6 +897,7 @@ nsFaviconService::SetFaviconDataFromDataURL(nsIURI* aFaviconURI,
return NS_OK;
}
NS_IMETHODIMP
nsFaviconService::GetFaviconData(nsIURI* aFaviconURI, nsACString& aMimeType,
PRUint32* aDataLen, PRUint8** aData)
@ -869,20 +906,23 @@ nsFaviconService::GetFaviconData(nsIURI* aFaviconURI, nsACString& aMimeType,
NS_ENSURE_ARG_POINTER(aDataLen);
NS_ENSURE_ARG_POINTER(aData);
mozStorageStatementScoper scoper(mDBGetData);
nsresult rv = BindStatementURI(mDBGetData, 0, aFaviconURI);
mozIStorageStatement* stmt = GetStatement(mDBGetData);
NS_ENSURE_STATE(stmt);
mozStorageStatementScoper scoper(stmt);
nsresult rv = BindStatementURI(stmt, 0, aFaviconURI);
NS_ENSURE_SUCCESS(rv, rv);
PRBool hasResult = PR_FALSE;
if (NS_SUCCEEDED(mDBGetData->ExecuteStep(&hasResult)) && hasResult) {
rv = mDBGetData->GetUTF8String(1, aMimeType);
if (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
rv = stmt->GetUTF8String(1, aMimeType);
NS_ENSURE_SUCCESS(rv, rv);
return mDBGetData->GetBlob(0, aDataLen, aData);
return stmt->GetBlob(0, aDataLen, aData);
}
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsFaviconService::GetFaviconDataAsDataURL(nsIURI* aFaviconURI,
nsAString& aDataURL)
@ -917,20 +957,23 @@ nsFaviconService::GetFaviconDataAsDataURL(nsIURI* aFaviconURI,
return NS_OK;
}
NS_IMETHODIMP
nsFaviconService::GetFaviconForPage(nsIURI* aPageURI, nsIURI** _retval)
{
NS_ENSURE_ARG(aPageURI);
NS_ENSURE_ARG_POINTER(_retval);
mozStorageStatementScoper scoper(mDBGetURL);
nsresult rv = BindStatementURI(mDBGetURL, 0, aPageURI);
mozIStorageStatement* stmt = GetStatement(mDBGetURL);
NS_ENSURE_STATE(stmt);
mozStorageStatementScoper scoper(stmt);
nsresult rv = BindStatementURI(stmt, 0, aPageURI);
NS_ENSURE_SUCCESS(rv, rv);
PRBool hasResult;
if (NS_SUCCEEDED(mDBGetURL->ExecuteStep(&hasResult)) && hasResult) {
if (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
nsCAutoString url;
rv = mDBGetURL->GetUTF8String(1, url);
rv = stmt->GetUTF8String(1, url);
NS_ENSURE_SUCCESS(rv, rv);
return NS_NewURI(_retval, url);
@ -938,26 +981,29 @@ nsFaviconService::GetFaviconForPage(nsIURI* aPageURI, nsIURI** _retval)
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsFaviconService::GetFaviconImageForPage(nsIURI* aPageURI, nsIURI** _retval)
{
NS_ENSURE_ARG(aPageURI);
NS_ENSURE_ARG_POINTER(_retval);
mozStorageStatementScoper scoper(mDBGetURL);
nsresult rv = BindStatementURI(mDBGetURL, 0, aPageURI);
mozIStorageStatement* stmt = GetStatement(mDBGetURL);
NS_ENSURE_STATE(stmt);
mozStorageStatementScoper scoper(stmt);
nsresult rv = BindStatementURI(stmt, 0, aPageURI);
NS_ENSURE_SUCCESS(rv, rv);
PRBool hasResult;
nsCOMPtr<nsIURI> faviconURI;
if (NS_SUCCEEDED(mDBGetURL->ExecuteStep(&hasResult)) && hasResult) {
if (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
PRInt32 dataLen;
rv = mDBGetURL->GetInt32(2, &dataLen);
rv = stmt->GetInt32(2, &dataLen);
NS_ENSURE_SUCCESS(rv, rv);
if (dataLen > 0) {
// this page has a favicon entry with data
nsCAutoString favIconUri;
rv = mDBGetURL->GetUTF8String(1, favIconUri);
rv = stmt->GetUTF8String(1, favIconUri);
NS_ENSURE_SUCCESS(rv, rv);
return GetFaviconLinkForIconString(favIconUri, _retval);
@ -968,6 +1014,7 @@ nsFaviconService::GetFaviconImageForPage(nsIURI* aPageURI, nsIURI** _retval)
return GetDefaultFavicon(_retval);
}
nsresult
nsFaviconService::GetFaviconLinkForIcon(nsIURI* aFaviconURI,
nsIURI** aOutputURI)
@ -983,6 +1030,7 @@ nsFaviconService::GetFaviconLinkForIcon(nsIURI* aFaviconURI,
return GetFaviconLinkForIconString(spec, aOutputURI);
}
static PLDHashOperator
ExpireFailedFaviconsCallback(nsCStringHashKey::KeyType aKey,
PRUint32& aData,
@ -994,6 +1042,7 @@ ExpireFailedFaviconsCallback(nsCStringHashKey::KeyType aKey,
return PL_DHASH_NEXT;
}
NS_IMETHODIMP
nsFaviconService::AddFailedFavicon(nsIURI* aFaviconURI)
{
@ -1017,6 +1066,7 @@ nsFaviconService::AddFailedFavicon(nsIURI* aFaviconURI)
return NS_OK;
}
NS_IMETHODIMP
nsFaviconService::RemoveFailedFavicon(nsIURI* aFaviconURI)
{
@ -1031,6 +1081,7 @@ nsFaviconService::RemoveFailedFavicon(nsIURI* aFaviconURI)
return NS_OK;
}
NS_IMETHODIMP
nsFaviconService::IsFailedFavicon(nsIURI* aFaviconURI, PRBool* _retval)
{
@ -1044,6 +1095,7 @@ nsFaviconService::IsFailedFavicon(nsIURI* aFaviconURI, PRBool* _retval)
return NS_OK;
}
// nsFaviconService::GetFaviconLinkForIconString
//
// This computes a favicon URL with string input and using the cached
@ -1075,6 +1127,7 @@ nsFaviconService::GetFaviconLinkForIconString(const nsCString& aSpec,
return NS_NewURI(aOutput, annoUri);
}
// nsFaviconService::GetFaviconSpecForIconString
//
// This computes a favicon spec for when you don't want a URI object (as in
@ -1093,6 +1146,7 @@ nsFaviconService::GetFaviconSpecForIconString(const nsCString& aSpec,
}
}
// nsFaviconService::OptimizeFaviconImage
//
// Given a blob of data (a image file already read into a buffer), optimize
@ -1136,15 +1190,21 @@ nsFaviconService::OptimizeFaviconImage(const PRUint8* aData, PRUint32 aDataLen,
return NS_OK;
}
nsresult
nsFaviconService::FinalizeStatements() {
mShuttingDown = true;
mozIStorageStatement* stmts[] = {
mDBGetURL,
mDBGetData,
mDBGetIconInfo,
mDBInsertIcon,
mDBUpdateIcon,
mDBSetPageFavicon
mDBSetPageFavicon,
mDBRemoveOnDiskReferences,
mDBRemoveTempReferences,
mDBRemoveAllFavicons,
};
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(stmts); i++) {
@ -1155,18 +1215,22 @@ nsFaviconService::FinalizeStatements() {
return NS_OK;
}
nsresult
nsFaviconService::GetFaviconDataAsync(nsIURI* aFaviconURI,
mozIStorageStatementCallback *aCallback)
{
NS_ASSERTION(aCallback, "Doesn't make sense to call this without a callback");
nsresult rv = BindStatementURI(mDBGetData, 0, aFaviconURI);
mozIStorageStatement* stmt = GetStatement(mDBGetData);
NS_ENSURE_STATE(stmt);
nsresult rv = BindStatementURI(stmt, 0, aFaviconURI);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<mozIStoragePendingStatement> pendingStatement;
return mDBGetData->ExecuteAsync(aCallback, getter_AddRefs(pendingStatement));
return stmt->ExecuteAsync(aCallback, getter_AddRefs(pendingStatement));
}
void
nsFaviconService::checkAndNotify(nsIURI *aPageURI,
nsIURI *aFaviconURI)
@ -1194,6 +1258,7 @@ nsFaviconService::checkAndNotify(nsIURI *aPageURI,
}
}
////////////////////////////////////////////////////////////////////////////////
//// FaviconLoadListener
@ -1203,6 +1268,7 @@ NS_IMPL_ISUPPORTS4(FaviconLoadListener,
nsIInterfaceRequestor,
nsIChannelEventSink)
FaviconLoadListener::FaviconLoadListener(nsIURI* aPageURI,
nsIURI* aFaviconURI,
nsIChannel* aChannel) :
@ -1212,16 +1278,19 @@ FaviconLoadListener::FaviconLoadListener(nsIURI* aPageURI,
{
}
FaviconLoadListener::~FaviconLoadListener()
{
}
NS_IMETHODIMP
FaviconLoadListener::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
{
return NS_OK;
}
NS_IMETHODIMP
FaviconLoadListener::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
nsresult aStatusCode)
@ -1322,10 +1391,11 @@ FaviconLoadListener::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
return NS_OK;
}
NS_IMETHODIMP
FaviconLoadListener::OnDataAvailable(nsIRequest *aRequest,
nsISupports *aContext,
nsIInputStream *aInputStream,
FaviconLoadListener::OnDataAvailable(nsIRequest* aRequest,
nsISupports* aContext,
nsIInputStream* aInputStream,
PRUint32 aOffset,
PRUint32 aCount)
{
@ -1338,12 +1408,14 @@ FaviconLoadListener::OnDataAvailable(nsIRequest *aRequest,
return NS_OK;
}
NS_IMETHODIMP
FaviconLoadListener::GetInterface(const nsIID& uuid, void** aResult)
{
return QueryInterface(uuid, aResult);
}
NS_IMETHODIMP
FaviconLoadListener::OnChannelRedirect(nsIChannel* oldChannel,
nsIChannel* newChannel,
@ -1353,18 +1425,21 @@ FaviconLoadListener::OnChannelRedirect(nsIChannel* oldChannel,
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
//// ExpireFaviconsStatementCallbackNotifier
NS_IMPL_ISUPPORTS1(ExpireFaviconsStatementCallbackNotifier,
mozIStorageStatementCallback)
ExpireFaviconsStatementCallbackNotifier::ExpireFaviconsStatementCallbackNotifier(bool *aFaviconsExpirationRunning)
: mFaviconsExpirationRunning(aFaviconsExpirationRunning)
ExpireFaviconsStatementCallbackNotifier::ExpireFaviconsStatementCallbackNotifier(
bool* aFaviconsExpirationRunning)
: mFaviconsExpirationRunning(aFaviconsExpirationRunning)
{
NS_ASSERTION(mFaviconsExpirationRunning, "Pointer to bool mFaviconsExpirationRunning can't be null");
}
NS_IMETHODIMP
ExpireFaviconsStatementCallbackNotifier::HandleCompletion(PRUint16 aReason)
{
@ -1385,8 +1460,9 @@ ExpireFaviconsStatementCallbackNotifier::HandleCompletion(PRUint16 aReason)
return NS_OK;
}
NS_IMETHODIMP
ExpireFaviconsStatementCallbackNotifier::HandleResult(mozIStorageResultSet *aResultSet)
ExpireFaviconsStatementCallbackNotifier::HandleResult(mozIStorageResultSet* aResultSet)
{
NS_ASSERTION(PR_FALSE, "You cannot use this statement callback to get async statements resultset");
return NS_OK;

View File

@ -41,11 +41,11 @@
#include "nsIFaviconService.h"
#include "nsServiceManagerUtils.h"
#include "nsString.h"
#include "mozIStorageConnection.h"
#include "mozIStorageValueArray.h"
#include "mozIStorageStatement.h"
#include "nsToolkitCompsCID.h"
#include "mozilla/storage.h"
// Favicons bigger than this size should not be saved to the db to avoid
// bloating it with large image blobs.
// This still allows us to accept a favicon even if we cannot optimize it.
@ -65,7 +65,7 @@ public:
/**
* Obtains the service's object.
*/
static nsFaviconService * GetSingleton();
static nsFaviconService* GetSingleton();
/**
* Initializes the service's object. This should only be called once.
@ -79,7 +79,7 @@ public:
* Returns a cached pointer to the favicon service for consumers in the
* places directory.
*/
static nsFaviconService * GetFaviconService()
static nsFaviconService* GetFaviconService()
{
if (!gFaviconService) {
nsCOMPtr<nsIFaviconService> serv =
@ -112,8 +112,8 @@ public:
* returned result, the favicon binary data will be at index 0, and the
* mime type will be at index 1.
*/
nsresult GetFaviconDataAsync(nsIURI *aFaviconURI,
mozIStorageStatementCallback *aCallback);
nsresult GetFaviconDataAsync(nsIURI* aFaviconURI,
mozIStorageStatementCallback* aCallback);
/**
* Checks to see if a favicon's URI has changed, and notifies callers if it
@ -124,7 +124,7 @@ public:
* @param aFaviconURI
* The URI for the favicon we want to test for on aPageURI.
*/
void checkAndNotify(nsIURI *aPageURI, nsIURI *aFaviconURI);
void checkAndNotify(nsIURI* aPageURI, nsIURI* aFaviconURI);
/**
* Finalize all internal statements.
@ -139,14 +139,21 @@ private:
nsCOMPtr<mozIStorageConnection> mDBConn; // from history service
/**
* Always use this getter and never use directly the statement nsCOMPtr.
*/
mozIStorageStatement* GetStatement(const nsCOMPtr<mozIStorageStatement>& aStmt);
nsCOMPtr<mozIStorageStatement> mDBGetURL; // returns URL, data len given page
nsCOMPtr<mozIStorageStatement> mDBGetData; // returns actual data given URL
nsCOMPtr<mozIStorageStatement> mDBGetIconInfo;
nsCOMPtr<mozIStorageStatement> mDBInsertIcon;
nsCOMPtr<mozIStorageStatement> mDBUpdateIcon;
nsCOMPtr<mozIStorageStatement> mDBSetPageFavicon;
nsCOMPtr<mozIStorageStatement> mDBRemoveOnDiskReferences;
nsCOMPtr<mozIStorageStatement> mDBRemoveTempReferences;
nsCOMPtr<mozIStorageStatement> mDBRemoveAllFavicons;
static nsFaviconService *gFaviconService;
static nsFaviconService* gFaviconService;
/**
* A cached URI for the default icon. We return this a lot, and don't want to
@ -176,6 +183,8 @@ private:
void SendFaviconNotifications(nsIURI* aPage, nsIURI* aFaviconURI);
friend class FaviconLoadListener;
bool mShuttingDown;
};
#define FAVICON_DEFAULT_URL "chrome://mozapps/skin/places/defaultFavicon.png"

View File

@ -2462,7 +2462,16 @@ Submission.prototype = {
// nsIBrowserSearchService
function SearchService() {
this._init();
// Replace empty LOG function with the useful one if the log pref is set.
if (getBoolPref(BROWSER_SEARCH_PREF + "log", false))
LOG = DO_LOG;
try {
this._loadEngines();
} catch (ex) {
LOG("_init: failure loading engines: " + ex);
}
this._addObservers();
}
SearchService.prototype = {
_engines: { },
@ -2477,27 +2486,6 @@ SearchService.prototype = {
// needs to happen anytime _sortedEngines is modified after initial startup.
_needToSetOrderPrefs: false,
_init: function() {
// Replace empty LOG function with the useful one if the log pref is set.
if (getBoolPref(BROWSER_SEARCH_PREF + "log", false))
LOG = DO_LOG;
engineUpdateService.init();
try {
this._loadEngines();
} catch (ex) {
LOG("_init: failure loading engines: " + ex);
}
this._addObservers();
let selectedEngineName = getLocalizedPref(BROWSER_SEARCH_PREF +
"selectedEngine");
this._currentEngine = this.getEngineByName(selectedEngineName) ||
this.defaultEngine;
},
_buildCache: function SRCH_SVC__buildCache() {
if (!getBoolPref(BROWSER_SEARCH_PREF + "cache.enabled", true))
return;
@ -2520,7 +2508,6 @@ SearchService.prototype = {
cache.directories = {};
function getParent(engine) {
if (engine._file)
return engine._file.parent;
@ -3380,6 +3367,12 @@ SearchService.prototype = {
},
get currentEngine() {
if (!this._currentEngine) {
let selectedEngine = getLocalizedPref(BROWSER_SEARCH_PREF +
"selectedEngine");
this._currentEngine = this.getEngineByName(selectedEngine);
}
if (!this._currentEngine || this._currentEngine.hidden)
this._currentEngine = this.defaultEngine;
return this._currentEngine;
@ -3442,6 +3435,45 @@ SearchService.prototype = {
}
},
// nsITimerCallback
notify: function SRCH_SVC_notify(aTimer) {
LOG("_notify: checking for updates");
if (!getBoolPref(BROWSER_SEARCH_PREF + "update", true))
return;
// Our timer has expired, but unfortunately, we can't get any data from it.
// Therefore, we need to walk our engine-list, looking for expired engines
var currentTime = Date.now();
LOG("currentTime: " + currentTime);
for each (engine in this._engines) {
engine = engine.wrappedJSObject;
if (!engine._hasUpdates)
continue;
LOG("checking " + engine.name);
var expirTime = engineMetadataService.getAttr(engine, "updateexpir");
LOG("expirTime: " + expirTime + "\nupdateURL: " + engine._updateURL +
"\niconUpdateURL: " + engine._iconUpdateURL);
var engineExpired = expirTime <= currentTime;
if (!expirTime || !engineExpired) {
LOG("skipping engine");
continue;
}
LOG(engine.name + " has expired");
engineUpdateService.update(engine);
// Schedule the next update
engineUpdateService.scheduleNextUpdate(engine);
} // end engine iteration
},
_addObservers: function SRCH_SVC_addObservers() {
gObsSvc.addObserver(this, SEARCH_ENGINE_TOPIC, false);
gObsSvc.addObserver(this, QUIT_APPLICATION_TOPIC, false);
@ -3455,6 +3487,7 @@ SearchService.prototype = {
QueryInterface: function SRCH_SVC_QI(aIID) {
if (aIID.equals(Ci.nsIBrowserSearchService) ||
aIID.equals(Ci.nsIObserver) ||
aIID.equals(Ci.nsITimerCallback) ||
aIID.equals(Ci.nsISupports))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
@ -3599,18 +3632,6 @@ function ULOG(aText) {
}
var engineUpdateService = {
init: function eus_init() {
var tm = Cc["@mozilla.org/updates/timer-manager;1"].
getService(Ci.nsIUpdateTimerManager);
// figure out how often to check for any expired engines
var interval = gPrefSvc.getIntPref(BROWSER_SEARCH_PREF + "updateinterval");
// Interval is stored in hours
var seconds = interval * 3600;
tm.registerTimer("search-engine-update-timer", engineUpdateService,
seconds);
},
scheduleNextUpdate: function eus_scheduleNextUpdate(aEngine) {
var interval = aEngine._updateInterval || SEARCH_DEFAULT_UPDATE_INTERVAL;
var milliseconds = interval * 86400000; // |interval| is in days
@ -3659,46 +3680,6 @@ var engineUpdateService = {
// otherwise use the existing engine object.
(testEngine || engine)._setIcon(engine._iconUpdateURL, true);
}
},
notify: function eus_Notify(aTimer) {
ULOG("notify called");
if (!getBoolPref(BROWSER_SEARCH_PREF + "update", true))
return;
// Our timer has expired, but unfortunately, we can't get any data from it.
// Therefore, we need to walk our engine-list, looking for expired engines
var searchService = Cc["@mozilla.org/browser/search-service;1"].
getService(Ci.nsIBrowserSearchService);
var currentTime = Date.now();
ULOG("currentTime: " + currentTime);
for each (engine in searchService.getEngines()) {
engine = engine.wrappedJSObject;
if (!engine._hasUpdates)
continue;
ULOG("checking " + engine.name);
var expirTime = engineMetadataService.getAttr(engine, "updateexpir");
ULOG("expirTime: " + expirTime + "\nupdateURL: " + engine._updateURL +
"\niconUpdateURL: " + engine._iconUpdateURL);
var engineExpired = expirTime <= currentTime;
if (!expirTime || !engineExpired) {
ULOG("skipping engine");
continue;
}
ULOG(engine.name + " has expired");
this.update(engine);
// Schedule the next update
this.scheduleNextUpdate(engine);
} // end engine iteration
}
};
@ -3717,17 +3698,30 @@ const kFactory = {
// nsIModule
const gModule = {
get _catMan() {
return Cc["@mozilla.org/categorymanager;1"].
getService(Ci.nsICategoryManager);
},
registerSelf: function (componentManager, fileSpec, location, type) {
componentManager.QueryInterface(Ci.nsIComponentRegistrar);
componentManager.registerFactoryLocation(kClassID,
kClassName,
kContractID,
fileSpec, location, type);
this._catMan.addCategoryEntry("update-timer", kClassName,
kContractID +
",getService," +
"search-engine-update-timer," +
BROWSER_SEARCH_PREF + "update.interval," +
"21600", /* 6 hours */
true, true);
},
unregisterSelf: function(componentManager, fileSpec, location) {
componentManager.QueryInterface(Ci.nsIComponentRegistrar);
componentManager.unregisterFactoryLocation(kClassID, fileSpec);
this._catMan.deleteCategoryEntry("update-timer", kClassName, true);
},
getClassObject: function (componentManager, cid, iid) {

View File

@ -93,14 +93,14 @@ bool MozQWidget::event(QEvent *e)
}
break;
*/
case QEvent::FocusIn:
case QEvent::WindowActivate:
{
QFocusEvent *fev = (QFocusEvent*)(e);
mReceiver->OnFocusInEvent(fev);
return TRUE;
}
break;
case QEvent::FocusOut:
case QEvent::WindowDeactivate:
{
QFocusEvent *fev = (QFocusEvent*)(e);
mReceiver->OnFocusOutEvent(fev);

View File

@ -141,10 +141,10 @@ isContextMenuKeyEvent(const QKeyEvent *qe)
static void
InitKeyEvent(nsKeyEvent &aEvent, QKeyEvent *aQEvent)
{
aEvent.isShift = aQEvent->modifiers() & Qt::ShiftModifier;
aEvent.isControl = aQEvent->modifiers() & Qt::ControlModifier;
aEvent.isAlt = aQEvent->modifiers() & Qt::AltModifier;
aEvent.isMeta = aQEvent->modifiers() & Qt::MetaModifier;
aEvent.isShift = (aQEvent->modifiers() & Qt::ShiftModifier) ? PR_TRUE : PR_FALSE;
aEvent.isControl = (aQEvent->modifiers() & Qt::ControlModifier) ? PR_TRUE : PR_FALSE;
aEvent.isAlt = (aQEvent->modifiers() & Qt::AltModifier) ? PR_TRUE : PR_FALSE;
aEvent.isMeta = (aQEvent->modifiers() & Qt::MetaModifier) ? PR_TRUE : PR_FALSE;
aEvent.time = 0;
// The transformations above and in gdk for the keyval are not invertible