Commits:
-
db889181
by Charlie Jiang
at 2022-09-13T07:10:33+08:00
[ftinspect] Add transformation and scaling info to the composite glyph view.
Note: Untested since no font with non-1.0 scale subglyphs is found.
* src/ftinspect/engine/fontinfo.cpp, src/ftinspect/engine/fontinfo.hpp:
Fetch transformation and scaling info from the font.
* src/ftinspect/models/fontinfomodels.cpp,
src/ftinspect/models/fontinfomodels.hpp:
Change the "Position" column to "Position and Transformation".
Display the transformation info.
-
c3004701
by Charlie Jiang
at 2022-09-13T07:10:40+08:00
[ftinspect] Fix memory-related crash, and refactor outline-retaining...
graphics items. Also fix some compiler warnings.
* src/ftinspect/glyphcomponents/glyphoutline.cpp,
src/ftinspect/glyphcomponents/glyphoutline.hpp:
Don't retain the `FT_Outline*` whose lifetime is bound to the glyph.
Prepare the path in the ctor so the outline isn't saved.
Add `GlyphUsingOutline` as the base class for all classes that have to
retain a `FT_Outline` object.
* src/ftinspect/glyphcomponents/glyphpointnumbers.cpp,
src/ftinspect/glyphcomponents/glyphpointnumbers.hpp,
src/ftinspect/glyphcomponents/glyphpoints.cpp,
src/ftinspect/glyphcomponents/glyphpoints.hpp: Refactored.
* src/ftinspect/engine/engine.hpp, src/ftinspect/panels/singular.hpp,
src/ftinspect/engine/rendering.hpp
Add default values to initialize member fields.
* src/ftinspect/panels/singular.cpp:
Pass the `FT_Library` into the graphics items.
* src/ftinspect/models/fontinfomodels.cpp: Fix warning.
-
5ec65b9b
by Charlie Jiang
at 2022-09-13T07:10:40+08:00
[ftinspect] Activate the color layers by default.
Don't deactivate it when color layers are absent. Also fix typo.
* src/ftinspect/panels/settingpanel.cpp: Updated.
15 changed files:
Changes:
src/ftinspect/engine/engine.hpp
... |
... |
@@ -228,7 +228,7 @@ private: |
228
|
228
|
|
229
|
229
|
// font info
|
230
|
230
|
int curFontIndex_ = -1;
|
231
|
|
- int fontType_;
|
|
231
|
+ int fontType_ = FontType_Other;
|
232
|
232
|
QString curFamilyName_;
|
233
|
233
|
QString curStyleName_;
|
234
|
234
|
int curNumGlyphs_ = -1;
|
... |
... |
@@ -242,11 +242,11 @@ private: |
242
|
242
|
std::vector<SFNTName> curSFNTNames_;
|
243
|
243
|
|
244
|
244
|
// basic objects
|
245
|
|
- FT_Library library_;
|
246
|
|
- FTC_Manager cacheManager_;
|
247
|
|
- FTC_ImageCache imageCache_;
|
248
|
|
- FTC_SBitCache sbitsCache_;
|
249
|
|
- FTC_CMapCache cmapCache_;
|
|
245
|
+ FT_Library library_ = NULL;
|
|
246
|
+ FTC_Manager cacheManager_ = NULL;
|
|
247
|
+ FTC_ImageCache imageCache_ = NULL;
|
|
248
|
+ FTC_SBitCache sbitsCache_ = NULL;
|
|
249
|
+ FTC_CMapCache cmapCache_ = NULL;
|
250
|
250
|
EngineDefaultValues engineDefaults_;
|
251
|
251
|
|
252
|
252
|
// settings
|
... |
... |
@@ -255,31 +255,31 @@ private: |
255
|
255
|
// Sometimes the font may be valid (i.e. a face object can be retrieved), but
|
256
|
256
|
// the size may be invalid (e.g. non-scalable fonts).
|
257
|
257
|
// Therefore, we use a fallback face for all non-rendering work.
|
258
|
|
- FT_Face ftFallbackFace_; // Never perform rendering or write to this!
|
259
|
|
- FT_Size ftSize_;
|
|
258
|
+ FT_Face ftFallbackFace_ = NULL; // Never perform rendering or write to this!
|
|
259
|
+ FT_Size ftSize_ = NULL;
|
260
|
260
|
FT_Palette_Data paletteData_ = {};
|
261
|
261
|
FT_Color* palette_ = NULL;
|
262
|
262
|
|
263
|
263
|
bool antiAliasingEnabled_ = true;
|
264
|
264
|
bool usingPixelSize_ = false;
|
265
|
|
- double pointSize_;
|
266
|
|
- double pixelSize_;
|
267
|
|
- unsigned int dpi_;
|
268
|
|
-
|
269
|
|
- bool doHinting_;
|
270
|
|
- bool doAutoHinting_;
|
271
|
|
- bool doHorizontalHinting_;
|
272
|
|
- bool doVerticalHinting_;
|
273
|
|
- bool doBlueZoneHinting_;
|
274
|
|
- bool showSegments_;
|
275
|
|
- bool embeddedBitmap_;
|
276
|
|
- bool useColorLayer_;
|
|
265
|
+ double pointSize_ = 20;
|
|
266
|
+ double pixelSize_ = 20;
|
|
267
|
+ unsigned int dpi_ = 98;
|
|
268
|
+
|
|
269
|
+ bool doHinting_ = false;
|
|
270
|
+ bool doAutoHinting_ = false;
|
|
271
|
+ bool doHorizontalHinting_ = false;
|
|
272
|
+ bool doVerticalHinting_ = false;
|
|
273
|
+ bool doBlueZoneHinting_ = false;
|
|
274
|
+ bool showSegments_ = false;
|
|
275
|
+ bool embeddedBitmap_ = false;
|
|
276
|
+ bool useColorLayer_ = false;
|
277
|
277
|
int paletteIndex_ = -1;
|
278
|
|
- int antiAliasingTarget_;
|
279
|
|
- bool lcdSubPixelPositioning_;
|
280
|
|
- int renderMode_;
|
|
278
|
+ int antiAliasingTarget_ = 0;
|
|
279
|
+ bool lcdSubPixelPositioning_ = false;
|
|
280
|
+ int renderMode_ = 0;
|
281
|
281
|
|
282
|
|
- unsigned long loadFlags_;
|
|
282
|
+ unsigned long loadFlags_ = FT_LOAD_DEFAULT;
|
283
|
283
|
|
284
|
284
|
std::unique_ptr<RenderingEngine> renderingEngine_;
|
285
|
285
|
|
src/ftinspect/engine/fontinfo.cpp
... |
... |
@@ -571,6 +571,21 @@ SFNTTableInfo::getForAll(Engine* engine, |
571
|
571
|
}
|
572
|
572
|
|
573
|
573
|
|
|
574
|
+
|
|
575
|
+FT_UInt16
|
|
576
|
+readUInt16(void* ptr)
|
|
577
|
+{
|
|
578
|
+ return bigEndianToNative(*static_cast<uint16_t*>(ptr));
|
|
579
|
+}
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+double
|
|
583
|
+readF2Dot14(void* ptr)
|
|
584
|
+{
|
|
585
|
+ return static_cast<int16_t>(readUInt16(ptr)) / 16384.0;
|
|
586
|
+}
|
|
587
|
+
|
|
588
|
+
|
574
|
589
|
void
|
575
|
590
|
CompositeGlyphInfo::get(Engine* engine,
|
576
|
591
|
std::vector<CompositeGlyphInfo>& list)
|
... |
... |
@@ -641,7 +656,7 @@ CompositeGlyphInfo::get(Engine* engine, |
641
|
656
|
if (loc + 16 > end)
|
642
|
657
|
continue;
|
643
|
658
|
|
644
|
|
- auto len = static_cast<FT_Int16>(buffer[loc] << 8 | buffer[loc + 1]);
|
|
659
|
+ auto len = static_cast<FT_Int16>(readUInt16(buffer + loc));
|
645
|
660
|
loc += 10; // skip header
|
646
|
661
|
if (len >= 0) // not a composite one
|
647
|
662
|
continue;
|
... |
... |
@@ -652,18 +667,18 @@ CompositeGlyphInfo::get(Engine* engine, |
652
|
667
|
{
|
653
|
668
|
if (loc + 6 > end)
|
654
|
669
|
break;
|
655
|
|
- auto flags = static_cast<FT_UInt16>(buffer[loc] << 8 | buffer[loc + 1]);
|
|
670
|
+ auto flags = readUInt16(buffer + loc);
|
656
|
671
|
loc += 2;
|
657
|
|
- auto index = static_cast<FT_UInt16>(buffer[loc] << 8 | buffer[loc + 1]);
|
|
672
|
+ auto index = readUInt16(buffer + loc);
|
658
|
673
|
loc += 2;
|
659
|
674
|
FT_Int16 arg1, arg2;
|
660
|
675
|
|
661
|
676
|
// https://docs.microsoft.com/en-us/typography/opentype/spec/glyf#composite-glyph-description
|
662
|
677
|
if (flags & 0x0001)
|
663
|
678
|
{
|
664
|
|
- arg1 = static_cast<FT_Int16>(buffer[loc] << 8 | buffer[loc + 1]);
|
|
679
|
+ arg1 = static_cast<FT_Int16>(readUInt16(buffer + loc));
|
665
|
680
|
loc += 2;
|
666
|
|
- arg2 = static_cast<FT_Int16>(buffer[loc] << 8 | buffer[loc + 1]);
|
|
681
|
+ arg2 = static_cast<FT_Int16>(readUInt16(buffer + loc));
|
667
|
682
|
loc += 2;
|
668
|
683
|
}
|
669
|
684
|
else
|
... |
... |
@@ -672,17 +687,43 @@ CompositeGlyphInfo::get(Engine* engine, |
672
|
687
|
arg2 = buffer[loc + 1];
|
673
|
688
|
loc += 2;
|
674
|
689
|
}
|
|
690
|
+
|
|
691
|
+ subglyphs.emplace_back(index, flags,
|
|
692
|
+ flags & 0x0002 ? SubGlyph::PT_Offset
|
|
693
|
+ : SubGlyph::PT_Align,
|
|
694
|
+ std::pair<short, short>(arg1, arg2),
|
|
695
|
+ (flags & 0x0800) != 0);
|
|
696
|
+ // TODO: Use "Default behavior" when neither SCALED_COMPONENT_OFFSET
|
|
697
|
+ // and UNSCALED_COMPONENT_OFFSET are set.
|
|
698
|
+
|
|
699
|
+ auto& glyph = subglyphs.back();
|
675
|
700
|
if (flags & 0x0008)
|
|
701
|
+ {
|
|
702
|
+ glyph.transformationType = SubGlyph::TT_UniformScale;
|
|
703
|
+ glyph.transformation[0] = readF2Dot14(buffer + loc);
|
676
|
704
|
loc += 2;
|
|
705
|
+ }
|
677
|
706
|
else if (flags & 0x0040)
|
|
707
|
+ {
|
|
708
|
+ glyph.transformationType = SubGlyph::TT_XYScale;
|
|
709
|
+ glyph.transformation[0] = readF2Dot14(buffer + loc);
|
|
710
|
+ glyph.transformation[1] = readF2Dot14(buffer + loc + 2);
|
678
|
711
|
loc += 4;
|
|
712
|
+ }
|
679
|
713
|
else if (flags & 0x0080)
|
|
714
|
+ {
|
|
715
|
+ glyph.transformationType = SubGlyph::TT_Matrix;
|
|
716
|
+ glyph.transformation[0] = readF2Dot14(buffer + loc);
|
|
717
|
+ glyph.transformation[1] = readF2Dot14(buffer + loc + 2);
|
|
718
|
+ glyph.transformation[2] = readF2Dot14(buffer + loc + 4);
|
|
719
|
+ glyph.transformation[3] = readF2Dot14(buffer + loc + 6);
|
680
|
720
|
loc += 8;
|
681
|
|
-
|
682
|
|
- subglyphs.emplace_back(index, flags,
|
683
|
|
- flags & 0x0002 ? SubGlyph::PT_Offset
|
684
|
|
- : SubGlyph::PT_Align,
|
685
|
|
- std::pair<short, short>(arg1, arg2));
|
|
721
|
+ }
|
|
722
|
+ else
|
|
723
|
+ {
|
|
724
|
+ glyph.transformationType = SubGlyph::TT_UniformScale;
|
|
725
|
+ glyph.transformation[0] = 1.0;
|
|
726
|
+ }
|
686
|
727
|
|
687
|
728
|
if (!(flags & 0x0020))
|
688
|
729
|
break;
|
src/ftinspect/engine/fontinfo.hpp
... |
... |
@@ -5,6 +5,7 @@ |
5
|
5
|
#pragma once
|
6
|
6
|
|
7
|
7
|
#include <set>
|
|
8
|
+#include <cstring>
|
8
|
9
|
#include <QDateTime>
|
9
|
10
|
#include <QByteArray>
|
10
|
11
|
#include <QString>
|
... |
... |
@@ -248,27 +249,44 @@ struct CompositeGlyphInfo |
248
|
249
|
{
|
249
|
250
|
struct SubGlyph
|
250
|
251
|
{
|
251
|
|
- enum PositionType
|
|
252
|
+ enum PositionType : uint8_t
|
252
|
253
|
{
|
253
|
254
|
PT_Offset, // Child's points are added with a xy-offset
|
254
|
255
|
PT_Align // One point of the child is aligned with one point of the parent
|
255
|
256
|
};
|
|
257
|
+ enum TransformationType : uint8_t
|
|
258
|
+ {
|
|
259
|
+ TT_UniformScale, // uniform scale for x- and y-axis
|
|
260
|
+ TT_XYScale, // separate scale for x- and y-axis
|
|
261
|
+ TT_Matrix // 2x2 matrix
|
|
262
|
+ };
|
256
|
263
|
unsigned short index;
|
257
|
264
|
unsigned short flag;
|
258
|
265
|
PositionType positionType;
|
259
|
266
|
// For PT_Offset: <deltaX, deltaY>
|
260
|
267
|
// For PT_Align: <childPoint, parentPoint>
|
261
|
268
|
std::pair<short, short> position;
|
|
269
|
+ bool positionScaled;
|
|
270
|
+ TransformationType transformationType;
|
|
271
|
+ // For TT_UniformScale: transformation[0] is the scale
|
|
272
|
+ // For TT_XYScale: transformation[0]: x-scale; transformation[1]: y-scale
|
|
273
|
+ // For TT_Matrix: transformation is layouted as
|
|
274
|
+ // [xscale, scale01, scale10, yscale]
|
|
275
|
+ double transformation[4];
|
|
276
|
+
|
262
|
277
|
|
263
|
278
|
SubGlyph(unsigned short index,
|
264
|
279
|
unsigned short flag,
|
265
|
280
|
PositionType positionType,
|
266
|
|
- std::pair<short, short> position)
|
|
281
|
+ std::pair<short, short> position,
|
|
282
|
+ bool positionScaled)
|
267
|
283
|
: index(index),
|
268
|
284
|
flag(flag),
|
269
|
285
|
positionType(positionType),
|
270
|
|
- position(std::move(position))
|
271
|
|
- { }
|
|
286
|
+ position(std::move(position)),
|
|
287
|
+ positionScaled(positionScaled)
|
|
288
|
+ {
|
|
289
|
+ }
|
272
|
290
|
|
273
|
291
|
|
274
|
292
|
friend bool
|
... |
... |
@@ -278,7 +296,11 @@ struct CompositeGlyphInfo |
278
|
296
|
return lhs.index == rhs.index
|
279
|
297
|
&& lhs.flag == rhs.flag
|
280
|
298
|
&& lhs.positionType == rhs.positionType
|
281
|
|
- && lhs.position == rhs.position;
|
|
299
|
+ && lhs.position == rhs.position
|
|
300
|
+ && lhs.positionScaled == rhs.positionScaled
|
|
301
|
+ && lhs.transformationType == rhs.transformationType
|
|
302
|
+ && !std::memcmp(lhs.transformation, rhs.transformation,
|
|
303
|
+ 4 * sizeof(double));
|
282
|
304
|
}
|
283
|
305
|
|
284
|
306
|
|
src/ftinspect/engine/rendering.hpp
... |
... |
@@ -53,12 +53,12 @@ public: |
53
|
53
|
private:
|
54
|
54
|
Engine* engine_;
|
55
|
55
|
|
56
|
|
- QRgb backgroundColor_;
|
57
|
|
- QRgb foregroundColor_;
|
58
|
|
- double gamma_;
|
|
56
|
+ QRgb backgroundColor_ = 0;
|
|
57
|
+ QRgb foregroundColor_ = 0;
|
|
58
|
+ double gamma_ = 1.8;
|
59
|
59
|
QVector<QRgb> foregroundTable_;
|
60
|
60
|
|
61
|
|
- bool lcdUsesBGR_;
|
|
61
|
+ bool lcdUsesBGR_ = false;
|
62
|
62
|
};
|
63
|
63
|
|
64
|
64
|
|
src/ftinspect/glyphcomponents/glyphoutline.cpp
... |
... |
@@ -92,22 +92,20 @@ GlyphOutline::GlyphOutline(const QPen& pen, |
92
|
92
|
: outlinePen_(pen)
|
93
|
93
|
{
|
94
|
94
|
if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
|
95
|
|
- {
|
96
|
|
- outline_ = NULL;
|
97
|
95
|
return;
|
98
|
|
- }
|
99
|
|
- outline_ = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
|
|
96
|
+ auto outline = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
|
|
97
|
+ FT_Outline_Decompose(outline, &outlineFuncs, &path_);
|
100
|
98
|
|
101
|
99
|
FT_BBox cbox;
|
102
|
100
|
|
103
|
101
|
qreal halfPenWidth = outlinePen_.widthF();
|
104
|
102
|
|
105
|
|
- FT_Outline_Get_CBox(outline_, &cbox);
|
|
103
|
+ FT_Outline_Get_CBox(outline, &cbox);
|
106
|
104
|
|
107
|
105
|
boundingRect_.setCoords(qreal(cbox.xMin) / 64 - halfPenWidth,
|
108
|
|
- -qreal(cbox.yMax) / 64 - halfPenWidth,
|
109
|
|
- qreal(cbox.xMax) / 64 + halfPenWidth,
|
110
|
|
- -qreal(cbox.yMin) / 64 + halfPenWidth);
|
|
106
|
+ -qreal(cbox.yMax) / 64 - halfPenWidth,
|
|
107
|
+ qreal(cbox.xMax) / 64 + halfPenWidth,
|
|
108
|
+ -qreal(cbox.yMin) / 64 + halfPenWidth);
|
111
|
109
|
}
|
112
|
110
|
|
113
|
111
|
|
... |
... |
@@ -123,14 +121,47 @@ GlyphOutline::paint(QPainter* painter, |
123
|
121
|
const QStyleOptionGraphicsItem*,
|
124
|
122
|
QWidget*)
|
125
|
123
|
{
|
126
|
|
- if (!outline_)
|
127
|
|
- return;
|
128
|
124
|
painter->setPen(outlinePen_);
|
|
125
|
+ painter->drawPath(path_);
|
|
126
|
+}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+GlyphUsingOutline::GlyphUsingOutline(FT_Library library,
|
|
130
|
+ FT_Glyph glyph)
|
|
131
|
+: library_(library)
|
|
132
|
+{
|
|
133
|
+ if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
|
|
134
|
+ {
|
|
135
|
+ outlineValid_ = false;
|
|
136
|
+ return;
|
|
137
|
+ }
|
129
|
138
|
|
130
|
|
- QPainterPath path;
|
131
|
|
- FT_Outline_Decompose(outline_, &outlineFuncs, &path);
|
|
139
|
+ auto outline = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
|
132
|
140
|
|
133
|
|
- painter->drawPath(path);
|
|
141
|
+ FT_BBox cbox;
|
|
142
|
+ FT_Outline_Get_CBox(outline, &cbox);
|
|
143
|
+ outlineValid_ = true;
|
|
144
|
+ FT_Outline_New(library, static_cast<unsigned int>(outline->n_points),
|
|
145
|
+ outline->n_contours, &outline_);
|
|
146
|
+ FT_Outline_Copy(outline, &outline_);
|
|
147
|
+
|
|
148
|
+ // XXX fix bRect size
|
|
149
|
+ boundingRect_.setCoords(qreal(cbox.xMin) / 64, -qreal(cbox.yMax) / 64,
|
|
150
|
+ qreal(cbox.xMax) / 64, -qreal(cbox.yMin) / 64);
|
|
151
|
+}
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+GlyphUsingOutline::~GlyphUsingOutline()
|
|
155
|
+{
|
|
156
|
+ if (outlineValid_)
|
|
157
|
+ FT_Outline_Done(library_, &outline_);
|
|
158
|
+}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+QRectF
|
|
162
|
+GlyphUsingOutline::boundingRect() const
|
|
163
|
+{
|
|
164
|
+ return boundingRect_;
|
134
|
165
|
}
|
135
|
166
|
|
136
|
167
|
|
src/ftinspect/glyphcomponents/glyphoutline.hpp
... |
... |
@@ -5,6 +5,7 @@ |
5
|
5
|
|
6
|
6
|
#pragma once
|
7
|
7
|
|
|
8
|
+#include <QPainterPath>
|
8
|
9
|
#include <QGraphicsItem>
|
9
|
10
|
#include <QPen>
|
10
|
11
|
|
... |
... |
@@ -27,7 +28,29 @@ public: |
27
|
28
|
|
28
|
29
|
private:
|
29
|
30
|
QPen outlinePen_;
|
30
|
|
- FT_Outline* outline_;
|
|
31
|
+ QPainterPath path_;
|
|
32
|
+ QRectF boundingRect_;
|
|
33
|
+};
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+/*
|
|
37
|
+ * This class is common for all classes holding an outline.
|
|
38
|
+ * But `GlyphOutline` class itself don't need to hold the outline...
|
|
39
|
+ */
|
|
40
|
+
|
|
41
|
+class GlyphUsingOutline
|
|
42
|
+: public QGraphicsItem
|
|
43
|
+{
|
|
44
|
+public:
|
|
45
|
+ GlyphUsingOutline(FT_Library library,
|
|
46
|
+ FT_Glyph glyph);
|
|
47
|
+ ~GlyphUsingOutline() override;
|
|
48
|
+ QRectF boundingRect() const override;
|
|
49
|
+
|
|
50
|
+protected:
|
|
51
|
+ FT_Library library_;
|
|
52
|
+ FT_Outline outline_;
|
|
53
|
+ bool outlineValid_;
|
31
|
54
|
QRectF boundingRect_;
|
32
|
55
|
};
|
33
|
56
|
|
src/ftinspect/glyphcomponents/glyphpointnumbers.cpp
... |
... |
@@ -10,35 +10,14 @@ |
10
|
10
|
#include <QVector2D>
|
11
|
11
|
|
12
|
12
|
|
13
|
|
-GlyphPointNumbers::GlyphPointNumbers(const QPen& onP,
|
|
13
|
+GlyphPointNumbers::GlyphPointNumbers(FT_Library library,
|
|
14
|
+ const QPen& onP,
|
14
|
15
|
const QPen& offP,
|
15
|
16
|
FT_Glyph glyph)
|
16
|
|
-: onPen_(onP),
|
|
17
|
+: GlyphUsingOutline(library, glyph),
|
|
18
|
+ onPen_(onP),
|
17
|
19
|
offPen_(offP)
|
18
|
20
|
{
|
19
|
|
- if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
|
20
|
|
- {
|
21
|
|
- outline_ = NULL;
|
22
|
|
- return;
|
23
|
|
- }
|
24
|
|
- outline_ = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
|
25
|
|
-
|
26
|
|
- FT_BBox cbox;
|
27
|
|
-
|
28
|
|
- FT_Outline_Get_CBox(outline_, &cbox);
|
29
|
|
-
|
30
|
|
- // XXX fix bRect size
|
31
|
|
- boundingRect_.setCoords(qreal(cbox.xMin) / 64,
|
32
|
|
- -qreal(cbox.yMax) / 64,
|
33
|
|
- qreal(cbox.xMax) / 64,
|
34
|
|
- -qreal(cbox.yMin) / 64);
|
35
|
|
-}
|
36
|
|
-
|
37
|
|
-
|
38
|
|
-QRectF
|
39
|
|
-GlyphPointNumbers::boundingRect() const
|
40
|
|
-{
|
41
|
|
- return boundingRect_;
|
42
|
21
|
}
|
43
|
22
|
|
44
|
23
|
|
... |
... |
@@ -47,10 +26,10 @@ GlyphPointNumbers::paint(QPainter* painter, |
47
|
26
|
const QStyleOptionGraphicsItem* option,
|
48
|
27
|
QWidget*)
|
49
|
28
|
{
|
50
|
|
- if (!outline_)
|
|
29
|
+ if (!outlineValid_)
|
51
|
30
|
return;
|
52
|
|
- const qreal lod = option->levelOfDetailFromTransform(
|
53
|
|
- painter->worldTransform());
|
|
31
|
+ auto lod = QStyleOptionGraphicsItem::levelOfDetailFromTransform(
|
|
32
|
+ painter->worldTransform());
|
54
|
33
|
|
55
|
34
|
// don't draw point numbers if magnification is too small
|
56
|
35
|
if (lod >= 10)
|
... |
... |
@@ -74,9 +53,9 @@ GlyphPointNumbers::paint(QPainter* painter, |
74
|
53
|
painter->scale(1 / lod, 1 / lod);
|
75
|
54
|
#endif
|
76
|
55
|
|
77
|
|
- FT_Vector* points = outline_->points;
|
78
|
|
- FT_Short* contours = outline_->contours;
|
79
|
|
- char* tags = outline_->tags;
|
|
56
|
+ FT_Vector* points = outline_.points;
|
|
57
|
+ FT_Short* contours = outline_.contours;
|
|
58
|
+ char* tags = outline_.tags;
|
80
|
59
|
|
81
|
60
|
QVector2D octants[8] = { QVector2D(1, 0),
|
82
|
61
|
QVector2D(0.707f, -0.707f),
|
... |
... |
@@ -89,7 +68,7 @@ GlyphPointNumbers::paint(QPainter* painter, |
89
|
68
|
|
90
|
69
|
|
91
|
70
|
short ptIdx = 0;
|
92
|
|
- for (int contIdx = 0; contIdx < outline_->n_contours; contIdx++ )
|
|
71
|
+ for (int contIdx = 0; contIdx < outline_.n_contours; contIdx++ )
|
93
|
72
|
{
|
94
|
73
|
for (;;)
|
95
|
74
|
{
|
src/ftinspect/glyphcomponents/glyphpointnumbers.hpp
... |
... |
@@ -5,23 +5,16 @@ |
5
|
5
|
|
6
|
6
|
#pragma once
|
7
|
7
|
|
8
|
|
-#include <QGraphicsItem>
|
9
|
|
-#include <QPen>
|
10
|
|
-
|
11
|
|
-#include <ft2build.h>
|
12
|
|
-#include <freetype/freetype.h>
|
13
|
|
-#include <freetype/ftglyph.h>
|
14
|
|
-#include <freetype/ftoutln.h>
|
15
|
|
-
|
|
8
|
+#include "glyphoutline.hpp"
|
16
|
9
|
|
17
|
10
|
class GlyphPointNumbers
|
18
|
|
-: public QGraphicsItem
|
|
11
|
+: public GlyphUsingOutline
|
19
|
12
|
{
|
20
|
13
|
public:
|
21
|
|
- GlyphPointNumbers(const QPen& onPen,
|
|
14
|
+ GlyphPointNumbers(FT_Library library,
|
|
15
|
+ const QPen& onPen,
|
22
|
16
|
const QPen& offPen,
|
23
|
17
|
FT_Glyph glyph);
|
24
|
|
- QRectF boundingRect() const override;
|
25
|
18
|
void paint(QPainter* painter,
|
26
|
19
|
const QStyleOptionGraphicsItem* option,
|
27
|
20
|
QWidget* widget) override;
|
... |
... |
@@ -29,8 +22,6 @@ public: |
29
|
22
|
private:
|
30
|
23
|
QPen onPen_;
|
31
|
24
|
QPen offPen_;
|
32
|
|
- FT_Outline* outline_;
|
33
|
|
- QRectF boundingRect_;
|
34
|
25
|
};
|
35
|
26
|
|
36
|
27
|
|
src/ftinspect/glyphcomponents/glyphpoints.cpp
... |
... |
@@ -9,36 +9,14 @@ |
9
|
9
|
#include <QStyleOptionGraphicsItem>
|
10
|
10
|
|
11
|
11
|
|
12
|
|
-GlyphPoints::GlyphPoints(const QPen& onP,
|
|
12
|
+GlyphPoints::GlyphPoints(FT_Library library,
|
|
13
|
+ const QPen& onP,
|
13
|
14
|
const QPen& offP,
|
14
|
15
|
FT_Glyph glyph)
|
15
|
|
-: onPen_(onP),
|
|
16
|
+: GlyphUsingOutline(library, glyph),
|
|
17
|
+ onPen_(onP),
|
16
|
18
|
offPen_(offP)
|
17
|
19
|
{
|
18
|
|
- if (glyph->format != FT_GLYPH_FORMAT_OUTLINE)
|
19
|
|
- {
|
20
|
|
- outline_ = NULL;
|
21
|
|
- return;
|
22
|
|
- }
|
23
|
|
- outline_ = &reinterpret_cast<FT_OutlineGlyph>(glyph)->outline;
|
24
|
|
-
|
25
|
|
- FT_BBox cbox;
|
26
|
|
-
|
27
|
|
- qreal halfPenWidth = qMax(onPen_.widthF(), offPen_.widthF()) / 2;
|
28
|
|
-
|
29
|
|
- FT_Outline_Get_CBox(outline_, &cbox);
|
30
|
|
-
|
31
|
|
- boundingRect_.setCoords(qreal(cbox.xMin) / 64 - halfPenWidth,
|
32
|
|
- -qreal(cbox.yMax) / 64 - halfPenWidth,
|
33
|
|
- qreal(cbox.xMax) / 64 + halfPenWidth,
|
34
|
|
- -qreal(cbox.yMin) / 64 + halfPenWidth);
|
35
|
|
-}
|
36
|
|
-
|
37
|
|
-
|
38
|
|
-QRectF
|
39
|
|
-GlyphPoints::boundingRect() const
|
40
|
|
-{
|
41
|
|
- return boundingRect_;
|
42
|
20
|
}
|
43
|
21
|
|
44
|
22
|
|
... |
... |
@@ -47,7 +25,7 @@ GlyphPoints::paint(QPainter* painter, |
47
|
25
|
const QStyleOptionGraphicsItem* option,
|
48
|
26
|
QWidget*)
|
49
|
27
|
{
|
50
|
|
- if (!outline_)
|
|
28
|
+ if (!outlineValid_)
|
51
|
29
|
return;
|
52
|
30
|
|
53
|
31
|
const qreal lod = option->levelOfDetailFromTransform(
|
... |
... |
@@ -90,21 +68,21 @@ GlyphPoints::paint(QPainter* painter, |
90
|
68
|
qreal onRadius = onPen_.widthF() / lod;
|
91
|
69
|
qreal offRadius = offPen_.widthF() / lod;
|
92
|
70
|
|
93
|
|
- for (int i = 0; i < outline_->n_points; i++)
|
|
71
|
+ for (int i = 0; i < outline_.n_points; i++)
|
94
|
72
|
{
|
95
|
|
- if (outline_->tags[i] & FT_CURVE_TAG_ON)
|
|
73
|
+ if (outline_.tags[i] & FT_CURVE_TAG_ON)
|
96
|
74
|
{
|
97
|
75
|
painter->setBrush(onBrush);
|
98
|
|
- painter->drawEllipse(QPointF(qreal(outline_->points[i].x) / 64,
|
99
|
|
- -qreal(outline_->points[i].y) / 64),
|
|
76
|
+ painter->drawEllipse(QPointF(qreal(outline_.points[i].x) / 64,
|
|
77
|
+ -qreal(outline_.points[i].y) / 64),
|
100
|
78
|
onRadius,
|
101
|
79
|
onRadius);
|
102
|
80
|
}
|
103
|
81
|
else
|
104
|
82
|
{
|
105
|
83
|
painter->setBrush(offBrush);
|
106
|
|
- painter->drawEllipse(QPointF(qreal(outline_->points[i].x) / 64,
|
107
|
|
- -qreal(outline_->points[i].y) / 64),
|
|
84
|
+ painter->drawEllipse(QPointF(qreal(outline_.points[i].x) / 64,
|
|
85
|
+ -qreal(outline_.points[i].y) / 64),
|
108
|
86
|
offRadius,
|
109
|
87
|
offRadius);
|
110
|
88
|
}
|
src/ftinspect/glyphcomponents/glyphpoints.hpp
... |
... |
@@ -5,6 +5,8 @@ |
5
|
5
|
|
6
|
6
|
#pragma once
|
7
|
7
|
|
|
8
|
+#include "glyphoutline.hpp"
|
|
9
|
+
|
8
|
10
|
#include <QGraphicsItem>
|
9
|
11
|
#include <QPen>
|
10
|
12
|
|
... |
... |
@@ -15,13 +17,13 @@ |
15
|
17
|
|
16
|
18
|
|
17
|
19
|
class GlyphPoints
|
18
|
|
-: public QGraphicsItem
|
|
20
|
+: public GlyphUsingOutline
|
19
|
21
|
{
|
20
|
22
|
public:
|
21
|
|
- GlyphPoints(const QPen& onPen,
|
|
23
|
+ GlyphPoints(FT_Library library,
|
|
24
|
+ const QPen& onPen,
|
22
|
25
|
const QPen& offPen,
|
23
|
26
|
FT_Glyph glyph);
|
24
|
|
- QRectF boundingRect() const override;
|
25
|
27
|
void paint(QPainter* painter,
|
26
|
28
|
const QStyleOptionGraphicsItem* option,
|
27
|
29
|
QWidget* widget) override;
|
... |
... |
@@ -29,8 +31,6 @@ public: |
29
|
31
|
private:
|
30
|
32
|
QPen onPen_;
|
31
|
33
|
QPen offPen_;
|
32
|
|
- FT_Outline* outline_;
|
33
|
|
- QRectF boundingRect_;
|
34
|
34
|
};
|
35
|
35
|
|
36
|
36
|
|
src/ftinspect/models/fontinfomodels.cpp
... |
... |
@@ -5,6 +5,8 @@ |
5
|
5
|
#include "fontinfomodels.hpp"
|
6
|
6
|
#include "../engine/engine.hpp"
|
7
|
7
|
|
|
8
|
+#include <cstdint>
|
|
9
|
+
|
8
|
10
|
int
|
9
|
11
|
FixedSizeInfoModel::rowCount(const QModelIndex& parent) const
|
10
|
12
|
{
|
... |
... |
@@ -474,8 +476,8 @@ CompositeGlyphsInfoModel::rowCount(const QModelIndex& parent) const |
474
|
476
|
{
|
475
|
477
|
if (!parent.isValid())
|
476
|
478
|
return static_cast<int>(glyphs_.size());
|
477
|
|
- auto id = parent.internalId();
|
478
|
|
- if (id < 0 || id >= nodes_.size())
|
|
479
|
+ uint64_t id = parent.internalId();
|
|
480
|
+ if (id >= nodes_.size())
|
479
|
481
|
return 0;
|
480
|
482
|
auto gid = nodes_[id].glyphIndex;
|
481
|
483
|
auto iter = glyphMapper_.find(gid);
|
... |
... |
@@ -571,6 +573,52 @@ CompositeGlyphsInfoModel::parent(const QModelIndex& child) const |
571
|
573
|
}
|
572
|
574
|
|
573
|
575
|
|
|
576
|
+QString
|
|
577
|
+generatePositionTransformationText(CompositeGlyphInfo::SubGlyph const& info)
|
|
578
|
+{
|
|
579
|
+ QString result;
|
|
580
|
+ switch (info.transformationType)
|
|
581
|
+ {
|
|
582
|
+ case CompositeGlyphInfo::SubGlyph::TT_UniformScale:
|
|
583
|
+ result += QString("scale: %1, ")
|
|
584
|
+ .arg(QString::number(info.transformation[0]));
|
|
585
|
+ break;
|
|
586
|
+ case CompositeGlyphInfo::SubGlyph::TT_XYScale:
|
|
587
|
+ result += QString("xy scale: (%1, %2), ")
|
|
588
|
+ .arg(QString::number(info.transformation[0]),
|
|
589
|
+ QString::number(info.transformation[1]));
|
|
590
|
+ break;
|
|
591
|
+ case CompositeGlyphInfo::SubGlyph::TT_Matrix:
|
|
592
|
+ result += QString("2x2 scale: [%1, %2; %3, %4], ")
|
|
593
|
+ .arg(QString::number(info.transformation[0]),
|
|
594
|
+ QString::number(info.transformation[1]),
|
|
595
|
+ QString::number(info.transformation[2]),
|
|
596
|
+ QString::number(info.transformation[3]));
|
|
597
|
+ break;
|
|
598
|
+ }
|
|
599
|
+
|
|
600
|
+ switch (info.positionType)
|
|
601
|
+ {
|
|
602
|
+ case CompositeGlyphInfo::SubGlyph::PT_Offset:
|
|
603
|
+ if (info.positionScaled)
|
|
604
|
+ result += QString("scaled offset: (%1, %2)")
|
|
605
|
+ .arg(QString::number(info.position.first),
|
|
606
|
+ QString::number(info.position.second));
|
|
607
|
+ else
|
|
608
|
+ result += QString("offset: (%1, %2)")
|
|
609
|
+ .arg(QString::number(info.position.first),
|
|
610
|
+ QString::number(info.position.second));
|
|
611
|
+ break;
|
|
612
|
+ case CompositeGlyphInfo::SubGlyph::PT_Align:
|
|
613
|
+ result += QString("anchor points: %1 (parent) <- %2 (this glyph)")
|
|
614
|
+ .arg(QString::number(info.position.first),
|
|
615
|
+ QString::number(info.position.second));
|
|
616
|
+ break;
|
|
617
|
+ }
|
|
618
|
+ return result;
|
|
619
|
+}
|
|
620
|
+
|
|
621
|
+
|
574
|
622
|
QVariant
|
575
|
623
|
CompositeGlyphsInfoModel::data(const QModelIndex& index,
|
576
|
624
|
int role) const
|
... |
... |
@@ -584,25 +632,6 @@ CompositeGlyphsInfoModel::data(const QModelIndex& index, |
584
|
632
|
auto& n = nodes_[id];
|
585
|
633
|
auto glyphIdx = n.glyphIndex;
|
586
|
634
|
|
587
|
|
- if (role == Qt::ToolTipRole && index.column() == CGIM_Position)
|
588
|
|
- {
|
589
|
|
- if (!n.subGlyphInfo)
|
590
|
|
- return {};
|
591
|
|
- auto pos = n.subGlyphInfo->position;
|
592
|
|
- switch (n.subGlyphInfo->positionType)
|
593
|
|
- {
|
594
|
|
- case CompositeGlyphInfo::SubGlyph::PT_Offset:
|
595
|
|
- return QString("Add a offset (%1, %2) to the subglyph's points")
|
596
|
|
- .arg(pos.first)
|
597
|
|
- .arg(pos.second);
|
598
|
|
- case CompositeGlyphInfo::SubGlyph::PT_Align:
|
599
|
|
- return QString("Align parent's point %1 to subglyph's point %2")
|
600
|
|
- .arg(pos.first)
|
601
|
|
- .arg(pos.second);
|
602
|
|
- }
|
603
|
|
- return {};
|
604
|
|
- }
|
605
|
|
-
|
606
|
635
|
if (role == Qt::DecorationRole && index.column() == CGIM_Glyph)
|
607
|
636
|
{
|
608
|
637
|
auto glyphIndex = n.glyphIndex;
|
... |
... |
@@ -628,19 +657,12 @@ CompositeGlyphsInfoModel::data(const QModelIndex& index, |
628
|
657
|
case CGIM_Flag:
|
629
|
658
|
if (!n.subGlyphInfo)
|
630
|
659
|
return {};
|
631
|
|
- return QString::number(n.subGlyphInfo->flag, 16).rightJustified(4, '0');
|
632
|
|
- case CGIM_Position:
|
|
660
|
+ return QString("0x%1").arg(n.subGlyphInfo->flag, 4, 16, QLatin1Char('0'));
|
|
661
|
+ case CGIM_PositionTransformation:
|
633
|
662
|
{
|
634
|
663
|
if (!n.subGlyphInfo)
|
635
|
664
|
return {};
|
636
|
|
- auto pos = n.subGlyphInfo->position;
|
637
|
|
- switch (n.subGlyphInfo->positionType)
|
638
|
|
- {
|
639
|
|
- case CompositeGlyphInfo::SubGlyph::PT_Offset:
|
640
|
|
- return QString("Offset (%1, %2)").arg(pos.first).arg(pos.second);
|
641
|
|
- case CompositeGlyphInfo::SubGlyph::PT_Align:
|
642
|
|
- return QString("Align %1 -> %2").arg(pos.first).arg(pos.second);
|
643
|
|
- }
|
|
665
|
+ return generatePositionTransformationText(*n.subGlyphInfo);
|
644
|
666
|
}
|
645
|
667
|
default:;
|
646
|
668
|
}
|
... |
... |
@@ -665,8 +687,8 @@ CompositeGlyphsInfoModel::headerData(int section, |
665
|
687
|
return tr("Glyph");
|
666
|
688
|
case CGIM_Flag:
|
667
|
689
|
return tr("Flags");
|
668
|
|
- case CGIM_Position:
|
669
|
|
- return tr("Position");
|
|
690
|
+ case CGIM_PositionTransformation:
|
|
691
|
+ return tr("Position and Transformation");
|
670
|
692
|
default:;
|
671
|
693
|
}
|
672
|
694
|
return {};
|
src/ftinspect/models/fontinfomodels.hpp
... |
... |
@@ -259,9 +259,9 @@ public: |
259
|
259
|
|
260
|
260
|
enum Columns : int
|
261
|
261
|
{
|
262
|
|
- CGIM_Glyph = 0, // TODO: transformation, scale? consider more flags?
|
|
262
|
+ CGIM_Glyph = 0,
|
263
|
263
|
CGIM_Flag = 1,
|
264
|
|
- CGIM_Position = 2,
|
|
264
|
+ CGIM_PositionTransformation = 2,
|
265
|
265
|
CGIM_Max
|
266
|
266
|
};
|
267
|
267
|
|
src/ftinspect/panels/settingpanel.cpp
... |
... |
@@ -341,8 +341,6 @@ SettingPanel::onFontChanged() |
341
|
341
|
engine_->reloadFont();
|
342
|
342
|
auto hasColor = engine_->currentFontHasColorLayers();
|
343
|
343
|
colorLayerCheckBox_->setEnabled(hasColor);
|
344
|
|
- if (!hasColor)
|
345
|
|
- colorLayerCheckBox_->setChecked(false);
|
346
|
344
|
paletteComboBox_->setEnabled(colorLayerCheckBox_->isChecked()
|
347
|
345
|
&& paletteComboBox_->count() > 0);
|
348
|
346
|
populatePalettes();
|
... |
... |
@@ -781,9 +779,10 @@ SettingPanel::setDefaults() |
781
|
779
|
horizontalHintingCheckBox_->setChecked(true);
|
782
|
780
|
verticalHintingCheckBox_->setChecked(true);
|
783
|
781
|
blueZoneHintingCheckBox_->setChecked(true);
|
784
|
|
- embeddedBitmapCheckBox_->setChecked(false);
|
|
782
|
+ segmentDrawingCheckBox_->setChecked(false);
|
785
|
783
|
}
|
786
|
|
-
|
|
784
|
+
|
|
785
|
+ embeddedBitmapCheckBox_->setChecked(false);
|
787
|
786
|
colorLayerCheckBox_->setChecked(true);
|
788
|
787
|
paletteComboBox_->setEnabled(false);
|
789
|
788
|
|
src/ftinspect/panels/singular.cpp
... |
... |
@@ -115,7 +115,8 @@ SingularTab::drawGlyph() |
115
|
115
|
|
116
|
116
|
if (showPointsCheckBox_->isChecked())
|
117
|
117
|
{
|
118
|
|
- currentGlyphPointsItem_ = new GlyphPoints(graphicsDefault_->onPen,
|
|
118
|
+ currentGlyphPointsItem_ = new GlyphPoints(engine_->ftLibrary(),
|
|
119
|
+ graphicsDefault_->onPen,
|
119
|
120
|
graphicsDefault_->offPen,
|
120
|
121
|
glyph);
|
121
|
122
|
currentGlyphPointsItem_->setZValue(1);
|
... |
... |
@@ -124,7 +125,8 @@ SingularTab::drawGlyph() |
124
|
125
|
if (showPointNumbersCheckBox_->isChecked())
|
125
|
126
|
{
|
126
|
127
|
currentGlyphPointNumbersItem_
|
127
|
|
- = new GlyphPointNumbers(graphicsDefault_->onPen,
|
|
128
|
+ = new GlyphPointNumbers(engine_->ftLibrary(),
|
|
129
|
+ graphicsDefault_->onPen,
|
128
|
130
|
graphicsDefault_->offPen,
|
129
|
131
|
glyph);
|
130
|
132
|
currentGlyphPointNumbersItem_->setZValue(1);
|
src/ftinspect/panels/singular.hpp
... |
... |
@@ -63,8 +63,8 @@ protected: |
63
|
63
|
void resizeEvent(QResizeEvent* event) override;
|
64
|
64
|
|
65
|
65
|
private:
|
66
|
|
- int currentGlyphIndex_;
|
67
|
|
- int currentGlyphCount_;
|
|
66
|
+ int currentGlyphIndex_ = 0;
|
|
67
|
+ int currentGlyphCount_ = 0;
|
68
|
68
|
|
69
|
69
|
Engine* engine_;
|
70
|
70
|
|
|