2009-08-16 17:52:12 +04:00
|
|
|
/* -*- 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.
|
|
|
|
*
|
2009-12-22 00:50:30 +03:00
|
|
|
* The Initial Developer of the Original Code is Mozilla Foundation.
|
2009-08-16 17:52:12 +04:00
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2006-2009
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Jonathan Kew <jfkthame@gmail.com>
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* Based in part on sample code provided by Apple Computer, Inc.,
|
|
|
|
* under the following license:
|
|
|
|
*
|
|
|
|
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
|
|
|
|
* its contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
|
|
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
|
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
2011-01-21 19:44:33 +03:00
|
|
|
#ifdef MOZ_LOGGING
|
|
|
|
#define FORCE_PR_LOG /* Allow logging in the release build */
|
|
|
|
#endif
|
|
|
|
#include "prlog.h"
|
|
|
|
|
2009-08-16 17:52:12 +04:00
|
|
|
#include "gfxPlatformFontList.h"
|
2009-10-07 21:16:52 +04:00
|
|
|
#include "gfxTextRunWordCache.h"
|
2009-08-16 17:52:12 +04:00
|
|
|
|
|
|
|
#include "nsUnicharUtils.h"
|
2011-01-21 19:44:33 +03:00
|
|
|
#include "nsUnicodeRange.h"
|
|
|
|
#include "gfxUnicodeProperties.h"
|
2009-08-16 17:52:12 +04:00
|
|
|
|
2011-06-12 06:30:16 +04:00
|
|
|
#include "mozilla/Preferences.h"
|
2011-07-27 10:42:53 +04:00
|
|
|
#include "mozilla/Telemetry.h"
|
2011-06-12 06:30:16 +04:00
|
|
|
|
|
|
|
using namespace mozilla;
|
|
|
|
|
2009-08-16 17:52:12 +04:00
|
|
|
// 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
|
|
|
|
|
2011-01-21 19:44:33 +03:00
|
|
|
#ifdef PR_LOGGING
|
|
|
|
|
|
|
|
#define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
|
|
|
|
PR_LOG_DEBUG, args)
|
|
|
|
#define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \
|
|
|
|
gfxPlatform::GetLog(eGfxLog_fontlist), \
|
|
|
|
PR_LOG_DEBUG)
|
2009-08-16 17:52:12 +04:00
|
|
|
|
2011-01-21 19:44:33 +03:00
|
|
|
#endif // PR_LOGGING
|
2009-08-16 17:52:12 +04:00
|
|
|
|
|
|
|
gfxPlatformFontList *gfxPlatformFontList::sPlatformFontList = nsnull;
|
|
|
|
|
|
|
|
|
2011-06-12 06:30:16 +04:00
|
|
|
static const char* kObservedPrefs[] = {
|
|
|
|
"font.",
|
|
|
|
"font.name-list.",
|
|
|
|
"intl.accept_languages", // hmmmm...
|
|
|
|
nsnull
|
|
|
|
};
|
|
|
|
|
2009-08-16 17:52:12 +04:00
|
|
|
class gfxFontListPrefObserver : public nsIObserver {
|
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
NS_DECL_NSIOBSERVER
|
|
|
|
};
|
|
|
|
|
2011-06-12 06:30:16 +04:00
|
|
|
static gfxFontListPrefObserver* gFontListPrefObserver = nsnull;
|
|
|
|
|
2009-08-16 17:52:12 +04:00
|
|
|
NS_IMPL_ISUPPORTS1(gfxFontListPrefObserver, nsIObserver)
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
gfxFontListPrefObserver::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.
|
|
|
|
gfxPlatformFontList::PlatformFontList()->ClearPrefFonts();
|
2009-10-07 21:16:52 +04:00
|
|
|
gfxFontCache::GetCache()->AgeAllGenerations();
|
2009-08-16 17:52:12 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames)
|
2010-01-29 04:41:25 +03:00
|
|
|
: mNeedFullnamePostscriptNames(aNeedFullnamePostscriptNames),
|
|
|
|
mStartIndex(0), mIncrement(kNumFontsPerSlice), mNumFamilies(0)
|
2009-08-16 17:52:12 +04:00
|
|
|
{
|
|
|
|
mFontFamilies.Init(100);
|
|
|
|
mOtherFamilyNames.Init(30);
|
|
|
|
mOtherFamilyNamesInitialized = PR_FALSE;
|
2010-01-29 04:41:25 +03:00
|
|
|
|
|
|
|
if (mNeedFullnamePostscriptNames) {
|
|
|
|
mFullnames.Init(100);
|
|
|
|
mPostscriptNames.Init(100);
|
|
|
|
}
|
|
|
|
mFaceNamesInitialized = PR_FALSE;
|
|
|
|
|
2009-08-16 17:52:12 +04:00
|
|
|
mPrefFonts.Init(10);
|
|
|
|
|
2010-01-28 09:56:16 +03:00
|
|
|
mBadUnderlineFamilyNames.Init(10);
|
|
|
|
LoadBadUnderlineList();
|
|
|
|
|
2009-08-16 17:52:12 +04:00
|
|
|
// pref changes notification setup
|
2011-06-12 06:30:16 +04:00
|
|
|
NS_ASSERTION(!gFontListPrefObserver,
|
|
|
|
"There has been font list pref observer already");
|
|
|
|
gFontListPrefObserver = new gfxFontListPrefObserver();
|
|
|
|
NS_ADDREF(gFontListPrefObserver);
|
|
|
|
Preferences::AddStrongObservers(gFontListPrefObserver, kObservedPrefs);
|
|
|
|
}
|
|
|
|
|
|
|
|
gfxPlatformFontList::~gfxPlatformFontList()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(gFontListPrefObserver, "There is no font list pref observer");
|
|
|
|
Preferences::RemoveObservers(gFontListPrefObserver, kObservedPrefs);
|
|
|
|
NS_RELEASE(gFontListPrefObserver);
|
2009-08-16 17:52:12 +04:00
|
|
|
}
|
|
|
|
|
2010-11-08 14:02:27 +03:00
|
|
|
nsresult
|
2010-01-29 04:41:25 +03:00
|
|
|
gfxPlatformFontList::InitFontList()
|
|
|
|
{
|
|
|
|
mFontFamilies.Clear();
|
|
|
|
mOtherFamilyNames.Clear();
|
|
|
|
mOtherFamilyNamesInitialized = PR_FALSE;
|
|
|
|
if (mNeedFullnamePostscriptNames) {
|
|
|
|
mFullnames.Clear();
|
|
|
|
mPostscriptNames.Clear();
|
|
|
|
}
|
|
|
|
mFaceNamesInitialized = 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
|
2010-11-08 14:02:27 +03:00
|
|
|
|
|
|
|
sPlatformFontList = this;
|
|
|
|
|
|
|
|
return NS_OK;
|
2010-01-29 04:41:25 +03:00
|
|
|
}
|
|
|
|
|
2009-08-16 17:52:12 +04:00
|
|
|
void
|
|
|
|
gfxPlatformFontList::GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult)
|
|
|
|
{
|
|
|
|
aResult = aKeyName;
|
|
|
|
ToLowerCase(aResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gfxPlatformFontList::InitOtherFamilyNames()
|
|
|
|
{
|
|
|
|
mOtherFamilyNamesInitialized = PR_TRUE;
|
|
|
|
|
2011-07-27 10:42:53 +04:00
|
|
|
Telemetry::AutoTimer<Telemetry::FONTLIST_INITOTHERFAMILYNAMES> timer;
|
2009-08-16 17:52:12 +04:00
|
|
|
// iterate over all font families and read in other family names
|
|
|
|
mFontFamilies.Enumerate(gfxPlatformFontList::InitOtherFamilyNamesProc, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
PLDHashOperator PR_CALLBACK
|
|
|
|
gfxPlatformFontList::InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
|
|
|
|
nsRefPtr<gfxFontFamily>& aFamilyEntry,
|
|
|
|
void* userArg)
|
|
|
|
{
|
|
|
|
gfxPlatformFontList *fc = static_cast<gfxPlatformFontList*>(userArg);
|
2010-01-29 04:41:25 +03:00
|
|
|
aFamilyEntry->ReadOtherFamilyNames(fc);
|
2009-08-16 17:52:12 +04:00
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-01-29 04:41:25 +03:00
|
|
|
gfxPlatformFontList::InitFaceNameLists()
|
2009-08-16 17:52:12 +04:00
|
|
|
{
|
2010-01-29 04:41:25 +03:00
|
|
|
mFaceNamesInitialized = PR_TRUE;
|
2009-08-16 17:52:12 +04:00
|
|
|
|
2010-01-29 04:41:25 +03:00
|
|
|
// iterate over all font families and read in other family names
|
2011-07-27 10:42:53 +04:00
|
|
|
Telemetry::AutoTimer<Telemetry::FONTLIST_INITFACENAMELISTS> timer;
|
2010-01-29 04:41:25 +03:00
|
|
|
mFontFamilies.Enumerate(gfxPlatformFontList::InitFaceNameListsProc, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
PLDHashOperator PR_CALLBACK
|
|
|
|
gfxPlatformFontList::InitFaceNameListsProc(nsStringHashKey::KeyType aKey,
|
|
|
|
nsRefPtr<gfxFontFamily>& aFamilyEntry,
|
|
|
|
void* userArg)
|
|
|
|
{
|
|
|
|
gfxPlatformFontList *fc = static_cast<gfxPlatformFontList*>(userArg);
|
|
|
|
aFamilyEntry->ReadFaceNames(fc, fc->NeedFullnamePostscriptNames());
|
|
|
|
return PL_DHASH_NEXT;
|
2009-08-16 17:52:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gfxPlatformFontList::PreloadNamesList()
|
|
|
|
{
|
|
|
|
nsAutoTArray<nsString, 10> preloadFonts;
|
|
|
|
gfxFontUtils::GetPrefsFontList("font.preload-names-list", preloadFonts);
|
|
|
|
|
|
|
|
PRUint32 numFonts = preloadFonts.Length();
|
|
|
|
for (PRUint32 i = 0; i < numFonts; i++) {
|
2011-09-29 10:19:26 +04:00
|
|
|
bool found;
|
2009-08-16 17:52:12 +04:00
|
|
|
nsAutoString key;
|
|
|
|
GenerateFontListKey(preloadFonts[i], key);
|
|
|
|
|
|
|
|
// only search canonical names!
|
|
|
|
gfxFontFamily *familyEntry = mFontFamilies.GetWeak(key, &found);
|
|
|
|
if (familyEntry) {
|
2010-01-29 04:41:25 +03:00
|
|
|
familyEntry->ReadOtherFamilyNames(this);
|
2009-08-16 17:52:12 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gfxPlatformFontList::SetFixedPitch(const nsAString& aFamilyName)
|
|
|
|
{
|
|
|
|
gfxFontFamily *family = FindFamily(aFamilyName);
|
|
|
|
if (!family) return;
|
|
|
|
|
2009-10-13 03:43:43 +04:00
|
|
|
family->FindStyleVariations();
|
2009-08-16 17:52:12 +04:00
|
|
|
nsTArray<nsRefPtr<gfxFontEntry> >& fontlist = family->GetFontList();
|
|
|
|
|
|
|
|
PRUint32 i, numFonts = fontlist.Length();
|
|
|
|
|
|
|
|
for (i = 0; i < numFonts; i++) {
|
|
|
|
fontlist[i]->mFixedPitch = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-01-28 09:56:16 +03:00
|
|
|
gfxPlatformFontList::LoadBadUnderlineList()
|
2009-08-16 17:52:12 +04:00
|
|
|
{
|
|
|
|
nsAutoTArray<nsString, 10> blacklist;
|
|
|
|
gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset", blacklist);
|
|
|
|
PRUint32 numFonts = blacklist.Length();
|
|
|
|
for (PRUint32 i = 0; i < numFonts; i++) {
|
|
|
|
nsAutoString key;
|
|
|
|
GenerateFontListKey(blacklist[i], key);
|
2010-02-11 15:00:07 +03:00
|
|
|
mBadUnderlineFamilyNames.Put(key);
|
2009-08-16 17:52:12 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2009-08-16 17:52:12 +04:00
|
|
|
gfxPlatformFontList::ResolveFontName(const nsAString& aFontName, nsAString& aResolvedFontName)
|
|
|
|
{
|
|
|
|
gfxFontFamily *family = FindFamily(aFontName);
|
|
|
|
if (family) {
|
|
|
|
aResolvedFontName = family->Name();
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct FontListData {
|
2010-02-24 20:57:57 +03:00
|
|
|
FontListData(nsIAtom *aLangGroup,
|
2009-08-16 17:52:12 +04:00
|
|
|
const nsACString& aGenericFamily,
|
|
|
|
nsTArray<nsString>& aListOfFonts) :
|
|
|
|
mLangGroup(aLangGroup), mGenericFamily(aGenericFamily),
|
|
|
|
mListOfFonts(aListOfFonts) {}
|
2010-02-24 20:57:57 +03:00
|
|
|
nsIAtom *mLangGroup;
|
2009-08-16 17:52:12 +04:00
|
|
|
const nsACString& mGenericFamily;
|
|
|
|
nsTArray<nsString>& mListOfFonts;
|
|
|
|
};
|
|
|
|
|
|
|
|
PLDHashOperator PR_CALLBACK
|
|
|
|
gfxPlatformFontList::HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
|
|
|
|
nsRefPtr<gfxFontFamily>& aFamilyEntry,
|
|
|
|
void *aUserArg)
|
|
|
|
{
|
|
|
|
FontListData *data = static_cast<FontListData*>(aUserArg);
|
|
|
|
|
2009-10-07 18:13:40 +04:00
|
|
|
// 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;
|
2010-02-24 20:57:44 +03:00
|
|
|
style.language = data->mLangGroup;
|
2011-09-29 10:19:26 +04:00
|
|
|
bool needsBold;
|
2009-10-07 18:13:40 +04:00
|
|
|
nsRefPtr<gfxFontEntry> aFontEntry = aFamilyEntry->FindFontForStyle(style, needsBold);
|
|
|
|
NS_ASSERTION(aFontEntry, "couldn't find any font entry in family");
|
|
|
|
if (!aFontEntry)
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
|
|
|
|
/* skip symbol fonts */
|
|
|
|
if (aFontEntry->IsSymbolFont())
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
|
|
|
|
if (aFontEntry->SupportsLangGroup(data->mLangGroup) &&
|
|
|
|
aFontEntry->MatchesGenericFamily(data->mGenericFamily)) {
|
|
|
|
nsAutoString localizedFamilyName;
|
|
|
|
aFamilyEntry->LocalizedName(localizedFamilyName);
|
|
|
|
data->mListOfFonts.AppendElement(localizedFamilyName);
|
|
|
|
}
|
|
|
|
|
2009-08-16 17:52:12 +04:00
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-02-24 20:57:57 +03:00
|
|
|
gfxPlatformFontList::GetFontList(nsIAtom *aLangGroup,
|
2009-08-16 17:52:12 +04:00
|
|
|
const nsACString& aGenericFamily,
|
|
|
|
nsTArray<nsString>& aListOfFonts)
|
|
|
|
{
|
|
|
|
FontListData data(aLangGroup, aGenericFamily, aListOfFonts);
|
|
|
|
|
|
|
|
mFontFamilies.Enumerate(gfxPlatformFontList::HashEnumFuncForFamilies, &data);
|
|
|
|
|
|
|
|
aListOfFonts.Sort();
|
|
|
|
aListOfFonts.Compact();
|
|
|
|
}
|
|
|
|
|
|
|
|
struct FontFamilyListData {
|
|
|
|
FontFamilyListData(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
|
|
|
|
: mFamilyArray(aFamilyArray)
|
|
|
|
{}
|
|
|
|
|
|
|
|
static PLDHashOperator PR_CALLBACK AppendFamily(nsStringHashKey::KeyType aKey,
|
|
|
|
nsRefPtr<gfxFontFamily>& aFamilyEntry,
|
|
|
|
void *aUserArg)
|
|
|
|
{
|
|
|
|
FontFamilyListData *data = static_cast<FontFamilyListData*>(aUserArg);
|
|
|
|
data->mFamilyArray.AppendElement(aFamilyEntry);
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsTArray<nsRefPtr<gfxFontFamily> >& mFamilyArray;
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
gfxPlatformFontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
|
|
|
|
{
|
|
|
|
FontFamilyListData data(aFamilyArray);
|
|
|
|
mFontFamilies.Enumerate(FontFamilyListData::AppendFamily, &data);
|
|
|
|
}
|
|
|
|
|
|
|
|
gfxFontEntry*
|
|
|
|
gfxPlatformFontList::FindFontForChar(const PRUint32 aCh, gfxFont *aPrevFont)
|
|
|
|
{
|
|
|
|
// is codepoint with no matching font? return null immediately
|
|
|
|
if (mCodepointsWithNoFonts.test(aCh)) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: optimize fallback e.g. by caching lists of fonts to try for a given
|
|
|
|
// unicode range or script
|
|
|
|
|
|
|
|
// try to short-circuit font fallback for U+FFFD, used to represent encoding errors:
|
|
|
|
// just use a platform-specific fallback system font that is guaranteed (or at least
|
|
|
|
// highly likely) to be around, or a cached family from last time U+FFFD was seen.
|
|
|
|
// this helps speed up pages with lots of encoding errors, binary-as-text, etc.
|
|
|
|
if (aCh == 0xFFFD && mReplacementCharFallbackFamily.Length() > 0) {
|
|
|
|
gfxFontEntry* fontEntry = nsnull;
|
2011-09-29 10:19:26 +04:00
|
|
|
bool needsBold; // ignored in the system fallback case
|
2009-08-16 17:52:12 +04:00
|
|
|
|
|
|
|
if (aPrevFont) {
|
|
|
|
fontEntry = FindFontForFamily(mReplacementCharFallbackFamily, aPrevFont->GetStyle(), needsBold);
|
|
|
|
} else {
|
|
|
|
gfxFontStyle normalStyle;
|
|
|
|
fontEntry = FindFontForFamily(mReplacementCharFallbackFamily, &normalStyle, needsBold);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fontEntry && fontEntry->TestCharacterMap(aCh))
|
|
|
|
return fontEntry;
|
|
|
|
}
|
|
|
|
|
|
|
|
FontSearch data(aCh, aPrevFont);
|
|
|
|
|
|
|
|
// iterate over all font families to find a font that support the character
|
|
|
|
mFontFamilies.Enumerate(gfxPlatformFontList::FindFontForCharProc, &data);
|
|
|
|
|
2011-01-21 19:44:33 +03:00
|
|
|
#ifdef PR_LOGGING
|
|
|
|
PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textrun);
|
|
|
|
|
|
|
|
if (NS_UNLIKELY(log)) {
|
|
|
|
PRUint32 charRange = gfxFontUtils::CharRangeBit(aCh);
|
|
|
|
PRUint32 unicodeRange = FindCharUnicodeRange(aCh);
|
|
|
|
PRUint32 hbscript = gfxUnicodeProperties::GetScriptCode(aCh);
|
|
|
|
PR_LOG(log, PR_LOG_DEBUG,\
|
|
|
|
("(textrun-systemfallback) char: u+%6.6x "
|
|
|
|
"char-range: %d unicode-range: %d script: %d match: [%s] count: %d\n",
|
|
|
|
aCh,
|
|
|
|
charRange, unicodeRange, hbscript,
|
|
|
|
(data.mBestMatch ?
|
|
|
|
NS_ConvertUTF16toUTF8(data.mBestMatch->Name()).get() :
|
|
|
|
"<none>"),
|
|
|
|
data.mCount));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-08-16 17:52:12 +04:00
|
|
|
// no match? add to set of non-matching codepoints
|
|
|
|
if (!data.mBestMatch) {
|
|
|
|
mCodepointsWithNoFonts.set(aCh);
|
|
|
|
} else if (aCh == 0xFFFD) {
|
|
|
|
mReplacementCharFallbackFamily = data.mBestMatch->FamilyName();
|
|
|
|
}
|
|
|
|
|
|
|
|
return data.mBestMatch;
|
|
|
|
}
|
|
|
|
|
|
|
|
PLDHashOperator PR_CALLBACK
|
|
|
|
gfxPlatformFontList::FindFontForCharProc(nsStringHashKey::KeyType aKey, nsRefPtr<gfxFontFamily>& aFamilyEntry,
|
|
|
|
void *userArg)
|
|
|
|
{
|
|
|
|
FontSearch *data = static_cast<FontSearch*>(userArg);
|
|
|
|
|
|
|
|
// evaluate all fonts in this family for a match
|
|
|
|
aFamilyEntry->FindFontForChar(data);
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
2011-01-21 19:44:33 +03:00
|
|
|
#ifdef XP_WIN
|
|
|
|
#include <windows.h>
|
|
|
|
|
|
|
|
// crude hack for using when monitoring process
|
|
|
|
static void LogRegistryEvent(const wchar_t *msg)
|
|
|
|
{
|
|
|
|
HKEY dummyKey;
|
|
|
|
HRESULT hr;
|
|
|
|
wchar_t buf[512];
|
|
|
|
|
|
|
|
wsprintfW(buf, L" log %s", msg);
|
|
|
|
hr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
RegCloseKey(dummyKey);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-08-16 17:52:12 +04:00
|
|
|
gfxFontFamily*
|
|
|
|
gfxPlatformFontList::FindFamily(const nsAString& aFamily)
|
|
|
|
{
|
|
|
|
nsAutoString key;
|
|
|
|
gfxFontFamily *familyEntry;
|
2011-09-29 10:19:26 +04:00
|
|
|
bool found;
|
2009-08-16 17:52:12 +04:00
|
|
|
GenerateFontListKey(aFamily, key);
|
|
|
|
|
2011-01-28 03:40:06 +03:00
|
|
|
NS_ASSERTION(mFontFamilies.Count() != 0, "system font list was not initialized correctly");
|
|
|
|
|
2009-08-16 17:52:12 +04:00
|
|
|
// lookup in canonical (i.e. English) family name list
|
|
|
|
if ((familyEntry = mFontFamilies.GetWeak(key, &found))) {
|
|
|
|
return familyEntry;
|
|
|
|
}
|
|
|
|
|
|
|
|
// lookup in other family names list (mostly localized names)
|
2011-01-07 15:29:49 +03:00
|
|
|
if ((familyEntry = mOtherFamilyNames.GetWeak(key, &found)) != nsnull) {
|
2009-08-16 17:52:12 +04:00
|
|
|
return familyEntry;
|
|
|
|
}
|
|
|
|
|
|
|
|
// name not found and other family names not yet fully initialized so
|
|
|
|
// initialize the rest of the list and try again. this is done lazily
|
2011-01-07 15:29:49 +03:00
|
|
|
// since reading name table entries is expensive.
|
|
|
|
// although ASCII localized family names are possible they don't occur
|
|
|
|
// in practice so avoid pulling in names at startup
|
|
|
|
if (!mOtherFamilyNamesInitialized && !IsASCII(aFamily)) {
|
2009-08-16 17:52:12 +04:00
|
|
|
InitOtherFamilyNames();
|
2011-01-07 15:29:49 +03:00
|
|
|
if ((familyEntry = mOtherFamilyNames.GetWeak(key, &found)) != nsnull) {
|
2009-08-16 17:52:12 +04:00
|
|
|
return familyEntry;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
gfxFontEntry*
|
2011-09-29 10:19:26 +04:00
|
|
|
gfxPlatformFontList::FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, bool& aNeedsBold)
|
2009-08-16 17:52:12 +04:00
|
|
|
{
|
|
|
|
gfxFontFamily *familyEntry = FindFamily(aFamily);
|
|
|
|
|
|
|
|
aNeedsBold = PR_FALSE;
|
|
|
|
|
|
|
|
if (familyEntry)
|
|
|
|
return familyEntry->FindFontForStyle(*aStyle, aNeedsBold);
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2009-08-16 17:52:12 +04:00
|
|
|
gfxPlatformFontList::GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> > *array)
|
|
|
|
{
|
|
|
|
return mPrefFonts.Get(PRUint32(aLangGroup), array);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gfxPlatformFontList::SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> >& array)
|
|
|
|
{
|
|
|
|
mPrefFonts.Put(PRUint32(aLangGroup), array);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gfxPlatformFontList::AddOtherFamilyName(gfxFontFamily *aFamilyEntry, nsAString& aOtherFamilyName)
|
|
|
|
{
|
|
|
|
nsAutoString key;
|
2011-09-29 10:19:26 +04:00
|
|
|
bool found;
|
2009-08-16 17:52:12 +04:00
|
|
|
GenerateFontListKey(aOtherFamilyName, key);
|
|
|
|
|
|
|
|
if (!mOtherFamilyNames.GetWeak(key, &found)) {
|
|
|
|
mOtherFamilyNames.Put(key, aFamilyEntry);
|
2011-01-21 19:44:33 +03:00
|
|
|
#ifdef PR_LOGGING
|
|
|
|
LOG_FONTLIST(("(fontlist-otherfamily) canonical family: %s, "
|
|
|
|
"other family: %s\n",
|
|
|
|
NS_ConvertUTF16toUTF8(aFamilyEntry->Name()).get(),
|
|
|
|
NS_ConvertUTF16toUTF8(aOtherFamilyName).get()));
|
|
|
|
#endif
|
2010-02-11 15:00:07 +03:00
|
|
|
if (mBadUnderlineFamilyNames.Contains(key))
|
2010-01-28 09:56:16 +03:00
|
|
|
aFamilyEntry->SetBadUnderlineFamily();
|
2009-08-16 17:52:12 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-29 04:41:25 +03:00
|
|
|
void
|
|
|
|
gfxPlatformFontList::AddFullname(gfxFontEntry *aFontEntry, nsAString& aFullname)
|
|
|
|
{
|
2011-09-29 10:19:26 +04:00
|
|
|
bool found;
|
2010-01-29 04:41:25 +03:00
|
|
|
|
|
|
|
if (!mFullnames.GetWeak(aFullname, &found)) {
|
|
|
|
mFullnames.Put(aFullname, aFontEntry);
|
2011-01-21 19:44:33 +03:00
|
|
|
#ifdef PR_LOGGING
|
|
|
|
LOG_FONTLIST(("(fontlist-fullname) name: %s, fullname: %s\n",
|
|
|
|
NS_ConvertUTF16toUTF8(aFontEntry->Name()).get(),
|
|
|
|
NS_ConvertUTF16toUTF8(aFullname).get()));
|
|
|
|
#endif
|
2010-01-29 04:41:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gfxPlatformFontList::AddPostscriptName(gfxFontEntry *aFontEntry, nsAString& aPostscriptName)
|
|
|
|
{
|
2011-09-29 10:19:26 +04:00
|
|
|
bool found;
|
2010-01-29 04:41:25 +03:00
|
|
|
|
|
|
|
if (!mPostscriptNames.GetWeak(aPostscriptName, &found)) {
|
|
|
|
mPostscriptNames.Put(aPostscriptName, aFontEntry);
|
2011-01-21 19:44:33 +03:00
|
|
|
#ifdef PR_LOGGING
|
|
|
|
LOG_FONTLIST(("(fontlist-postscript) name: %s, psname: %s\n",
|
|
|
|
NS_ConvertUTF16toUTF8(aFontEntry->Name()).get(),
|
|
|
|
NS_ConvertUTF16toUTF8(aPostscriptName).get()));
|
|
|
|
#endif
|
2010-01-29 04:41:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2009-10-07 18:13:40 +04:00
|
|
|
gfxPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
|
|
|
|
{
|
|
|
|
aFamilyName.Truncate();
|
|
|
|
ResolveFontName(aFontName, aFamilyName);
|
|
|
|
return !aFamilyName.IsEmpty();
|
|
|
|
}
|
|
|
|
|
2009-08-16 17:52:12 +04:00
|
|
|
void
|
|
|
|
gfxPlatformFontList::InitLoader()
|
|
|
|
{
|
|
|
|
GetFontFamilyList(mFontFamiliesToLoad);
|
|
|
|
mStartIndex = 0;
|
|
|
|
mNumFamilies = mFontFamiliesToLoad.Length();
|
|
|
|
}
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2009-08-16 17:52:12 +04:00
|
|
|
gfxPlatformFontList::RunLoader()
|
|
|
|
{
|
|
|
|
PRUint32 i, endIndex = (mStartIndex + mIncrement < mNumFamilies ? mStartIndex + mIncrement : mNumFamilies);
|
|
|
|
|
|
|
|
// for each font family, load in various font info
|
|
|
|
for (i = mStartIndex; i < endIndex; i++) {
|
2009-10-13 03:43:43 +04:00
|
|
|
gfxFontFamily* familyEntry = mFontFamiliesToLoad[i];
|
|
|
|
|
|
|
|
// find all faces that are members of this family
|
|
|
|
familyEntry->FindStyleVariations();
|
2010-02-11 14:59:47 +03:00
|
|
|
if (familyEntry->GetFontList().Length() == 0) {
|
|
|
|
// failed to load any faces for this family, so discard it
|
|
|
|
nsAutoString key;
|
|
|
|
GenerateFontListKey(familyEntry->Name(), key);
|
|
|
|
mFontFamilies.Remove(key);
|
|
|
|
continue;
|
|
|
|
}
|
2009-08-16 17:52:12 +04:00
|
|
|
|
2009-10-13 03:43:43 +04:00
|
|
|
// load the cmaps
|
|
|
|
familyEntry->ReadCMAP();
|
2009-08-16 17:52:12 +04:00
|
|
|
|
2010-01-29 04:41:25 +03:00
|
|
|
// read in face names
|
|
|
|
familyEntry->ReadFaceNames(this, mNeedFullnamePostscriptNames);
|
2009-08-16 17:52:12 +04:00
|
|
|
|
|
|
|
// check whether the family can be considered "simple" for style matching
|
2009-10-13 03:43:43 +04:00
|
|
|
familyEntry->CheckForSimpleFamily();
|
2009-08-16 17:52:12 +04:00
|
|
|
}
|
|
|
|
|
2010-02-11 14:59:47 +03:00
|
|
|
mStartIndex = endIndex;
|
|
|
|
|
|
|
|
return (mStartIndex >= mNumFamilies);
|
2009-08-16 17:52:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gfxPlatformFontList::FinishLoader()
|
|
|
|
{
|
|
|
|
mFontFamiliesToLoad.Clear();
|
|
|
|
mNumFamilies = 0;
|
|
|
|
}
|