diff options
Diffstat (limited to 'gfx/thebes/gfxDWriteFontList.h')
-rw-r--r-- | gfx/thebes/gfxDWriteFontList.h | 504 |
1 files changed, 504 insertions, 0 deletions
diff --git a/gfx/thebes/gfxDWriteFontList.h b/gfx/thebes/gfxDWriteFontList.h new file mode 100644 index 0000000000..3ff0e6f7c5 --- /dev/null +++ b/gfx/thebes/gfxDWriteFontList.h @@ -0,0 +1,504 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * 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 GFX_DWRITEFONTLIST_H +#define GFX_DWRITEFONTLIST_H + +#include "mozilla/FontPropertyTypes.h" +#include "mozilla/MathAlgorithms.h" +#include "mozilla/MemoryReporting.h" +#include "gfxDWriteCommon.h" +#include "dwrite_3.h" + +// Currently, we build with WINVER=0x601 (Win7), which means newer +// declarations in dwrite_3.h will not be visible. Also, we don't +// yet have the Fall Creators Update SDK available on build machines, +// so even with updated WINVER, some of the interfaces we need would +// not be present. +// To work around this, until the build environment is updated, +// we #include an extra header that contains copies of the relevant +// classes/interfaces we need. +#if !defined(__MINGW32__) && WINVER < 0x0A00 +# include "mozilla/gfx/dw-extra.h" +#endif + +#include "gfxFont.h" +#include "gfxUserFontSet.h" +#include "cairo-win32.h" + +#include "gfxPlatformFontList.h" +#include "gfxPlatform.h" +#include <algorithm> + +#include "mozilla/gfx/UnscaledFontDWrite.h" + +/** + * \brief Class representing directwrite font family. + * + * gfxDWriteFontFamily is a class that describes one of the font families on + * the user's system. It holds each gfxDWriteFontEntry (maps more directly to + * a font face) which holds font type, charset info and character map info. + */ +class gfxDWriteFontFamily final : public gfxFontFamily { + public: + typedef mozilla::FontStretch FontStretch; + typedef mozilla::FontSlantStyle FontSlantStyle; + typedef mozilla::FontWeight FontWeight; + + /** + * Constructs a new DWriteFont Family. + * + * \param aName Name identifying the family + * \param aFamily IDWriteFontFamily object representing the directwrite + * family object. + */ + gfxDWriteFontFamily(const nsACString& aName, FontVisibility aVisibility, + IDWriteFontFamily* aFamily, + bool aIsSystemFontFamily = false) + : gfxFontFamily(aName, aVisibility), + mDWFamily(aFamily), + mIsSystemFontFamily(aIsSystemFontFamily), + mForceGDIClassic(false) {} + virtual ~gfxDWriteFontFamily(); + + void FindStyleVariationsLocked(FontInfoData* aFontInfoData = nullptr) + MOZ_REQUIRES(mLock) final; + + void LocalizedName(nsACString& aLocalizedName) final; + + void ReadFaceNames(gfxPlatformFontList* aPlatformFontList, + bool aNeedFullnamePostscriptNames, + FontInfoData* aFontInfoData = nullptr) final; + + void SetForceGDIClassic(bool aForce) { mForceGDIClassic = aForce; } + + void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, + FontListSizes* aSizes) const final; + void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, + FontListSizes* aSizes) const final; + + bool FilterForFontList(nsAtom* aLangGroup, + const nsACString& aGeneric) const final { + return !IsSymbolFontFamily(); + } + + protected: + // helper for FilterForFontList + bool IsSymbolFontFamily() const; + + /** This font family's directwrite fontfamily object */ + RefPtr<IDWriteFontFamily> mDWFamily; + bool mIsSystemFontFamily; + bool mForceGDIClassic; +}; + +/** + * \brief Class representing DirectWrite FontEntry (a unique font style/family) + */ +class gfxDWriteFontEntry final : public gfxFontEntry { + public: + /** + * Constructs a font entry. + * + * \param aFaceName The name of the corresponding font face. + * \param aFont DirectWrite font object + */ + gfxDWriteFontEntry(const nsACString& aFaceName, IDWriteFont* aFont, + bool aIsSystemFont = false) + : gfxFontEntry(aFaceName), + mFont(aFont), + mFontFile(nullptr), + mIsSystemFont(aIsSystemFont), + mForceGDIClassic(false), + mHasVariations(false), + mHasVariationsInitialized(false) { + DWRITE_FONT_STYLE dwriteStyle = aFont->GetStyle(); + FontSlantStyle style = (dwriteStyle == DWRITE_FONT_STYLE_ITALIC + ? FontSlantStyle::ITALIC + : (dwriteStyle == DWRITE_FONT_STYLE_OBLIQUE + ? FontSlantStyle::OBLIQUE + : FontSlantStyle::NORMAL)); + mStyleRange = SlantStyleRange(style); + + mStretchRange = + StretchRange(FontStretchFromDWriteStretch(aFont->GetStretch())); + + int weight = NS_ROUNDUP(aFont->GetWeight() - 50, 100); + weight = mozilla::Clamp(weight, 100, 900); + mWeightRange = WeightRange(FontWeight::FromInt(weight)); + + mIsCJK = UNINITIALIZED_VALUE; + } + + /** + * Constructs a font entry using a font. But with custom font values. + * This is used for creating correct font entries for @font-face with local + * font source. + * + * \param aFaceName The name of the corresponding font face. + * \param aFont DirectWrite font object + * \param aWeight Weight of the font + * \param aStretch Stretch of the font + * \param aStyle italic or oblique of font + */ + gfxDWriteFontEntry(const nsACString& aFaceName, IDWriteFont* aFont, + WeightRange aWeight, StretchRange aStretch, + SlantStyleRange aStyle) + : gfxFontEntry(aFaceName), + mFont(aFont), + mFontFile(nullptr), + mIsSystemFont(false), + mForceGDIClassic(false), + mHasVariations(false), + mHasVariationsInitialized(false) { + mWeightRange = aWeight; + mStretchRange = aStretch; + mStyleRange = aStyle; + mIsLocalUserFont = true; + mIsCJK = UNINITIALIZED_VALUE; + } + + /** + * Constructs a font entry using a font file. + * + * \param aFaceName The name of the corresponding font face. + * \param aFontFile DirectWrite fontfile object + * \param aFontFileStream DirectWrite fontfile stream object + * \param aWeight Weight of the font + * \param aStretch Stretch of the font + * \param aStyle italic or oblique of font + */ + gfxDWriteFontEntry(const nsACString& aFaceName, IDWriteFontFile* aFontFile, + IDWriteFontFileStream* aFontFileStream, + WeightRange aWeight, StretchRange aStretch, + SlantStyleRange aStyle) + : gfxFontEntry(aFaceName), + mFont(nullptr), + mFontFile(aFontFile), + mFontFileStream(aFontFileStream), + mIsSystemFont(false), + mForceGDIClassic(false), + mHasVariations(false), + mHasVariationsInitialized(false) { + mWeightRange = aWeight; + mStretchRange = aStretch; + mStyleRange = aStyle; + mIsDataUserFont = true; + mIsCJK = UNINITIALIZED_VALUE; + } + + gfxFontEntry* Clone() const override; + + virtual ~gfxDWriteFontEntry(); + + hb_blob_t* GetFontTable(uint32_t aTableTag) override; + + nsresult ReadCMAP(FontInfoData* aFontInfoData = nullptr) override; + + bool IsCJKFont(); + + bool HasVariations() override; + void GetVariationAxes(nsTArray<gfxFontVariationAxis>& aAxes) override; + void GetVariationInstances( + nsTArray<gfxFontVariationInstance>& aInstances) override; + + void SetForceGDIClassic(bool aForce) { mForceGDIClassic = aForce; } + bool GetForceGDIClassic() { return mForceGDIClassic; } + + void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, + FontListSizes* aSizes) const override; + void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, + FontListSizes* aSizes) const override; + + protected: + friend class gfxDWriteFont; + friend class gfxDWriteFontList; + friend class gfxDWriteFontFamily; + + virtual nsresult CopyFontTable(uint32_t aTableTag, + nsTArray<uint8_t>& aBuffer) override; + + virtual gfxFont* CreateFontInstance(const gfxFontStyle* aFontStyle); + + nsresult CreateFontFace( + IDWriteFontFace** aFontFace, const gfxFontStyle* aFontStyle = nullptr, + DWRITE_FONT_SIMULATIONS aSimulations = DWRITE_FONT_SIMULATIONS_NONE, + const nsTArray<gfxFontVariation>* aVariations = nullptr); + + static bool InitLogFont(IDWriteFont* aFont, LOGFONTW* aLogFont); + + /** + * A fontentry only needs to have either of these. If it has both only + * the IDWriteFont will be used. + */ + RefPtr<IDWriteFont> mFont; + RefPtr<IDWriteFontFile> mFontFile; + + // For custom fonts, we hold a reference to the IDWriteFontFileStream for + // for the IDWriteFontFile, so that the data is available. + RefPtr<IDWriteFontFileStream> mFontFileStream; + + // font face corresponding to the mFont/mFontFile *without* any DWrite + // style simulations applied + RefPtr<IDWriteFontFace> mFontFace; + // Extended fontface interface if supported, else null + RefPtr<IDWriteFontFace5> mFontFace5; + + DWRITE_FONT_FACE_TYPE mFaceType; + + int8_t mIsCJK; + bool mIsSystemFont; + bool mForceGDIClassic; + bool mHasVariations; + bool mHasVariationsInitialized; + + // Set to true only if the font belongs to a "simple" family where the + // faces can be reliably identified via a GDI LOGFONT structure. + bool mMayUseGDIAccess = false; + + mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFontDWrite> mUnscaledFont; + mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFontDWrite> + mUnscaledFontBold; +}; + +// custom text renderer used to determine the fallback font for a given char +class DWriteFontFallbackRenderer final : public IDWriteTextRenderer { + public: + explicit DWriteFontFallbackRenderer(IDWriteFactory* aFactory) : mRefCount(0) { + HRESULT hr = + aFactory->GetSystemFontCollection(getter_AddRefs(mSystemFonts)); + NS_ASSERTION(SUCCEEDED(hr), "GetSystemFontCollection failed!"); + (void)hr; + } + + ~DWriteFontFallbackRenderer() {} + + // If we don't have an mSystemFonts pointer, this renderer is unusable. + bool IsValid() const { return mSystemFonts; } + + // IDWriteTextRenderer methods + IFACEMETHOD(DrawGlyphRun) + (void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, + DWRITE_MEASURING_MODE measuringMode, DWRITE_GLYPH_RUN const* glyphRun, + DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, + IUnknown* clientDrawingEffect); + + IFACEMETHOD(DrawUnderline) + (void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, + DWRITE_UNDERLINE const* underline, IUnknown* clientDrawingEffect) { + return E_NOTIMPL; + } + + IFACEMETHOD(DrawStrikethrough) + (void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, + DWRITE_STRIKETHROUGH const* strikethrough, IUnknown* clientDrawingEffect) { + return E_NOTIMPL; + } + + IFACEMETHOD(DrawInlineObject) + (void* clientDrawingContext, FLOAT originX, FLOAT originY, + IDWriteInlineObject* inlineObject, BOOL isSideways, BOOL isRightToLeft, + IUnknown* clientDrawingEffect) { + return E_NOTIMPL; + } + + // IDWritePixelSnapping methods + + IFACEMETHOD(IsPixelSnappingDisabled) + (void* clientDrawingContext, BOOL* isDisabled) { + *isDisabled = FALSE; + return S_OK; + } + + IFACEMETHOD(GetCurrentTransform) + (void* clientDrawingContext, DWRITE_MATRIX* transform) { + const DWRITE_MATRIX ident = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0}; + *transform = ident; + return S_OK; + } + + IFACEMETHOD(GetPixelsPerDip) + (void* clientDrawingContext, FLOAT* pixelsPerDip) { + *pixelsPerDip = 1.0f; + return S_OK; + } + + // IUnknown methods + + IFACEMETHOD_(unsigned long, AddRef)() { + return InterlockedIncrement(&mRefCount); + } + + IFACEMETHOD_(unsigned long, Release)() { + unsigned long newCount = InterlockedDecrement(&mRefCount); + if (newCount == 0) { + delete this; + return 0; + } + + return newCount; + } + + IFACEMETHOD(QueryInterface)(IID const& riid, void** ppvObject) { + if (__uuidof(IDWriteTextRenderer) == riid) { + *ppvObject = this; + } else if (__uuidof(IDWritePixelSnapping) == riid) { + *ppvObject = this; + } else if (__uuidof(IUnknown) == riid) { + *ppvObject = this; + } else { + *ppvObject = nullptr; + return E_FAIL; + } + + this->AddRef(); + return S_OK; + } + + const nsCString& FallbackFamilyName() { return mFamilyName; } + + protected: + long mRefCount; + RefPtr<IDWriteFontCollection> mSystemFonts; + nsCString mFamilyName; +}; + +class gfxDWriteFontList final : public gfxPlatformFontList { + public: + gfxDWriteFontList(); + virtual ~gfxDWriteFontList() { AutoLock lock(mLock); } + + static gfxDWriteFontList* PlatformFontList() { + return static_cast<gfxDWriteFontList*>( + gfxPlatformFontList::PlatformFontList()); + } + + // initialize font lists + nsresult InitFontListForPlatform() MOZ_REQUIRES(mLock) override; + void InitSharedFontListForPlatform() MOZ_REQUIRES(mLock) override; + + FontVisibility GetVisibilityForFamily(const nsACString& aName) const; + + gfxFontFamily* CreateFontFamily(const nsACString& aName, + FontVisibility aVisibility) const override; + + gfxFontEntry* CreateFontEntry( + mozilla::fontlist::Face* aFace, + const mozilla::fontlist::Family* aFamily) override; + + void ReadFaceNamesForFamily(mozilla::fontlist::Family* aFamily, + bool aNeedFullnamePostscriptNames) + MOZ_REQUIRES(mLock) override; + + bool ReadFaceNames(const mozilla::fontlist::Family* aFamily, + const mozilla::fontlist::Face* aFace, nsCString& aPSName, + nsCString& aFullName) override; + + void GetFacesInitDataForFamily( + const mozilla::fontlist::Family* aFamily, + nsTArray<mozilla::fontlist::Face::InitData>& aFaces, + bool aLoadCmaps) const override; + + gfxFontEntry* LookupLocalFont(nsPresContext* aPresContext, + const nsACString& aFontName, + WeightRange aWeightForEntry, + StretchRange aStretchForEntry, + SlantStyleRange aStyleForEntry) override; + + gfxFontEntry* MakePlatformFont(const nsACString& aFontName, + WeightRange aWeightForEntry, + StretchRange aStretchForEntry, + SlantStyleRange aStyleForEntry, + const uint8_t* aFontData, + uint32_t aLength) override; + + IDWriteGdiInterop* GetGDIInterop() { return mGDIInterop; } + bool UseGDIFontTableAccess() const; + + bool FindAndAddFamiliesLocked( + nsPresContext* aPresContext, mozilla::StyleGenericFontFamily aGeneric, + const nsACString& aFamily, nsTArray<FamilyAndGeneric>* aOutput, + FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, + nsAtom* aLanguage = nullptr, gfxFloat aDevToCssSize = 1.0) + MOZ_REQUIRES(mLock) override; + + gfxFloat GetForceGDIClassicMaxFontSize() { + return mForceGDIClassicMaxFontSize; + } + + virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, + FontListSizes* aSizes) const; + virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, + FontListSizes* aSizes) const; + + protected: + FontFamily GetDefaultFontForPlatform(nsPresContext* aPresContext, + const gfxFontStyle* aStyle, + nsAtom* aLanguage = nullptr) + MOZ_REQUIRES(mLock) override; + + // attempt to use platform-specific fallback for the given character, + // return null if no usable result found + gfxFontEntry* PlatformGlobalFontFallback(nsPresContext* aPresContext, + const uint32_t aCh, + Script aRunScript, + const gfxFontStyle* aMatchStyle, + FontFamily& aMatchedFamily) + MOZ_REQUIRES(mLock) override; + + private: + friend class gfxDWriteFontFamily; + + nsresult GetFontSubstitutes() MOZ_REQUIRES(mLock); + + void GetDirectWriteSubstitutes() MOZ_REQUIRES(mLock); + + virtual bool UsesSystemFallback() { return true; } + + void GetFontsFromCollection(IDWriteFontCollection* aCollection) + MOZ_REQUIRES(mLock); + + void AppendFamiliesFromCollection( + IDWriteFontCollection* aCollection, + nsTArray<mozilla::fontlist::Family::InitData>& aFamilies, + const nsTArray<nsCString>* aForceClassicFams = nullptr) + MOZ_REQUIRES(mLock); + +#ifdef MOZ_BUNDLED_FONTS + already_AddRefed<IDWriteFontCollection> CreateBundledFontsCollection( + IDWriteFactory* aFactory); +#endif + + /** + * Fonts listed in the registry as substitutes but for which no actual + * font family is found. + */ + nsTArray<nsCString> mNonExistingFonts; + + /** + * Table of font substitutes, we grab this from the registry to get + * alternative font names. + */ + FontFamilyTable mFontSubstitutes; + nsClassHashtable<nsCStringHashKey, nsCString> mSubstitutions; + + virtual already_AddRefed<FontInfoData> CreateFontInfoData(); + + gfxFloat mForceGDIClassicMaxFontSize; + + // whether to use GDI font table access routines + bool mGDIFontTableAccess; + RefPtr<IDWriteGdiInterop> mGDIInterop; + + RefPtr<DWriteFontFallbackRenderer> mFallbackRenderer; + RefPtr<IDWriteTextFormat> mFallbackFormat; + + RefPtr<IDWriteFontCollection> mSystemFonts; +#ifdef MOZ_BUNDLED_FONTS + RefPtr<IDWriteFontCollection> mBundledFonts; +#endif +}; + +#endif /* GFX_DWRITEFONTLIST_H */ |