8#include <QtGui/private/qdistancefield_p.h>
87 , m_doubleGlyphResolution(
false)
94 if (uint(cmap.size()) < tableOffset +
sizeof(T)) {
95 emit worker->error(QObject::tr(
"End of file when reading subtable of format '%1'").arg(format));
99 const T *subtable =
reinterpret_cast<
const T *>(cmap.constData() + tableOffset);
100 quint16 length = qFromBigEndian(subtable->length);
101 if (uint(cmap.size()) < tableOffset + length) {
102 emit worker->error(QObject::tr(
"Corrupt data found when reading subtable of format '%1'. Table offset: %2. Length: %3. Cmap length: %4.")
103 .arg(format).arg(tableOffset).arg(length).arg(cmap.size()));
107 const void *end = cmap.constData() + tableOffset + length;
108 worker->readCmapSubtable(subtable, end);
114 for (
int i = 0; i < 256; ++i)
115 m_cmapping[glyph_t(subtable->glyphIdArray[i])] = i;
120 quint16 segCount = qFromBigEndian(subtable->segCountX2) / 2;
121 const quint16 *endCodes =
reinterpret_cast<
const quint16 *>(subtable + 1);
122 const quint16 *startCodes = endCodes + segCount + 1;
123 const qint16 *idDeltas =
reinterpret_cast<
const qint16 *>(startCodes + segCount);
124 const quint16 *idRangeOffsets =
reinterpret_cast<
const quint16 *>(idDeltas + segCount);
125 const quint16 *glyphIdArray = idRangeOffsets + segCount;
126 if (glyphIdArray > end) {
127 emit error(tr(
"End of cmap table reached when parsing subtable format '4'"));
131 for (
int i = 0; i < segCount - 1; ++i) {
132 quint16 startCode = qFromBigEndian(startCodes[i]);
133 quint16 endCode = qFromBigEndian(endCodes[i]);
134 quint16 rangeOffset = qFromBigEndian(idRangeOffsets[i]);
136 for (quint16 c = startCode; c <= endCode; ++c) {
137 if (rangeOffset != 0) {
138 const quint16 *glyphIndex = (idRangeOffsets + i) + (c - startCode) + rangeOffset / 2;
139 if (glyphIndex + 1 > end) {
140 emit error(tr(
"End of cmap, subtable format '4', reached when fetching character '%1' in range [%2, %3]").arg(c).arg(startCode).arg(endCode));
144 m_cmapping[glyph_t(qFromBigEndian(*glyphIndex))] = quint32(c);
146 quint16 idDelta = qFromBigEndian(idDeltas[i]);
147 m_cmapping[glyph_t((idDelta + c) % 65536)] = quint32(c);
156 quint16 entryCount = qFromBigEndian(subtable->entryCount);
157 const quint16 *glyphIndexes =
reinterpret_cast<
const quint16 *>(subtable + 1);
158 if (glyphIndexes + entryCount > end) {
159 emit error(tr(
"End of cmap reached while parsing subtable format '6'"));
163 quint16 firstCode = qFromBigEndian(subtable->firstCode);
164 for (quint16 i = 0; i < entryCount; ++i)
165 m_cmapping[glyph_t(qFromBigEndian(glyphIndexes[i]))] = firstCode + i;
170 quint32 numChars = qFromBigEndian(subtable->numChars);
171 const quint16 *glyphs =
reinterpret_cast<
const quint16 *>(subtable + 1);
172 if (glyphs + numChars > end) {
173 emit error(tr(
"End of cmap reached while parsing subtable of format '10'"));
177 quint32 startCharCode = qFromBigEndian(subtable->startCharCode);
178 for (quint32 i = 0; i < numChars; ++i)
179 m_cmapping[glyph_t(qFromBigEndian(glyphs[i]))] = startCharCode + i;
184 quint32 numGroups = qFromBigEndian(subtable->numGroups);
186 if (sequentialMapGroups + numGroups > end) {
187 emit error(tr(
"End of cmap reached while parsing subtable of format '12'"));
191 for (quint32 i = 0; i < numGroups; ++i) {
192 quint32 startCharCode = qFromBigEndian(sequentialMapGroups[i].startCharCode);
193 quint32 endCharCode = qFromBigEndian(sequentialMapGroups[i].endCharCode);
194 quint32 startGlyphIndex = qFromBigEndian(sequentialMapGroups[i].glyphIndex);
196 for (quint32 j = 0; j < endCharCode - startCharCode + 1; ++j)
197 m_cmapping[glyph_t(startGlyphIndex + j)] = startCharCode + j;
203 if (m_font.isValid()) {
204 QByteArray cmap = m_font.fontTable(
"cmap");
206 emit error(tr(
"Invalid cmap table. No header."));
211 quint16 numTables = qFromBigEndian(header->numTables);
214 emit error(tr(
"Invalid cmap table. No space for %1 encoding records.").arg(numTables));
220 static quint32 encodingPreferenceOrder[] =
222 quint32(0) << 16 | 4,
223 quint32(0) << 16 | 3,
224 quint32(0) << 16 | 1,
225 quint32(3) << 16 | 10,
226 quint32(3) << 16 | 1,
230 QHash<quint32,
const CmapEncodingRecord *> encodingRecords;
233 while (numTables-- > 0) {
234 quint32 encoding = quint32(qFromBigEndian(encodingRecord->platformId)) << 16 | qFromBigEndian(encodingRecord->encodingId);
235 encodingRecords[encoding] = encodingRecord++;
240 for (
int i = 0; encodingPreferenceOrder[i] != 0; ++i) {
241 const CmapEncodingRecord *encodingRecord = encodingRecords.value(encodingPreferenceOrder[i],
nullptr);
242 if (encodingRecord !=
nullptr) {
243 quint32 offset = qFromBigEndian(encodingRecord->offset);
244 if (uint(cmap.size()) < offset +
sizeof(quint16)) {
245 emit error(tr(
"Invalid offset '%1' in cmap").arg(offset));
249 quint16 format = qFromBigEndian(*
reinterpret_cast<
const quint16 *>(cmap.constData() + offset));
252 ::readCmapSubtable<
CmapSubtable0>(
this, cmap, offset, format);
255 ::readCmapSubtable<
CmapSubtable4>(
this, cmap, offset, format);
258 ::readCmapSubtable<
CmapSubtable6>(
this, cmap, offset, format);
267 qWarning() << tr(
"Unsupported cmap subtable format '%1'").arg(format);
272 emit error(tr(
"No suitable cmap subtable found"));
280 if (m_font.isValid()) {
281 QByteArray maxp = m_font.fontTable(
"maxp");
282 if (uint(maxp.size()) >=
sizeof(MaxpHeader)) {
283 const MaxpHeader *header =
reinterpret_cast<
const MaxpHeader *>(maxp.constData());
284 m_glyphCount = qFromBigEndian(header->numGlyphs);
288 m_doubleGlyphResolution = qt_fontHasNarrowOutlines(m_font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT();
293 m_font = QRawFont(fileName, 64);
294 if (!m_font.isValid())
295 emit error(tr(
"File '%1' is not a valid font file.").arg(fileName));
300 qreal pixelSize = QT_DISTANCEFIELD_BASEFONTSIZE(m_doubleGlyphResolution) * QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution);
301 m_font.setPixelSize(pixelSize);
303 emit fontLoaded(m_glyphCount,
304 m_doubleGlyphResolution,
310 Q_ASSERT(m_nextGlyphId <= m_glyphCount);
312 if (m_nextGlyphId == m_glyphCount) {
313 emit fontGenerated();
317 QPainterPath path = m_font.pathForGlyph(m_nextGlyphId);
318 QDistanceField distanceField(path, m_nextGlyphId, m_doubleGlyphResolution);
319 emit distanceFieldGenerated(distanceField.toImage(QImage::Format_Alpha8),
322 m_cmapping.value(m_nextGlyphId));
void readCmapSubtable(const CmapSubtable4 *subtable, const void *end)
void readCmapSubtable(const CmapSubtable6 *subtable, const void *end)
void readCmapSubtable(const CmapSubtable10 *subtable, const void *end)
Q_INVOKABLE void generateOneDistanceField()
void readCmapSubtable(const CmapSubtable12 *subtable, const void *end)
void readCmapSubtable(const CmapSubtable0 *subtable, const void *end)
Q_INVOKABLE void loadFont(const QString &fileName)
static void readCmapSubtable(DistanceFieldModelWorker *worker, const QByteArray &cmap, quint32 tableOffset, quint16 format)
Combined button and popup list for selecting options.