From b58a7314eeaaa5a703ee7b3bed15caa2b335ca59 Mon Sep 17 00:00:00 2001 From: Ryan Flint Date: Thu, 7 Jan 2010 23:25:44 -0500 Subject: [PATCH 01/10] Bug 520284 - Use the update-timer category. r=robstrong --- browser/app/profile/firefox.js | 2 +- toolkit/components/search/nsSearchService.js | 144 +++++++++---------- 2 files changed, 70 insertions(+), 76 deletions(-) diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 25f06bfbfd2..4642acd15b9 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -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); diff --git a/toolkit/components/search/nsSearchService.js b/toolkit/components/search/nsSearchService.js index 4bf221ffe1b..15cbeeab00f 100644 --- a/toolkit/components/search/nsSearchService.js +++ b/toolkit/components/search/nsSearchService.js @@ -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) { From bdd34ba6bead018b92b60b25bd71d3081bc6828e Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 8 Jan 2010 13:59:23 +0900 Subject: [PATCH 02/10] Bug 538466 "ASSERTION: Wrong document somewhere" with contenteditable r=bz --- content/base/src/nsGenericElement.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index fe4d4778f9f..4806c62b65b 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -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(this)->GetPrimaryFrame(); if (frame && frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION) { // This node should be a descendant of input/textarea editor. From 864c94c4cda5ce2e79aac76adc3e31464d9c6187 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 8 Jan 2010 14:01:42 +0900 Subject: [PATCH 03/10] Bug 532422, this landing just removes unused variable r=Olli --- layout/base/nsPresShell.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 7b634b8fb97..5f4c5668e03 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -5958,8 +5958,7 @@ PresShell::GetFocusedDOMWindowInOurWindow() nsCOMPtr 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; } From ccb6231a015ba6e33ac52e0091e2c083f49e1a46 Mon Sep 17 00:00:00 2001 From: Alexander Surkov Date: Fri, 8 Jan 2010 14:50:38 +0800 Subject: [PATCH 04/10] Bug 166994 - Make our MSAA objects also support IDispatch methods for scripters, r=davidb --- accessible/src/msaa/nsAccessibleWrap.cpp | 81 +++++++++++++++++++----- accessible/src/msaa/nsAccessibleWrap.h | 33 +++++++--- 2 files changed, 89 insertions(+), 25 deletions(-) diff --git a/accessible/src/msaa/nsAccessibleWrap.cpp b/accessible/src/msaa/nsAccessibleWrap.cpp index 7e9e91ef228..64ccb53df6f 100644 --- a/accessible/src/msaa/nsAccessibleWrap.cpp +++ b/accessible/src/msaa/nsAccessibleWrap.cpp @@ -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(this), dispIdMember, + wFlags, pDispParams, pVarResult, pExcepInfo, + puArgErr); } +// nsIAccessible method NS_IMETHODIMP nsAccessibleWrap::GetNativeInterface(void **aOutAccessible) { *aOutAccessible = static_cast(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; +} diff --git a/accessible/src/msaa/nsAccessibleWrap.h b/accessible/src/msaa/nsAccessibleWrap.h index 7845ef306e6..30afd8a19da 100644 --- a/accessible/src/msaa/nsAccessibleWrap.h +++ b/accessible/src/msaa/nsAccessibleWrap.h @@ -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, From 06350c488f9c52cc7766dc08496d45f84fa4a40a Mon Sep 17 00:00:00 2001 From: Miika Jarvinen Date: Fri, 8 Jan 2010 09:12:21 +0100 Subject: [PATCH 05/10] Bug 537907 - [qt] Can't type with keyboard because of broken focus. r=vlad --- widget/src/qt/mozqwidget.cpp | 4 ++-- widget/src/qt/nsWindow.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/widget/src/qt/mozqwidget.cpp b/widget/src/qt/mozqwidget.cpp index fb00e371831..8447558d42e 100644 --- a/widget/src/qt/mozqwidget.cpp +++ b/widget/src/qt/mozqwidget.cpp @@ -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); diff --git a/widget/src/qt/nsWindow.cpp b/widget/src/qt/nsWindow.cpp index 3b372c8eb69..f62e0311dde 100644 --- a/widget/src/qt/nsWindow.cpp +++ b/widget/src/qt/nsWindow.cpp @@ -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 From a9db4161828cf6f4e6e31d04524d00500ec364bf Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Wed, 7 Oct 2009 15:13:40 +0100 Subject: [PATCH 06/10] Bug 493280: restructure Windows font management based on cross-platform font-list classes. r=jdaggett sr=roc --- gfx/thebes/public/gfxFT2Fonts.h | 8 +- gfx/thebes/public/gfxFont.h | 24 +- gfx/thebes/public/gfxWindowsFonts.h | 290 +------ gfx/thebes/public/gfxWindowsPlatform.h | 82 +- gfx/thebes/src/Makefile.in | 5 +- gfx/thebes/src/gfxFT2FontList.cpp | 286 +++++++ gfx/thebes/src/gfxFT2FontList.h | 72 ++ gfx/thebes/src/gfxFT2Fonts.cpp | 36 +- gfx/thebes/src/gfxGDIFontList.cpp | 961 ++++++++++++++++++++++ gfx/thebes/src/gfxGDIFontList.h | 353 ++++++++ gfx/thebes/src/gfxMacPlatformFontList.h | 4 +- gfx/thebes/src/gfxMacPlatformFontList.mm | 63 +- gfx/thebes/src/gfxPlatform.cpp | 28 +- gfx/thebes/src/gfxPlatformFontList.cpp | 34 +- gfx/thebes/src/gfxPlatformFontList.h | 5 +- gfx/thebes/src/gfxPlatformMac.cpp | 14 +- gfx/thebes/src/gfxWindowsFonts.cpp | 996 +++-------------------- gfx/thebes/src/gfxWindowsPlatform.cpp | 718 +--------------- 18 files changed, 2029 insertions(+), 1950 deletions(-) create mode 100644 gfx/thebes/src/gfxFT2FontList.cpp create mode 100644 gfx/thebes/src/gfxFT2FontList.h create mode 100644 gfx/thebes/src/gfxGDIFontList.cpp create mode 100644 gfx/thebes/src/gfxGDIFontList.h diff --git a/gfx/thebes/public/gfxFT2Fonts.h b/gfx/thebes/public/gfxFT2Fonts.h index e45c00a32ae..2d42d2120c2 100644 --- a/gfx/thebes/public/gfxFT2Fonts.h +++ b/gfx/thebes/public/gfxFT2Fonts.h @@ -204,12 +204,12 @@ protected: // new functions PRBool mEnableKerning; void GetPrefFonts(const char *aLangGroup, - nsTArray >& aFontEntryList); - void GetCJKPrefFonts(nsTArray >& aFontEntryList); + nsTArray >& aFontEntryList); + void GetCJKPrefFonts(nsTArray >& aFontEntryList); void FamilyListToArrayList(const nsString& aFamilies, const nsCString& aLangGroup, - nsTArray > *aFontEntryList); - already_AddRefed WhichFontSupportsChar(const nsTArray >& aFontEntryList, + nsTArray > *aFontEntryList); + already_AddRefed WhichFontSupportsChar(const nsTArray >& aFontEntryList, PRUint32 aCh); already_AddRefed WhichPrefFontSupportsChar(PRUint32 aCh); already_AddRefed WhichSystemFontSupportsChar(PRUint32 aCh); diff --git a/gfx/thebes/public/gfxFont.h b/gfx/thebes/public/gfxFont.h index afc4fa900f8..db77b29ea0a 100644 --- a/gfx/thebes/public/gfxFont.h +++ b/gfx/thebes/public/gfxFont.h @@ -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), diff --git a/gfx/thebes/public/gfxWindowsFonts.h b/gfx/thebes/public/gfxWindowsFonts.h index e4d00413c88..e2efe489008 100644 --- a/gfx/thebes/public/gfxWindowsFonts.h +++ b/gfx/thebes/public/gfxWindowsFonts.h @@ -57,246 +57,7 @@ // exceptions. use gfxSparseBitSet instead? #include -/** - * 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 - 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 >& 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 > *list, + void GroupFamilyListToArrayList(nsTArray > *list, nsTArray *aNeedsBold); void FamilyListToArrayList(const nsString& aFamilies, const nsCString& aLangGroup, - nsTArray > *list); + nsTArray > *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(static_cast(mFonts[aFontIndex])); + } protected: void InitFontList(); @@ -423,14 +182,19 @@ protected: already_AddRefed WhichPrefFontSupportsChar(PRUint32 aCh); already_AddRefed WhichSystemFontSupportsChar(PRUint32 aCh); - already_AddRefed WhichFontSupportsChar(const nsTArray >& fonts, PRUint32 ch); - void GetPrefFonts(const char *aLangGroup, nsTArray >& array); - void GetCJKPrefFonts(nsTArray >& array); + already_AddRefed WhichFontSupportsChar(const nsTArray >& fonts, PRUint32 ch); + void GetPrefFonts(const char *aLangGroup, nsTArray >& array); + void GetCJKPrefFonts(nsTArray >& array); + + static PRBool FindWindowsFont(const nsAString& aName, + const nsACString& aGenericName, + void *closure); + + PRBool HasFont(gfxFontEntry *aFontEntry); private: nsCString mGenericFamily; - nsTArray > mFontEntries; nsTArray mFontNeedsBold; const char *mItemLangGroup; // used by pref-lang handling code diff --git a/gfx/thebes/public/gfxWindowsPlatform.h b/gfx/thebes/public/gfxWindowsPlatform.h index 11515827f41..12dc821ba18 100644 --- a/gfx/thebes/public/gfxWindowsPlatform.h +++ b/gfx/thebes/public/gfxWindowsPlatform.h @@ -61,7 +61,7 @@ typedef struct FT_LibraryRec_ *FT_Library; #include -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 CreateOffscreenSurface(const gfxIntSize& size, gfxASurface::gfxImageFormat imageFormat); @@ -104,8 +106,6 @@ public: nsresult UpdateFontList(); - void GetFontFamilyList(nsTArray >& 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 - 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 > *array); - void SetPrefFontEntries(const nsCString& aLangGroup, nsTArray >& array); + PRBool GetPrefFontEntries(const nsCString& aLangGroup, nsTArray > *array); + void SetPrefFontEntries(const nsCString& aLangGroup, nsTArray >& array); void ClearPrefFonts() { mPrefFonts.Clear(); } - typedef nsDataHashtable > 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& aFontFamily, - void* userArg); - - static PLDHashOperator FontGetCMapDataProc(nsStringHashKey::KeyType aKey, - nsRefPtr& aFontFamily, - void* userArg); - - static int CALLBACK FontResolveProc(const ENUMLOGFONTEXW *lpelfe, - const NEWTEXTMETRICEXW *metrics, - DWORD fontType, LPARAM data); - - static PLDHashOperator HashEnumFunc(nsStringHashKey::KeyType aKey, - nsRefPtr& aData, - void* userArg); - - static PLDHashOperator FindFontForCharProc(nsStringHashKey::KeyType aKey, - nsRefPtr& 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 mNonExistingFonts; - - // when system-wide font lookup fails for a character, cache it to skip future searches - gfxSparseBitSet mCodepointsWithNoFonts; - - nsDataHashtable > > mPrefFonts; - - // data used as part of the font cmap loading process - nsTArray > mFontFamilies; - PRUint32 mStartIndex; - PRUint32 mIncrement; - PRUint32 mNumFamilies; + // TODO: unify this with mPrefFonts (NB: holds families, not fonts) in gfxPlatformFontList + nsDataHashtable > > mPrefFonts; }; #endif /* GFX_WINDOWS_PLATFORM_H */ diff --git a/gfx/thebes/src/Makefile.in b/gfx/thebes/src/Makefile.in index 3dedaae5070..6fc1ac2b6ce 100644 --- a/gfx/thebes/src/Makefile.in +++ b/gfx/thebes/src/Makefile.in @@ -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 diff --git a/gfx/thebes/src/gfxFT2FontList.cpp b/gfx/thebes/src/gfxFT2FontList.cpp new file mode 100644 index 00000000000..90ed23b55b7 --- /dev/null +++ b/gfx/thebes/src/gfxFT2FontList.cpp @@ -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 + * Masayuki Nakano + * Mats Palmgren + * John Daggett + * Jonathan Kew + * + * 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 +#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 searchPaths(3); + nsTArray 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 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(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& aFontFamily, + void* userArg) +{ + FullFontNameSearch *data = reinterpret_cast(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 >& 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); +} diff --git a/gfx/thebes/src/gfxFT2FontList.h b/gfx/thebes/src/gfxFT2FontList.h new file mode 100644 index 00000000000..ae50a336e96 --- /dev/null +++ b/gfx/thebes/src/gfxFT2FontList.h @@ -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 + * Masayuki Nakano + * John Daggett + * Jonathan Kew + * + * 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 +#include + +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 */ diff --git a/gfx/thebes/src/gfxFT2Fonts.cpp b/gfx/thebes/src/gfxFT2Fonts.cpp index 7a17d0ac9f3..ac8e885dd7c 100644 --- a/gfx/thebes/src/gfxFT2Fonts.cpp +++ b/gfx/thebes/src/gfxFT2Fonts.cpp @@ -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 > *aFontEntryList) + nsTArray > *aFontEntryList) { nsAutoTArray 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 fe = gfxToolkitPlatform::GetPlatform()->FindFontEntry(str, mStyle); + nsRefPtr fe = (gfxToolkitPlatform::GetPlatform()->FindFontEntry(str, mStyle)); aFontEntryList->AppendElement(fe); } } -void gfxFT2FontGroup::GetPrefFonts(const char *aLangGroup, nsTArray >& aFontEntryList) { +void gfxFT2FontGroup::GetPrefFonts(const char *aLangGroup, nsTArray >& aFontEntryList) { NS_ASSERTION(aLangGroup, "aLangGroup is null"); gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform(); - nsAutoTArray, 5> fonts; + nsAutoTArray, 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 >& aFontEntryList) { +void gfxFT2FontGroup::GetCJKPrefFonts(nsTArray >& aFontEntryList) { gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform(); nsCAutoString key("x-internal-cjk-"); @@ -622,13 +623,13 @@ void gfxFT2FontGroup::GetCJKPrefFonts(nsTArray >& aFontEntry } already_AddRefed -gfxFT2FontGroup::WhichFontSupportsChar(const nsTArray >& aFontEntryList, PRUint32 aCh) +gfxFT2FontGroup::WhichFontSupportsChar(const nsTArray >& aFontEntryList, PRUint32 aCh) { for (PRUint32 i = 0; i < aFontEntryList.Length(); i++) { - nsRefPtr fe = aFontEntryList[i]; + gfxFontEntry *fe = aFontEntryList[i].get(); if (fe->HasCharacter(aCh)) { nsRefPtr font = - gfxFT2Font::GetOrMakeFont(fe, &mStyle); + gfxFT2Font::GetOrMakeFont(static_cast(fe), &mStyle); return font.forget(); } } @@ -644,7 +645,7 @@ gfxFT2FontGroup::WhichPrefFontSupportsChar(PRUint32 aCh) nsRefPtr selectedFont; // check out the style's language group - nsAutoTArray, 5> fonts; + nsAutoTArray, 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, 15> fonts; + nsAutoTArray, 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, 5> fonts; + nsAutoTArray, 5> fonts; GetPrefFonts(langGroup, fonts); selectedFont = WhichFontSupportsChar(fonts, aCh); } @@ -684,12 +685,22 @@ gfxFT2FontGroup::WhichPrefFontSupportsChar(PRUint32 aCh) already_AddRefed gfxFT2FontGroup::WhichSystemFontSupportsChar(PRUint32 aCh) { +#ifdef XP_WIN + FontEntry *fe = static_cast + (gfxPlatformFontList::PlatformFontList()->FindFontForChar(aCh, GetFontAt(0))); + if (fe) { + nsRefPtr f = gfxFT2Font::GetOrMakeFont(fe, &mStyle); + nsRefPtr font = f.get(); + return font.forget(); + } +#else nsRefPtr selectedFont; nsRefPtr 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::GetOrMakeFont(const nsAString& aName, const gfxFontStyle *aStyle) { - FontEntry *fe = gfxToolkitPlatform::GetPlatform()->FindFontEntry(aName, *aStyle); + FontEntry *fe = static_cast + (gfxToolkitPlatform::GetPlatform()->FindFontEntry(aName, *aStyle)); if (!fe) { NS_WARNING("Failed to find font entry for font!"); return nsnull; diff --git a/gfx/thebes/src/gfxGDIFontList.cpp b/gfx/thebes/src/gfxGDIFontList.cpp new file mode 100644 index 00000000000..bf14ef60375 --- /dev/null +++ b/gfx/thebes/src/gfxGDIFontList.cpp @@ -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 + * Masayuki Nakano + * Mats Palmgren + * John Daggett + * Jonathan Kew + * + * 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 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& 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 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(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(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(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 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 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 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 (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 (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 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 (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 newFontData; + + isEmbedded = PR_FALSE; + rv = gfxFontUtils::RenameFont(uniqueName, aFontData, aLength, &newFontData); + + if (NS_FAILED(rv)) + return nsnull; + + DWORD numFonts = 0; + + PRUint8 *fontData = reinterpret_cast (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 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; +} diff --git a/gfx/thebes/src/gfxGDIFontList.h b/gfx/thebes/src/gfxGDIFontList.h new file mode 100644 index 00000000000..0c3f17fa6c2 --- /dev/null +++ b/gfx/thebes/src/gfxGDIFontList.h @@ -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 + * Masayuki Nakano + * John Daggett + * Jonathan Kew + * + * 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 +#include + +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& 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(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 > FontTable; + + FontTable mFontSubstitutes; + nsTArray mNonExistingFonts; +}; + +#endif /* GFX_GDIFONTLIST_H */ diff --git a/gfx/thebes/src/gfxMacPlatformFontList.h b/gfx/thebes/src/gfxMacPlatformFontList.h index 557119c2819..cd48521c59f 100644 --- a/gfx/thebes/src/gfxMacPlatformFontList.h +++ b/gfx/thebes/src/gfxMacPlatformFontList.h @@ -92,7 +92,7 @@ protected: class gfxMacPlatformFontList : public gfxPlatformFontList { public: static gfxMacPlatformFontList* PlatformFontList() { - return (gfxMacPlatformFontList*)sPlatformFontList; + return static_cast(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(); } diff --git a/gfx/thebes/src/gfxMacPlatformFontList.mm b/gfx/thebes/src/gfxMacPlatformFontList.mm index 8f02e59529e..4bccb03b58a 100644 --- a/gfx/thebes/src/gfxMacPlatformFontList.mm +++ b/gfx/thebes/src/gfxMacPlatformFontList.mm @@ -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 (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 (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 (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 (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; diff --git a/gfx/thebes/src/gfxPlatform.cpp b/gfx/thebes/src/gfxPlatform.cpp index 9d975451bb8..4fb63a4adf7 100644 --- a/gfx/thebes/src/gfxPlatform.cpp +++ b/gfx/thebes/src/gfxPlatform.cpp @@ -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++; + } } } diff --git a/gfx/thebes/src/gfxPlatformFontList.cpp b/gfx/thebes/src/gfxPlatformFontList.cpp index de0edda5159..9407be211db 100644 --- a/gfx/thebes/src/gfxPlatformFontList.cpp +++ b/gfx/thebes/src/gfxPlatformFontList.cpp @@ -247,9 +247,28 @@ gfxPlatformFontList::HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey, { FontListData *data = static_cast(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 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; } - diff --git a/gfx/thebes/src/gfxPlatformFontList.h b/gfx/thebes/src/gfxPlatformFontList.h index 72a90d408ef..646cb821837 100644 --- a/gfx/thebes/src/gfxPlatformFontList.h +++ b/gfx/thebes/src/gfxPlatformFontList.h @@ -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(); diff --git a/gfx/thebes/src/gfxPlatformMac.cpp b/gfx/thebes/src/gfxPlatformMac.cpp index c1933dc8f14..de012ad09a7 100644 --- a/gfx/thebes/src/gfxPlatformMac.cpp +++ b/gfx/thebes/src/gfxPlatformMac.cpp @@ -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 diff --git a/gfx/thebes/src/gfxWindowsFonts.cpp b/gfx/thebes/src/gfxWindowsFonts.cpp index 9b6938ec9fc..3e5f9cec1df 100644 --- a/gfx/thebes/src/gfxWindowsFonts.cpp +++ b/gfx/thebes/src/gfxWindowsFonts.cpp @@ -48,6 +48,7 @@ #include "gfxWindowsFonts.h" #include "gfxWindowsSurface.h" #include "gfxWindowsPlatform.h" +#include "gfxGDIFontList.h" #include "gfxFontTest.h" @@ -76,37 +77,6 @@ static PRLogModuleInfo *gFontLog = PR_NewLogModule("winfonts"); #define ROUND(x) floor((x) + 0.5) -BYTE -FontTypeToOutPrecision(PRUint8 fontType) -{ -#ifdef WINCE - return OUT_DEFAULT_PRECIS; -#else - 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; -#endif -} - struct DCFromContext { DCFromContext(gfxContext *aContext) { dc = NULL; @@ -140,743 +110,13 @@ struct DCFromContext { }; -/********************************************************************** - * - * class FontFamily - * - **********************************************************************/ -static nsresult -ReadCMAP(HDC hdc, FontEntry *aFontEntry) -{ - const PRUint32 kCMAP = NS_SWAP32(TRUETYPE_TAG('c','m','a','p')); - - DWORD len = GetFontData(hdc, kCMAP, 0, nsnull, 0); - if (len == GDI_ERROR || len == 0) // not a truetype font -- - return NS_ERROR_FAILURE; // we'll treat it as a symbol font - - nsAutoTArray buffer; - if (!buffer.AppendElements(len)) - return NS_ERROR_OUT_OF_MEMORY; - PRUint8 *buf = buffer.Elements(); - - DWORD newLen = GetFontData(hdc, kCMAP, 0, buf, len); - NS_ENSURE_TRUE(newLen == len, NS_ERROR_FAILURE); - - // can't pass bits as references... - PRPackedBool unicodeFont = aFontEntry->mUnicodeFont; - PRPackedBool symbolFont = aFontEntry->mSymbolFont; - nsresult rv = gfxFontUtils::ReadCMAP(buf, len, aFontEntry->mCharacterMap, - unicodeFont, symbolFont); - aFontEntry->mUnicodeFont = unicodeFont; - aFontEntry->mSymbolFont = symbolFont; - - return rv; -} - -struct FamilyAddStyleProcData { - HDC dc; - FontFamily *ff; -}; - -int CALLBACK -FontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe, - const NEWTEXTMETRICEXW *nmetrics, - DWORD fontType, LPARAM data) -{ - const NEWTEXTMETRICW& metrics = nmetrics->ntmTm; - LOGFONTW logFont = lpelfe->elfLogFont; - - FamilyAddStyleProcData *faspd = reinterpret_cast(data); - FontFamily *ff = faspd->ff; - HDC hdc = faspd->dc; - - // 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); - - FontEntry *fe = nsnull; - for (PRUint32 i = 0; i < ff->mAvailableFonts.Length(); ++i) { - fe = static_cast(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(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; - } - } - - logFont.lfCharSet = DEFAULT_CHARSET; - logFont.lfOutPrecision = FontTypeToOutPrecision(feType); - fe = FontEntry::CreateFontEntry(ff->mName, feType, (logFont.lfItalic == 0xFF), (PRUint16) (logFont.lfWeight), nsnull, hdc, &logFont); - - if (!fe) - return 1; - - ff->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; - } - } - } - - fe->mIsBadUnderlineFont = ff->mIsBadUnderlineFontFamily; - - return 1; -} - -// general cmap reading routines moved to gfxFontUtils.cpp -void -FontFamily::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; - - FamilyAddStyleProcData faspd; - faspd.dc = hdc; - faspd.ff = this; - - EnumFontFamiliesExW(hdc, &logFont, (FONTENUMPROCW)FontFamily::FamilyAddStylesProc, (LPARAM)&faspd, 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); - - // Look for font families without bold variations and add a FontEntry - // with synthetic bold (weight 600) for them. - FontEntry *darkestItalic = nsnull; - FontEntry *darkestNonItalic = nsnull; - PRUint8 highestItalic = 0, highestNonItalic = 0; - for (PRUint32 i = 0; i < mAvailableFonts.Length(); i++) { - FontEntry *fe = static_cast(mAvailableFonts[i].get()); - if (fe->mItalic) { - if (!darkestItalic || fe->mWeight > darkestItalic->mWeight) - darkestItalic = fe; - } else { - if (!darkestNonItalic || fe->mWeight > darkestNonItalic->mWeight) - darkestNonItalic = fe; - } - } - - if (darkestItalic && darkestItalic->mWeight < 600) { - FontEntry *newEntry = new FontEntry(*darkestItalic); - newEntry->mWeight = 600; - mAvailableFonts.AppendElement(newEntry); - } - if (darkestNonItalic && darkestNonItalic->mWeight < 600) { - FontEntry *newEntry = new FontEntry(*darkestNonItalic); - newEntry->mWeight = 600; - mAvailableFonts.AppendElement(newEntry); - } -} - - -FontEntry * -FontFamily::FindFontEntry(const gfxFontStyle& aFontStyle) -{ - PRBool needsBold; - return static_cast (FindFontForStyle(aFontStyle, needsBold)); -} - -PRBool -FontFamily::FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], - PRBool anItalic, PRInt16 aStretch) -{ - PRBool matchesSomething = PR_FALSE; - - for (PRUint32 j = 0; j < 2; j++) { - // build up an array of weights that match the italicness we're looking for - for (PRUint32 i = 0; i < mAvailableFonts.Length(); i++) { - gfxFontEntry *fe = mAvailableFonts[i]; - const PRUint8 weight = (fe->mWeight / 100); - if (fe->mItalic == anItalic) { - aFontsForWeights[weight] = fe; - matchesSomething = PR_TRUE; - } - } - if (matchesSomething) - break; - anItalic = !anItalic; - } - - return matchesSomething; -} - -// 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; - -void FontEntry::InitializeFontEmbeddingProcs() -{ - HMODULE fontlib = LoadLibraryW(L"t2embed.dll"); - if (!fontlib) - return; - TTLoadEmbeddedFontPtr = (TTLoadEmbeddedFontProc) GetProcAddress(fontlib, "TTLoadEmbeddedFont"); - TTDeleteEmbeddedFontPtr = (TTDeleteEmbeddedFontProc) GetProcAddress(fontlib, "TTDeleteEmbeddedFont"); -} - -class WinUserFontData : public gfxUserFontData { -public: - WinUserFontData(HANDLE aFontRef, PRBool aIsEmbeddedFont) - : mFontRef(aFontRef), mIsEmbeddedFont(aIsEmbeddedFont) - { } - - virtual ~WinUserFontData() - { - if (!mIsEmbeddedFont) { - RemoveFontMemResourceEx(mFontRef); - } else { - ULONG pulStatus; - TTDeleteEmbeddedFontPtr(mFontRef, 0, &pulStatus); - } - } - - HANDLE mFontRef; - PRPackedBool mIsEmbeddedFont; -}; - -// 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 (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 (aReadStream); - return eotReader->Read(outBuffer, aBytesToRead); - } - -}; - -/* static */ -FontEntry* -FontEntry::LoadFont(const gfxProxyFontEntry &aProxyEntry, - const PRUint8 *aFontData, - PRUint32 aLength) -{ - // 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 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 (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 newFontData; - - isEmbedded = PR_FALSE; - rv = gfxFontUtils::RenameFont(uniqueName, aFontData, aLength, &newFontData); - - if (NS_FAILED(rv)) - return nsnull; - - DWORD numFonts = 0; - - PRUint8 *fontData = reinterpret_cast (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, isEmbedded); - PRUint16 w = (aProxyEntry.mWeight == 0 ? 400 : aProxyEntry.mWeight); - - FontEntry *fe = FontEntry::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; - - // Uniscribe doesn't place CFF fonts loaded privately via AddFontMemResourceEx - if (isCFF) - fe->mForceGDI = PR_TRUE; - - return fe; -} - -class AutoReleaseDC { -public: - AutoReleaseDC(HDC hdc) : mDC(hdc) { - SetGraphicsMode(hdc, GM_ADVANCED); - } - ~AutoReleaseDC() { ReleaseDC(nsnull, mDC); } - HDC mDC; -}; - -class AutoPushPopFont { -public: - AutoPushPopFont(HDC hdc, HFONT aFont) : mDC(hdc), mFont(aFont) { - mOldFont = (HFONT)SelectObject(mDC, mFont); - } - ~AutoPushPopFont() { - SelectObject(mDC, mOldFont); - DeleteObject(mFont); - } - HDC mDC; - HFONT mFont; - HFONT mOldFont; -}; - -/* static */ -FontEntry* -FontEntry::CreateFontEntry(const nsAString& aName, gfxWindowsFontType aFontType, - PRBool aItalic, PRUint16 aWeight, - gfxUserFontData* aUserFontData, - HDC hdc, LOGFONTW *aLogFont) -{ - LOGFONTW logFont; - PRBool needRelease = PR_FALSE; - - // jtdfix - need to set charset, unicode ranges, pitch/family - - FontEntry *fe; - - fe = new FontEntry(aName, aFontType, aItalic, aWeight, aUserFontData); - if (!fe) - return nsnull; - - if (!aLogFont) { - aLogFont = &logFont; - FontEntry::FillLogFont(aLogFont, aName, aFontType, aItalic, aWeight, 0); - } - - if (!hdc) { - hdc = GetDC(nsnull); - SetGraphicsMode(hdc, GM_ADVANCED); - needRelease = PR_TRUE; - } - - HFONT font = CreateFontIndirectW(aLogFont); - - if (font) { - AutoPushPopFont fontCleanup(hdc, font); - nsresult rv; - - rv = ::ReadCMAP(hdc, fe); - - if (NS_FAILED(rv)) { - - // ReadCMAP can fail but only handle failure cases when the font - // did *not* have a cmap that appears to be malformed. Uniscribe - // can crash with corrupt cmaps. - if (rv == NS_ERROR_GFX_CMAP_MALFORMED) { - delete fe; - return nsnull; - } else { - - // ReadCMAP may change the values of mUnicodeFont and mSymbolFont - - // 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; - } - } - } - - if (needRelease) - ReleaseDC(nsnull, hdc); - - return fe; -} - -/* static */ -FontEntry* -FontEntry::LoadLocalFont(const gfxProxyFontEntry &aProxyEntry, - const nsAString& aFullname) -{ - // lookup name with CreateFontIndirect - HDC hdc = GetDC(nsnull); - AutoReleaseDC dcCleanup(hdc); - SetGraphicsMode(hdc, GM_ADVANCED); - - 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; - - HFONT font = CreateFontIndirectW(&logFont); - if (!font) - 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; - - { - AutoPushPopFont fontCleanup(hdc, font); - - DWORD len = GetFontData(hdc, kNameTag, 0, nsnull, 0); - if (len == GDI_ERROR || len == 0) // not a truetype font -- - return nsnull; // so just ignore - - nsAutoTArray nameData; - if (!nameData.AppendElements(len)) - return nsnull; - PRUint8 *nameTable = nameData.Elements(); - - DWORD newLen = GetFontData(hdc, 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 - - FontEntry *fe = FontEntry::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 -FontEntry::FillLogFont(LOGFONTW *aLogFont, const nsAString& aName, - gfxWindowsFontType aFontType, PRBool aItalic, - PRUint16 aWeight, gfxFloat aSize) -{ -#define CLIP_TURNOFF_FONTASSOCIATION 0x40 - - aLogFont->lfHeight = (LONG)-ROUND(aSize); - - if (aLogFont->lfHeight == 0) - aLogFont->lfHeight = -1; - - // Fill in logFont structure - aLogFont->lfWidth = 0; - aLogFont->lfEscapement = 0; - aLogFont->lfOrientation = 0; - aLogFont->lfUnderline = FALSE; - aLogFont->lfStrikeOut = FALSE; - aLogFont->lfCharSet = DEFAULT_CHARSET; - aLogFont->lfOutPrecision = FontTypeToOutPrecision(aFontType); - aLogFont->lfClipPrecision = CLIP_TURNOFF_FONTASSOCIATION; - aLogFont->lfQuality = DEFAULT_QUALITY; - aLogFont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; - // always force lfItalic if we want it. Font selection code will - // do its best to give us an italic font entry, but if no face exists - // it may give us a regular one based on weight. Windows should - // do fake italic for us in that case. - aLogFont->lfItalic = aItalic; - aLogFont->lfWeight = aWeight; - - int len = PR_MIN(aName.Length(), LF_FACESIZE - 1); - memcpy(aLogFont->lfFaceName, nsPromiseFlatString(aName).get(), len * 2); - aLogFont->lfFaceName[len] = '\0'; -} - - -PRBool -FontEntry::TestCharacterMap(PRUint32 aCh) -{ - 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 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; - } - } - - return PR_FALSE; -} - /********************************************************************** * * class gfxWindowsFont * **********************************************************************/ -gfxWindowsFont::gfxWindowsFont(FontEntry *aFontEntry, const gfxFontStyle *aFontStyle, +gfxWindowsFont::gfxWindowsFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aFontStyle, cairo_antialias_t anAntialiasOption) : gfxFont(aFontEntry, aFontStyle), mFont(nsnull), mAdjustedSize(0.0), mScriptCache(nsnull), @@ -1100,7 +340,7 @@ gfxWindowsFont::ComputeMetrics() void gfxWindowsFont::FillLogFont(gfxFloat aSize) { - FontEntry *fe = GetFontEntry(); + GDIFontEntry *fe = GetFontEntry(); PRBool isItalic; isItalic = (GetStyle()->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)); @@ -1124,8 +364,7 @@ gfxWindowsFont::FillLogFont(gfxFloat aSize) } } - FontEntry::FillLogFont(&mLogFont, fe->Name(), fe->mFontType, isItalic, - weight, aSize); + fe->FillLogFont(&mLogFont, isItalic, weight, aSize); } @@ -1195,10 +434,10 @@ gfxWindowsFont::Measure(gfxTextRun *aTextRun, aBoundingBoxType, aRefContext, aSpacing); } -FontEntry* +GDIFontEntry* gfxWindowsFont::GetFontEntry() { - return static_cast (mFontEntry.get()); + return static_cast (mFontEntry.get()); } PRBool @@ -1226,7 +465,7 @@ gfxWindowsFont::SetupCairoFont(gfxContext *aContext) * except for OOM in which case we do nothing and return null. */ already_AddRefed -gfxWindowsFont::GetOrMakeFont(FontEntry *aFontEntry, const gfxFontStyle *aStyle, +gfxWindowsFont::GetOrMakeFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aStyle, PRBool aNeedsBold) { // because we know the FontEntry has the weight we really want, use it for matching @@ -1280,7 +519,7 @@ AddFontNameToArray(const nsAString& aName, void -gfxWindowsFontGroup::GroupFamilyListToArrayList(nsTArray > *list, +gfxWindowsFontGroup::GroupFamilyListToArrayList(nsTArray > *list, nsTArray *aNeedsBold) { nsAutoTArray fonts; @@ -1288,14 +527,14 @@ gfxWindowsFontGroup::GroupFamilyListToArrayList(nsTArray > * PRUint32 len = fonts.Length(); for (PRUint32 i = 0; i < len; ++i) { - nsRefPtr fe; + nsRefPtr fe; // first, look up in the user font set gfxFontEntry *gfe; PRBool needsBold = PR_FALSE; if (mUserFontSet && (gfe = mUserFontSet->FindFontEntry(fonts[i], mStyle, needsBold))) { // assume for now platform font if not SVG - fe = static_cast (gfe); + fe = gfe; } // nothing in the user font set ==> check system fonts @@ -1314,7 +553,7 @@ gfxWindowsFontGroup::GroupFamilyListToArrayList(nsTArray > * void gfxWindowsFontGroup::FamilyListToArrayList(const nsString& aFamilies, const nsCString& aLangGroup, - nsTArray > *list) + nsTArray > *list) { nsAutoTArray fonts; ForEachFont(aFamilies, aLangGroup, AddFontNameToArray, &fonts); @@ -1322,7 +561,8 @@ gfxWindowsFontGroup::FamilyListToArrayList(const nsString& aFamilies, PRUint32 len = fonts.Length(); for (PRUint32 i = 0; i < len; ++i) { const nsString& str = fonts[i]; - nsRefPtr fe = gfxWindowsPlatform::GetPlatform()->FindFontEntry(str, mStyle); + nsRefPtr fe = + gfxWindowsPlatform::GetPlatform()->FindFontEntry(str, mStyle); if (fe) { list->AppendElement(fe); } @@ -1339,26 +579,6 @@ gfxWindowsFontGroup::~gfxWindowsFontGroup() { } -gfxWindowsFont * -gfxWindowsFontGroup::GetFontAt(PRInt32 i) -{ - // 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"); - - if (!mFonts[i]) { - nsRefPtr font = - gfxWindowsFont::GetOrMakeFont(mFontEntries[i], &mStyle, mFontNeedsBold[i]); - mFonts[i] = font; - } - - return static_cast(mFonts[i].get()); -} - gfxFontGroup * gfxWindowsFontGroup::Copy(const gfxFontStyle *aStyle) { @@ -1372,7 +592,6 @@ gfxWindowsFontGroup::UpdateFontList() if (mUserFontSet && mCurrGeneration != GetGeneration()) { // xxx - can probably improve this to detect when all fonts were found, so no need to update list mFonts.Clear(); - mFontEntries.Clear(); mFontNeedsBold.Clear(); InitFontList(); mCurrGeneration = GetGeneration(); @@ -1380,65 +599,86 @@ gfxWindowsFontGroup::UpdateFontList() } +PRBool +gfxWindowsFontGroup::FindWindowsFont(const nsAString& aName, + const nsACString& aGenericName, + void *closure) +{ + gfxWindowsFontGroup *fontGroup = (gfxWindowsFontGroup*) closure; + const gfxFontStyle *fontStyle = fontGroup->GetStyle(); + + PRBool needsBold; + gfxFontEntry *fe = nsnull; + + // first, look up in the user font set + gfxUserFontSet *fs = fontGroup->GetUserFontSet(); + gfxFontEntry *gfe; + if (fs && (gfe = fs->FindFontEntry(aName, *fontStyle, needsBold))) { + // assume for now platform font if not SVG + fe = gfe; + } + + // nothing in the user font set ==> check system fonts + if (!fe) { + fe = gfxPlatformFontList::PlatformFontList()->FindFontForFamily(aName, fontStyle, needsBold); + } + + if (fe && !fontGroup->HasFont(fe)) { + nsRefPtr font = gfxWindowsFont::GetOrMakeFont(fe, fontStyle, needsBold); + if (font) { + fontGroup->mFonts.AppendElement(font); + } + } + + return PR_TRUE; +} + +PRBool +gfxWindowsFontGroup::HasFont(gfxFontEntry *aFontEntry) +{ + for (PRUint32 i = 0; i < mFonts.Length(); ++i) { + if (aFontEntry == mFonts.ElementAt(i).get()->GetFontEntry()) + return PR_TRUE; + } + return PR_FALSE; +} + void gfxWindowsFontGroup::InitFontList() { - GroupFamilyListToArrayList(&mFontEntries, &mFontNeedsBold); + ForEachFont(FindWindowsFont, this); - mFonts.AppendElements(mFontEntries.Length()); + if (mFonts.Length() == 0) { + // If we get here, we most likely didn't have a default font for + // a specific langGroup. Let's just pick the default Windows + // user font. - // Ensure that the first font is usable. Precompute its metrics since - // we'll surely need them anyway. - while (mFontEntries.Length() > 0) { - nsRefPtr font = - gfxWindowsFont::GetOrMakeFont(mFontEntries[0], &mStyle, mFontNeedsBold[0]); - if (!font->IsValid()) { - mFontEntries.RemoveElementAt(0); - mFonts.RemoveElementAt(0); - mFontNeedsBold.RemoveElementAt(0); - continue; + PRBool needsBold; + gfxFontEntry *defaultFont = + gfxPlatformFontList::PlatformFontList()->GetDefaultFont(&mStyle, needsBold); + NS_ASSERTION(defaultFont, "invalid default font returned by GetDefaultFont"); + + nsRefPtr font = gfxWindowsFont::GetOrMakeFont(defaultFont, &mStyle); + + if (font) { + mFonts.AppendElement(font); } - mFonts[0] = font; - break; - } - - if (mFontEntries.Length() == 0) { - // It is pretty important that we have at least one font, so - // try a few system fonts that should be there. - nsAutoString str; - HGDIOBJ hGDI = ::GetStockObject(DEFAULT_GUI_FONT); - LOGFONTW logFont; - if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont)) { - str.AppendLiteral("\""); - str.Append(nsDependentString(logFont.lfFaceName)); - str.AppendLiteral("\""); - } - - NONCLIENTMETRICSW ncm; - ncm.cbSize = sizeof(ncm); - BOOL status = ::SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, - sizeof(ncm), &ncm, 0); - if (status) { - str.AppendLiteral(",\""); - str.Append(nsDependentString(ncm.lfMessageFont.lfFaceName)); - str.AppendLiteral("\""); - } - - FamilyListToArrayList(str, mStyle.langGroup, &mFontEntries); - - // Keep length of mFonts in sync with length of mFontEntries. - // Maybe we should eagerly set up mFonts[0] like we do above, - // but if the resulting gfxWindowsFont is invalid then we can't - // do much anyway. In that case the font will return zero metrics, - // its mUnknownCMAP will be set to true, and HasCharacter will - // just report false for all characters, so the fact that the font - // is bogus should not cause problems. - mFonts.AppendElements(mFontEntries.Length()); - mFontNeedsBold.AppendElements(mFontEntries.Length()); } // force the underline offset to get recalculated mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET; + + if (!mStyle.systemFont) { + for (PRUint32 i = 0; i < mFonts.Length(); ++i) { + gfxWindowsFont* font = static_cast(mFonts[i].get()); + if (font->GetFontEntry()->mIsBadUnderlineFont) { + gfxFloat first = mFonts[0]->GetMetrics().underlineOffset; + gfxFloat bad = font->GetMetrics().underlineOffset; + mUnderlineOffset = PR_MIN(first, bad); + break; + } + } + } } gfxFloat @@ -1449,8 +689,8 @@ gfxWindowsFontGroup::GetUnderlineOffset() // not yet initialized, need to calculate if (!mStyle.systemFont) { - for (PRUint32 i = 0; i < mFontEntries.Length(); ++i) { - if (mFontEntries[i]->mIsBadUnderlineFont) { + for (PRUint32 i = 0; i < mFonts.Length(); ++i) { + if (mFonts[i]->GetFontEntry()->mIsBadUnderlineFont) { gfxFloat first = GetFontAt(0)->GetMetrics().underlineOffset; gfxFloat bad = GetFontAt(i)->GetMetrics().underlineOffset; mUnderlineOffset = PR_MIN(first, bad); @@ -1634,7 +874,7 @@ void gfxWindowsFontGroup::InitTextRunGDI(gfxContext *aContext, gfxTextRun *aRun, const char *aString, PRUint32 aLength) { - nsRefPtr font = GetFontAt(0); + nsRefPtr font = static_cast(GetFontAt(0)); DCFromContext dc(aContext); if (SetupDCFont(dc, font)) { nsAutoTArray glyphArray; @@ -1658,7 +898,7 @@ void gfxWindowsFontGroup::InitTextRunGDI(gfxContext *aContext, gfxTextRun *aRun, const PRUnichar *aString, PRUint32 aLength) { - nsRefPtr font = GetFontAt(0); + nsRefPtr font = static_cast(GetFontAt(0)); DCFromContext dc(aContext); if (SetupDCFont(dc, font)) { nsAutoTArray glyphArray; @@ -1900,6 +1140,20 @@ public: continue; } + // http://msdn.microsoft.com/en-us/library/dd368564(VS.85).aspx: + // Uniscribe will return this if "the font corresponding to the + // DC does not support the script required by the run...". + // In this case, we'll set the script code to SCRIPT_UNDEFINED + // and try again, so that we'll at least get glyphs even though + // they won't necessarily have proper shaping. + // (We probably shouldn't have selected this font at all, + // but it's too late to fix that here.) + if (rv == USP_E_SCRIPT_NOT_IN_FONT) { + sa.eScript = SCRIPT_UNDEFINED; + NS_WARNING("Uniscribe says font does not support script needed"); + continue; + } + return rv; } } @@ -1962,10 +1216,12 @@ public: HRESULT rv; HDC placeDC = nsnull; + SCRIPT_ANALYSIS sa = mScriptItem->a; + while (PR_TRUE) { rv = ScriptPlace(placeDC, mCurrentFont->ScriptCache(), mGlyphs.Elements(), mNumGlyphs, - mAttr.Elements(), &mScriptItem->a, + mAttr.Elements(), &sa, mAdvances.Elements(), mOffsets.Elements(), NULL); if (rv == E_PENDING) { @@ -1974,6 +1230,11 @@ public: continue; } + if (rv == USP_E_SCRIPT_NOT_IN_FONT) { + sa.eScript = SCRIPT_UNDEFINED; + continue; + } + break; } @@ -2194,7 +1455,7 @@ public: if (mRanges[i].font) font = static_cast (mRanges[i].font.get()); else - font = mGroup->GetFontAt(0); + font = static_cast (mGroup->GetFontAt(0)); SetCurrentFont(font); @@ -2432,9 +1693,10 @@ private: }; already_AddRefed -gfxWindowsFontGroup::WhichFontSupportsChar(const nsTArray >& fonts, PRUint32 ch) { +gfxWindowsFontGroup::WhichFontSupportsChar(const nsTArray >& fonts, + PRUint32 ch) { for (PRUint32 i = 0; i < fonts.Length(); i++) { - nsRefPtr fe = fonts[i]; + GDIFontEntry* fe = static_cast(fonts[i].get()); if (fe->mSymbolFont && !mStyle.familyNameQuirks) continue; if (fe->HasCharacter(ch)) { @@ -2450,10 +1712,11 @@ gfxWindowsFontGroup::WhichFontSupportsChar(const nsTArray >& } // this function appends to the array passed in. -void gfxWindowsFontGroup::GetPrefFonts(const char *aLangGroup, nsTArray >& array) { +void gfxWindowsFontGroup::GetPrefFonts(const char *aLangGroup, + nsTArray >& array) { NS_ASSERTION(aLangGroup, "aLangGroup is null"); gfxWindowsPlatform *platform = gfxWindowsPlatform::GetPlatform(); - nsAutoTArray, 5> fonts; + nsAutoTArray, 5> fonts; /* this lookup has to depend on weight and style */ nsCAutoString key(aLangGroup); key.Append("-"); @@ -2484,7 +1747,7 @@ static PRInt32 GetCJKLangGroupIndex(const char *aLangGroup) { } // this function assigns to the array passed in. -void gfxWindowsFontGroup::GetCJKPrefFonts(nsTArray >& array) { +void gfxWindowsFontGroup::GetCJKPrefFonts(nsTArray >& array) { gfxWindowsPlatform *platform = gfxWindowsPlatform::GetPlatform(); nsCAutoString key("x-internal-cjk-"); @@ -2563,7 +1826,7 @@ gfxWindowsFontGroup::WhichPrefFontSupportsChar(PRUint32 aCh) // check out the style's language group if (!selectedFont) { - nsAutoTArray, 5> fonts; + nsAutoTArray, 5> fonts; this->GetPrefFonts(mStyle.langGroup.get(), fonts); selectedFont = WhichFontSupportsChar(fonts, aCh); } @@ -2574,7 +1837,7 @@ gfxWindowsFontGroup::WhichPrefFontSupportsChar(PRUint32 aCh) if (mItemLangGroup) { PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Trying to find fonts for: %s ", mItemLangGroup)); - nsAutoTArray, 5> fonts; + nsAutoTArray, 5> fonts; this->GetPrefFonts(mItemLangGroup, fonts); selectedFont = WhichFontSupportsChar(fonts, aCh); } else if (aCh <= 0xFFFF) { @@ -2585,7 +1848,7 @@ gfxWindowsFontGroup::WhichPrefFontSupportsChar(PRUint32 aCh) if (PR_LOG_TEST(gFontLog, PR_LOG_DEBUG)) PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Trying to find fonts for: CJK")); - nsAutoTArray, 15> fonts; + nsAutoTArray, 15> fonts; this->GetCJKPrefFonts(fonts); selectedFont = WhichFontSupportsChar(fonts, aCh); } else { @@ -2593,7 +1856,7 @@ gfxWindowsFontGroup::WhichPrefFontSupportsChar(PRUint32 aCh) if (langGroup) { PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Trying to find fonts for: %s", langGroup)); - nsAutoTArray, 5> fonts; + nsAutoTArray, 5> fonts; this->GetPrefFonts(langGroup, fonts); selectedFont = WhichFontSupportsChar(fonts, aCh); } @@ -2613,17 +1876,12 @@ gfxWindowsFontGroup::WhichPrefFontSupportsChar(PRUint32 aCh) already_AddRefed gfxWindowsFontGroup::WhichSystemFontSupportsChar(PRUint32 aCh) { - nsRefPtr selectedFont; - - // system font lookup - PR_LOG(gFontLog, PR_LOG_DEBUG, (" - Looking for best match")); - - nsRefPtr refFont = GetFontAt(0); - gfxWindowsPlatform *platform = gfxWindowsPlatform::GetPlatform(); - selectedFont = platform->FindFontForChar(aCh, refFont); - - if (selectedFont) { - return selectedFont.forget(); + gfxFontEntry *fe = gfxPlatformFontList::PlatformFontList()->FindFontForChar(aCh, GetFontAt(0)); + if (fe) { + nsRefPtr windowsFont = gfxWindowsFont::GetOrMakeFont(fe, &mStyle); + NS_ASSERTION(windowsFont, "failed to make font from font entry"); + nsRefPtr font = (gfxFont*) windowsFont; + return font.forget(); } return nsnull; diff --git a/gfx/thebes/src/gfxWindowsPlatform.cpp b/gfx/thebes/src/gfxWindowsPlatform.cpp index ffe8579ef6d..05f627a209e 100644 --- a/gfx/thebes/src/gfxWindowsPlatform.cpp +++ b/gfx/thebes/src/gfxWindowsPlatform.cpp @@ -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 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 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 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(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 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& aListOfFonts) : - mLangGroup(aLangGroup), mGenericFamily(aGenericFamily), mStringArray(aListOfFonts) {} - const nsACString& mLangGroup; - const nsACString& mGenericFamily; - nsTArray& mStringArray; -}; - -PLDHashOperator -gfxWindowsPlatform::HashEnumFunc(nsStringHashKey::KeyType aKey, - nsRefPtr& 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 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& 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 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 searchPaths(3); - nsTArray 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 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(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 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 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 >& aFamilyArray) - : mFamilyArray(aFamilyArray) - {} - - static PLDHashOperator AppendFamily(nsStringHashKey::KeyType aKey, - nsRefPtr& aFamilyEntry, - void *aUserArg) - { - FontFamilyListData *data = (FontFamilyListData*)aUserArg; - data->mFamilyArray.AppendElement(aFamilyEntry); - return PL_DHASH_NEXT; - } - - nsTArray >& mFamilyArray; -}; - -void -gfxWindowsPlatform::GetFontFamilyList(nsTArray >& aFamilyArray) -{ - FontFamilyListData data(aFamilyArray); - mFonts.Enumerate(FontFamilyListData::AppendFamily, &data); -} - -static PRBool SimpleResolverCallback(const nsAString& aName, void* aClosure) -{ - nsString *result = static_cast(aClosure); - result->Assign(aName); - return PR_FALSE; -} - -void -gfxWindowsPlatform::InitBadUnderlineList() -{ -// Only windows fonts have mIsBadUnderlineFontFamily flag -#ifndef MOZ_FT2_FONTS - nsAutoTArray 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 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(data); - - nsAutoString name(logFont.lfFaceName); - - // Save the alias name to cache - nsRefPtr 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& aFontFamily, - void* userArg) -{ - FontSearch *data = (FontSearch*)userArg; - -#ifdef MOZ_FT2_FONTS - aFontFamily->FindFontForChar(data); -#else - const PRUint32 ch = data->mCh; - - nsRefPtr 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(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 -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 font = - gfxFT2Font::GetOrMakeFont(static_cast(data.mBestMatch.get()), - aFont->GetStyle()); - gfxFont* ret = font.forget().get(); - return already_AddRefed(ret); -#else - nsRefPtr font = - gfxWindowsFont::GetOrMakeFont(static_cast(data.mBestMatch.get()), - aFont->GetStyle()); - if (font->IsValid()) { - gfxFont* ret = font.forget().get(); - return already_AddRefed(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(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& aFontFamily, - void* userArg) -{ - FullFontNameSearch *data = reinterpret_cast(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 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 ff = FindFontFamily(aName); + nsRefPtr 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 > *array) +gfxWindowsPlatform::GetPrefFontEntries(const nsCString& aKey, nsTArray > *array) { return mPrefFonts.Get(aKey, array); } void -gfxWindowsPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray >& array) +gfxWindowsPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray >& 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() From f553d22ebdfb9b4edc6a22129a48868446dc1b00 Mon Sep 17 00:00:00 2001 From: Robert Longson Date: Fri, 8 Jan 2010 11:35:18 +0000 Subject: [PATCH 07/10] Bug 495968 - Only update the active switch child in nsSVGSwitchFrame::UpdateCoveredRegion. r=roc --- layout/svg/base/src/nsSVGSwitchFrame.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/layout/svg/base/src/nsSVGSwitchFrame.cpp b/layout/svg/base/src/nsSVGSwitchFrame.cpp index e2464222c25..815bc87b398 100644 --- a/layout/svg/base/src/nsSVGSwitchFrame.cpp +++ b/layout/svg/base/src/nsSVGSwitchFrame.cpp @@ -167,7 +167,14 @@ nsSVGSwitchFrame::UpdateCoveredRegion() { static_cast(mContent)->UpdateActiveChild(); - return nsSVGSwitchFrameBase::UpdateCoveredRegion(); + nsIFrame *kid = GetActiveChildFrame(); + if (kid) { + nsISVGChildFrame* child = do_QueryFrame(kid); + if (child) { + child->UpdateCoveredRegion(); + } + } + return NS_OK; } NS_IMETHODIMP From 4f0bde9d4dbb05d345db8efc1f8d226c79fc6b4c Mon Sep 17 00:00:00 2001 From: Marco Bonardo Date: Fri, 8 Jan 2010 13:57:46 +0100 Subject: [PATCH 08/10] Bug 537271 - Add .pyo files to .hgignore, r=ted --- .hgignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.hgignore b/.hgignore index 171ba1a624a..ea9e905d796 100644 --- a/.hgignore +++ b/.hgignore @@ -2,7 +2,7 @@ # Filenames that should be ignored wherever they appear ~$ -\.pyc$ +\.py(c|o)$ (^|/)TAGS$ (^|/)ID$ (^|/)\.DS_Store$ From 4408d52845a26acbcde57b9d1a429a839c6bf558 Mon Sep 17 00:00:00 2001 From: Marco Bonardo Date: Fri, 8 Jan 2010 13:57:49 +0100 Subject: [PATCH 09/10] Part4: lazy statements creation (and minor cleanup) in nsFaviconService, r=sdwilsh --- .../places/src/nsFaviconService.cpp | 378 +++++++++++------- .../components/places/src/nsFaviconService.h | 27 +- 2 files changed, 245 insertions(+), 160 deletions(-) diff --git a/toolkit/components/places/src/nsFaviconService.cpp b/toolkit/components/places/src/nsFaviconService.cpp index cd5dda8c2e7..cd4c6f34288 100644 --- a/toolkit/components/places/src/nsFaviconService.cpp +++ b/toolkit/components/places/src/nsFaviconService.cpp @@ -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 -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 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 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 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 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 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& 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 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 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 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 ps; nsCOMPtr 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 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 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; diff --git a/toolkit/components/places/src/nsFaviconService.h b/toolkit/components/places/src/nsFaviconService.h index 980b898e9b8..1d51f8ce794 100644 --- a/toolkit/components/places/src/nsFaviconService.h +++ b/toolkit/components/places/src/nsFaviconService.h @@ -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 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 mDBConn; // from history service + /** + * Always use this getter and never use directly the statement nsCOMPtr. + */ + mozIStorageStatement* GetStatement(const nsCOMPtr& aStmt); nsCOMPtr mDBGetURL; // returns URL, data len given page nsCOMPtr mDBGetData; // returns actual data given URL nsCOMPtr mDBGetIconInfo; nsCOMPtr mDBInsertIcon; nsCOMPtr mDBUpdateIcon; nsCOMPtr mDBSetPageFavicon; + nsCOMPtr mDBRemoveOnDiskReferences; + nsCOMPtr mDBRemoveTempReferences; + nsCOMPtr 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" From 52e8e4cf65487c23eaef9cc79ba82e148b81d942 Mon Sep 17 00:00:00 2001 From: Marco Bonardo Date: Fri, 8 Jan 2010 13:57:51 +0100 Subject: [PATCH 10/10] Add some logging to browserGlue random failing tests --- .../components/places/tests/unit/head_bookmarks.js | 14 +++++++++++--- .../tests/unit/test_browserGlue_distribution.js | 2 ++ .../places/tests/unit/test_browserGlue_prefs.js | 3 ++- .../tests/unit/test_browserGlue_smartBookmarks.js | 11 +++++++---- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/browser/components/places/tests/unit/head_bookmarks.js b/browser/components/places/tests/unit/head_bookmarks.js index 8eafc649848..afac82c4926 100644 --- a/browser/components/places/tests/unit/head_bookmarks.js +++ b/browser/components/places/tests/unit/head_bookmarks.js @@ -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; } diff --git a/browser/components/places/tests/unit/test_browserGlue_distribution.js b/browser/components/places/tests/unit/test_browserGlue_distribution.js index ed7e63eb84a..de0a61e3633 100644 --- a/browser/components/places/tests/unit/test_browserGlue_distribution.js +++ b/browser/components/places/tests/unit/test_browserGlue_distribution.js @@ -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); diff --git a/browser/components/places/tests/unit/test_browserGlue_prefs.js b/browser/components/places/tests/unit/test_browserGlue_prefs.js index d529a6d0f78..be637c00301 100644 --- a/browser/components/places/tests/unit/test_browserGlue_prefs.js +++ b/browser/components/places/tests/unit/test_browserGlue_prefs.js @@ -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(); diff --git a/browser/components/places/tests/unit/test_browserGlue_smartBookmarks.js b/browser/components/places/tests/unit/test_browserGlue_smartBookmarks.js index 5efad4b3834..c1e65d10285 100644 --- a/browser/components/places/tests/unit/test_browserGlue_smartBookmarks.js +++ b/browser/components/places/tests/unit/test_browserGlue_smartBookmarks.js @@ -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();