michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef GFX_GDIFONTLIST_H michael@0: #define GFX_GDIFONTLIST_H michael@0: michael@0: #include "mozilla/MemoryReporting.h" michael@0: #include "gfxWindowsPlatform.h" michael@0: #include "gfxPlatformFontList.h" michael@0: #include "nsGkAtoms.h" michael@0: michael@0: #include michael@0: michael@0: class AutoDC // get the global device context, and auto-release it on destruction michael@0: { michael@0: public: michael@0: AutoDC() { michael@0: mDC = ::GetDC(nullptr); michael@0: } michael@0: michael@0: ~AutoDC() { michael@0: ::ReleaseDC(nullptr, mDC); michael@0: } michael@0: michael@0: HDC GetDC() { michael@0: return mDC; michael@0: } michael@0: michael@0: private: michael@0: HDC mDC; michael@0: }; michael@0: michael@0: class AutoSelectFont // select a font into the given DC, and auto-restore michael@0: { michael@0: public: michael@0: AutoSelectFont(HDC aDC, LOGFONTW *aLogFont) michael@0: : mOwnsFont(false) michael@0: { michael@0: mFont = ::CreateFontIndirectW(aLogFont); michael@0: if (mFont) { michael@0: mOwnsFont = true; michael@0: mDC = aDC; michael@0: mOldFont = (HFONT)::SelectObject(aDC, mFont); michael@0: } else { michael@0: mOldFont = nullptr; michael@0: } michael@0: } michael@0: michael@0: AutoSelectFont(HDC aDC, HFONT aFont) michael@0: : mOwnsFont(false) michael@0: { michael@0: mDC = aDC; michael@0: mFont = aFont; michael@0: mOldFont = (HFONT)::SelectObject(aDC, aFont); michael@0: } michael@0: michael@0: ~AutoSelectFont() { michael@0: if (mOldFont) { michael@0: ::SelectObject(mDC, mOldFont); michael@0: if (mOwnsFont) { michael@0: ::DeleteObject(mFont); michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool IsValid() const { michael@0: return mFont != nullptr; michael@0: } michael@0: michael@0: HFONT GetFont() const { michael@0: return mFont; michael@0: } michael@0: michael@0: private: michael@0: HDC mDC; michael@0: HFONT mFont; michael@0: HFONT mOldFont; michael@0: bool mOwnsFont; michael@0: }; michael@0: michael@0: /** michael@0: * List of different types of fonts we support on Windows. michael@0: * These can generally be lumped in to 3 categories where we have to michael@0: * do special things: Really old fonts bitmap and vector fonts (device michael@0: * and raster), Type 1 fonts, and TrueType/OpenType fonts. michael@0: * michael@0: * This list is sorted in order from least prefered to most prefered. michael@0: * We prefer Type1 fonts over OpenType fonts to avoid falling back to michael@0: * things like Arial (opentype) when you ask for Helvetica (type1) michael@0: **/ michael@0: enum gfxWindowsFontType { michael@0: GFX_FONT_TYPE_UNKNOWN = 0, michael@0: GFX_FONT_TYPE_DEVICE, michael@0: GFX_FONT_TYPE_RASTER, michael@0: GFX_FONT_TYPE_TRUETYPE, michael@0: GFX_FONT_TYPE_PS_OPENTYPE, michael@0: GFX_FONT_TYPE_TT_OPENTYPE, michael@0: GFX_FONT_TYPE_TYPE1 michael@0: }; michael@0: michael@0: // A single member of a font family (i.e. a single face, such as Times Italic) michael@0: // represented as a LOGFONT that will resolve to the correct face. michael@0: // This replaces FontEntry from gfxWindowsFonts.h/cpp. michael@0: class GDIFontEntry : public gfxFontEntry michael@0: { michael@0: public: michael@0: LPLOGFONTW GetLogFont() { return &mLogFont; } michael@0: michael@0: nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr); michael@0: michael@0: virtual bool IsSymbolFont(); michael@0: michael@0: void FillLogFont(LOGFONTW *aLogFont, uint16_t aWeight, gfxFloat aSize, michael@0: bool aUseCleartype); michael@0: michael@0: static gfxWindowsFontType DetermineFontType(const NEWTEXTMETRICW& metrics, michael@0: DWORD fontType) michael@0: { michael@0: gfxWindowsFontType feType; michael@0: if (metrics.ntmFlags & NTM_TYPE1) michael@0: feType = GFX_FONT_TYPE_TYPE1; michael@0: else if (metrics.ntmFlags & NTM_PS_OPENTYPE) michael@0: feType = GFX_FONT_TYPE_PS_OPENTYPE; michael@0: else if (metrics.ntmFlags & NTM_TT_OPENTYPE) michael@0: feType = GFX_FONT_TYPE_TT_OPENTYPE; michael@0: else if (fontType == TRUETYPE_FONTTYPE) michael@0: feType = GFX_FONT_TYPE_TRUETYPE; michael@0: else if (fontType == RASTER_FONTTYPE) michael@0: feType = GFX_FONT_TYPE_RASTER; michael@0: else if (fontType == DEVICE_FONTTYPE) michael@0: feType = GFX_FONT_TYPE_DEVICE; michael@0: else michael@0: feType = GFX_FONT_TYPE_UNKNOWN; michael@0: michael@0: return feType; michael@0: } michael@0: michael@0: bool IsType1() const { michael@0: return (mFontType == GFX_FONT_TYPE_TYPE1); michael@0: } michael@0: michael@0: bool IsTrueType() const { michael@0: return (mFontType == GFX_FONT_TYPE_TRUETYPE || michael@0: mFontType == GFX_FONT_TYPE_PS_OPENTYPE || michael@0: mFontType == GFX_FONT_TYPE_TT_OPENTYPE); michael@0: } michael@0: michael@0: virtual bool MatchesGenericFamily(const nsACString& aGeneric) const { michael@0: if (aGeneric.IsEmpty()) { michael@0: return true; michael@0: } michael@0: michael@0: // Japanese 'Mincho' fonts do not belong to FF_MODERN even if michael@0: // they are fixed pitch because they have variable stroke width. michael@0: if (mWindowsFamily == FF_ROMAN && mWindowsPitch & FIXED_PITCH) { michael@0: return aGeneric.EqualsLiteral("monospace"); michael@0: } michael@0: michael@0: // Japanese 'Gothic' fonts do not belong to FF_SWISS even if michael@0: // they are variable pitch because they have constant stroke width. michael@0: if (mWindowsFamily == FF_MODERN && mWindowsPitch & VARIABLE_PITCH) { michael@0: return aGeneric.EqualsLiteral("sans-serif"); michael@0: } michael@0: michael@0: // All other fonts will be grouped correctly using family... michael@0: switch (mWindowsFamily) { michael@0: case FF_DONTCARE: michael@0: return false; michael@0: case FF_ROMAN: michael@0: return aGeneric.EqualsLiteral("serif"); michael@0: case FF_SWISS: michael@0: return aGeneric.EqualsLiteral("sans-serif"); michael@0: case FF_MODERN: michael@0: return aGeneric.EqualsLiteral("monospace"); michael@0: case FF_SCRIPT: michael@0: return aGeneric.EqualsLiteral("cursive"); michael@0: case FF_DECORATIVE: michael@0: return aGeneric.EqualsLiteral("fantasy"); michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: virtual bool SupportsLangGroup(nsIAtom* aLangGroup) const { michael@0: if (!aLangGroup || aLangGroup == nsGkAtoms::Unicode) { michael@0: return true; michael@0: } michael@0: michael@0: int16_t bit = -1; michael@0: michael@0: /* map our langgroup names in to Windows charset bits */ michael@0: if (aLangGroup == nsGkAtoms::x_western) { michael@0: bit = ANSI_CHARSET; michael@0: } else if (aLangGroup == nsGkAtoms::Japanese) { michael@0: bit = SHIFTJIS_CHARSET; michael@0: } else if (aLangGroup == nsGkAtoms::ko) { michael@0: bit = HANGEUL_CHARSET; michael@0: } else if (aLangGroup == nsGkAtoms::ko_xxx) { michael@0: bit = JOHAB_CHARSET; michael@0: } else if (aLangGroup == nsGkAtoms::zh_cn) { michael@0: bit = GB2312_CHARSET; michael@0: } else if (aLangGroup == nsGkAtoms::zh_tw) { michael@0: bit = CHINESEBIG5_CHARSET; michael@0: } else if (aLangGroup == nsGkAtoms::el_) { michael@0: bit = GREEK_CHARSET; michael@0: } else if (aLangGroup == nsGkAtoms::tr) { michael@0: bit = TURKISH_CHARSET; michael@0: } else if (aLangGroup == nsGkAtoms::he) { michael@0: bit = HEBREW_CHARSET; michael@0: } else if (aLangGroup == nsGkAtoms::ar) { michael@0: bit = ARABIC_CHARSET; michael@0: } else if (aLangGroup == nsGkAtoms::x_baltic) { michael@0: bit = BALTIC_CHARSET; michael@0: } else if (aLangGroup == nsGkAtoms::x_cyrillic) { michael@0: bit = RUSSIAN_CHARSET; michael@0: } else if (aLangGroup == nsGkAtoms::th) { michael@0: bit = THAI_CHARSET; michael@0: } else if (aLangGroup == nsGkAtoms::x_central_euro) { michael@0: bit = EASTEUROPE_CHARSET; michael@0: } else if (aLangGroup == nsGkAtoms::x_symbol) { michael@0: bit = SYMBOL_CHARSET; michael@0: } michael@0: michael@0: if (bit != -1) { michael@0: return mCharset.test(bit); michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: virtual bool SupportsRange(uint8_t range) { michael@0: return mUnicodeRanges.test(range); michael@0: } michael@0: michael@0: virtual bool SkipDuringSystemFallback() { michael@0: return !HasCmapTable(); // explicitly skip non-SFNT fonts michael@0: } michael@0: michael@0: virtual bool TestCharacterMap(uint32_t aCh); michael@0: michael@0: virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, michael@0: FontListSizes* aSizes) const; michael@0: michael@0: // create a font entry for a font with a given name michael@0: static GDIFontEntry* CreateFontEntry(const nsAString& aName, michael@0: gfxWindowsFontType aFontType, michael@0: bool aItalic, michael@0: uint16_t aWeight, int16_t aStretch, michael@0: gfxUserFontData* aUserFontData, michael@0: bool aFamilyHasItalicFace); michael@0: michael@0: // create a font entry for a font referenced by its fullname michael@0: static GDIFontEntry* LoadLocalFont(const gfxProxyFontEntry &aProxyEntry, michael@0: const nsAString& aFullname); michael@0: michael@0: uint8_t mWindowsFamily; michael@0: uint8_t mWindowsPitch; michael@0: michael@0: gfxWindowsFontType mFontType; michael@0: bool mForceGDI : 1; michael@0: michael@0: // For src:local user-fonts, we keep track of whether the platform family michael@0: // contains an italic face, because in this case we can't safely ask GDI michael@0: // to create synthetic italics (oblique) via the LOGFONT. michael@0: // (For other types of font, this is just set to false.) michael@0: bool mFamilyHasItalicFace : 1; michael@0: michael@0: gfxSparseBitSet mCharset; michael@0: gfxSparseBitSet mUnicodeRanges; michael@0: michael@0: protected: michael@0: friend class gfxWindowsFont; michael@0: michael@0: GDIFontEntry(const nsAString& aFaceName, gfxWindowsFontType aFontType, michael@0: bool aItalic, uint16_t aWeight, int16_t aStretch, michael@0: gfxUserFontData *aUserFontData, bool aFamilyHasItalicFace); michael@0: michael@0: void InitLogFont(const nsAString& aName, gfxWindowsFontType aFontType); michael@0: michael@0: virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold); michael@0: michael@0: virtual nsresult CopyFontTable(uint32_t aTableTag, michael@0: FallibleTArray& aBuffer) MOZ_OVERRIDE; michael@0: michael@0: LOGFONTW mLogFont; michael@0: }; michael@0: michael@0: // a single font family, referencing one or more faces michael@0: class GDIFontFamily : public gfxFontFamily michael@0: { michael@0: public: michael@0: GDIFontFamily(nsAString &aName) : michael@0: gfxFontFamily(aName) {} michael@0: michael@0: virtual void FindStyleVariations(FontInfoData *aFontInfoData = nullptr); michael@0: michael@0: private: michael@0: static int CALLBACK FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe, michael@0: const NEWTEXTMETRICEXW *nmetrics, michael@0: DWORD fontType, LPARAM data); michael@0: }; michael@0: michael@0: class gfxGDIFontList : public gfxPlatformFontList { michael@0: public: michael@0: static gfxGDIFontList* PlatformFontList() { michael@0: return static_cast(sPlatformFontList); michael@0: } michael@0: michael@0: // initialize font lists michael@0: virtual nsresult InitFontList(); michael@0: michael@0: virtual gfxFontFamily* GetDefaultFont(const gfxFontStyle* aStyle); michael@0: michael@0: virtual gfxFontEntry* LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, michael@0: const nsAString& aFontName); michael@0: michael@0: virtual gfxFontEntry* MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, michael@0: const uint8_t *aFontData, uint32_t aLength); michael@0: michael@0: virtual bool ResolveFontName(const nsAString& aFontName, michael@0: nsAString& aResolvedFontName); michael@0: michael@0: virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, michael@0: FontListSizes* aSizes) const; michael@0: virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, michael@0: FontListSizes* aSizes) const; michael@0: michael@0: private: michael@0: friend class gfxWindowsPlatform; michael@0: michael@0: gfxGDIFontList(); michael@0: michael@0: nsresult GetFontSubstitutes(); michael@0: michael@0: static int CALLBACK EnumFontFamExProc(ENUMLOGFONTEXW *lpelfe, michael@0: NEWTEXTMETRICEXW *lpntme, michael@0: DWORD fontType, michael@0: LPARAM lParam); michael@0: michael@0: virtual already_AddRefed CreateFontInfoData(); michael@0: michael@0: typedef nsRefPtrHashtable FontTable; michael@0: michael@0: FontTable mFontSubstitutes; michael@0: nsTArray mNonExistingFonts; michael@0: }; michael@0: michael@0: #endif /* GFX_GDIFONTLIST_H */