1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef GFX_FT2FONTBASE_H
7 #define GFX_FT2FONTBASE_H
8 
9 #include "gfxContext.h"
10 #include "gfxFont.h"
11 #include "gfxFontEntry.h"
12 #include "mozilla/gfx/2D.h"
13 #include "mozilla/gfx/UnscaledFontFreeType.h"
14 #include "nsDataHashtable.h"
15 #include "nsHashKeys.h"
16 
17 class gfxFT2FontEntryBase : public gfxFontEntry {
18  public:
gfxFT2FontEntryBase(const nsACString & aName)19   explicit gfxFT2FontEntryBase(const nsACString& aName) : gfxFontEntry(aName) {}
20 
21   struct CmapCacheSlot {
CmapCacheSlotCmapCacheSlot22     CmapCacheSlot() : mCharCode(0), mGlyphIndex(0) {}
23 
24     uint32_t mCharCode;
25     uint32_t mGlyphIndex;
26   };
27 
28   CmapCacheSlot* GetCmapCacheSlot(uint32_t aCharCode);
29 
30  private:
31   enum { kNumCmapCacheSlots = 256 };
32 
33   mozilla::UniquePtr<CmapCacheSlot[]> mCmapCache;
34 };
35 
36 class gfxFT2FontBase : public gfxFont {
37  public:
38   gfxFT2FontBase(
39       const RefPtr<mozilla::gfx::UnscaledFontFreeType>& aUnscaledFont,
40       RefPtr<mozilla::gfx::SharedFTFace>&& aFTFace, gfxFontEntry* aFontEntry,
41       const gfxFontStyle* aFontStyle, int aLoadFlags, bool aEmbolden);
42   virtual ~gfxFT2FontBase();
43 
44   uint32_t GetGlyph(uint32_t aCharCode);
ProvidesGetGlyph()45   bool ProvidesGetGlyph() const override { return true; }
46   virtual uint32_t GetGlyph(uint32_t unicode,
47                             uint32_t variation_selector) override;
ProvidesGlyphWidths()48   bool ProvidesGlyphWidths() const override { return true; }
49   int32_t GetGlyphWidth(uint16_t aGID) override;
50   bool GetGlyphBounds(uint16_t aGID, gfxRect* aBounds, bool aTight) override;
51 
GetType()52   FontType GetType() const override { return FONT_TYPE_FT2; }
53 
54   bool ShouldRoundXOffset(cairo_t* aCairo) const override;
55 
56   static void SetupVarCoords(FT_MM_Var* aMMVar,
57                              const nsTArray<gfxFontVariation>& aVariations,
58                              FT_Face aFTFace);
59 
60   FT_Face LockFTFace();
61   void UnlockFTFace();
62 
63  private:
64   uint32_t GetCharExtents(char aChar, gfxFloat* aWidth,
65                           gfxRect* aBounds = nullptr);
66 
67   // Get advance (and optionally bounds) of a single glyph from FreeType,
68   // and return true, or return false if we failed.
69   bool GetFTGlyphExtents(uint16_t aGID, int32_t* aWidth,
70                          mozilla::gfx::IntRect* aBounds = nullptr);
71 
72  protected:
73   void InitMetrics();
74   const Metrics& GetHorizontalMetrics() override;
75   FT_Vector GetEmboldenStrength(FT_Face aFace);
76 
77   RefPtr<mozilla::gfx::SharedFTFace> mFTFace;
78 
79   Metrics mMetrics;
80   int mFTLoadFlags;
81   bool mEmbolden;
82   gfxFloat mFTSize;
83 
84   // For variation/multiple-master fonts, this will be an array of the values
85   // for each axis, as specified by mStyle.variationSettings (or the font's
86   // default for axes not present in variationSettings). Values here are in
87   // freetype's 16.16 fixed-point format, and clamped to the valid min/max
88   // range reported by the face.
89   nsTArray<FT_Fixed> mCoords;
90 
91   // Store cached glyph metrics for reasonably small glyph sizes. The bounds
92   // are stored unscaled to losslessly compress 26.6 fixed point to an int16_t.
93   // Larger glyphs are handled directly via GetFTGlyphExtents.
94   struct GlyphMetrics {
95     // Set the X coord to INT16_MIN to signal the bounds are invalid, or
96     // INT16_MAX to signal that the bounds would overflow an int16_t.
97     enum { INVALID = INT16_MIN, LARGE = INT16_MAX };
98 
GlyphMetricsGlyphMetrics99     GlyphMetrics() : mAdvance(0), mX(INVALID), mY(0), mWidth(0), mHeight(0) {}
100 
HasValidBoundsGlyphMetrics101     bool HasValidBounds() const { return mX != INVALID; }
HasCachedBoundsGlyphMetrics102     bool HasCachedBounds() const { return mX != LARGE; }
103 
104     // If the bounds can fit in an int16_t, set them. Otherwise, leave the
105     // bounds invalid to signal that GetFTGlyphExtents should be queried
106     // directly.
SetBoundsGlyphMetrics107     void SetBounds(const mozilla::gfx::IntRect& aBounds) {
108       if (aBounds.x > INT16_MIN && aBounds.x < INT16_MAX &&
109           aBounds.y > INT16_MIN && aBounds.y < INT16_MAX &&
110           aBounds.width <= UINT16_MAX && aBounds.height <= UINT16_MAX) {
111         mX = aBounds.x;
112         mY = aBounds.y;
113         mWidth = aBounds.width;
114         mHeight = aBounds.height;
115       } else {
116         mX = LARGE;
117       }
118     }
119 
GetBoundsGlyphMetrics120     mozilla::gfx::IntRect GetBounds() const {
121       return mozilla::gfx::IntRect(mX, mY, mWidth, mHeight);
122     }
123 
124     int32_t mAdvance;
125     int16_t mX;
126     int16_t mY;
127     uint16_t mWidth;
128     uint16_t mHeight;
129   };
130 
131   const GlyphMetrics& GetCachedGlyphMetrics(
132       uint16_t aGID, mozilla::gfx::IntRect* aBounds = nullptr);
133 
134   mozilla::UniquePtr<nsDataHashtable<nsUint32HashKey, GlyphMetrics>>
135       mGlyphMetrics;
136 };
137 
138 // Helper classes used for clearing out user font data when FT font
139 // face is destroyed. Since multiple faces may use the same data, be
140 // careful to assure that the data is only cleared out when all uses
141 // expire. The font entry object contains a refptr to FTUserFontData and
142 // each FT face created from that font entry contains a refptr to that
143 // same FTUserFontData object.
144 
145 class FTUserFontData final
146     : public mozilla::gfx::SharedFTFaceRefCountedData<FTUserFontData> {
147  public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FTUserFontData)148   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FTUserFontData)
149 
150   FTUserFontData(const uint8_t* aData, uint32_t aLength)
151       : mFontData(aData), mLength(aLength) {}
152 
FontData()153   const uint8_t* FontData() const { return mFontData; }
154 
155   already_AddRefed<mozilla::gfx::SharedFTFace> CloneFace(
156       int aFaceIndex = 0) override;
157 
158  private:
~FTUserFontData()159   ~FTUserFontData() {
160     if (mFontData) {
161       free((void*)mFontData);
162     }
163   }
164 
165   const uint8_t* mFontData;
166   uint32_t mLength;
167 };
168 
169 #endif /* GFX_FT2FONTBASE_H */
170