Bug 1056479 p2 - implement platform fontlist based on fontconfig. r=karlt

This patch implements a derived class of gfxPlatformFontList and a set of associated objects that uses fontconfig. It's a replacement for the existing gfxPangoFontGroup and gfxFontconfigUtils code. The fontconfig API is used to lookup all fonts on the system, which are grouped by family name.

Changes due to this patch:
- font style matching, the mapping of style attributes to a specific font, is now handled by the same Gecko code that is used on other plaforms. fontconfig substitutions are handled but fontconfig style matching no longer used.
- downloadable fonts using unicode-range are now supported
- local fullname lookups are only done with the English name of the font, as per the CSS3 Fonts spec, and not only other localized fullnames
- size-specific bitmap fonts are no longer supported
- fonts lacking a Unicode character map are no longer supported
This commit is contained in:
John Daggett 2015-05-12 17:44:16 +09:00
parent 14ad02c693
commit 6609ef3561
14 changed files with 1897 additions and 30 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,255 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GFXFCPLATFORMFONTLIST_H_
#define GFXFCPLATFORMFONTLIST_H_
#include "gfxFont.h"
#include "gfxFontEntry.h"
#include "gfxFT2FontBase.h"
#include "gfxPlatformFontList.h"
#include "mozilla/mozalloc.h"
#include <fontconfig/fontconfig.h>
#include "ft2build.h"
#include FT_FREETYPE_H
#include FT_TRUETYPE_TABLES_H
#include <cairo.h>
#include <cairo-ft.h>
#include "gfxFontconfigUtils.h" // xxx - only for nsAutoRefTraits<FcPattern>, etc.
template <>
class nsAutoRefTraits<FcObjectSet> : public nsPointerRefTraits<FcObjectSet>
{
public:
static void Release(FcObjectSet *ptr) { FcObjectSetDestroy(ptr); }
};
// Helper classes used for clearning out user font data when cairo font
// face is destroyed. Since multiple faces may use the same data, be
// careful to assure that the data is only cleared out when all uses
// expire. The font entry object contains a refptr to FTUserFontData and
// each cairo font created from that font entry contains a
// FTUserFontDataRef with a refptr to that same FTUserFontData object.
class FTUserFontData {
public:
NS_INLINE_DECL_REFCOUNTING(FTUserFontData)
explicit FTUserFontData(FT_Face aFace, const uint8_t* aData)
: mFace(aFace), mFontData(aData)
{
}
const uint8_t *FontData() const { return mFontData; }
private:
~FTUserFontData()
{
FT_Done_Face(mFace);
if (mFontData) {
NS_Free((void*)mFontData);
}
}
FT_Face mFace;
const uint8_t *mFontData;
};
class FTUserFontDataRef {
public:
explicit FTUserFontDataRef(FTUserFontData *aUserFontData)
: mUserFontData(aUserFontData)
{
}
static void Destroy(void* aData) {
FTUserFontDataRef* aUserFontDataRef =
static_cast<FTUserFontDataRef*>(aData);
delete aUserFontDataRef;
}
private:
nsRefPtr<FTUserFontData> mUserFontData;
};
// The names for the font entry and font classes should really
// the common 'Fc' abbreviation but the gfxPangoFontGroup code already
// defines versions of these, so use the verbose name for now.
class gfxFontConfigFontEntry : public gfxFontEntry {
public:
// used for system fonts with explicit patterns
explicit gfxFontConfigFontEntry(const nsAString& aFaceName,
FcPattern* aFontPattern);
// used for data fonts where the fontentry takes ownership
// of the font data and the FT_Face
explicit gfxFontConfigFontEntry(const nsAString& aFaceName,
uint16_t aWeight,
int16_t aStretch,
bool aItalic,
const uint8_t *aData,
FT_Face aFace);
// used for @font-face local system fonts with explicit patterns
explicit gfxFontConfigFontEntry(const nsAString& aFaceName,
FcPattern* aFontPattern,
uint16_t aWeight,
int16_t aStretch,
bool aItalic);
FcPattern* GetPattern() { return mFontPattern; }
bool SupportsLangGroup(nsIAtom *aLangGroup) const override;
nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr) override;
bool TestCharacterMap(uint32_t aCh) override;
hb_blob_t* GetFontTable(uint32_t aTableTag) override;
void ForgetHBFace() override;
void ReleaseGrFace(gr_face* aFace) override;
protected:
virtual ~gfxFontConfigFontEntry();
gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle,
bool aNeedsBold) override;
// helper method for creating cairo font from pattern
cairo_scaled_font_t*
CreateScaledFont(FcPattern* aRenderPattern,
const gfxFontStyle *aStyle,
bool aNeedsBold);
// override to pull data from FTFace
virtual nsresult
CopyFontTable(uint32_t aTableTag,
FallibleTArray<uint8_t>& aBuffer) override;
// if HB or GR faces are gone, close down the FT_Face
void MaybeReleaseFTFace();
double GetAspect();
// pattern for a single face of a family
nsCountedRef<FcPattern> mFontPattern;
// user font data, when needed
nsRefPtr<FTUserFontData> mUserFontData;
// FTFace - initialized when needed
FT_Face mFTFace;
bool mFTFaceInitialized;
double mAspect;
// data font
const uint8_t* mFontData;
};
class gfxFontConfigFontFamily : public gfxFontFamily {
public:
gfxFontConfigFontFamily(const nsAString& aName) :
gfxFontFamily(aName) { }
void FindStyleVariations(FontInfoData *aFontInfoData = nullptr) override;
// Families are constructed initially with just references to patterns.
// When necessary, these are enumerated within FindStyleVariations.
void AddFontPattern(FcPattern* aFontPattern);
protected:
virtual ~gfxFontConfigFontFamily() { }
nsTArray<nsCountedRef<FcPattern> > mFontPatterns;
};
class gfxFontConfigFont : public gfxFT2FontBase {
public:
gfxFontConfigFont(cairo_scaled_font_t *aScaledFont,
gfxFontEntry *aFontEntry,
const gfxFontStyle *aFontStyle,
bool aNeedsBold);
#ifdef USE_SKIA
virtual mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions>
GetGlyphRenderingOptions(const TextRunDrawParams* aRunParams = nullptr) override;
#endif
protected:
virtual ~gfxFontConfigFont();
};
class gfxFcPlatformFontList : public gfxPlatformFontList {
public:
gfxFcPlatformFontList()
: mLocalNames(64), mGenericMappings(32)
{
#ifdef MOZ_BUNDLED_FONTS
mBundledFontsInitialized = false;
#endif
}
// initialize font lists
nsresult InitFontList() override;
void GetFontList(nsIAtom *aLangGroup,
const nsACString& aGenericFamily,
nsTArray<nsString>& aListOfFonts) override;
gfxFontFamily*
GetDefaultFont(const gfxFontStyle* aStyle) override;
gfxFontEntry*
LookupLocalFont(const nsAString& aFontName, uint16_t aWeight,
int16_t aStretch, bool aItalic) override;
gfxFontEntry*
MakePlatformFont(const nsAString& aFontName, uint16_t aWeight,
int16_t aStretch, bool aItalic,
const uint8_t* aFontData,
uint32_t aLength) override;
gfxFontFamily* FindFamily(const nsAString& aFamily,
nsIAtom* aLanguage = nullptr,
bool aUseSystemFonts = false) override;
bool GetStandardFamilyName(const nsAString& aFontName,
nsAString& aFamilyName) override;
static FT_Library GetFTLibrary();
protected:
virtual ~gfxFcPlatformFontList();
// add all the font families found in a font set
void AddFontSetFamilies(FcFontSet* aFontSet);
// figure out which family fontconfig maps a generic to
// (aGeneric assumed already lowercase)
gfxFontFamily* FindGenericFamily(const nsAString& aGeneric,
nsIAtom* aLanguage);
#ifdef MOZ_BUNDLED_FONTS
void ActivateBundledFonts();
nsCString mBundledFontsPath;
bool mBundledFontsInitialized;
#endif
// to avoid enumerating all fonts, maintain a mapping of local font
// names to family
nsRefPtrHashtable<nsStringHashKey, gfxFontFamily> mLocalNames;
// caching generic/lang ==> font family
nsRefPtrHashtable<nsCStringHashKey, gfxFontFamily> mGenericMappings;
static FT_Library sCairoFTLibrary;
};
#endif /* GFXPLATFORMFONTLIST_H_ */

View File

@ -54,6 +54,8 @@ class gfxTextContextPaint;
// we use a platform-dependent value to harmonize with the platform's own APIs.
#ifdef XP_WIN
#define OBLIQUE_SKEW_FACTOR 0.3
#elif defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
#define OBLIQUE_SKEW_FACTOR 0.2
#else
#define OBLIQUE_SKEW_FACTOR 0.25
#endif

View File

@ -1262,6 +1262,7 @@ gfxPangoFontGroup::gfxPangoFontGroup(const FontFamilyList& aFontFamilyList,
// dummy entry, will be replaced when actually needed
mFonts.AppendElement(FamilyFace());
mSkipUpdateUserFonts = true;
}
gfxPangoFontGroup::~gfxPangoFontGroup()

View File

@ -76,6 +76,10 @@
#include "GLContextProvider.h"
#include "mozilla/gfx/Logging.h"
#if defined(MOZ_WIDGET_GTK)
#include "gfxPlatformGtk.h" // xxx - for UseFcFontList
#endif
#ifdef MOZ_WIDGET_ANDROID
#include "TexturePoolOGL.h"
#endif
@ -536,13 +540,20 @@ gfxPlatform::Init()
nsresult rv;
#if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID) // temporary, until this is implemented on others
rv = gfxPlatformFontList::Init();
if (NS_FAILED(rv)) {
NS_RUNTIMEABORT("Could not initialize gfxPlatformFontList");
}
bool usePlatformFontList = true;
#if defined(MOZ_WIDGET_GTK)
usePlatformFontList = gfxPlatformGtk::UseFcFontList();
#elif defined(MOZ_WIDGET_QT)
usePlatformFontList = false;
#endif
if (usePlatformFontList) {
rv = gfxPlatformFontList::Init();
if (NS_FAILED(rv)) {
NS_RUNTIMEABORT("Could not initialize gfxPlatformFontList");
}
}
gPlatform->mScreenReferenceSurface =
gPlatform->CreateOffscreenSurface(IntSize(1, 1),
gfxContentType::COLOR_ALPHA);

View File

@ -650,8 +650,7 @@ gfxPlatformFontList::CommonFontFallback(uint32_t aCh, uint32_t aNextCh,
const char *fallbackFamily = defaultFallbacks[i];
familyName.AppendASCII(fallbackFamily);
gfxFontFamily *fallback =
gfxPlatformFontList::PlatformFontList()->FindFamily(familyName);
gfxFontFamily *fallback = FindFamilyByCanonicalName(familyName);
if (!fallback)
continue;

View File

@ -110,9 +110,9 @@ public:
// initialize font lists
virtual nsresult InitFontList();
void GetFontList (nsIAtom *aLangGroup,
const nsACString& aGenericFamily,
nsTArray<nsString>& aListOfFonts);
virtual void GetFontList(nsIAtom *aLangGroup,
const nsACString& aGenericFamily,
nsTArray<nsString>& aListOfFonts);
void UpdateFontList();
@ -211,6 +211,18 @@ protected:
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void* userArg);
// Lookup family name in global family list without substitutions or
// localized family name lookup. Used for common font fallback families.
gfxFontFamily* FindFamilyByCanonicalName(const nsAString& aFamily) {
nsAutoString key;
gfxFontFamily *familyEntry;
GenerateFontListKey(aFamily, key);
if ((familyEntry = mFontFamilies.GetWeak(key))) {
return CheckFamily(familyEntry);
}
return nullptr;
}
// returns default font for a given character, null otherwise
gfxFontEntry* CommonFontFallback(uint32_t aCh, uint32_t aNextCh,
int32_t aRunScript,

View File

@ -12,6 +12,7 @@
#include "nsUnicharUtils.h"
#include "nsUnicodeProperties.h"
#include "gfx2DGlue.h"
#include "gfxFcPlatformFontList.h"
#include "gfxFontconfigUtils.h"
#include "gfxPangoFonts.h"
#include "gfxContext.h"
@ -59,10 +60,15 @@ static cairo_user_data_key_t cairo_gdk_drawable_key;
bool gfxPlatformGtk::sUseXRender = true;
#endif
bool gfxPlatformGtk::sUseFcFontList = false;
gfxPlatformGtk::gfxPlatformGtk()
{
if (!sFontconfigUtils)
sUseFcFontList = mozilla::Preferences::GetBool("gfx.font_rendering.fontconfig.fontlist.enabled");
if (!sUseFcFontList && !sFontconfigUtils) {
sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils();
}
#ifdef MOZ_X11
sUseXRender = (GDK_IS_X11_DISPLAY(gdk_display_get_default())) ?
mozilla::Preferences::GetBool("gfx.xrender.enabled") : false;
@ -76,10 +82,11 @@ gfxPlatformGtk::gfxPlatformGtk()
gfxPlatformGtk::~gfxPlatformGtk()
{
gfxFontconfigUtils::Shutdown();
sFontconfigUtils = nullptr;
gfxPangoFontGroup::Shutdown();
if (!sUseFcFontList) {
gfxFontconfigUtils::Shutdown();
sFontconfigUtils = nullptr;
gfxPangoFontGroup::Shutdown();
}
}
void
@ -149,19 +156,84 @@ gfxPlatformGtk::GetFontList(nsIAtom *aLangGroup,
const nsACString& aGenericFamily,
nsTArray<nsString>& aListOfFonts)
{
return sFontconfigUtils->GetFontList(aLangGroup, aGenericFamily,
if (sUseFcFontList) {
gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup,
aGenericFamily,
aListOfFonts);
return NS_OK;
}
return sFontconfigUtils->GetFontList(aLangGroup,
aGenericFamily,
aListOfFonts);
}
nsresult
gfxPlatformGtk::UpdateFontList()
{
if (sUseFcFontList) {
gfxPlatformFontList::PlatformFontList()->UpdateFontList();
return NS_OK;
}
return sFontconfigUtils->UpdateFontList();
}
// xxx - this is ubuntu centric, need to go through other distros and flesh
// out a more general list
static const char kFontDejaVuSans[] = "DejaVu Sans";
static const char kFontDejaVuSerif[] = "DejaVu Serif";
static const char kFontFreeSans[] = "FreeSans";
static const char kFontFreeSerif[] = "FreeSerif";
static const char kFontTakaoPGothic[] = "TakaoPGothic";
static const char kFontDroidSansFallback[] = "Droid Sans Fallback";
static const char kFontWenQuanYiMicroHei[] = "WenQuanYi Micro Hei";
static const char kFontNanumGothic[] = "NanumGothic";
void
gfxPlatformGtk::GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
int32_t aRunScript,
nsTArray<const char*>& aFontList)
{
aFontList.AppendElement(kFontDejaVuSerif);
aFontList.AppendElement(kFontFreeSerif);
aFontList.AppendElement(kFontDejaVuSans);
aFontList.AppendElement(kFontFreeSans);
// add fonts for CJK ranges
// xxx - this isn't really correct, should use the same CJK font ordering
// as the pref font code
if (aCh >= 0x3000 &&
((aCh < 0xe000) ||
(aCh >= 0xf900 && aCh < 0xfff0) ||
((aCh >> 16) == 2))) {
aFontList.AppendElement(kFontTakaoPGothic);
aFontList.AppendElement(kFontDroidSansFallback);
aFontList.AppendElement(kFontWenQuanYiMicroHei);
aFontList.AppendElement(kFontNanumGothic);
}
}
gfxPlatformFontList*
gfxPlatformGtk::CreatePlatformFontList()
{
gfxPlatformFontList* list = new gfxFcPlatformFontList();
if (NS_SUCCEEDED(list->InitFontList())) {
return list;
}
gfxPlatformFontList::Shutdown();
return nullptr;
}
nsresult
gfxPlatformGtk::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
{
if (sUseFcFontList) {
gfxPlatformFontList::PlatformFontList()->
GetStandardFamilyName(aFontName, aFamilyName);
return NS_OK;
}
return sFontconfigUtils->GetStandardFamilyName(aFontName, aFamilyName);
}
@ -170,6 +242,10 @@ gfxPlatformGtk::CreateFontGroup(const FontFamilyList& aFontFamilyList,
const gfxFontStyle *aStyle,
gfxUserFontSet *aUserFontSet)
{
if (sUseFcFontList) {
return new gfxFontGroup(aFontFamilyList, aStyle, aUserFontSet);
}
return new gfxPangoFontGroup(aFontFamilyList, aStyle, aUserFontSet);
}
@ -179,6 +255,11 @@ gfxPlatformGtk::LookupLocalFont(const nsAString& aFontName,
int16_t aStretch,
bool aItalic)
{
if (sUseFcFontList) {
gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
return pfl->LookupLocalFont(aFontName, aWeight, aStretch, aItalic);
}
return gfxPangoFontGroup::NewFontEntry(aFontName, aWeight,
aStretch, aItalic);
}
@ -191,6 +272,12 @@ gfxPlatformGtk::MakePlatformFont(const nsAString& aFontName,
const uint8_t* aFontData,
uint32_t aLength)
{
if (sUseFcFontList) {
gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
return pfl->MakePlatformFont(aFontName, aWeight, aStretch, aItalic,
aFontData, aLength);
}
// passing ownership of the font data to the new font entry
return gfxPangoFontGroup::NewFontEntry(aFontName, aWeight,
aStretch, aItalic,

View File

@ -41,6 +41,13 @@ public:
virtual nsresult UpdateFontList() override;
virtual void
GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
int32_t aRunScript,
nsTArray<const char*>& aFontList) override;
virtual gfxPlatformFontList* CreatePlatformFontList();
virtual nsresult GetStandardFamilyName(const nsAString& aFontName,
nsAString& aFamilyName) override;
@ -101,6 +108,8 @@ public:
#endif
}
static bool UseFcFontList() { return sUseFcFontList; }
bool UseImageOffscreenSurfaces() {
// We want to turn on image offscreen surfaces ONLY for GTK3 builds
// since GTK2 theme rendering still requires xlib surfaces per se.
@ -129,6 +138,10 @@ private:
#ifdef MOZ_X11
static bool sUseXRender;
#endif
// xxx - this will be removed once the new fontconfig platform font list
// replaces gfxPangoFontGroup
static bool sUseFcFontList;
};
#endif /* GFX_PLATFORM_GTK_H */

View File

@ -23,6 +23,10 @@
#include "mozilla/Likely.h"
#include "gfx2DGlue.h"
#if defined(MOZ_WIDGET_GTK)
#include "gfxPlatformGtk.h" // xxx - for UseFcFontList
#endif
#include "cairo.h"
using namespace mozilla;
@ -1536,6 +1540,7 @@ gfxFontGroup::gfxFontGroup(const FontFamilyList& aFontFamilyList,
, mTextPerf(nullptr)
, mPageLang(gfxPlatform::GetFontPrefLangFor(aStyle->language))
, mSkipDrawing(false)
, mSkipUpdateUserFonts(false)
{
// We don't use SetUserFontSet() here, as we want to unconditionally call
// BuildFontList() rather than only do UpdateUserFonts() if it changed.
@ -1682,10 +1687,17 @@ void gfxFontGroup::EnumerateFontList(nsIAtom *aLanguage, void *aClosure)
void
gfxFontGroup::BuildFontList()
{
// gfxPangoFontGroup behaves differently, so this method is a no-op on that platform
#if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID)
EnumerateFontList(mStyle.language);
bool enumerateFonts = true;
#if defined(MOZ_WIDGET_GTK)
// xxx - eliminate this once gfxPangoFontGroup is no longer needed
enumerateFonts = gfxPlatformGtk::UseFcFontList();
#elif defined(MOZ_WIDGET_QT)
enumerateFonts = false;
#endif
if (enumerateFonts) {
EnumerateFontList(mStyle.language);
}
}
void
@ -2345,13 +2357,11 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
NS_ASSERTION(aTextRun->GetShapingState() != gfxTextRun::eShapingState_Aborted,
"don't call InitScriptRun with aborted shaping state");
#if defined(XP_MACOSX) || defined(XP_WIN) || defined(ANDROID)
// non-linux platforms build the fontlist lazily and include userfonts
// so need to confirm the load state of userfonts in the list
if (mUserFontSet && mCurrGeneration != mUserFontSet->GetGeneration()) {
// confirm the load state of userfonts in the list
if (!mSkipUpdateUserFonts && mUserFontSet &&
mCurrGeneration != mUserFontSet->GetGeneration()) {
UpdateUserFonts();
}
#endif
gfxFont *mainFont = GetFirstValidFont();
@ -2607,10 +2617,6 @@ gfxFontGroup::FindNonItalicFaceForChar(gfxFontFamily* aFamily, uint32_t aCh)
NS_ASSERTION(mStyle.style != NS_FONT_STYLE_NORMAL,
"should only be called in the italic/oblique case");
if (!aFamily->TestCharacterMap(aCh)) {
return nullptr;
}
gfxFontStyle regularStyle = mStyle;
regularStyle.style = NS_FONT_STYLE_NORMAL;
bool needsBold;

View File

@ -1056,6 +1056,9 @@ protected:
// download to complete (or fallback
// timer to fire)
// xxx - gfxPangoFontGroup skips UpdateUserFonts
bool mSkipUpdateUserFonts;
/**
* Textrun creation short-cuts for special cases where we don't need to
* call a font shaper to generate glyphs.

View File

@ -111,6 +111,7 @@ elif CONFIG['MOZ_WIDGET_GTK']:
]
SOURCES += [
'gfxFcPlatformFontList.cpp',
'gfxFontconfigUtils.cpp',
'gfxFT2FontBase.cpp',
'gfxFT2Utils.cpp',

View File

@ -68,6 +68,11 @@
#include "gfxTextRun.h"
#include "nsFontFaceUtils.h"
#if defined(MOZ_WIDGET_GTK)
#include "gfxPlatformGtk.h" // xxx - for UseFcFontList
#endif
// Needed for Start/Stop of Image Animation
#include "imgIContainer.h"
#include "nsIImageLoadingContent.h"
@ -2170,8 +2175,10 @@ nsPresContext::UserFontSetUpdated(gfxUserFontEntry* aUpdatedFont)
return;
bool usePlatformFontList = true;
#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
usePlatformFontList = false;
#if defined(MOZ_WIDGET_GTK)
usePlatformFontList = gfxPlatformGtk::UseFcFontList();
#elif defined(MOZ_WIDGET_QT)
usePlatformFontList = false;
#endif
// xxx - until the Linux platform font list is always used, use full

View File

@ -3608,6 +3608,18 @@ pref("intl.ime.use_simple_context_on_password_field", true);
pref("intl.ime.use_simple_context_on_password_field", false);
#endif
# enable new platform fontlist for linux on GTK platforms
# temporary pref to allow flipping back to the existing
# gfxPangoFontGroup/gfxFontconfigUtils code for handling system fonts
#ifdef MOZ_WIDGET_GTK
#ifdef RELEASE_BUILD
pref("gfx.font_rendering.fontconfig.fontlist.enabled", false);
#else
pref("gfx.font_rendering.fontconfig.fontlist.enabled", true);
#endif
#endif
# XP_UNIX
#endif
#endif