1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 #ifndef QFONTENGINE_FT_P_H
40 #define QFONTENGINE_FT_P_H
41 //
42 //  W A R N I N G
43 //  -------------
44 //
45 // This file is not part of the Qt API.  It exists purely as an
46 // implementation detail.  This header file may change from version to
47 // version without notice, or even be removed.
48 //
49 // We mean it.
50 //
51 
52 #include "private/qfontengine_p.h"
53 
54 #ifndef QT_NO_FREETYPE
55 
56 #include <ft2build.h>
57 #include FT_FREETYPE_H
58 
59 
60 #ifndef Q_OS_WIN
61 #include <unistd.h>
62 #endif
63 
64 #include <qmutex.h>
65 
66 QT_BEGIN_NAMESPACE
67 
68 class QFontEngineFTRawFont;
69 class QFontconfigDatabase;
70 
71 /*
72  * This class represents one font file on disk (like Arial.ttf) and is shared between all the font engines
73  * that show this font file (at different pixel sizes).
74  */
75 class QFreetypeFace
76 {
77 public:
78     void computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing, QFixed *scalableBitmapScaleFactor);
79     QFontEngine::Properties properties() const;
80     bool getSfntTable(uint tag, uchar *buffer, uint *length) const;
81 
82     static QFreetypeFace *getFace(const QFontEngine::FaceId &face_id,
83                                   const QByteArray &fontData = QByteArray());
84     void release(const QFontEngine::FaceId &face_id);
85 
86     // locks the struct for usage. Any read/write operations require locking.
lock()87     void lock()
88     {
89         _lock.lock();
90     }
unlock()91     void unlock()
92     {
93         _lock.unlock();
94     }
95 
96     FT_Face face;
97     int xsize; // 26.6
98     int ysize; // 26.6
99     FT_Matrix matrix;
100     FT_CharMap unicode_map;
101     FT_CharMap symbol_map;
102 
103     enum { cmapCacheSize = 0x200 };
104     glyph_t cmapCache[cmapCacheSize];
105 
106     int fsType() const;
107 
108     int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints);
109 
110     bool isScalableBitmap() const;
111 
112     static void addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale);
113     static void addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path);
114 
115 private:
116     friend class QFontEngineFT;
117     friend class QtFreetypeData;
118     friend struct QScopedPointerDeleter<QFreetypeFace>;
119     QFreetypeFace() = default;
120     ~QFreetypeFace() {}
121     void cleanup();
122     QAtomicInt ref;
123     QRecursiveMutex _lock;
124     QByteArray fontData;
125 
126     QFontEngine::Holder hbFace;
127 };
128 
129 class QFontEngineFT : public QFontEngine
130 {
131 public:
132     struct GlyphInfo {
133         int             linearAdvance;
134         unsigned short  width;
135         unsigned short  height;
136         short           x;
137         short           y;
138         short           xOff;
139         short           yOff;
140     };
141 
142     struct GlyphAndSubPixelPosition
143     {
144         GlyphAndSubPixelPosition(glyph_t g, QFixed spp) : glyph(g), subPixelPosition(spp) {}
145 
146         bool operator==(const GlyphAndSubPixelPosition &other) const
147         {
148             return glyph == other.glyph && subPixelPosition == other.subPixelPosition;
149         }
150 
151         glyph_t glyph;
152         QFixed subPixelPosition;
153     };
154 
155     struct QGlyphSet
156     {
157         QGlyphSet();
158         ~QGlyphSet();
159         FT_Matrix transformationMatrix;
160         bool outline_drawing;
161 
162         void removeGlyphFromCache(glyph_t index, QFixed subPixelPosition);
163         void clear();
164         inline bool useFastGlyphData(glyph_t index, QFixed subPixelPosition) const {
165             return (index < 256 && subPixelPosition == 0);
166         }
167         inline Glyph *getGlyph(glyph_t index, QFixed subPixelPosition = 0) const;
168         void setGlyph(glyph_t index, QFixed spp, Glyph *glyph);
169 
170         inline bool isGlyphMissing(glyph_t index) const { return missing_glyphs.contains(index); }
171         inline void setGlyphMissing(glyph_t index) const { missing_glyphs.insert(index); }
172 private:
173         mutable QHash<GlyphAndSubPixelPosition, Glyph *> glyph_data; // maps from glyph index to glyph data
174         mutable QSet<glyph_t> missing_glyphs;
175         mutable Glyph *fast_glyph_data[256]; // for fast lookup of glyphs < 256
176         mutable int fast_glyph_count;
177     };
178 
179     QFontEngine::FaceId faceId() const override;
180     QFontEngine::Properties properties() const override;
181     QFixed emSquareSize() const override;
182     bool supportsSubPixelPositions() const override
183     {
184         return default_hint_style == HintLight ||
185                default_hint_style == HintNone;
186     }
187 
188     bool getSfntTableData(uint tag, uchar *buffer, uint *length) const override;
189     int synthesized() const override;
190 
191     QFixed ascent() const override;
192     QFixed capHeight() const override;
193     QFixed descent() const override;
194     QFixed leading() const override;
195     QFixed xHeight() const override;
196     QFixed averageCharWidth() const override;
197 
198     qreal maxCharWidth() const override;
199     QFixed lineThickness() const override;
200     QFixed underlinePosition() const override;
201 
202     glyph_t glyphIndex(uint ucs4) const override;
203     void doKerning(QGlyphLayout *, ShaperFlags) const override;
204 
205     void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) override;
206 
207     bool supportsTransformation(const QTransform &transform) const override;
208 
209     void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
210                  QPainterPath *path, QTextItem::RenderFlags flags) override;
211     void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
212                   QPainterPath *path, QTextItem::RenderFlags flags) override;
213 
214     bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
215 
216     glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override;
217     glyph_metrics_t boundingBox(glyph_t glyph) override;
218     glyph_metrics_t boundingBox(glyph_t glyph, const QTransform &matrix) override;
219 
220     void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags flags) const override;
221     QImage alphaMapForGlyph(glyph_t g) override { return alphaMapForGlyph(g, 0); }
222     QImage alphaMapForGlyph(glyph_t, QFixed) override;
223     QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) override;
224     QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t) override;
225     QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t, const QColor &color) override;
226     glyph_metrics_t alphaMapBoundingBox(glyph_t glyph,
227                                         QFixed subPixelPosition,
228                                         const QTransform &matrix,
229                                         QFontEngine::GlyphFormat format) override;
230     Glyph *glyphData(glyph_t glyph, QFixed subPixelPosition,
231                      GlyphFormat neededFormat, const QTransform &t) override;
232     bool hasInternalCaching() const override { return cacheEnabled; }
233     bool expectsGammaCorrectedBlending() const override;
234 
235     void removeGlyphFromCache(glyph_t glyph) override;
236     int glyphMargin(QFontEngine::GlyphFormat /* format */) override { return 0; }
237 
238     int glyphCount() const override;
239 
240     enum Scaling {
241         Scaled,
242         Unscaled
243     };
244     FT_Face lockFace(Scaling scale = Scaled) const;
245     void unlockFace() const;
246 
247     FT_Face non_locked_face() const;
248 
249     inline bool drawAntialiased() const { return antialias; }
250     inline bool invalid() const { return xsize == 0 && ysize == 0; }
251     inline bool isBitmapFont() const { return defaultFormat == Format_Mono; }
252     inline bool isScalableBitmap() const { return freetype->isScalableBitmap(); }
253 
254     inline Glyph *loadGlyph(uint glyph, QFixed subPixelPosition, GlyphFormat format = Format_None, bool fetchMetricsOnly = false, bool disableOutlineDrawing = false) const
255     { return loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr, glyph, subPixelPosition, format, fetchMetricsOnly, disableOutlineDrawing); }
256     Glyph *loadGlyph(QGlyphSet *set, uint glyph, QFixed subPixelPosition, GlyphFormat = Format_None, bool fetchMetricsOnly = false, bool disableOutlineDrawing = false) const;
257     Glyph *loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format, const QTransform &t, bool fetchBoundingBox = false, bool disableOutlineDrawing = false);
258 
259     QGlyphSet *loadGlyphSet(const QTransform &matrix);
260 
261     QFontEngineFT(const QFontDef &fd);
262     virtual ~QFontEngineFT();
263 
264     bool init(FaceId faceId, bool antiaalias, GlyphFormat defaultFormat = Format_None,
265               const QByteArray &fontData = QByteArray());
266     bool init(FaceId faceId, bool antialias, GlyphFormat format,
267               QFreetypeFace *freetypeFace);
268 
269     int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints) override;
270 
271     void setQtDefaultHintStyle(QFont::HintingPreference hintingPreference);
272     void setDefaultHintStyle(HintStyle style) override;
273 
274     QFontEngine *cloneWithSize(qreal pixelSize) const override;
275     Qt::HANDLE handle() const override;
276     bool initFromFontEngine(const QFontEngineFT *fontEngine);
277 
278     HintStyle defaultHintStyle() const { return default_hint_style; }
279 
280     static QFontEngineFT *create(const QFontDef &fontDef, FaceId faceId, const QByteArray &fontData = QByteArray());
281     static QFontEngineFT *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference);
282 
283 protected:
284 
285     QFreetypeFace *freetype;
286     mutable int default_load_flags;
287     HintStyle default_hint_style;
288     bool antialias;
289     bool transform;
290     bool embolden;
291     bool obliquen;
292     SubpixelAntialiasingType subpixelType;
293     int lcdFilterType;
294     bool embeddedbitmap;
295     bool cacheEnabled;
296     bool forceAutoHint;
297     bool stemDarkeningDriver;
298 
299 private:
300     friend class QFontEngineFTRawFont;
301     friend class QFontconfigDatabase;
302     friend class QFreeTypeFontDatabase;
303     friend class QFontEngineMultiFontConfig;
304 
305     int loadFlags(QGlyphSet *set, GlyphFormat format, int flags, bool &hsubpixel, int &vfactor) const;
306     bool shouldUseDesignMetrics(ShaperFlags flags) const;
307     QFixed scaledBitmapMetrics(QFixed m) const;
308     glyph_metrics_t scaledBitmapMetrics(const glyph_metrics_t &m, const QTransform &matrix) const;
309 
310     GlyphFormat defaultFormat;
311     FT_Matrix matrix;
312 
313     QList<QGlyphSet> transformedGlyphSets;
314     mutable QGlyphSet defaultGlyphSet;
315 
316     QFontEngine::FaceId face_id;
317 
318     int xsize;
319     int ysize;
320 
321     QFixed line_thickness;
322     QFixed underline_position;
323 
324     FT_Size_Metrics metrics;
325     mutable bool kerning_pairs_loaded;
326     QFixed scalableBitmapScaleFactor;
327 };
328 
329 inline uint qHash(const QFontEngineFT::GlyphAndSubPixelPosition &g)
330 {
331     return (g.glyph << 8)  | (g.subPixelPosition * 10).round().toInt();
332 }
333 
334 inline QFontEngineFT::Glyph *QFontEngineFT::QGlyphSet::getGlyph(glyph_t index, QFixed subPixelPosition) const
335 {
336     if (useFastGlyphData(index, subPixelPosition))
337         return fast_glyph_data[index];
338     return glyph_data.value(GlyphAndSubPixelPosition(index, subPixelPosition));
339 }
340 
341 extern FT_Library qt_getFreetype();
342 
343 QT_END_NAMESPACE
344 
345 #endif // QT_NO_FREETYPE
346 
347 #endif // QFONTENGINE_FT_P_H
348