Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
distancefieldmodelworker.cpp
Go to the documentation of this file.
1
// Copyright (C) 2018 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4
#
include
"distancefieldmodelworker.h"
5
6
#
include
"distancefieldmodel.h"
7
#
include
<
qendian
.
h
>
8
#
include
<
QtGui
/
private
/
qdistancefield_p
.
h
>
9
10
QT_BEGIN_NAMESPACE
11
12
#
pragma
pack
(
1
)
13
struct
MaxpHeader
14
{
15
quint32 version;
16
quint16 numGlyphs;
17
};
18
19
struct
CmapHeader
{
20
quint16
version
;
21
quint16
numTables
;
22
};
23
24
struct
CmapEncodingRecord
{
25
quint16
platformId
;
26
quint16
encodingId
;
27
quint32
offset
;
28
};
29
30
struct
CmapSubtable
31
{
32
quint16
format
;
33
quint16
length
;
34
quint16
language
;
35
};
36
37
struct
CmapSubtable0
:
public
CmapSubtable
38
{
39
quint8
glyphIdArray
[256];
40
};
41
42
struct
CmapSubtable4
:
public
CmapSubtable
43
{
44
quint16
segCountX2
;
45
quint16
searchRange
;
46
quint16
entrySelector
;
47
quint16
rangeShift
;
48
};
49
50
struct
CmapSubtable6
:
public
CmapSubtable
51
{
52
quint16
firstCode
;
53
quint16
entryCount
;
54
};
55
56
struct
CmapSubtable10
57
{
58
quint32
format
;
59
quint32
length
;
60
quint32
language
;
61
quint32
startCharCode
;
62
quint32
numChars
;
63
};
64
65
struct
CmapSubtable12
66
{
67
quint16
format
;
68
quint16
reserved
;
69
quint32
length
;
70
quint32
language
;
71
quint32
numGroups
;
72
};
73
74
struct
SequentialMapGroup
75
{
76
quint32
startCharCode
;
77
quint32
endCharCode
;
78
quint32
glyphIndex
;
79
};
80
81
#
pragma
pack
(
)
82
83
DistanceFieldModelWorker
::DistanceFieldModelWorker(QObject *parent)
84
: QObject(parent)
85
, m_glyphCount(0)
86
, m_nextGlyphId(0)
87
, m_doubleGlyphResolution(
false
)
88
{
89
}
90
91
template
<
typename
T>
92
static
void
readCmapSubtable
(
DistanceFieldModelWorker
*worker,
const
QByteArray &cmap, quint32 tableOffset, quint16 format)
93
{
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));
96
return
;
97
}
98
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()));
104
return
;
105
}
106
107
const
void
*end = cmap.constData() + tableOffset + length;
108
worker->readCmapSubtable(subtable, end);
109
}
110
111
void
DistanceFieldModelWorker
::
readCmapSubtable
(
const
CmapSubtable0
*subtable,
const
void
*end)
112
{
113
Q_UNUSED(end);
// Already checked for length
114
for
(
int
i = 0; i < 256; ++i)
115
m_cmapping[glyph_t(subtable->glyphIdArray[i])] = i;
116
}
117
118
void
DistanceFieldModelWorker
::
readCmapSubtable
(
const
CmapSubtable4
*subtable,
const
void
*end)
119
{
120
quint16 segCount = qFromBigEndian(subtable->segCountX2) / 2;
121
const
quint16 *endCodes =
reinterpret_cast
<
const
quint16 *>(subtable + 1);
122
const
quint16 *startCodes = endCodes + segCount + 1;
// endCodes[segCount] + reservedPad
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'"
));
128
return
;
129
}
130
131
for
(
int
i = 0; i < segCount - 1; ++i) {
// Last entry in arrays is the sentinel
132
quint16 startCode = qFromBigEndian(startCodes[i]);
133
quint16 endCode = qFromBigEndian(endCodes[i]);
134
quint16 rangeOffset = qFromBigEndian(idRangeOffsets[i]);
135
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));
141
return
;
142
}
143
144
m_cmapping[glyph_t(qFromBigEndian(*glyphIndex))] = quint32(c);
145
}
else
{
146
quint16 idDelta = qFromBigEndian(idDeltas[i]);
147
m_cmapping[glyph_t((idDelta + c) % 65536)] = quint32(c);
148
}
149
}
150
151
}
152
}
153
154
void
DistanceFieldModelWorker
::
readCmapSubtable
(
const
CmapSubtable6
*subtable,
const
void
*end)
155
{
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'"
));
160
return
;
161
}
162
163
quint16 firstCode = qFromBigEndian(subtable->firstCode);
164
for
(quint16 i = 0; i < entryCount; ++i)
165
m_cmapping[glyph_t(qFromBigEndian(glyphIndexes[i]))] = firstCode + i;
166
}
167
168
void
DistanceFieldModelWorker
::
readCmapSubtable
(
const
CmapSubtable10
*subtable,
const
void
*end)
169
{
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'"
));
174
return
;
175
}
176
177
quint32 startCharCode = qFromBigEndian(subtable->startCharCode);
178
for
(quint32 i = 0; i < numChars; ++i)
179
m_cmapping[glyph_t(qFromBigEndian(glyphs[i]))] = startCharCode + i;
180
}
181
182
void
DistanceFieldModelWorker
::
readCmapSubtable
(
const
CmapSubtable12
*subtable,
const
void
*end)
183
{
184
quint32 numGroups = qFromBigEndian(subtable->numGroups);
185
const
SequentialMapGroup
*sequentialMapGroups =
reinterpret_cast
<
const
SequentialMapGroup
*>(subtable + 1);
186
if
(sequentialMapGroups + numGroups > end) {
187
emit error(tr(
"End of cmap reached while parsing subtable of format '12'"
));
188
return
;
189
}
190
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);
195
196
for
(quint32 j = 0; j < endCharCode - startCharCode + 1; ++j)
197
m_cmapping[glyph_t(startGlyphIndex + j)] = startCharCode + j;
198
}
199
}
200
201
void
DistanceFieldModelWorker
::readCmap()
202
{
203
if
(m_font.isValid()) {
204
QByteArray cmap = m_font.fontTable(
"cmap"
);
205
if
(uint(cmap.size()) <
sizeof
(
CmapHeader
)) {
206
emit error(tr(
"Invalid cmap table. No header."
));
207
return
;
208
}
209
210
const
CmapHeader
*header =
reinterpret_cast
<
const
CmapHeader
*>(cmap.constData());
211
quint16 numTables = qFromBigEndian(header->numTables);
212
213
if
(uint(cmap.size()) <
sizeof
(
CmapHeader
) + numTables *
sizeof
(
CmapEncodingRecord
)) {
214
emit error(tr(
"Invalid cmap table. No space for %1 encoding records."
).arg(numTables));
215
return
;
216
}
217
218
// Support the same encodings as macOS (and same order of prefernece), since this should
219
// cover most fonts
220
static
quint32 encodingPreferenceOrder[] =
221
{
222
quint32(0) << 16 | 4,
// Unicode 2.0 +
223
quint32(0) << 16 | 3,
// Unicode 2.0 BMP
224
quint32(0) << 16 | 1,
// Unicode 1.1
225
quint32(3) << 16 | 10,
// Windows, UCS-4
226
quint32(3) << 16 | 1,
// Windows, UCS-2
227
quint32(0)
228
};
229
230
QHash<quint32,
const
CmapEncodingRecord *> encodingRecords;
231
{
232
const
CmapEncodingRecord
*encodingRecord =
reinterpret_cast
<
const
CmapEncodingRecord
*>(cmap.constData() +
sizeof
(
CmapHeader
));
233
while
(numTables-- > 0) {
234
quint32 encoding = quint32(qFromBigEndian(encodingRecord->platformId)) << 16 | qFromBigEndian(encodingRecord->encodingId);
235
encodingRecords[encoding] = encodingRecord++;
236
}
237
}
238
239
// Find the first subtable we support in order of preference
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));
246
return
;
247
}
248
249
quint16 format = qFromBigEndian(*
reinterpret_cast
<
const
quint16 *>(cmap.constData() + offset));
250
switch
(format) {
251
case
0:
252
::readCmapSubtable<
CmapSubtable0
>(
this
, cmap, offset, format);
253
return
;
254
case
4:
255
::readCmapSubtable<
CmapSubtable4
>(
this
, cmap, offset, format);
256
return
;
257
case
6:
258
::readCmapSubtable<
CmapSubtable6
>(
this
, cmap, offset, format);
259
return
;
260
case
10:
261
::readCmapSubtable<
CmapSubtable10
>(
this
, cmap, offset, format);
262
return
;
263
case
12:
264
::readCmapSubtable<
CmapSubtable12
>(
this
, cmap, offset, format);
265
return
;
266
default
:
267
qWarning() << tr(
"Unsupported cmap subtable format '%1'"
).arg(format);
268
};
269
}
270
}
271
272
emit error(tr(
"No suitable cmap subtable found"
));
273
}
274
}
275
276
void
DistanceFieldModelWorker
::readGlyphCount()
277
{
278
m_nextGlyphId = 0;
279
m_glyphCount = 0;
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);
285
}
286
}
287
288
m_doubleGlyphResolution = qt_fontHasNarrowOutlines(m_font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT();
289
}
290
291
void
DistanceFieldModelWorker
::
loadFont
(
const
QString &fileName)
292
{
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));
296
297
readGlyphCount();
298
readCmap();
299
300
qreal pixelSize = QT_DISTANCEFIELD_BASEFONTSIZE(m_doubleGlyphResolution) * QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution);
301
m_font.setPixelSize(pixelSize);
302
303
emit fontLoaded(m_glyphCount,
304
m_doubleGlyphResolution,
305
pixelSize);
306
}
307
308
void
DistanceFieldModelWorker
::
generateOneDistanceField
()
309
{
310
Q_ASSERT(m_nextGlyphId <= m_glyphCount);
311
312
if
(m_nextGlyphId == m_glyphCount) {
313
emit fontGenerated();
314
return
;
315
}
316
317
QPainterPath path = m_font.pathForGlyph(m_nextGlyphId);
318
QDistanceField distanceField(path, m_nextGlyphId, m_doubleGlyphResolution);
319
emit distanceFieldGenerated(distanceField.toImage(QImage::Format_Alpha8),
320
path,
321
m_nextGlyphId,
322
m_cmapping.value(m_nextGlyphId));
323
324
m_nextGlyphId++;
325
}
326
327
QT_END_NAMESPACE
DistanceFieldModelWorker
Definition
distancefieldmodelworker.h:19
DistanceFieldModelWorker::readCmapSubtable
void readCmapSubtable(const CmapSubtable4 *subtable, const void *end)
Definition
distancefieldmodelworker.cpp:118
DistanceFieldModelWorker::readCmapSubtable
void readCmapSubtable(const CmapSubtable6 *subtable, const void *end)
Definition
distancefieldmodelworker.cpp:154
DistanceFieldModelWorker::readCmapSubtable
void readCmapSubtable(const CmapSubtable10 *subtable, const void *end)
Definition
distancefieldmodelworker.cpp:168
DistanceFieldModelWorker::generateOneDistanceField
Q_INVOKABLE void generateOneDistanceField()
Definition
distancefieldmodelworker.cpp:308
DistanceFieldModelWorker::readCmapSubtable
void readCmapSubtable(const CmapSubtable12 *subtable, const void *end)
Definition
distancefieldmodelworker.cpp:182
DistanceFieldModelWorker::readCmapSubtable
void readCmapSubtable(const CmapSubtable0 *subtable, const void *end)
Definition
distancefieldmodelworker.cpp:111
DistanceFieldModelWorker::loadFont
Q_INVOKABLE void loadFont(const QString &fileName)
Definition
distancefieldmodelworker.cpp:291
readCmapSubtable
static void readCmapSubtable(DistanceFieldModelWorker *worker, const QByteArray &cmap, quint32 tableOffset, quint16 format)
Definition
distancefieldmodelworker.cpp:92
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
CmapEncodingRecord
Definition
distancefieldmodelworker.cpp:24
CmapEncodingRecord::encodingId
quint16 encodingId
Definition
distancefieldmodelworker.cpp:26
CmapEncodingRecord::platformId
quint16 platformId
Definition
distancefieldmodelworker.cpp:25
CmapEncodingRecord::offset
quint32 offset
Definition
distancefieldmodelworker.cpp:27
CmapHeader
Definition
distancefieldmodelworker.cpp:19
CmapHeader::version
quint16 version
Definition
distancefieldmodelworker.cpp:20
CmapHeader::numTables
quint16 numTables
Definition
distancefieldmodelworker.cpp:21
CmapSubtable0
Definition
distancefieldmodelworker.cpp:38
CmapSubtable0::glyphIdArray
quint8 glyphIdArray[256]
Definition
distancefieldmodelworker.cpp:39
CmapSubtable10
Definition
distancefieldmodelworker.cpp:57
CmapSubtable10::language
quint32 language
Definition
distancefieldmodelworker.cpp:60
CmapSubtable10::format
quint32 format
Definition
distancefieldmodelworker.cpp:58
CmapSubtable10::numChars
quint32 numChars
Definition
distancefieldmodelworker.cpp:62
CmapSubtable10::startCharCode
quint32 startCharCode
Definition
distancefieldmodelworker.cpp:61
CmapSubtable10::length
quint32 length
Definition
distancefieldmodelworker.cpp:59
CmapSubtable12
Definition
distancefieldmodelworker.cpp:66
CmapSubtable12::length
quint32 length
Definition
distancefieldmodelworker.cpp:69
CmapSubtable12::reserved
quint16 reserved
Definition
distancefieldmodelworker.cpp:68
CmapSubtable12::language
quint32 language
Definition
distancefieldmodelworker.cpp:70
CmapSubtable12::format
quint16 format
Definition
distancefieldmodelworker.cpp:67
CmapSubtable12::numGroups
quint32 numGroups
Definition
distancefieldmodelworker.cpp:71
CmapSubtable4
Definition
distancefieldmodelworker.cpp:43
CmapSubtable4::searchRange
quint16 searchRange
Definition
distancefieldmodelworker.cpp:45
CmapSubtable4::rangeShift
quint16 rangeShift
Definition
distancefieldmodelworker.cpp:47
CmapSubtable4::segCountX2
quint16 segCountX2
Definition
distancefieldmodelworker.cpp:44
CmapSubtable4::entrySelector
quint16 entrySelector
Definition
distancefieldmodelworker.cpp:46
CmapSubtable6
Definition
distancefieldmodelworker.cpp:51
CmapSubtable6::entryCount
quint16 entryCount
Definition
distancefieldmodelworker.cpp:53
CmapSubtable6::firstCode
quint16 firstCode
Definition
distancefieldmodelworker.cpp:52
CmapSubtable
Definition
distancefieldmodelworker.cpp:31
CmapSubtable::language
quint16 language
Definition
distancefieldmodelworker.cpp:34
CmapSubtable::length
quint16 length
Definition
distancefieldmodelworker.cpp:33
CmapSubtable::format
quint16 format
Definition
distancefieldmodelworker.cpp:32
SequentialMapGroup
Definition
distancefieldmodelworker.cpp:75
SequentialMapGroup::startCharCode
quint32 startCharCode
Definition
distancefieldmodelworker.cpp:76
SequentialMapGroup::endCharCode
quint32 endCharCode
Definition
distancefieldmodelworker.cpp:77
SequentialMapGroup::glyphIndex
quint32 glyphIndex
Definition
distancefieldmodelworker.cpp:78
qttools
src
distancefieldgenerator
distancefieldmodelworker.cpp
Generated on
for Qt by
1.18.0