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 "nsTHashMap.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   static bool FaceHasTable(mozilla::gfx::SharedFTFace*, uint32_t aTableTag);
31   static nsresult CopyFaceTable(mozilla::gfx::SharedFTFace*, uint32_t aTableTag,
32                                 nsTArray<uint8_t>&);
33 
34  private:
35   enum { kNumCmapCacheSlots = 256 };
36 
37   mozilla::UniquePtr<CmapCacheSlot[]> mCmapCache;
38 };
39 
40 class gfxFT2FontBase : public gfxFont {
41  public:
42   gfxFT2FontBase(
43       const RefPtr<mozilla::gfx::UnscaledFontFreeType>& aUnscaledFont,
44       RefPtr<mozilla::gfx::SharedFTFace>&& aFTFace, gfxFontEntry* aFontEntry,
45       const gfxFontStyle* aFontStyle, int aLoadFlags, bool aEmbolden);
46   virtual ~gfxFT2FontBase();
47 
48   uint32_t GetGlyph(uint32_t aCharCode);
ProvidesGetGlyph()49   bool ProvidesGetGlyph() const override { return true; }
50   virtual uint32_t GetGlyph(uint32_t unicode,
51                             uint32_t variation_selector) override;
ProvidesGlyphWidths()52   bool ProvidesGlyphWidths() const override { return true; }
53   int32_t GetGlyphWidth(uint16_t aGID) override;
54   bool GetGlyphBounds(uint16_t aGID, gfxRect* aBounds, bool aTight) override;
55 
GetType()56   FontType GetType() const override { return FONT_TYPE_FT2; }
57 
58   bool ShouldRoundXOffset(cairo_t* aCairo) const override;
59 
60   static void SetupVarCoords(FT_MM_Var* aMMVar,
61                              const nsTArray<gfxFontVariation>& aVariations,
62                              FT_Face aFTFace);
63 
64   FT_Face LockFTFace();
65   void UnlockFTFace();
66 
67  private:
68   uint32_t GetCharExtents(uint32_t aChar, gfxFloat* aWidth,
69                           gfxRect* aBounds = nullptr);
70 
71   // Get advance (and optionally bounds) of a single glyph from FreeType,
72   // and return true, or return false if we failed.
73   bool GetFTGlyphExtents(uint16_t aGID, int32_t* aWidth,
74                          mozilla::gfx::IntRect* aBounds = nullptr);
75 
76  protected:
77   void InitMetrics();
78   const Metrics& GetHorizontalMetrics() override;
79   FT_Vector GetEmboldenStrength(FT_Face aFace);
80 
81   RefPtr<mozilla::gfx::SharedFTFace> mFTFace;
82 
83   Metrics mMetrics;
84   int mFTLoadFlags;
85   bool mEmbolden;
86   gfxFloat mFTSize;
87 
88   // For variation/multiple-master fonts, this will be an array of the values
89   // for each axis, as specified by mStyle.variationSettings (or the font's
90   // default for axes not present in variationSettings). Values here are in
91   // freetype's 16.16 fixed-point format, and clamped to the valid min/max
92   // range reported by the face.
93   nsTArray<FT_Fixed> mCoords;
94 
95   // Store cached glyph metrics for reasonably small glyph sizes. The bounds
96   // are stored unscaled to losslessly compress 26.6 fixed point to an int16_t.
97   // Larger glyphs are handled directly via GetFTGlyphExtents.
98   struct GlyphMetrics {
99     // Set the X coord to INT16_MIN to signal the bounds are invalid, or
100     // INT16_MAX to signal that the bounds would overflow an int16_t.
101     enum { INVALID = INT16_MIN, LARGE = INT16_MAX };
102 
GlyphMetricsGlyphMetrics103     GlyphMetrics() : mAdvance(0), mX(INVALID), mY(0), mWidth(0), mHeight(0) {}
104 
HasValidBoundsGlyphMetrics105     bool HasValidBounds() const { return mX != INVALID; }
HasCachedBoundsGlyphMetrics106     bool HasCachedBounds() const { return mX != LARGE; }
107 
108     // If the bounds can fit in an int16_t, set them. Otherwise, leave the
109     // bounds invalid to signal that GetFTGlyphExtents should be queried
110     // directly.
SetBoundsGlyphMetrics111     void SetBounds(const mozilla::gfx::IntRect& aBounds) {
112       if (aBounds.x > INT16_MIN && aBounds.x < INT16_MAX &&
113           aBounds.y > INT16_MIN && aBounds.y < INT16_MAX &&
114           aBounds.width <= UINT16_MAX && aBounds.height <= UINT16_MAX) {
115         mX = aBounds.x;
116         mY = aBounds.y;
117         mWidth = aBounds.width;
118         mHeight = aBounds.height;
119       } else {
120         mX = LARGE;
121       }
122     }
123 
GetBoundsGlyphMetrics124     mozilla::gfx::IntRect GetBounds() const {
125       return mozilla::gfx::IntRect(mX, mY, mWidth, mHeight);
126     }
127 
128     int32_t mAdvance;
129     int16_t mX;
130     int16_t mY;
131     uint16_t mWidth;
132     uint16_t mHeight;
133   };
134 
135   const GlyphMetrics& GetCachedGlyphMetrics(
136       uint16_t aGID, mozilla::gfx::IntRect* aBounds = nullptr);
137 
138   mozilla::UniquePtr<nsTHashMap<nsUint32HashKey, GlyphMetrics>> mGlyphMetrics;
139 };
140 
141 // Helper classes used for clearing out user font data when FT font
142 // face is destroyed. Since multiple faces may use the same data, be
143 // careful to assure that the data is only cleared out when all uses
144 // expire. The font entry object contains a refptr to FTUserFontData and
145 // each FT face created from that font entry contains a refptr to that
146 // same FTUserFontData object.
147 
148 class FTUserFontData final
149     : public mozilla::gfx::SharedFTFaceRefCountedData<FTUserFontData> {
150  public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FTUserFontData)151   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FTUserFontData)
152 
153   FTUserFontData(const uint8_t* aData, uint32_t aLength)
154       : mFontData(aData), mLength(aLength) {}
155 
FontData()156   const uint8_t* FontData() const { return mFontData; }
157 
158   already_AddRefed<mozilla::gfx::SharedFTFace> CloneFace(
159       int aFaceIndex = 0) override;
160 
161  private:
~FTUserFontData()162   ~FTUserFontData() {
163     if (mFontData) {
164       free((void*)mFontData);
165     }
166   }
167 
168   const uint8_t* mFontData;
169   uint32_t mLength;
170 };
171 
172 #endif /* GFX_FT2FONTBASE_H */
173