summaryrefslogtreecommitdiffstats
path: root/gfx/thebes/gfxFT2Utils.cpp
blob: 94403c9dc195c385b465a5d436a16ac22d218157 (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
153
154
155
156
157
/* -*- 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/. */

#include "gfxFT2FontBase.h"
#include "gfxFT2Utils.h"
#include "mozilla/Likely.h"

#ifdef USE_FC_FREETYPE
#  include <fontconfig/fcfreetype.h>
#endif

#include "ft2build.h"
#include FT_MULTIPLE_MASTERS_H

#include "prlink.h"

uint32_t gfxFT2LockedFace::GetGlyph(uint32_t aCharCode) {
  if (MOZ_UNLIKELY(!mFace)) return 0;

#ifdef USE_FC_FREETYPE
  // FcFreeTypeCharIndex will search starting from the most recently
  // selected charmap.  This can cause non-determistic behavior when more
  // than one charmap supports a character but with different glyphs, as
  // with older versions of MS Gothic, for example.  Always prefer a Unicode
  // charmap, if there is one; failing that, try MS_SYMBOL.
  // (FcFreeTypeCharIndex usually does the appropriate Unicode conversion,
  // but some fonts have non-Roman glyphs for FT_ENCODING_APPLE_ROMAN
  // characters.)
  if (!mFace->charmap || (mFace->charmap->encoding != FT_ENCODING_UNICODE &&
                          mFace->charmap->encoding != FT_ENCODING_MS_SYMBOL)) {
    if (FT_Err_Ok != FT_Select_Charmap(mFace, FT_ENCODING_UNICODE) &&
        FT_Err_Ok != FT_Select_Charmap(mFace, FT_ENCODING_MS_SYMBOL)) {
      NS_WARNING("failed to select Unicode or symbol charmap");
    }
  }

  uint32_t gid = FcFreeTypeCharIndex(mFace, aCharCode);
#else
  uint32_t gid = FT_Get_Char_Index(mFace, aCharCode);
#endif
  if (!gid && mFace->charmap &&
      mFace->charmap->encoding == FT_ENCODING_MS_SYMBOL) {
    if (auto pua = gfxFontUtils::MapLegacySymbolFontCharToPUA(aCharCode)) {
      gid = FT_Get_Char_Index(mFace, pua);
    }
  }
  return gid;
}

typedef FT_UInt (*GetCharVariantFunction)(FT_Face face, FT_ULong charcode,
                                          FT_ULong variantSelector);

uint32_t gfxFT2LockedFace::GetUVSGlyph(uint32_t aCharCode,
                                       uint32_t aVariantSelector) {
  MOZ_ASSERT(aVariantSelector, "aVariantSelector should not be NULL");

  if (MOZ_UNLIKELY(!mFace)) return 0;

  // This function is available from FreeType 2.3.6 (June 2008).
  static CharVariantFunction sGetCharVariantPtr = FindCharVariantFunction();
  if (!sGetCharVariantPtr) return 0;

#ifdef USE_FC_FREETYPE
  // FcFreeTypeCharIndex may have changed the selected charmap.
  // FT_Face_GetCharVariantIndex needs a unicode charmap.
  if (!mFace->charmap || mFace->charmap->encoding != FT_ENCODING_UNICODE) {
    FT_Select_Charmap(mFace, FT_ENCODING_UNICODE);
  }
#endif

  return (*sGetCharVariantPtr)(mFace, aCharCode, aVariantSelector);
}

gfxFT2LockedFace::CharVariantFunction
gfxFT2LockedFace::FindCharVariantFunction() {
  // This function is available from FreeType 2.3.6 (June 2008).
  PRLibrary* lib = nullptr;
  CharVariantFunction function = reinterpret_cast<CharVariantFunction>(
      PR_FindFunctionSymbolAndLibrary("FT_Face_GetCharVariantIndex", &lib));
  if (!lib) {
    return nullptr;
  }

  FT_Int major;
  FT_Int minor;
  FT_Int patch;
  FT_Library_Version(mFace->glyph->library, &major, &minor, &patch);

  // Versions 2.4.0 to 2.4.3 crash if configured with
  // FT_CONFIG_OPTION_OLD_INTERNALS.  Presence of the symbol FT_Alloc
  // indicates FT_CONFIG_OPTION_OLD_INTERNALS.
  if (major == 2 && minor == 4 && patch < 4 &&
      PR_FindFunctionSymbol(lib, "FT_Alloc")) {
    function = nullptr;
  }

  // Decrement the reference count incremented in
  // PR_FindFunctionSymbolAndLibrary.
  PR_UnloadLibrary(lib);

  return function;
}

/*static*/
void gfxFT2Utils::GetVariationAxes(const FT_MM_Var* aMMVar,
                                   nsTArray<gfxFontVariationAxis>& aAxes) {
  MOZ_ASSERT(aAxes.IsEmpty());
  if (!aMMVar) {
    return;
  }
  aAxes.SetCapacity(aMMVar->num_axis);
  for (unsigned i = 0; i < aMMVar->num_axis; i++) {
    const auto& a = aMMVar->axis[i];
    gfxFontVariationAxis axis;
    axis.mMinValue = a.minimum / 65536.0;
    axis.mMaxValue = a.maximum / 65536.0;
    axis.mDefaultValue = a.def / 65536.0;
    axis.mTag = a.tag;
    axis.mName = a.name;
    aAxes.AppendElement(axis);
  }
}

/*static*/
void gfxFT2Utils::GetVariationInstances(
    gfxFontEntry* aFontEntry, const FT_MM_Var* aMMVar,
    nsTArray<gfxFontVariationInstance>& aInstances) {
  MOZ_ASSERT(aInstances.IsEmpty());
  if (!aMMVar) {
    return;
  }
  gfxFontUtils::AutoHBBlob nameTable(
      aFontEntry->GetFontTable(TRUETYPE_TAG('n', 'a', 'm', 'e')));
  if (!nameTable) {
    return;
  }
  aInstances.SetCapacity(aMMVar->num_namedstyles);
  for (unsigned i = 0; i < aMMVar->num_namedstyles; i++) {
    const auto& ns = aMMVar->namedstyle[i];
    gfxFontVariationInstance inst;
    nsresult rv =
        gfxFontUtils::ReadCanonicalName(nameTable, ns.strid, inst.mName);
    if (NS_FAILED(rv)) {
      continue;
    }
    inst.mValues.SetCapacity(aMMVar->num_axis);
    for (unsigned j = 0; j < aMMVar->num_axis; j++) {
      gfxFontVariationValue value;
      value.mAxis = aMMVar->axis[j].tag;
      value.mValue = ns.coords[j] / 65536.0;
      inst.mValues.AppendElement(value);
    }
    aInstances.AppendElement(inst);
  }
}