summaryrefslogtreecommitdiffstats
path: root/gfx/thebes/gfxFT2FontBase.h
blob: 1699cba683cba5a56074517e32e3a593fafbac7d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/* -*- 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_FT2FONTBASE_H
#define GFX_FT2FONTBASE_H

#include "gfxContext.h"
#include "gfxFont.h"
#include "gfxFontEntry.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/UnscaledFontFreeType.h"
#include "nsTHashMap.h"
#include "nsHashKeys.h"

class gfxFT2FontBase;

class gfxFT2FontEntryBase : public gfxFontEntry {
 public:
  explicit gfxFT2FontEntryBase(const nsACString& aName) : gfxFontEntry(aName) {}

  uint32_t GetGlyph(uint32_t aCharCode, gfxFT2FontBase* aFont);

  static bool FaceHasTable(mozilla::gfx::SharedFTFace*, uint32_t aTableTag);
  static nsresult CopyFaceTable(mozilla::gfx::SharedFTFace*, uint32_t aTableTag,
                                nsTArray<uint8_t>&);

 private:
  enum { kNumCmapCacheSlots = 256 };

  struct CmapCacheSlot {
    CmapCacheSlot() : mCharCode(0), mGlyphIndex(0) {}

    uint32_t mCharCode;
    uint32_t mGlyphIndex;
  };

  mozilla::UniquePtr<CmapCacheSlot[]> mCmapCache MOZ_GUARDED_BY(mLock);
};

class gfxFT2FontBase : public gfxFont {
 public:
  gfxFT2FontBase(
      const RefPtr<mozilla::gfx::UnscaledFontFreeType>& aUnscaledFont,
      RefPtr<mozilla::gfx::SharedFTFace>&& aFTFace, gfxFontEntry* aFontEntry,
      const gfxFontStyle* aFontStyle, int aLoadFlags, bool aEmbolden);

  uint32_t GetGlyph(uint32_t aCharCode) {
    auto* entry = static_cast<gfxFT2FontEntryBase*>(mFontEntry.get());
    return entry->GetGlyph(aCharCode, this);
  }

  bool ProvidesGetGlyph() const override { return true; }
  virtual uint32_t GetGlyph(uint32_t unicode,
                            uint32_t variation_selector) override;

  bool ProvidesGlyphWidths() const override { return true; }
  int32_t GetGlyphWidth(uint16_t aGID) override {
    return GetCachedGlyphMetrics(aGID).mAdvance;
  }

  bool GetGlyphBounds(uint16_t aGID, gfxRect* aBounds, bool aTight) override;

  FontType GetType() const override { return FONT_TYPE_FT2; }

  bool ShouldRoundXOffset(cairo_t* aCairo) const override;

  static void SetupVarCoords(FT_MM_Var* aMMVar,
                             const nsTArray<gfxFontVariation>& aVariations,
                             FT_Face aFTFace);

  FT_Face LockFTFace() const;
  void UnlockFTFace() const;

 private:
  uint32_t GetCharExtents(uint32_t aChar, gfxFloat* aWidth,
                          gfxRect* aBounds = nullptr);

  // Get advance (and optionally bounds) of a single glyph from FreeType,
  // and return true, or return false if we failed.
  bool GetFTGlyphExtents(uint16_t aGID, int32_t* aWidth,
                         mozilla::gfx::IntRect* aBounds = nullptr) const;

 protected:
  ~gfxFT2FontBase() override;
  void InitMetrics();
  const Metrics& GetHorizontalMetrics() const override { return mMetrics; }
  FT_Vector GetEmboldenStrength(FT_Face aFace) const;

  RefPtr<mozilla::gfx::SharedFTFace> mFTFace;

  Metrics mMetrics;
  int mFTLoadFlags;
  bool mEmbolden;
  gfxFloat mFTSize;

  // For variation/multiple-master fonts, this will be an array of the values
  // for each axis, as specified by mStyle.variationSettings (or the font's
  // default for axes not present in variationSettings). Values here are in
  // freetype's 16.16 fixed-point format, and clamped to the valid min/max
  // range reported by the face.
  nsTArray<FT_Fixed> mCoords;

  // Store cached glyph metrics for reasonably small glyph sizes. The bounds
  // are stored unscaled to losslessly compress 26.6 fixed point to an int16_t.
  // Larger glyphs are handled directly via GetFTGlyphExtents.
  struct GlyphMetrics {
    // Set the X coord to INT16_MIN to signal the bounds are invalid, or
    // INT16_MAX to signal that the bounds would overflow an int16_t.
    enum { INVALID = INT16_MIN, LARGE = INT16_MAX };

    GlyphMetrics() : mAdvance(0), mX(INVALID), mY(0), mWidth(0), mHeight(0) {}

    bool HasValidBounds() const { return mX != INVALID; }
    bool HasCachedBounds() const { return mX != LARGE; }

    // If the bounds can fit in an int16_t, set them. Otherwise, leave the
    // bounds invalid to signal that GetFTGlyphExtents should be queried
    // directly.
    void SetBounds(const mozilla::gfx::IntRect& aBounds) {
      if (aBounds.x > INT16_MIN && aBounds.x < INT16_MAX &&
          aBounds.y > INT16_MIN && aBounds.y < INT16_MAX &&
          aBounds.width <= UINT16_MAX && aBounds.height <= UINT16_MAX) {
        mX = aBounds.x;
        mY = aBounds.y;
        mWidth = aBounds.width;
        mHeight = aBounds.height;
      } else {
        mX = LARGE;
      }
    }

    mozilla::gfx::IntRect GetBounds() const {
      return mozilla::gfx::IntRect(mX, mY, mWidth, mHeight);
    }

    int32_t mAdvance;
    int16_t mX;
    int16_t mY;
    uint16_t mWidth;
    uint16_t mHeight;
  };

  const GlyphMetrics& GetCachedGlyphMetrics(
      uint16_t aGID, mozilla::gfx::IntRect* aBounds = nullptr) const;

  mutable mozilla::UniquePtr<nsTHashMap<nsUint32HashKey, GlyphMetrics>>
      mGlyphMetrics MOZ_GUARDED_BY(mLock);
};

#endif /* GFX_FT2FONTBASE_H */