Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/2d/SFNTData.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "SFNTData.h"
8
9
#include <algorithm>
10
11
#include "BigEndianInts.h"
12
#include "Logging.h"
13
#include "mozilla/HashFunctions.h"
14
#include "SFNTNameTable.h"
15
16
namespace mozilla {
17
namespace gfx {
18
19
0
#define TRUETYPE_TAG(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
20
21
#pragma pack(push, 1)
22
23
struct TTCHeader
24
{
25
  BigEndianUint32 ttcTag;    // Always 'ttcf'
26
  BigEndianUint32 version;   // Fixed, 0x00010000
27
  BigEndianUint32 numFonts;
28
};
29
30
struct OffsetTable
31
{
32
  BigEndianUint32 sfntVersion;   // Fixed, 0x00010000 for version 1.0.
33
  BigEndianUint16 numTables;
34
  BigEndianUint16 searchRange;   // (Maximum power of 2 <= numTables) x 16.
35
  BigEndianUint16 entrySelector; // Log2(maximum power of 2 <= numTables).
36
  BigEndianUint16 rangeShift;    // NumTables x 16-searchRange.
37
};
38
39
struct TableDirEntry
40
{
41
  BigEndianUint32 tag;      // 4 -byte identifier.
42
  BigEndianUint32 checkSum; // CheckSum for this table.
43
  BigEndianUint32 offset;   // Offset from beginning of TrueType font file.
44
  BigEndianUint32 length;   // Length of this table.
45
46
  friend bool operator<(const TableDirEntry& lhs, const uint32_t aTag)
47
0
  {
48
0
    return lhs.tag < aTag;
49
0
  }
50
};
51
52
#pragma pack(pop)
53
54
class SFNTData::Font
55
{
56
public:
57
  Font(const OffsetTable *aOffsetTable, const uint8_t *aFontData,
58
       uint32_t aDataLength)
59
    : mFontData(aFontData)
60
    , mFirstDirEntry(reinterpret_cast<const TableDirEntry*>(aOffsetTable + 1))
61
    , mEndOfDirEntries(mFirstDirEntry + aOffsetTable->numTables)
62
    , mDataLength(aDataLength)
63
0
  {
64
0
  }
65
66
  bool GetU16FullName(mozilla::u16string& aU16FullName)
67
0
  {
68
0
    const TableDirEntry* dirEntry =
69
0
      GetDirEntry(TRUETYPE_TAG('n', 'a', 'm', 'e'));
70
0
    if (!dirEntry) {
71
0
      gfxWarning() << "Name table entry not found.";
72
0
      return false;
73
0
    }
74
0
75
0
    UniquePtr<SFNTNameTable> nameTable =
76
0
      SFNTNameTable::Create((mFontData + dirEntry->offset), dirEntry->length);
77
0
    if (!nameTable) {
78
0
      return false;
79
0
    }
80
0
81
0
    return nameTable->GetU16FullName(aU16FullName);
82
0
  }
83
84
private:
85
86
  const TableDirEntry*
87
  GetDirEntry(const uint32_t aTag)
88
0
  {
89
0
    const TableDirEntry* foundDirEntry =
90
0
      std::lower_bound(mFirstDirEntry, mEndOfDirEntries, aTag);
91
0
92
0
    if (foundDirEntry == mEndOfDirEntries || foundDirEntry->tag != aTag) {
93
0
      gfxWarning() << "Font data does not contain tag.";
94
0
      return nullptr;
95
0
    }
96
0
97
0
    if (mDataLength < (foundDirEntry->offset + foundDirEntry->length)) {
98
0
      gfxWarning() << "Font data too short to contain table.";
99
0
      return nullptr;
100
0
    }
101
0
102
0
    return foundDirEntry;
103
0
  }
104
105
  const uint8_t *mFontData;
106
  const TableDirEntry *mFirstDirEntry;
107
  const TableDirEntry *mEndOfDirEntries;
108
  uint32_t mDataLength;
109
};
110
111
/* static */
112
UniquePtr<SFNTData>
113
SFNTData::Create(const uint8_t *aFontData, uint32_t aDataLength)
114
0
{
115
0
  MOZ_ASSERT(aFontData);
116
0
117
0
  // Check to see if this is a font collection.
118
0
  if (aDataLength < sizeof(TTCHeader)) {
119
0
    gfxWarning() << "Font data too short.";
120
0
    return nullptr;
121
0
  }
122
0
123
0
  const TTCHeader *ttcHeader = reinterpret_cast<const TTCHeader*>(aFontData);
124
0
  if (ttcHeader->ttcTag == TRUETYPE_TAG('t', 't', 'c', 'f')) {
125
0
    uint32_t numFonts = ttcHeader->numFonts;
126
0
    if (aDataLength < sizeof(TTCHeader) + (numFonts * sizeof(BigEndianUint32))) {
127
0
      gfxWarning() << "Font data too short to contain full TTC Header.";
128
0
      return nullptr;
129
0
    }
130
0
131
0
    UniquePtr<SFNTData> sfntData(new SFNTData);
132
0
    const BigEndianUint32* offset =
133
0
      reinterpret_cast<const BigEndianUint32*>(aFontData + sizeof(TTCHeader));
134
0
    const BigEndianUint32* endOfOffsets = offset + numFonts;
135
0
    while (offset != endOfOffsets) {
136
0
      if (!sfntData->AddFont(aFontData, aDataLength, *offset)) {
137
0
        return nullptr;
138
0
      }
139
0
      ++offset;
140
0
    }
141
0
142
0
    return sfntData;
143
0
  }
144
0
145
0
  UniquePtr<SFNTData> sfntData(new SFNTData);
146
0
  if (!sfntData->AddFont(aFontData, aDataLength, 0)) {
147
0
    return nullptr;
148
0
  }
149
0
150
0
  return sfntData;
151
0
}
152
153
/* static */
154
uint64_t
155
SFNTData::GetUniqueKey(const uint8_t *aFontData, uint32_t aDataLength,
156
                       uint32_t aVarDataSize, const void* aVarData)
157
0
{
158
0
  uint64_t hash;
159
0
  UniquePtr<SFNTData> sfntData = SFNTData::Create(aFontData, aDataLength);
160
0
  mozilla::u16string firstName;
161
0
  if (sfntData && sfntData->GetU16FullName(0, firstName)) {
162
0
    hash = HashString(firstName.c_str(), firstName.length());
163
0
  } else {
164
0
    gfxWarning() << "Failed to get name from font data hashing whole font.";
165
0
    hash = HashString(aFontData, aDataLength);
166
0
  }
167
0
168
0
  if (aVarDataSize) {
169
0
    hash = AddToHash(hash, HashBytes(aVarData, aVarDataSize));
170
0
  }
171
0
172
0
  return hash << 32 | aDataLength;;
173
0
}
174
175
SFNTData::~SFNTData()
176
0
{
177
0
  for (size_t i = 0; i < mFonts.length(); ++i) {
178
0
    delete mFonts[i];
179
0
  }
180
0
}
181
182
bool
183
SFNTData::GetU16FullName(uint32_t aIndex, mozilla::u16string& aU16FullName)
184
0
{
185
0
  if (aIndex >= mFonts.length()) {
186
0
    gfxWarning() << "aIndex to font data too high.";
187
0
    return false;
188
0
  }
189
0
190
0
  return mFonts[aIndex]->GetU16FullName(aU16FullName);
191
0
}
192
193
bool
194
SFNTData::GetU16FullNames(Vector<mozilla::u16string>& aU16FullNames)
195
0
{
196
0
  bool fontFound = false;
197
0
  for (size_t i = 0; i < mFonts.length(); ++i) {
198
0
    mozilla::u16string name;
199
0
    if (mFonts[i]->GetU16FullName(name)) {
200
0
      fontFound = true;
201
0
    }
202
0
    if (!aU16FullNames.append(std::move(name))) {
203
0
      return false;
204
0
    }
205
0
  }
206
0
207
0
  return fontFound;
208
0
}
209
210
bool
211
SFNTData::GetIndexForU16Name(const mozilla::u16string& aU16FullName,
212
                             uint32_t* aIndex, size_t aTruncatedLen)
213
0
{
214
0
  for (size_t i = 0; i < mFonts.length(); ++i) {
215
0
    mozilla::u16string name;
216
0
    if (!mFonts[i]->GetU16FullName(name)) {
217
0
      continue;
218
0
    }
219
0
220
0
    if (aTruncatedLen) {
221
0
      MOZ_ASSERT(aU16FullName.length() <= aTruncatedLen);
222
0
      name = name.substr(0, aTruncatedLen);
223
0
    }
224
0
225
0
    if (name == aU16FullName) {
226
0
      *aIndex = i;
227
0
      return true;
228
0
    }
229
0
  }
230
0
231
0
  return false;
232
0
}
233
234
bool
235
SFNTData::AddFont(const uint8_t *aFontData, uint32_t aDataLength,
236
                  uint32_t aOffset)
237
0
{
238
0
  uint32_t remainingLength = aDataLength - aOffset;
239
0
  if (remainingLength < sizeof(OffsetTable)) {
240
0
    gfxWarning() << "Font data too short to contain OffsetTable " << aOffset;
241
0
    return false;
242
0
  }
243
0
244
0
  const OffsetTable *offsetTable =
245
0
    reinterpret_cast<const OffsetTable*>(aFontData + aOffset);
246
0
  if (remainingLength <
247
0
      sizeof(OffsetTable) + (offsetTable->numTables * sizeof(TableDirEntry))) {
248
0
    gfxWarning() << "Font data too short to contain tables.";
249
0
    return false;
250
0
  }
251
0
252
0
  return mFonts.append(new Font(offsetTable, aFontData, aDataLength));
253
0
}
254
255
} // gfx
256
} // mozilla