1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 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 
40 #include <qdebug.h>
41 #include <private/qfontengine_p.h>
42 #include <private/qfontengineglyphcache_p.h>
43 #include <private/qguiapplication_p.h>
44 
45 #include <qpa/qplatformfontdatabase.h>
46 #include <qpa/qplatformintegration.h>
47 
48 #include "qbitmap.h"
49 #include "qpainter.h"
50 #include "qpainterpath.h"
51 #include "qvarlengtharray.h"
52 #include <qmath.h>
53 #include <qendian.h>
54 #include <private/qstringiterator_p.h>
55 
56 #if QT_CONFIG(harfbuzz)
57 #  include "qharfbuzzng_p.h"
58 #  include <harfbuzz/hb-ot.h>
59 #endif
60 #include <private/qharfbuzz_p.h>
61 
62 #include <algorithm>
63 #include <limits.h>
64 
65 QT_BEGIN_NAMESPACE
66 
qtransform_equals_no_translate(const QTransform & a,const QTransform & b)67 static inline bool qtransform_equals_no_translate(const QTransform &a, const QTransform &b)
68 {
69     if (a.type() <= QTransform::TxTranslate && b.type() <= QTransform::TxTranslate) {
70         return true;
71     } else {
72         // We always use paths for perspective text anyway, so no
73         // point in checking the full matrix...
74         Q_ASSERT(a.type() < QTransform::TxProject);
75         Q_ASSERT(b.type() < QTransform::TxProject);
76 
77         return a.m11() == b.m11()
78             && a.m12() == b.m12()
79             && a.m21() == b.m21()
80             && a.m22() == b.m22();
81     }
82 }
83 
84 template<typename T>
qSafeFromBigEndian(const uchar * source,const uchar * end,T * output)85 static inline bool qSafeFromBigEndian(const uchar *source, const uchar *end, T *output)
86 {
87     if (source + sizeof(T) > end)
88         return false;
89 
90     *output = qFromBigEndian<T>(source);
91     return true;
92 }
93 
94 // Harfbuzz helper functions
95 
96 #if QT_CONFIG(harfbuzz)
97 Q_GLOBAL_STATIC_WITH_ARGS(bool, useHarfbuzzNG,(qgetenv("QT_HARFBUZZ") != "old"))
98 
qt_useHarfbuzzNG()99 bool qt_useHarfbuzzNG()
100 {
101     return *useHarfbuzzNG();
102 }
103 #endif
104 
105 Q_STATIC_ASSERT(sizeof(HB_Glyph) == sizeof(glyph_t));
106 Q_STATIC_ASSERT(sizeof(HB_Fixed) == sizeof(QFixed));
107 
hb_stringToGlyphs(HB_Font font,const HB_UChar16 * string,hb_uint32 length,HB_Glyph * glyphs,hb_uint32 * numGlyphs,HB_Bool rightToLeft)108 static HB_Bool hb_stringToGlyphs(HB_Font font, const HB_UChar16 *string, hb_uint32 length, HB_Glyph *glyphs, hb_uint32 *numGlyphs, HB_Bool rightToLeft)
109 {
110     QFontEngine *fe = (QFontEngine *)font->userData;
111 
112     const QChar *str = reinterpret_cast<const QChar *>(string);
113 
114     QGlyphLayout qglyphs;
115     qglyphs.numGlyphs = *numGlyphs;
116     qglyphs.glyphs = glyphs;
117     int nGlyphs = *numGlyphs;
118     bool result = fe->stringToCMap(str, length, &qglyphs, &nGlyphs, QFontEngine::GlyphIndicesOnly);
119     *numGlyphs = nGlyphs;
120 
121     if (rightToLeft && result && !fe->symbol) {
122         QStringIterator it(str, str + length);
123         while (it.hasNext()) {
124             const uint ucs4 = it.next();
125             const uint mirrored = QChar::mirroredChar(ucs4);
126             if (Q_UNLIKELY(mirrored != ucs4))
127                 *glyphs = fe->glyphIndex(mirrored);
128             ++glyphs;
129         }
130     }
131 
132     return result;
133 }
134 
hb_getAdvances(HB_Font font,const HB_Glyph * glyphs,hb_uint32 numGlyphs,HB_Fixed * advances,int flags)135 static void hb_getAdvances(HB_Font font, const HB_Glyph *glyphs, hb_uint32 numGlyphs, HB_Fixed *advances, int flags)
136 {
137     QFontEngine *fe = (QFontEngine *)font->userData;
138 
139     QGlyphLayout qglyphs;
140     qglyphs.numGlyphs = numGlyphs;
141     qglyphs.glyphs = const_cast<glyph_t *>(glyphs);
142     qglyphs.advances = reinterpret_cast<QFixed *>(advances);
143 
144     fe->recalcAdvances(&qglyphs, (flags & HB_ShaperFlag_UseDesignMetrics) ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlags{});
145 }
146 
hb_canRender(HB_Font font,const HB_UChar16 * string,hb_uint32 length)147 static HB_Bool hb_canRender(HB_Font font, const HB_UChar16 *string, hb_uint32 length)
148 {
149     QFontEngine *fe = (QFontEngine *)font->userData;
150     return fe->canRender(reinterpret_cast<const QChar *>(string), length);
151 }
152 
hb_getGlyphMetrics(HB_Font font,HB_Glyph glyph,HB_GlyphMetrics * metrics)153 static void hb_getGlyphMetrics(HB_Font font, HB_Glyph glyph, HB_GlyphMetrics *metrics)
154 {
155     QFontEngine *fe = (QFontEngine *)font->userData;
156     glyph_metrics_t m = fe->boundingBox(glyph);
157     metrics->x = m.x.value();
158     metrics->y = m.y.value();
159     metrics->width = m.width.value();
160     metrics->height = m.height.value();
161     metrics->xOffset = m.xoff.value();
162     metrics->yOffset = m.yoff.value();
163 }
164 
hb_getFontMetric(HB_Font font,HB_FontMetric metric)165 static HB_Fixed hb_getFontMetric(HB_Font font, HB_FontMetric metric)
166 {
167     if (metric == HB_FontAscent) {
168         QFontEngine *fe = (QFontEngine *)font->userData;
169         return fe->ascent().value();
170     }
171     return 0;
172 }
173 
getPointInOutline(glyph_t glyph,int flags,quint32 point,QFixed * xpos,QFixed * ypos,quint32 * nPoints)174 int QFontEngine::getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints)
175 {
176     Q_UNUSED(glyph)
177     Q_UNUSED(flags)
178     Q_UNUSED(point)
179     Q_UNUSED(xpos)
180     Q_UNUSED(ypos)
181     Q_UNUSED(nPoints)
182     return Err_Not_Covered;
183 }
184 
hb_getPointInOutline(HB_Font font,HB_Glyph glyph,int flags,hb_uint32 point,HB_Fixed * xpos,HB_Fixed * ypos,hb_uint32 * nPoints)185 static HB_Error hb_getPointInOutline(HB_Font font, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
186 {
187     QFontEngine *fe = (QFontEngine *)font->userData;
188     return (HB_Error)fe->getPointInOutline(glyph, flags, point, (QFixed *)xpos, (QFixed *)ypos, (quint32 *)nPoints);
189 }
190 
191 static const HB_FontClass hb_fontClass = {
192     hb_stringToGlyphs, hb_getAdvances, hb_canRender, hb_getPointInOutline,
193     hb_getGlyphMetrics, hb_getFontMetric
194 };
195 
hb_getSFntTable(void * font,HB_Tag tableTag,HB_Byte * buffer,HB_UInt * length)196 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
197 {
198     QFontEngine::FaceData *data = (QFontEngine::FaceData *)font;
199     Q_ASSERT(data);
200 
201     qt_get_font_table_func_t get_font_table = data->get_font_table;
202     Q_ASSERT(get_font_table);
203 
204     if (!get_font_table(data->user_data, tableTag, buffer, length))
205         return HB_Err_Invalid_Argument;
206     return HB_Err_Ok;
207 }
208 
hb_freeFace(void * face)209 static void hb_freeFace(void *face)
210 {
211     qHBFreeFace((HB_Face)face);
212 }
213 
214 
qt_get_font_table_default(void * user_data,uint tag,uchar * buffer,uint * length)215 static bool qt_get_font_table_default(void *user_data, uint tag, uchar *buffer, uint *length)
216 {
217     QFontEngine *fe = (QFontEngine *)user_data;
218     return fe->getSfntTableData(tag, buffer, length);
219 }
220 
221 
222 #ifdef QT_BUILD_INTERNAL
223 // for testing purpose only, not thread-safe!
224 static QList<QFontEngine *> *enginesCollector = nullptr;
225 
QFontEngine_startCollectingEngines()226 Q_AUTOTEST_EXPORT void QFontEngine_startCollectingEngines()
227 {
228     delete enginesCollector;
229     enginesCollector = new QList<QFontEngine *>();
230 }
231 
QFontEngine_stopCollectingEngines()232 Q_AUTOTEST_EXPORT QList<QFontEngine *> QFontEngine_stopCollectingEngines()
233 {
234     Q_ASSERT(enginesCollector);
235     QList<QFontEngine *> ret = *enginesCollector;
236     delete enginesCollector;
237     enginesCollector = nullptr;
238     return ret;
239 }
240 #endif // QT_BUILD_INTERNAL
241 
242 
243 // QFontEngine
244 
245 #define kBearingNotInitialized std::numeric_limits<qreal>::max()
246 
QFontEngine(Type type)247 QFontEngine::QFontEngine(Type type)
248     : m_type(type), ref(0),
249       font_(),
250       face_(),
251       m_minLeftBearing(kBearingNotInitialized),
252       m_minRightBearing(kBearingNotInitialized)
253 {
254     faceData.user_data = this;
255     faceData.get_font_table = qt_get_font_table_default;
256 
257     cache_cost = 0;
258     fsType = 0;
259     symbol = false;
260     isSmoothlyScalable = false;
261 
262     glyphFormat = Format_None;
263     m_subPixelPositionCount = 0;
264 
265 #ifdef QT_BUILD_INTERNAL
266     if (enginesCollector)
267         enginesCollector->append(this);
268 #endif
269 }
270 
~QFontEngine()271 QFontEngine::~QFontEngine()
272 {
273 #ifdef QT_BUILD_INTERNAL
274     if (enginesCollector)
275         enginesCollector->removeOne(this);
276 #endif
277 }
278 
lineThickness() const279 QFixed QFontEngine::lineThickness() const
280 {
281     // ad hoc algorithm
282     int score = fontDef.weight * fontDef.pixelSize;
283     int lw = score / 700;
284 
285     // looks better with thicker line for small pointsizes
286     if (lw < 2 && score >= 1050) lw = 2;
287     if (lw == 0) lw = 1;
288 
289     return lw;
290 }
291 
underlinePosition() const292 QFixed QFontEngine::underlinePosition() const
293 {
294     return ((lineThickness() * 2) + 3) / 6;
295 }
296 
harfbuzzFont() const297 void *QFontEngine::harfbuzzFont() const
298 {
299     Q_ASSERT(type() != QFontEngine::Multi);
300 #if QT_CONFIG(harfbuzz)
301     if (qt_useHarfbuzzNG())
302         return hb_qt_font_get_for_engine(const_cast<QFontEngine *>(this));
303 #endif
304     if (!font_) {
305         HB_Face hbFace = (HB_Face)harfbuzzFace();
306         if (hbFace->font_for_init) {
307             void *data = hbFace->font_for_init;
308             q_check_ptr(qHBLoadFace(hbFace));
309             free(data);
310         }
311 
312         HB_FontRec *hbFont = (HB_FontRec *) malloc(sizeof(HB_FontRec));
313         Q_CHECK_PTR(hbFont);
314         hbFont->klass = &hb_fontClass;
315         hbFont->userData = const_cast<QFontEngine *>(this);
316 
317         qint64 emSquare = emSquareSize().truncate();
318         Q_ASSERT(emSquare == emSquareSize().toInt()); // ensure no truncation
319         if (emSquare == 0)
320             emSquare = 1000; // a fallback value suitable for Type1 fonts
321         hbFont->y_ppem = fontDef.pixelSize;
322         hbFont->x_ppem = fontDef.pixelSize * fontDef.stretch / 100;
323         // same as QFixed(x)/QFixed(emSquare) but without int32 overflow for x
324         hbFont->x_scale = (((qint64)hbFont->x_ppem << 6) * 0x10000L + (emSquare >> 1)) / emSquare;
325         hbFont->y_scale = (((qint64)hbFont->y_ppem << 6) * 0x10000L + (emSquare >> 1)) / emSquare;
326 
327         font_ = Holder(hbFont, free);
328     }
329     return font_.get();
330 }
331 
harfbuzzFace() const332 void *QFontEngine::harfbuzzFace() const
333 {
334     Q_ASSERT(type() != QFontEngine::Multi);
335 #if QT_CONFIG(harfbuzz)
336     if (qt_useHarfbuzzNG())
337         return hb_qt_face_get_for_engine(const_cast<QFontEngine *>(this));
338 #endif
339     if (!face_) {
340         QFontEngine::FaceData *data = (QFontEngine::FaceData *)malloc(sizeof(QFontEngine::FaceData));
341         Q_CHECK_PTR(data);
342         data->user_data = faceData.user_data;
343         data->get_font_table = faceData.get_font_table;
344 
345         HB_Face hbFace = qHBNewFace(data, hb_getSFntTable);
346         Q_CHECK_PTR(hbFace);
347         hbFace->isSymbolFont = symbol;
348 
349         face_ = Holder(hbFace, hb_freeFace);
350     }
351     return face_.get();
352 }
353 
supportsScript(QChar::Script script) const354 bool QFontEngine::supportsScript(QChar::Script script) const
355 {
356     if (type() <= QFontEngine::Multi)
357         return true;
358 
359     // ### TODO: This only works for scripts that require OpenType. More generally
360     // for scripts that do not require OpenType we should just look at the list of
361     // supported writing systems in the font's OS/2 table.
362     if (!scriptRequiresOpenType(script))
363         return true;
364 
365 #if QT_CONFIG(harfbuzz)
366     if (qt_useHarfbuzzNG()) {
367 #if defined(Q_OS_DARWIN)
368         // in AAT fonts, 'gsub' table is effectively replaced by 'mort'/'morx' table
369         uint lenMort = 0, lenMorx = 0;
370         if (getSfntTableData(MAKE_TAG('m','o','r','t'), 0, &lenMort) || getSfntTableData(MAKE_TAG('m','o','r','x'), 0, &lenMorx))
371             return true;
372 #endif
373 
374         bool ret = false;
375         if (hb_face_t *face = hb_qt_face_get_for_engine(const_cast<QFontEngine *>(this))) {
376             hb_tag_t script_tag_1, script_tag_2;
377             hb_ot_tags_from_script(hb_qt_script_to_script(script), &script_tag_1, &script_tag_2);
378 
379             unsigned int script_index;
380             ret = hb_ot_layout_table_find_script(face, HB_OT_TAG_GSUB, script_tag_1, &script_index);
381             if (!ret) {
382                 ret = hb_ot_layout_table_find_script(face, HB_OT_TAG_GSUB, script_tag_2, &script_index);
383                 if (!ret && script_tag_2 != HB_OT_TAG_DEFAULT_SCRIPT)
384                     ret = hb_ot_layout_table_find_script(face, HB_OT_TAG_GSUB, HB_OT_TAG_DEFAULT_SCRIPT, &script_index);
385             }
386         }
387         return ret;
388     }
389 #endif
390     HB_Face hbFace = (HB_Face)harfbuzzFace();
391     if (hbFace->font_for_init) {
392         void *data = hbFace->font_for_init;
393         q_check_ptr(qHBLoadFace(hbFace));
394         free(data);
395     }
396     return hbFace->supported_scripts[script_to_hbscript(script)];
397 }
398 
canRender(const QChar * str,int len) const399 bool QFontEngine::canRender(const QChar *str, int len) const
400 {
401     QStringIterator it(str, str + len);
402     while (it.hasNext()) {
403         if (glyphIndex(it.next()) == 0)
404             return false;
405     }
406 
407     return true;
408 }
409 
boundingBox(glyph_t glyph,const QTransform & matrix)410 glyph_metrics_t QFontEngine::boundingBox(glyph_t glyph, const QTransform &matrix)
411 {
412     glyph_metrics_t metrics = boundingBox(glyph);
413 
414     if (matrix.type() > QTransform::TxTranslate) {
415         return metrics.transformed(matrix);
416     }
417     return metrics;
418 }
419 
calculatedCapHeight() const420 QFixed QFontEngine::calculatedCapHeight() const
421 {
422     const glyph_t glyph = glyphIndex('H');
423     glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph);
424     return bb.height;
425 }
426 
xHeight() const427 QFixed QFontEngine::xHeight() const
428 {
429     const glyph_t glyph = glyphIndex('x');
430     glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph);
431     return bb.height;
432 }
433 
averageCharWidth() const434 QFixed QFontEngine::averageCharWidth() const
435 {
436     const glyph_t glyph = glyphIndex('x');
437     glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph);
438     return bb.xoff;
439 }
440 
supportsTransformation(const QTransform & transform) const441 bool QFontEngine::supportsTransformation(const QTransform &transform) const
442 {
443     return transform.type() < QTransform::TxProject;
444 }
445 
expectsGammaCorrectedBlending() const446 bool QFontEngine::expectsGammaCorrectedBlending() const
447 {
448     return true;
449 }
450 
getGlyphPositions(const QGlyphLayout & glyphs,const QTransform & matrix,QTextItem::RenderFlags flags,QVarLengthArray<glyph_t> & glyphs_out,QVarLengthArray<QFixedPoint> & positions)451 void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags,
452                                     QVarLengthArray<glyph_t> &glyphs_out, QVarLengthArray<QFixedPoint> &positions)
453 {
454     QFixed xpos;
455     QFixed ypos;
456 
457     const bool transform = matrix.m11() != 1.
458                            || matrix.m12() != 0.
459                            || matrix.m21() != 0.
460                            || matrix.m22() != 1.;
461     if (!transform) {
462         xpos = QFixed::fromReal(matrix.dx());
463         ypos = QFixed::fromReal(matrix.dy());
464     }
465 
466     int current = 0;
467     if (flags & QTextItem::RightToLeft) {
468         int i = glyphs.numGlyphs;
469         int totalKashidas = 0;
470         while(i--) {
471             if (glyphs.attributes[i].dontPrint)
472                 continue;
473             xpos += glyphs.advances[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);
474             totalKashidas += glyphs.justifications[i].nKashidas;
475         }
476         positions.resize(glyphs.numGlyphs+totalKashidas);
477         glyphs_out.resize(glyphs.numGlyphs+totalKashidas);
478 
479         i = 0;
480         while(i < glyphs.numGlyphs) {
481             if (glyphs.attributes[i].dontPrint) {
482                 ++i;
483                 continue;
484             }
485             xpos -= glyphs.advances[i];
486 
487             QFixed gpos_x = xpos + glyphs.offsets[i].x;
488             QFixed gpos_y = ypos + glyphs.offsets[i].y;
489             if (transform) {
490                 QPointF gpos(gpos_x.toReal(), gpos_y.toReal());
491                 gpos = gpos * matrix;
492                 gpos_x = QFixed::fromReal(gpos.x());
493                 gpos_y = QFixed::fromReal(gpos.y());
494             }
495             positions[current].x = gpos_x;
496             positions[current].y = gpos_y;
497             glyphs_out[current] = glyphs.glyphs[i];
498             ++current;
499             if (glyphs.justifications[i].nKashidas) {
500                 QChar ch(0x640); // Kashida character
501 
502                 glyph_t kashidaGlyph = glyphIndex(ch.unicode());
503                 QFixed kashidaWidth;
504 
505                 QGlyphLayout g;
506                 g.numGlyphs = 1;
507                 g.glyphs = &kashidaGlyph;
508                 g.advances = &kashidaWidth;
509                 recalcAdvances(&g, { });
510 
511                 for (uint k = 0; k < glyphs.justifications[i].nKashidas; ++k) {
512                     xpos -= kashidaWidth;
513 
514                     QFixed gpos_x = xpos + glyphs.offsets[i].x;
515                     QFixed gpos_y = ypos + glyphs.offsets[i].y;
516                     if (transform) {
517                         QPointF gpos(gpos_x.toReal(), gpos_y.toReal());
518                         gpos = gpos * matrix;
519                         gpos_x = QFixed::fromReal(gpos.x());
520                         gpos_y = QFixed::fromReal(gpos.y());
521                     }
522                     positions[current].x = gpos_x;
523                     positions[current].y = gpos_y;
524                     glyphs_out[current] = kashidaGlyph;
525                     ++current;
526                 }
527             } else {
528                 xpos -= QFixed::fromFixed(glyphs.justifications[i].space_18d6);
529             }
530             ++i;
531         }
532     } else {
533         positions.resize(glyphs.numGlyphs);
534         glyphs_out.resize(glyphs.numGlyphs);
535         int i = 0;
536         if (!transform) {
537             while (i < glyphs.numGlyphs) {
538                 if (!glyphs.attributes[i].dontPrint) {
539                     positions[current].x = xpos + glyphs.offsets[i].x;
540                     positions[current].y = ypos + glyphs.offsets[i].y;
541                     glyphs_out[current] = glyphs.glyphs[i];
542                     xpos += glyphs.advances[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);
543                     ++current;
544                 }
545                 ++i;
546             }
547         } else {
548             while (i < glyphs.numGlyphs) {
549                 if (!glyphs.attributes[i].dontPrint) {
550                     QFixed gpos_x = xpos + glyphs.offsets[i].x;
551                     QFixed gpos_y = ypos + glyphs.offsets[i].y;
552                     QPointF gpos(gpos_x.toReal(), gpos_y.toReal());
553                     gpos = gpos * matrix;
554                     positions[current].x = QFixed::fromReal(gpos.x());
555                     positions[current].y = QFixed::fromReal(gpos.y());
556                     glyphs_out[current] = glyphs.glyphs[i];
557                     xpos += glyphs.advances[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);
558                     ++current;
559                 }
560                 ++i;
561             }
562         }
563     }
564     positions.resize(current);
565     glyphs_out.resize(current);
566     Q_ASSERT(positions.size() == glyphs_out.size());
567 }
568 
getGlyphBearings(glyph_t glyph,qreal * leftBearing,qreal * rightBearing)569 void QFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
570 {
571     glyph_metrics_t gi = boundingBox(glyph);
572     if (leftBearing != nullptr)
573         *leftBearing = gi.leftBearing().toReal();
574     if (rightBearing != nullptr)
575         *rightBearing = gi.rightBearing().toReal();
576 }
577 
minLeftBearing() const578 qreal QFontEngine::minLeftBearing() const
579 {
580     if (m_minLeftBearing == kBearingNotInitialized)
581         minRightBearing(); // Initializes both (see below)
582 
583     return m_minLeftBearing;
584 }
585 
586 #define q16Dot16ToFloat(i) ((i) / 65536.0)
587 
588 #define kMinLeftSideBearingOffset 12
589 #define kMinRightSideBearingOffset 14
590 
minRightBearing() const591 qreal QFontEngine::minRightBearing() const
592 {
593     if (m_minRightBearing == kBearingNotInitialized) {
594 
595         // Try the 'hhea' font table first, which covers the entire font
596         QByteArray hheaTable = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a'));
597         if (hheaTable.size() >= int(kMinRightSideBearingOffset + sizeof(qint16))) {
598             const uchar *tableData = reinterpret_cast<const uchar *>(hheaTable.constData());
599             Q_ASSERT(q16Dot16ToFloat(qFromBigEndian<quint32>(tableData)) == 1.0);
600 
601             qint16 minLeftSideBearing = qFromBigEndian<qint16>(tableData + kMinLeftSideBearingOffset);
602             qint16 minRightSideBearing = qFromBigEndian<qint16>(tableData + kMinRightSideBearingOffset);
603 
604             // The table data is expressed as FUnits, meaning we have to take the number
605             // of units per em into account. Since pixelSize already has taken DPI into
606             // account we can use that directly instead of the point size.
607             int unitsPerEm = emSquareSize().toInt();
608             qreal funitToPixelFactor = fontDef.pixelSize / unitsPerEm;
609 
610             // Some fonts on OS X (such as Gurmukhi Sangam MN, Khmer MN, Lao Sangam MN, etc.), have
611             // invalid values for their NBSPACE left bearing, causing the 'hhea' minimum bearings to
612             // be way off. We detect this by assuming that the minimum bearsings are within a certain
613             // range of the em square size.
614             static const int largestValidBearing = 4 * unitsPerEm;
615 
616             if (qAbs(minLeftSideBearing) < largestValidBearing)
617                 m_minLeftBearing = minLeftSideBearing * funitToPixelFactor;
618             if (qAbs(minRightSideBearing) < largestValidBearing)
619                 m_minRightBearing = minRightSideBearing * funitToPixelFactor;
620         }
621 
622         // Fallback in case of missing 'hhea' table (bitmap fonts e.g.) or broken 'hhea' values
623         if (m_minLeftBearing == kBearingNotInitialized || m_minRightBearing == kBearingNotInitialized) {
624 
625             // To balance performance and correctness we only look at a subset of the
626             // possible glyphs in the font, based on which characters are more likely
627             // to have a left or right bearing.
628             static const ushort characterSubset[] = {
629                 '(', 'C', 'F', 'K', 'V', 'X', 'Y', ']', '_', 'f', 'r', '|',
630                 127, 205, 645, 884, 922, 1070, 12386
631             };
632 
633             // The font may have minimum bearings larger than 0, so we have to start at the max
634             m_minLeftBearing = m_minRightBearing = std::numeric_limits<qreal>::max();
635 
636             for (uint i = 0; i < (sizeof(characterSubset) / sizeof(ushort)); ++i) {
637                 const glyph_t glyph = glyphIndex(characterSubset[i]);
638                 if (!glyph)
639                     continue;
640 
641                 glyph_metrics_t glyphMetrics = const_cast<QFontEngine *>(this)->boundingBox(glyph);
642 
643                 // Glyphs with no contours shouldn't contribute to bearings
644                 if (!glyphMetrics.width || !glyphMetrics.height)
645                     continue;
646 
647                 m_minLeftBearing = qMin(m_minLeftBearing, glyphMetrics.leftBearing().toReal());
648                 m_minRightBearing = qMin(m_minRightBearing, glyphMetrics.rightBearing().toReal());
649             }
650         }
651 
652         if (m_minLeftBearing == kBearingNotInitialized || m_minRightBearing == kBearingNotInitialized)
653             qWarning() << "Failed to compute left/right minimum bearings for" << fontDef.family;
654     }
655 
656     return m_minRightBearing;
657 }
658 
tightBoundingBox(const QGlyphLayout & glyphs)659 glyph_metrics_t QFontEngine::tightBoundingBox(const QGlyphLayout &glyphs)
660 {
661     glyph_metrics_t overall;
662 
663     QFixed ymax = 0;
664     QFixed xmax = 0;
665     for (int i = 0; i < glyphs.numGlyphs; i++) {
666         // If shaping has found this should be ignored, ignore it.
667         if (!glyphs.advances[i] || glyphs.attributes[i].dontPrint)
668             continue;
669         glyph_metrics_t bb = boundingBox(glyphs.glyphs[i]);
670         QFixed x = overall.xoff + glyphs.offsets[i].x + bb.x;
671         QFixed y = overall.yoff + glyphs.offsets[i].y + bb.y;
672         overall.x = qMin(overall.x, x);
673         overall.y = qMin(overall.y, y);
674         xmax = qMax(xmax, x + bb.width);
675         ymax = qMax(ymax, y + bb.height);
676         overall.xoff += bb.xoff;
677         overall.yoff += bb.yoff;
678     }
679     overall.height = qMax(overall.height, ymax - overall.y);
680     overall.width = xmax - overall.x;
681 
682     return overall;
683 }
684 
685 
addOutlineToPath(qreal x,qreal y,const QGlyphLayout & glyphs,QPainterPath * path,QTextItem::RenderFlags flags)686 void QFontEngine::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path,
687                                    QTextItem::RenderFlags flags)
688 {
689     if (!glyphs.numGlyphs)
690         return;
691 
692     QVarLengthArray<QFixedPoint> positions;
693     QVarLengthArray<glyph_t> positioned_glyphs;
694     QTransform matrix = QTransform::fromTranslate(x, y);
695     getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
696     addGlyphsToPath(positioned_glyphs.data(), positions.data(), positioned_glyphs.size(), path, flags);
697 }
698 
699 #define GRID(x, y) grid[(y)*(w+1) + (x)]
700 #define SET(x, y) (*(image_data + (y)*bpl + ((x) >> 3)) & (0x80 >> ((x) & 7)))
701 
702 enum { EdgeRight = 0x1,
703        EdgeDown = 0x2,
704        EdgeLeft = 0x4,
705        EdgeUp = 0x8
706 };
707 
collectSingleContour(qreal x0,qreal y0,uint * grid,int x,int y,int w,int h,QPainterPath * path)708 static void collectSingleContour(qreal x0, qreal y0, uint *grid, int x, int y, int w, int h, QPainterPath *path)
709 {
710     Q_UNUSED(h);
711 
712     path->moveTo(x + x0, y + y0);
713     while (GRID(x, y)) {
714         if (GRID(x, y) & EdgeRight) {
715             while (GRID(x, y) & EdgeRight) {
716                 GRID(x, y) &= ~EdgeRight;
717                 ++x;
718             }
719             Q_ASSERT(x <= w);
720             path->lineTo(x + x0, y + y0);
721             continue;
722         }
723         if (GRID(x, y) & EdgeDown) {
724             while (GRID(x, y) & EdgeDown) {
725                 GRID(x, y) &= ~EdgeDown;
726                 ++y;
727             }
728             Q_ASSERT(y <= h);
729             path->lineTo(x + x0, y + y0);
730             continue;
731         }
732         if (GRID(x, y) & EdgeLeft) {
733             while (GRID(x, y) & EdgeLeft) {
734                 GRID(x, y) &= ~EdgeLeft;
735                 --x;
736             }
737             Q_ASSERT(x >= 0);
738             path->lineTo(x + x0, y + y0);
739             continue;
740         }
741         if (GRID(x, y) & EdgeUp) {
742             while (GRID(x, y) & EdgeUp) {
743                 GRID(x, y) &= ~EdgeUp;
744                 --y;
745             }
746             Q_ASSERT(y >= 0);
747             path->lineTo(x + x0, y + y0);
748             continue;
749         }
750     }
751     path->closeSubpath();
752 }
753 
qt_addBitmapToPath(qreal x0,qreal y0,const uchar * image_data,int bpl,int w,int h,QPainterPath * path)754 Q_GUI_EXPORT void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path)
755 {
756     uint *grid = new uint[(w+1)*(h+1)];
757     // set up edges
758     for (int y = 0; y <= h; ++y) {
759         for (int x = 0; x <= w; ++x) {
760             bool topLeft = (x == 0 || y == 0) ? false : SET(x - 1, y - 1);
761             bool topRight = (x == w || y == 0) ? false : SET(x, y - 1);
762             bool bottomLeft = (x == 0 || y == h) ? false : SET(x - 1, y);
763             bool bottomRight = (x == w || y == h) ? false : SET(x, y);
764 
765             GRID(x, y) = 0;
766             if ((!topRight) & bottomRight)
767                 GRID(x, y) |= EdgeRight;
768             if ((!bottomRight) & bottomLeft)
769                 GRID(x, y) |= EdgeDown;
770             if ((!bottomLeft) & topLeft)
771                 GRID(x, y) |= EdgeLeft;
772             if ((!topLeft) & topRight)
773                 GRID(x, y) |= EdgeUp;
774         }
775     }
776 
777     // collect edges
778     for (int y = 0; y < h; ++y) {
779         for (int x = 0; x < w; ++x) {
780             if (!GRID(x, y))
781                 continue;
782             // found start of a contour, follow it
783             collectSingleContour(x0, y0, grid, x, y, w, h, path);
784         }
785     }
786     delete [] grid;
787 }
788 
789 #undef GRID
790 #undef SET
791 
792 
addBitmapFontToPath(qreal x,qreal y,const QGlyphLayout & glyphs,QPainterPath * path,QTextItem::RenderFlags flags)793 void QFontEngine::addBitmapFontToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
794                                       QPainterPath *path, QTextItem::RenderFlags flags)
795 {
796 // TODO what to do with 'flags' ??
797     Q_UNUSED(flags);
798     QFixed advanceX = QFixed::fromReal(x);
799     QFixed advanceY = QFixed::fromReal(y);
800     for (int i=0; i < glyphs.numGlyphs; ++i) {
801         glyph_metrics_t metrics = boundingBox(glyphs.glyphs[i]);
802         if (metrics.width.value() == 0 || metrics.height.value() == 0) {
803             advanceX += glyphs.advances[i];
804             continue;
805         }
806         const QImage alphaMask = alphaMapForGlyph(glyphs.glyphs[i]);
807 
808         const int w = alphaMask.width();
809         const int h = alphaMask.height();
810         const int srcBpl = alphaMask.bytesPerLine();
811         QImage bitmap;
812         if (alphaMask.depth() == 1) {
813             bitmap = alphaMask;
814         } else {
815             bitmap = QImage(w, h, QImage::Format_Mono);
816             const uchar *imageData = alphaMask.bits();
817             const int destBpl = bitmap.bytesPerLine();
818             uchar *bitmapData = bitmap.bits();
819 
820             for (int yi = 0; yi < h; ++yi) {
821                 const uchar *src = imageData + yi*srcBpl;
822                 uchar *dst = bitmapData + yi*destBpl;
823                 for (int xi = 0; xi < w; ++xi) {
824                     const int byte = xi / 8;
825                     const int bit = xi % 8;
826                     if (bit == 0)
827                         dst[byte] = 0;
828                     if (src[xi])
829                         dst[byte] |= 128 >> bit;
830                 }
831             }
832         }
833         const uchar *bitmap_data = bitmap.constBits();
834         QFixedPoint offset = glyphs.offsets[i];
835         advanceX += offset.x;
836         advanceY += offset.y;
837         qt_addBitmapToPath((advanceX + metrics.x).toReal(), (advanceY + metrics.y).toReal(), bitmap_data, bitmap.bytesPerLine(), w, h, path);
838         advanceX += glyphs.advances[i];
839     }
840 }
841 
addGlyphsToPath(glyph_t * glyphs,QFixedPoint * positions,int nGlyphs,QPainterPath * path,QTextItem::RenderFlags flags)842 void QFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nGlyphs,
843                                   QPainterPath *path, QTextItem::RenderFlags flags)
844 {
845     qreal x = positions[0].x.toReal();
846     qreal y = positions[0].y.toReal();
847     QVarLengthGlyphLayoutArray g(nGlyphs);
848 
849     for (int i = 0; i < nGlyphs - 1; ++i) {
850         g.glyphs[i] = glyphs[i];
851         g.advances[i] = positions[i + 1].x - positions[i].x;
852     }
853     g.glyphs[nGlyphs - 1] = glyphs[nGlyphs - 1];
854     g.advances[nGlyphs - 1] = QFixed::fromReal(maxCharWidth());
855 
856     addBitmapFontToPath(x, y, g, path, flags);
857 }
858 
alphaMapForGlyph(glyph_t glyph,QFixed)859 QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed /*subPixelPosition*/)
860 {
861     // For font engines don't support subpixel positioning
862     return alphaMapForGlyph(glyph);
863 }
864 
alphaMapForGlyph(glyph_t glyph,const QTransform & t)865 QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &t)
866 {
867     QImage i = alphaMapForGlyph(glyph);
868     if (t.type() > QTransform::TxTranslate)
869         i = i.transformed(t).convertToFormat(QImage::Format_Alpha8);
870     Q_ASSERT(i.depth() <= 8); // To verify that transformed didn't change the format...
871 
872     return i;
873 }
874 
alphaMapForGlyph(glyph_t glyph,QFixed subPixelPosition,const QTransform & t)875 QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
876 {
877     if (! supportsSubPixelPositions())
878         return alphaMapForGlyph(glyph, t);
879 
880     QImage i = alphaMapForGlyph(glyph, subPixelPosition);
881     if (t.type() > QTransform::TxTranslate)
882         i = i.transformed(t).convertToFormat(QImage::Format_Alpha8);
883     Q_ASSERT(i.depth() <= 8); // To verify that transformed didn't change the format...
884 
885     return i;
886 }
887 
alphaRGBMapForGlyph(glyph_t glyph,QFixed,const QTransform & t)888 QImage QFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed /*subPixelPosition*/, const QTransform &t)
889 {
890     const QImage alphaMask = alphaMapForGlyph(glyph, t);
891     QImage rgbMask(alphaMask.width(), alphaMask.height(), QImage::Format_RGB32);
892 
893     for (int y=0; y<alphaMask.height(); ++y) {
894         uint *dst = (uint *) rgbMask.scanLine(y);
895         const uchar *src = alphaMask.constScanLine(y);
896         for (int x=0; x<alphaMask.width(); ++x) {
897             int val = src[x];
898             dst[x] = qRgb(val, val, val);
899         }
900     }
901 
902     return rgbMask;
903 }
904 
bitmapForGlyph(glyph_t,QFixed subPixelPosition,const QTransform &,const QColor &)905 QImage QFontEngine::bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform&, const QColor &)
906 {
907     Q_UNUSED(subPixelPosition);
908 
909     return QImage();
910 }
911 
subPixelPositionForX(QFixed x) const912 QFixed QFontEngine::subPixelPositionForX(QFixed x) const
913 {
914     if (m_subPixelPositionCount <= 1 || !supportsSubPixelPositions())
915         return QFixed();
916 
917     QFixed subPixelPosition;
918     if (x != 0) {
919         subPixelPosition = x - x.floor();
920         QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor();
921 
922         // Compensate for precision loss in fixed point to make sure we are always drawing at a subpixel position over
923         // the lower boundary for the selected rasterization by adding 1/64.
924         subPixelPosition = fraction / QFixed(m_subPixelPositionCount) + QFixed::fromReal(0.015625);
925     }
926     return subPixelPosition;
927 }
928 
glyphData(glyph_t,QFixed,QFontEngine::GlyphFormat,const QTransform &)929 QFontEngine::Glyph *QFontEngine::glyphData(glyph_t, QFixed,
930                                            QFontEngine::GlyphFormat, const QTransform &)
931 {
932     return nullptr;
933 }
934 
alphaMapForGlyph(glyph_t glyph)935 QImage QFontEngine::alphaMapForGlyph(glyph_t glyph)
936 {
937     glyph_metrics_t gm = boundingBox(glyph);
938     int glyph_x = qFloor(gm.x.toReal());
939     int glyph_y = qFloor(gm.y.toReal());
940     int glyph_width = qCeil((gm.x + gm.width).toReal()) -  glyph_x;
941     int glyph_height = qCeil((gm.y + gm.height).toReal()) - glyph_y;
942 
943     if (glyph_width <= 0 || glyph_height <= 0)
944         return QImage();
945     QFixedPoint pt;
946     pt.x = -glyph_x;
947     pt.y = -glyph_y; // the baseline
948     QPainterPath path;
949     path.setFillRule(Qt::WindingFill);
950     QImage im(glyph_width, glyph_height, QImage::Format_ARGB32_Premultiplied);
951     im.fill(Qt::transparent);
952     QPainter p(&im);
953     p.setRenderHint(QPainter::Antialiasing);
954     addGlyphsToPath(&glyph, &pt, 1, &path, { });
955     p.setPen(Qt::NoPen);
956     p.setBrush(Qt::black);
957     p.drawPath(path);
958     p.end();
959 
960     QImage alphaMap(im.width(), im.height(), QImage::Format_Alpha8);
961 
962     for (int y=0; y<im.height(); ++y) {
963         uchar *dst = (uchar *) alphaMap.scanLine(y);
964         const uint *src = reinterpret_cast<const uint *>(im.constScanLine(y));
965         for (int x=0; x<im.width(); ++x)
966             dst[x] = qAlpha(src[x]);
967     }
968 
969     return alphaMap;
970 }
971 
removeGlyphFromCache(glyph_t)972 void QFontEngine::removeGlyphFromCache(glyph_t)
973 {
974 }
975 
properties() const976 QFontEngine::Properties QFontEngine::properties() const
977 {
978     Properties p;
979     p.postscriptName
980             = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8())
981             + '-'
982             + QByteArray::number(fontDef.style)
983             + '-'
984             + QByteArray::number(fontDef.weight);
985     p.ascent = ascent();
986     p.descent = descent();
987     p.leading = leading();
988     p.emSquare = p.ascent;
989     p.boundingBox = QRectF(0, -p.ascent.toReal(), maxCharWidth(), (p.ascent + p.descent).toReal());
990     p.italicAngle = 0;
991     p.capHeight = p.ascent;
992     p.lineWidth = lineThickness();
993     return p;
994 }
995 
getUnscaledGlyph(glyph_t glyph,QPainterPath * path,glyph_metrics_t * metrics)996 void QFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
997 {
998     *metrics = boundingBox(glyph);
999     QFixedPoint p;
1000     p.x = 0;
1001     p.y = 0;
1002     addGlyphsToPath(&glyph, &p, 1, path, QFlag(0));
1003 }
1004 
1005 /*!
1006     Returns \c true if the font table idetified by \a tag exists in the font;
1007     returns \c false otherwise.
1008 
1009     If \a buffer is \nullptr, stores the size of the buffer required for the font table data,
1010     in bytes, in \a length. If \a buffer is not \nullptr and the capacity
1011     of the buffer, passed in \a length, is sufficient to store the font table data,
1012     also copies the font table data to \a buffer.
1013 
1014     Note: returning \c false when the font table exists could lead to an undefined behavior.
1015 */
getSfntTableData(uint tag,uchar * buffer,uint * length) const1016 bool QFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1017 {
1018     Q_UNUSED(tag)
1019     Q_UNUSED(buffer)
1020     Q_UNUSED(length)
1021     return false;
1022 }
1023 
getSfntTable(uint tag) const1024 QByteArray QFontEngine::getSfntTable(uint tag) const
1025 {
1026     QByteArray table;
1027     uint len = 0;
1028     if (!getSfntTableData(tag, nullptr, &len))
1029         return table;
1030     table.resize(len);
1031     if (!getSfntTableData(tag, reinterpret_cast<uchar *>(table.data()), &len))
1032         return QByteArray();
1033     return table;
1034 }
1035 
clearGlyphCache(const void * context)1036 void QFontEngine::clearGlyphCache(const void *context)
1037 {
1038     m_glyphCaches.remove(context);
1039 }
1040 
setGlyphCache(const void * context,QFontEngineGlyphCache * cache)1041 void QFontEngine::setGlyphCache(const void *context, QFontEngineGlyphCache *cache)
1042 {
1043     Q_ASSERT(cache);
1044 
1045     GlyphCaches &caches = m_glyphCaches[context];
1046     for (auto & e : caches) {
1047         if (cache == e.cache.data())
1048             return;
1049     }
1050 
1051     // Limit the glyph caches to 4 per context. This covers all 90 degree rotations,
1052     // and limits memory use when there is continuous or random rotation
1053     if (caches.size() == 4)
1054         caches.pop_back();
1055 
1056     GlyphCacheEntry entry;
1057     entry.cache = cache;
1058     caches.push_front(entry);
1059 
1060 }
1061 
glyphCache(const void * context,GlyphFormat format,const QTransform & transform,const QColor & color) const1062 QFontEngineGlyphCache *QFontEngine::glyphCache(const void *context,
1063                                                GlyphFormat format,
1064                                                const QTransform &transform,
1065                                                const QColor &color) const
1066 {
1067     const QHash<const void*, GlyphCaches>::const_iterator caches = m_glyphCaches.constFind(context);
1068     if (caches == m_glyphCaches.cend())
1069         return nullptr;
1070 
1071     for (auto &e : *caches) {
1072         QFontEngineGlyphCache *cache = e.cache.data();
1073         if (format == cache->glyphFormat()
1074                 && (format != Format_ARGB || color == cache->color())
1075                 && qtransform_equals_no_translate(cache->m_transform, transform)) {
1076             return cache;
1077         }
1078     }
1079 
1080     return nullptr;
1081 }
1082 
kerning(int left,int right,const QFontEngine::KernPair * pairs,int numPairs)1083 static inline QFixed kerning(int left, int right, const QFontEngine::KernPair *pairs, int numPairs)
1084 {
1085     uint left_right = (left << 16) + right;
1086 
1087     left = 0, right = numPairs - 1;
1088     while (left <= right) {
1089         int middle = left + ( ( right - left ) >> 1 );
1090 
1091         if(pairs[middle].left_right == left_right)
1092             return pairs[middle].adjust;
1093 
1094         if (pairs[middle].left_right < left_right)
1095             left = middle + 1;
1096         else
1097             right = middle - 1;
1098     }
1099     return 0;
1100 }
1101 
doKerning(QGlyphLayout * glyphs,QFontEngine::ShaperFlags flags) const1102 void QFontEngine::doKerning(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
1103 {
1104     int numPairs = kerning_pairs.size();
1105     if(!numPairs)
1106         return;
1107 
1108     const KernPair *pairs = kerning_pairs.constData();
1109 
1110     if (flags & DesignMetrics) {
1111         for(int i = 0; i < glyphs->numGlyphs - 1; ++i)
1112             glyphs->advances[i] += kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs);
1113     } else {
1114         for(int i = 0; i < glyphs->numGlyphs - 1; ++i)
1115             glyphs->advances[i] += qRound(kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs));
1116     }
1117 }
1118 
loadKerningPairs(QFixed scalingFactor)1119 void QFontEngine::loadKerningPairs(QFixed scalingFactor)
1120 {
1121     kerning_pairs.clear();
1122 
1123     QByteArray tab = getSfntTable(MAKE_TAG('k', 'e', 'r', 'n'));
1124     if (tab.isEmpty())
1125         return;
1126 
1127     const uchar *table = reinterpret_cast<const uchar *>(tab.constData());
1128     const uchar *end = table + tab.size();
1129 
1130     quint16 version;
1131     if (!qSafeFromBigEndian(table, end, &version))
1132         return;
1133 
1134     if (version != 0) {
1135 //        qDebug("wrong version");
1136        return;
1137     }
1138 
1139     quint16 numTables;
1140     if (!qSafeFromBigEndian(table + 2, end, &numTables))
1141         return;
1142 
1143     {
1144         int offset = 4;
1145         for(int i = 0; i < numTables; ++i) {
1146             const uchar *header = table + offset;
1147 
1148             quint16 version;
1149             if (!qSafeFromBigEndian(header, end, &version))
1150                 goto end;
1151 
1152             quint16 length;
1153             if (!qSafeFromBigEndian(header + 2, end, &length))
1154                 goto end;
1155 
1156             quint16 coverage;
1157             if (!qSafeFromBigEndian(header + 4, end, &coverage))
1158                 goto end;
1159 
1160 //            qDebug("subtable: version=%d, coverage=%x",version, coverage);
1161             if(version == 0 && coverage == 0x0001) {
1162                 if (offset + length > tab.size()) {
1163 //                    qDebug("length ouf ot bounds");
1164                     goto end;
1165                 }
1166                 const uchar *data = table + offset + 6;
1167 
1168                 quint16 nPairs;
1169                 if (!qSafeFromBigEndian(data, end, &nPairs))
1170                     goto end;
1171 
1172                 if(nPairs * 6 + 8 > length - 6) {
1173 //                    qDebug("corrupt table!");
1174                     // corrupt table
1175                     goto end;
1176                 }
1177 
1178                 int off = 8;
1179                 for(int i = 0; i < nPairs; ++i) {
1180                     QFontEngine::KernPair p;
1181 
1182                     quint16 tmp;
1183                     if (!qSafeFromBigEndian(data + off, end, &tmp))
1184                         goto end;
1185 
1186                     p.left_right = uint(tmp) << 16;
1187                     if (!qSafeFromBigEndian(data + off + 2, end, &tmp))
1188                         goto end;
1189 
1190                     p.left_right |= tmp;
1191 
1192                     if (!qSafeFromBigEndian(data + off + 4, end, &tmp))
1193                         goto end;
1194 
1195                     p.adjust = QFixed(int(short(tmp))) / scalingFactor;
1196                     kerning_pairs.append(p);
1197                     off += 6;
1198                 }
1199             }
1200             offset += length;
1201         }
1202     }
1203 end:
1204     std::sort(kerning_pairs.begin(), kerning_pairs.end());
1205 //    for (int i = 0; i < kerning_pairs.count(); ++i)
1206 //        qDebug() << 'i' << i << "left_right" << Qt::hex << kerning_pairs.at(i).left_right;
1207 }
1208 
1209 
glyphCount() const1210 int QFontEngine::glyphCount() const
1211 {
1212     QByteArray maxpTable = getSfntTable(MAKE_TAG('m', 'a', 'x', 'p'));
1213     if (maxpTable.size() < 6)
1214         return 0;
1215 
1216     const uchar *source = reinterpret_cast<const uchar *>(maxpTable.constData() + 4);
1217     const uchar *end = source + maxpTable.size();
1218 
1219     quint16 count = 0;
1220     qSafeFromBigEndian(source, end, &count);
1221     return count;
1222 }
1223 
handle() const1224 Qt::HANDLE QFontEngine::handle() const
1225 {
1226     return nullptr;
1227 }
1228 
getCMap(const uchar * table,uint tableSize,bool * isSymbolFont,int * cmapSize)1229 const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize)
1230 {
1231     const uchar *header = table;
1232     const uchar *endPtr = table + tableSize;
1233 
1234     // version check
1235     quint16 version;
1236     if (!qSafeFromBigEndian(header, endPtr, &version) || version != 0)
1237         return nullptr;
1238 
1239     quint16 numTables;
1240     if (!qSafeFromBigEndian(header + 2, endPtr, &numTables))
1241         return nullptr;
1242 
1243     const uchar *maps = table + 4;
1244 
1245     enum {
1246         Invalid,
1247         AppleRoman,
1248         Symbol,
1249         Unicode11,
1250         Unicode,
1251         MicrosoftUnicode,
1252         MicrosoftUnicodeExtended
1253     };
1254 
1255     int symbolTable = -1;
1256     int tableToUse = -1;
1257     int score = Invalid;
1258     for (int n = 0; n < numTables; ++n) {
1259         quint16 platformId;
1260         if (!qSafeFromBigEndian(maps + 8 * n, endPtr, &platformId))
1261             return nullptr;
1262 
1263         quint16 platformSpecificId = 0;
1264         if (!qSafeFromBigEndian(maps + 8 * n + 2, endPtr, &platformSpecificId))
1265             return nullptr;
1266 
1267         switch (platformId) {
1268         case 0: // Unicode
1269             if (score < Unicode &&
1270                 (platformSpecificId == 0 ||
1271                  platformSpecificId == 2 ||
1272                  platformSpecificId == 3)) {
1273                 tableToUse = n;
1274                 score = Unicode;
1275             } else if (score < Unicode11 && platformSpecificId == 1) {
1276                 tableToUse = n;
1277                 score = Unicode11;
1278             }
1279             break;
1280         case 1: // Apple
1281             if (score < AppleRoman && platformSpecificId == 0) { // Apple Roman
1282                 tableToUse = n;
1283                 score = AppleRoman;
1284             }
1285             break;
1286         case 3: // Microsoft
1287             switch (platformSpecificId) {
1288             case 0:
1289                 symbolTable = n;
1290                 if (score < Symbol) {
1291                     tableToUse = n;
1292                     score = Symbol;
1293                 }
1294                 break;
1295             case 1:
1296                 if (score < MicrosoftUnicode) {
1297                     tableToUse = n;
1298                     score = MicrosoftUnicode;
1299                 }
1300                 break;
1301             case 0xa:
1302                 if (score < MicrosoftUnicodeExtended) {
1303                     tableToUse = n;
1304                     score = MicrosoftUnicodeExtended;
1305                 }
1306                 break;
1307             default:
1308                 break;
1309             }
1310         default:
1311             break;
1312         }
1313     }
1314     if(tableToUse < 0)
1315         return nullptr;
1316 
1317 resolveTable:
1318     *isSymbolFont = (symbolTable > -1);
1319 
1320     quint32 unicode_table = 0;
1321     if (!qSafeFromBigEndian(maps + 8 * tableToUse + 4, endPtr, &unicode_table))
1322         return nullptr;
1323 
1324     if (!unicode_table)
1325         return nullptr;
1326 
1327     // get the header of the unicode table
1328     header = table + unicode_table;
1329 
1330     quint16 format;
1331     if (!qSafeFromBigEndian(header, endPtr, &format))
1332         return nullptr;
1333 
1334     quint32 length;
1335     if (format < 8) {
1336         quint16 tmp;
1337         if (!qSafeFromBigEndian(header + 2, endPtr, &tmp))
1338             return nullptr;
1339         length = tmp;
1340     } else {
1341         if (!qSafeFromBigEndian(header + 4, endPtr, &length))
1342             return nullptr;
1343     }
1344 
1345     if (table + unicode_table + length > endPtr)
1346         return nullptr;
1347     *cmapSize = length;
1348 
1349     // To support symbol fonts that contain a unicode table for the symbol area
1350     // we check the cmap tables and fall back to symbol font unless that would
1351     // involve losing information from the unicode table
1352     if (symbolTable > -1 && ((score == Unicode) || (score == Unicode11))) {
1353         const uchar *selectedTable = table + unicode_table;
1354 
1355         // Check that none of the latin1 range are in the unicode table
1356         bool unicodeTableHasLatin1 = false;
1357         for (int uc=0x00; uc<0x100; ++uc) {
1358             if (getTrueTypeGlyphIndex(selectedTable, length, uc) != 0) {
1359                 unicodeTableHasLatin1 = true;
1360                 break;
1361             }
1362         }
1363 
1364         // Check that at least one symbol char is in the unicode table
1365         bool unicodeTableHasSymbols = false;
1366         if (!unicodeTableHasLatin1) {
1367             for (int uc=0xf000; uc<0xf100; ++uc) {
1368                 if (getTrueTypeGlyphIndex(selectedTable, length, uc) != 0) {
1369                     unicodeTableHasSymbols = true;
1370                     break;
1371                 }
1372             }
1373         }
1374 
1375         // Fall back to symbol table
1376         if (!unicodeTableHasLatin1 && unicodeTableHasSymbols) {
1377             tableToUse = symbolTable;
1378             score = Symbol;
1379             goto resolveTable;
1380         }
1381     }
1382 
1383     return table + unicode_table;
1384 }
1385 
getTrueTypeGlyphIndex(const uchar * cmap,int cmapSize,uint unicode)1386 quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode)
1387 {
1388     const uchar *end = cmap + cmapSize;
1389     quint16 format;
1390     if (!qSafeFromBigEndian(cmap, end, &format))
1391         return 0;
1392 
1393     if (format == 0) {
1394         const uchar *ptr = cmap + 6 + unicode;
1395         if (unicode < 256 && ptr < end)
1396             return quint32(*ptr);
1397     } else if (format == 4) {
1398         /* some fonts come with invalid cmap tables, where the last segment
1399            specified end = start = rangeoffset = 0xffff, delta = 0x0001
1400            Since 0xffff is never a valid Unicode char anyway, we just get rid of the issue
1401            by returning 0 for 0xffff
1402         */
1403         if(unicode >= 0xffff)
1404             return 0;
1405 
1406         quint16 segCountX2;
1407         if (!qSafeFromBigEndian(cmap + 6, end, &segCountX2))
1408             return 0;
1409 
1410         const unsigned char *ends = cmap + 14;
1411 
1412         int i = 0;
1413         for (; i < segCountX2/2; ++i) {
1414             quint16 codePoint;
1415             if (!qSafeFromBigEndian(ends + 2 * i, end, &codePoint))
1416                 return 0;
1417             if (codePoint >= unicode)
1418                 break;
1419         }
1420 
1421         const unsigned char *idx = ends + segCountX2 + 2 + 2*i;
1422 
1423         quint16 startIndex;
1424         if (!qSafeFromBigEndian(idx, end, &startIndex))
1425             return 0;
1426         if (startIndex > unicode)
1427             return 0;
1428 
1429         idx += segCountX2;
1430 
1431         quint16 tmp;
1432         if (!qSafeFromBigEndian(idx, end, &tmp))
1433             return 0;
1434         qint16 idDelta = qint16(tmp);
1435 
1436         idx += segCountX2;
1437 
1438         quint16 idRangeoffset_t;
1439         if (!qSafeFromBigEndian(idx, end, &idRangeoffset_t))
1440             return 0;
1441 
1442         quint16 glyphIndex;
1443         if (idRangeoffset_t) {
1444             quint16 id;
1445             if (!qSafeFromBigEndian(idRangeoffset_t + 2 * (unicode - startIndex) + idx, end, &id))
1446                 return 0;
1447 
1448             if (id)
1449                 glyphIndex = (idDelta + id) % 0x10000;
1450             else
1451                 glyphIndex = 0;
1452         } else {
1453             glyphIndex = (idDelta + unicode) % 0x10000;
1454         }
1455         return glyphIndex;
1456     } else if (format == 6) {
1457         quint16 tableSize;
1458         if (!qSafeFromBigEndian(cmap + 2, end, &tableSize))
1459             return 0;
1460 
1461         quint16 firstCode6;
1462         if (!qSafeFromBigEndian(cmap + 6, end, &firstCode6))
1463             return 0;
1464         if (unicode < firstCode6)
1465             return 0;
1466 
1467         quint16 entryCount6;
1468         if (!qSafeFromBigEndian(cmap + 8, end, &entryCount6))
1469             return 0;
1470         if (entryCount6 * 2 + 10 > tableSize)
1471             return 0;
1472 
1473         quint16 sentinel6 = firstCode6 + entryCount6;
1474         if (unicode >= sentinel6)
1475             return 0;
1476 
1477         quint16 entryIndex6 = unicode - firstCode6;
1478 
1479         quint16 index = 0;
1480         qSafeFromBigEndian(cmap + 10 + (entryIndex6 * 2), end, &index);
1481         return index;
1482     } else if (format == 12) {
1483         quint32 nGroups;
1484         if (!qSafeFromBigEndian(cmap + 12, end, &nGroups))
1485             return 0;
1486 
1487         cmap += 16; // move to start of groups
1488 
1489         int left = 0, right = nGroups - 1;
1490         while (left <= right) {
1491             int middle = left + ( ( right - left ) >> 1 );
1492 
1493             quint32 startCharCode;
1494             if (!qSafeFromBigEndian(cmap + 12 * middle, end, &startCharCode))
1495                 return 0;
1496 
1497             if(unicode < startCharCode)
1498                 right = middle - 1;
1499             else {
1500                 quint32 endCharCode;
1501                 if (!qSafeFromBigEndian(cmap + 12 * middle + 4, end, &endCharCode))
1502                     return 0;
1503 
1504                 if (unicode <= endCharCode) {
1505                     quint32 index;
1506                     if (!qSafeFromBigEndian(cmap + 12 * middle + 8, end, &index))
1507                         return 0;
1508 
1509                     return index + unicode - startCharCode;
1510                 }
1511                 left = middle + 1;
1512             }
1513         }
1514     } else {
1515         qDebug("cmap table of format %d not implemented", format);
1516     }
1517 
1518     return 0;
1519 }
1520 
convertToPostscriptFontFamilyName(const QByteArray & family)1521 QByteArray QFontEngine::convertToPostscriptFontFamilyName(const QByteArray &family)
1522 {
1523     QByteArray f = family;
1524     f.replace(' ', "");
1525     f.replace('(', "");
1526     f.replace(')', "");
1527     f.replace('<', "");
1528     f.replace('>', "");
1529     f.replace('[', "");
1530     f.replace(']', "");
1531     f.replace('{', "");
1532     f.replace('}', "");
1533     f.replace('/', "");
1534     f.replace('%', "");
1535     return f;
1536 }
1537 
1538 // Allow font engines (e.g. Windows) that can not reliably create
1539 // outline paths for distance-field rendering to switch the scene
1540 // graph over to native text rendering.
hasUnreliableGlyphOutline() const1541 bool QFontEngine::hasUnreliableGlyphOutline() const
1542 {
1543     // Color glyphs (Emoji) are generally not suited for outlining
1544     return glyphFormat == QFontEngine::Format_ARGB;
1545 }
1546 
lastRightBearing(const QGlyphLayout & glyphs,bool round)1547 QFixed QFontEngine::lastRightBearing(const QGlyphLayout &glyphs, bool round)
1548 {
1549     if (glyphs.numGlyphs >= 1) {
1550         glyph_t glyph = glyphs.glyphs[glyphs.numGlyphs - 1];
1551         glyph_metrics_t gi = boundingBox(glyph);
1552         if (gi.isValid())
1553             return round ? qRound(gi.rightBearing()) : gi.rightBearing();
1554     }
1555     return 0;
1556 }
1557 
1558 
GlyphCacheEntry()1559 QFontEngine::GlyphCacheEntry::GlyphCacheEntry()
1560 {
1561 }
1562 
GlyphCacheEntry(const GlyphCacheEntry & o)1563 QFontEngine::GlyphCacheEntry::GlyphCacheEntry(const GlyphCacheEntry &o)
1564     : cache(o.cache)
1565 {
1566 }
1567 
~GlyphCacheEntry()1568 QFontEngine::GlyphCacheEntry::~GlyphCacheEntry()
1569 {
1570 }
1571 
operator =(const GlyphCacheEntry & o)1572 QFontEngine::GlyphCacheEntry &QFontEngine::GlyphCacheEntry::operator=(const GlyphCacheEntry &o)
1573 {
1574     cache = o.cache;
1575     return *this;
1576 }
1577 
1578 // ------------------------------------------------------------------
1579 // The box font engine
1580 // ------------------------------------------------------------------
1581 
QFontEngineBox(int size)1582 QFontEngineBox::QFontEngineBox(int size)
1583     : QFontEngine(Box),
1584       _size(size)
1585 {
1586     cache_cost = sizeof(QFontEngineBox);
1587 }
1588 
QFontEngineBox(Type type,int size)1589 QFontEngineBox::QFontEngineBox(Type type, int size)
1590     : QFontEngine(type),
1591       _size(size)
1592 {
1593     cache_cost = sizeof(QFontEngineBox);
1594 }
1595 
~QFontEngineBox()1596 QFontEngineBox::~QFontEngineBox()
1597 {
1598 }
1599 
glyphIndex(uint ucs4) const1600 glyph_t QFontEngineBox::glyphIndex(uint ucs4) const
1601 {
1602     Q_UNUSED(ucs4)
1603     return 1;
1604 }
1605 
stringToCMap(const QChar * str,int len,QGlyphLayout * glyphs,int * nglyphs,QFontEngine::ShaperFlags flags) const1606 bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
1607 {
1608     Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
1609     if (*nglyphs < len) {
1610         *nglyphs = len;
1611         return false;
1612     }
1613 
1614     int ucs4Length = 0;
1615     QStringIterator it(str, str + len);
1616     while (it.hasNext()) {
1617         it.advance();
1618         glyphs->glyphs[ucs4Length++] = 1;
1619     }
1620 
1621     *nglyphs = ucs4Length;
1622     glyphs->numGlyphs = ucs4Length;
1623 
1624     if (!(flags & GlyphIndicesOnly))
1625         recalcAdvances(glyphs, flags);
1626 
1627     return true;
1628 }
1629 
recalcAdvances(QGlyphLayout * glyphs,QFontEngine::ShaperFlags) const1630 void QFontEngineBox::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const
1631 {
1632     for (int i = 0; i < glyphs->numGlyphs; i++)
1633         glyphs->advances[i] = _size;
1634 }
1635 
addOutlineToPath(qreal x,qreal y,const QGlyphLayout & glyphs,QPainterPath * path,QTextItem::RenderFlags flags)1636 void QFontEngineBox::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1637 {
1638     if (!glyphs.numGlyphs)
1639         return;
1640 
1641     QVarLengthArray<QFixedPoint> positions;
1642     QVarLengthArray<glyph_t> positioned_glyphs;
1643     QTransform matrix = QTransform::fromTranslate(x, y - _size);
1644     getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1645 
1646     QSize s(_size - 3, _size - 3);
1647     for (int k = 0; k < positions.size(); k++)
1648         path->addRect(QRectF(positions[k].toPointF(), s));
1649 }
1650 
boundingBox(const QGlyphLayout & glyphs)1651 glyph_metrics_t QFontEngineBox::boundingBox(const QGlyphLayout &glyphs)
1652 {
1653     glyph_metrics_t overall;
1654     overall.width = _size*glyphs.numGlyphs;
1655     overall.height = _size;
1656     overall.xoff = overall.width;
1657     return overall;
1658 }
1659 
draw(QPaintEngine * p,qreal x,qreal y,const QTextItemInt & ti)1660 void QFontEngineBox::draw(QPaintEngine *p, qreal x, qreal y, const QTextItemInt &ti)
1661 {
1662     if (!ti.glyphs.numGlyphs)
1663         return;
1664 
1665     // any fixes here should probably also be done in QPaintEnginePrivate::drawBoxTextItem
1666     QSize s(_size - 3, _size - 3);
1667 
1668     QVarLengthArray<QFixedPoint> positions;
1669     QVarLengthArray<glyph_t> glyphs;
1670     QTransform matrix = QTransform::fromTranslate(x, y - _size);
1671     ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
1672     if (glyphs.size() == 0)
1673         return;
1674 
1675 
1676     QPainter *painter = p->painter();
1677     painter->save();
1678     painter->setBrush(Qt::NoBrush);
1679     QPen pen = painter->pen();
1680     pen.setWidthF(lineThickness().toReal());
1681     painter->setPen(pen);
1682     for (int k = 0; k < positions.size(); k++)
1683         painter->drawRect(QRectF(positions[k].toPointF(), s));
1684     painter->restore();
1685 }
1686 
boundingBox(glyph_t)1687 glyph_metrics_t QFontEngineBox::boundingBox(glyph_t)
1688 {
1689     return glyph_metrics_t(0, -_size, _size, _size, _size, 0);
1690 }
1691 
cloneWithSize(qreal pixelSize) const1692 QFontEngine *QFontEngineBox::cloneWithSize(qreal pixelSize) const
1693 {
1694     QFontEngineBox *fe = new QFontEngineBox(pixelSize);
1695     return fe;
1696 }
1697 
ascent() const1698 QFixed QFontEngineBox::ascent() const
1699 {
1700     return _size;
1701 }
1702 
capHeight() const1703 QFixed QFontEngineBox::capHeight() const
1704 {
1705     return _size;
1706 }
1707 
descent() const1708 QFixed QFontEngineBox::descent() const
1709 {
1710     return 0;
1711 }
1712 
leading() const1713 QFixed QFontEngineBox::leading() const
1714 {
1715     QFixed l = _size * QFixed::fromReal(qreal(0.15));
1716     return l.ceil();
1717 }
1718 
maxCharWidth() const1719 qreal QFontEngineBox::maxCharWidth() const
1720 {
1721     return _size;
1722 }
1723 
canRender(const QChar *,int) const1724 bool QFontEngineBox::canRender(const QChar *, int) const
1725 {
1726     return true;
1727 }
1728 
alphaMapForGlyph(glyph_t)1729 QImage QFontEngineBox::alphaMapForGlyph(glyph_t)
1730 {
1731     QImage image(_size, _size, QImage::Format_Alpha8);
1732     image.fill(0);
1733 
1734     // FIXME: use qpainter
1735     for (int i=2; i <= _size-3; ++i) {
1736         image.setPixel(i, 2, 255);
1737         image.setPixel(i, _size-3, 255);
1738         image.setPixel(2, i, 255);
1739         image.setPixel(_size-3, i, 255);
1740     }
1741     return image;
1742 }
1743 
1744 // ------------------------------------------------------------------
1745 // Multi engine
1746 // ------------------------------------------------------------------
1747 
highByte(glyph_t glyph)1748 uchar QFontEngineMulti::highByte(glyph_t glyph)
1749 { return glyph >> 24; }
1750 
1751 // strip high byte from glyph
stripped(glyph_t glyph)1752 static inline glyph_t stripped(glyph_t glyph)
1753 { return glyph & 0x00ffffff; }
1754 
QFontEngineMulti(QFontEngine * engine,int script,const QStringList & fallbackFamilies)1755 QFontEngineMulti::QFontEngineMulti(QFontEngine *engine, int script, const QStringList &fallbackFamilies)
1756     : QFontEngine(Multi),
1757       m_fallbackFamilies(fallbackFamilies),
1758       m_script(script),
1759       m_fallbackFamiliesQueried(!m_fallbackFamilies.isEmpty())
1760 {
1761     Q_ASSERT(engine && engine->type() != QFontEngine::Multi);
1762 
1763     if (m_fallbackFamilies.isEmpty()) {
1764         // defer obtaining the fallback families until loadEngine(1)
1765         m_fallbackFamilies << QString();
1766     }
1767 
1768     m_engines.resize(m_fallbackFamilies.size() + 1);
1769 
1770     engine->ref.ref();
1771     m_engines[0] = engine;
1772 
1773     fontDef = engine->fontDef;
1774     cache_cost = engine->cache_cost;
1775 }
1776 
~QFontEngineMulti()1777 QFontEngineMulti::~QFontEngineMulti()
1778 {
1779     for (int i = 0; i < m_engines.size(); ++i) {
1780         QFontEngine *fontEngine = m_engines.at(i);
1781         if (fontEngine && !fontEngine->ref.deref())
1782             delete fontEngine;
1783     }
1784 }
1785 
1786 QStringList qt_fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script);
1787 
ensureFallbackFamiliesQueried()1788 void QFontEngineMulti::ensureFallbackFamiliesQueried()
1789 {
1790     QFont::StyleHint styleHint = QFont::StyleHint(fontDef.styleHint);
1791     if (styleHint == QFont::AnyStyle && fontDef.fixedPitch)
1792         styleHint = QFont::TypeWriter;
1793 
1794     setFallbackFamiliesList(qt_fallbacksForFamily(fontDef.family, QFont::Style(fontDef.style), styleHint, QChar::Script(m_script)));
1795 }
1796 
setFallbackFamiliesList(const QStringList & fallbackFamilies)1797 void QFontEngineMulti::setFallbackFamiliesList(const QStringList &fallbackFamilies)
1798 {
1799     Q_ASSERT(!m_fallbackFamiliesQueried);
1800 
1801     m_fallbackFamilies = fallbackFamilies;
1802     if (m_fallbackFamilies.isEmpty()) {
1803         // turns out we lied about having any fallback at all
1804         Q_ASSERT(m_engines.size() == 2); // see c-tor for details
1805         QFontEngine *engine = m_engines.at(0);
1806         engine->ref.ref();
1807         m_engines[1] = engine;
1808         m_fallbackFamilies << fontDef.family;
1809     } else {
1810         m_engines.resize(m_fallbackFamilies.size() + 1);
1811     }
1812 
1813     m_fallbackFamiliesQueried = true;
1814 }
1815 
ensureEngineAt(int at)1816 void QFontEngineMulti::ensureEngineAt(int at)
1817 {
1818     if (!m_fallbackFamiliesQueried && at > 0)
1819         ensureFallbackFamiliesQueried();
1820     Q_ASSERT(at < m_engines.size());
1821     if (!m_engines.at(at)) {
1822         QFontEngine *engine = loadEngine(at);
1823         if (!engine)
1824             engine = new QFontEngineBox(fontDef.pixelSize);
1825         Q_ASSERT(engine && engine->type() != QFontEngine::Multi);
1826         engine->ref.ref();
1827         m_engines[at] = engine;
1828     }
1829 }
1830 
loadEngine(int at)1831 QFontEngine *QFontEngineMulti::loadEngine(int at)
1832 {
1833     QFontDef request(fontDef);
1834     request.styleStrategy |= QFont::NoFontMerging;
1835     request.family = fallbackFamilyAt(at - 1);
1836     request.families = QStringList(request.family);
1837 
1838     // At this point, the main script of the text has already been considered
1839     // when fetching the list of fallback families from the database, and the
1840     // info about the actual script of the characters may have been discarded,
1841     // so we do not check for writing system support, but instead just load
1842     // the family indiscriminately.
1843     if (QFontEngine *engine = QFontDatabase::findFont(request, QChar::Script_Common)) {
1844         engine->fontDef.weight = request.weight;
1845         if (request.style > QFont::StyleNormal)
1846             engine->fontDef.style = request.style;
1847         return engine;
1848     }
1849 
1850     return nullptr;
1851 }
1852 
glyphIndex(uint ucs4) const1853 glyph_t QFontEngineMulti::glyphIndex(uint ucs4) const
1854 {
1855     glyph_t glyph = engine(0)->glyphIndex(ucs4);
1856     if (glyph == 0
1857             && ucs4 != QChar::LineSeparator
1858             && ucs4 != QChar::LineFeed
1859             && ucs4 != QChar::CarriageReturn
1860             && ucs4 != QChar::ParagraphSeparator) {
1861         if (!m_fallbackFamiliesQueried)
1862             const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
1863         for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
1864             QFontEngine *engine = m_engines.at(x);
1865             if (!engine) {
1866                 if (!shouldLoadFontEngineForCharacter(x, ucs4))
1867                     continue;
1868                 const_cast<QFontEngineMulti *>(this)->ensureEngineAt(x);
1869                 engine = m_engines.at(x);
1870             }
1871             Q_ASSERT(engine != nullptr);
1872             if (engine->type() == Box)
1873                 continue;
1874 
1875             glyph = engine->glyphIndex(ucs4);
1876             if (glyph != 0) {
1877                 // set the high byte to indicate which engine the glyph came from
1878                 glyph |= (x << 24);
1879                 break;
1880             }
1881         }
1882     }
1883 
1884     return glyph;
1885 }
1886 
stringToCMap(const QChar * str,int len,QGlyphLayout * glyphs,int * nglyphs,QFontEngine::ShaperFlags flags) const1887 bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
1888                                     QGlyphLayout *glyphs, int *nglyphs,
1889                                     QFontEngine::ShaperFlags flags) const
1890 {
1891     if (!engine(0)->stringToCMap(str, len, glyphs, nglyphs, flags))
1892         return false;
1893 
1894     int glyph_pos = 0;
1895     QStringIterator it(str, str + len);
1896 
1897     int lastFallback = -1;
1898     while (it.hasNext()) {
1899         const uint ucs4 = it.peekNext();
1900 
1901         // If we applied a fallback font to previous glyph, and the current is either
1902         // ZWJ or ZWNJ, we should also try applying the same fallback font to that, in order
1903         // to get the correct shaping rules applied.
1904         if (lastFallback >= 0 && (ucs4 == QChar(0x200d) || ucs4 == QChar(0x200c))) {
1905             QFontEngine *engine = m_engines.at(lastFallback);
1906             glyph_t glyph = engine->glyphIndex(ucs4);
1907             if (glyph != 0) {
1908                 glyphs->glyphs[glyph_pos] = glyph;
1909                 if (!(flags & GlyphIndicesOnly)) {
1910                     QGlyphLayout g = glyphs->mid(glyph_pos, 1);
1911                     engine->recalcAdvances(&g, flags);
1912                 }
1913 
1914                 // set the high byte to indicate which engine the glyph came from
1915                 glyphs->glyphs[glyph_pos] |= (lastFallback << 24);
1916             } else {
1917                 lastFallback = -1;
1918             }
1919         } else {
1920             lastFallback = -1;
1921         }
1922 
1923         if (glyphs->glyphs[glyph_pos] == 0
1924                 && ucs4 != QChar::LineSeparator
1925                 && ucs4 != QChar::LineFeed
1926                 && ucs4 != QChar::CarriageReturn
1927                 && ucs4 != QChar::ParagraphSeparator) {
1928             if (!m_fallbackFamiliesQueried)
1929                 const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
1930             for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
1931                 QFontEngine *engine = m_engines.at(x);
1932                 if (!engine) {
1933                     if (!shouldLoadFontEngineForCharacter(x, ucs4))
1934                         continue;
1935                     const_cast<QFontEngineMulti *>(this)->ensureEngineAt(x);
1936                     engine = m_engines.at(x);
1937                     if (!engine)
1938                         continue;
1939                 }
1940                 Q_ASSERT(engine != nullptr);
1941                 if (engine->type() == Box)
1942                     continue;
1943 
1944                 glyph_t glyph = engine->glyphIndex(ucs4);
1945                 if (glyph != 0) {
1946                     glyphs->glyphs[glyph_pos] = glyph;
1947                     if (!(flags & GlyphIndicesOnly)) {
1948                         QGlyphLayout g = glyphs->mid(glyph_pos, 1);
1949                         engine->recalcAdvances(&g, flags);
1950                     }
1951 
1952                     lastFallback = x;
1953 
1954                     // set the high byte to indicate which engine the glyph came from
1955                     glyphs->glyphs[glyph_pos] |= (x << 24);
1956                     break;
1957                 }
1958             }
1959         }
1960 
1961         it.advance();
1962         ++glyph_pos;
1963     }
1964 
1965     *nglyphs = glyph_pos;
1966     glyphs->numGlyphs = glyph_pos;
1967 
1968     return true;
1969 }
1970 
shouldLoadFontEngineForCharacter(int at,uint ucs4) const1971 bool QFontEngineMulti::shouldLoadFontEngineForCharacter(int at, uint ucs4) const
1972 {
1973     Q_UNUSED(at);
1974     Q_UNUSED(ucs4);
1975     return true;
1976 }
1977 
boundingBox(const QGlyphLayout & glyphs)1978 glyph_metrics_t QFontEngineMulti::boundingBox(const QGlyphLayout &glyphs)
1979 {
1980     if (glyphs.numGlyphs <= 0)
1981         return glyph_metrics_t();
1982 
1983     glyph_metrics_t overall;
1984 
1985     int which = highByte(glyphs.glyphs[0]);
1986     int start = 0;
1987     int end, i;
1988     for (end = 0; end < glyphs.numGlyphs; ++end) {
1989         const int e = highByte(glyphs.glyphs[end]);
1990         if (e == which)
1991             continue;
1992 
1993         // set the high byte to zero
1994         for (i = start; i < end; ++i)
1995             glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
1996 
1997         // merge the bounding box for this run
1998         const glyph_metrics_t gm = engine(which)->boundingBox(glyphs.mid(start, end - start));
1999 
2000         overall.x = qMin(overall.x, gm.x);
2001         overall.y = qMin(overall.y, gm.y);
2002         overall.width = overall.xoff + gm.width;
2003         overall.height = qMax(overall.height + overall.y, gm.height + gm.y) -
2004                          qMin(overall.y, gm.y);
2005         overall.xoff += gm.xoff;
2006         overall.yoff += gm.yoff;
2007 
2008         // reset the high byte for all glyphs
2009         const int hi = which << 24;
2010         for (i = start; i < end; ++i)
2011             glyphs.glyphs[i] = hi | glyphs.glyphs[i];
2012 
2013         // change engine
2014         start = end;
2015         which = e;
2016     }
2017 
2018     // set the high byte to zero
2019     for (i = start; i < end; ++i)
2020         glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
2021 
2022     // merge the bounding box for this run
2023     const glyph_metrics_t gm = engine(which)->boundingBox(glyphs.mid(start, end - start));
2024 
2025     overall.x = qMin(overall.x, gm.x);
2026     overall.y = qMin(overall.y, gm.y);
2027     overall.width = overall.xoff + gm.width;
2028     overall.height = qMax(overall.height + overall.y, gm.height + gm.y) -
2029                      qMin(overall.y, gm.y);
2030     overall.xoff += gm.xoff;
2031     overall.yoff += gm.yoff;
2032 
2033     // reset the high byte for all glyphs
2034     const int hi = which << 24;
2035     for (i = start; i < end; ++i)
2036         glyphs.glyphs[i] = hi | glyphs.glyphs[i];
2037 
2038     return overall;
2039 }
2040 
getGlyphBearings(glyph_t glyph,qreal * leftBearing,qreal * rightBearing)2041 void QFontEngineMulti::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
2042 {
2043     int which = highByte(glyph);
2044     ensureEngineAt(which);
2045     engine(which)->getGlyphBearings(stripped(glyph), leftBearing, rightBearing);
2046 }
2047 
addOutlineToPath(qreal x,qreal y,const QGlyphLayout & glyphs,QPainterPath * path,QTextItem::RenderFlags flags)2048 void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
2049                                         QPainterPath *path, QTextItem::RenderFlags flags)
2050 {
2051     if (glyphs.numGlyphs <= 0)
2052         return;
2053 
2054     int which = highByte(glyphs.glyphs[0]);
2055     int start = 0;
2056     int end, i;
2057     if (flags & QTextItem::RightToLeft) {
2058         for (int gl = 0; gl < glyphs.numGlyphs; gl++)
2059             x += glyphs.advances[gl].toReal();
2060     }
2061     for (end = 0; end < glyphs.numGlyphs; ++end) {
2062         const int e = highByte(glyphs.glyphs[end]);
2063         if (e == which)
2064             continue;
2065 
2066         if (flags & QTextItem::RightToLeft) {
2067             for (i = start; i < end; ++i)
2068                 x -= glyphs.advances[i].toReal();
2069         }
2070 
2071         // set the high byte to zero
2072         for (i = start; i < end; ++i)
2073             glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
2074         engine(which)->addOutlineToPath(x, y, glyphs.mid(start, end - start), path, flags);
2075         // reset the high byte for all glyphs and update x and y
2076         const int hi = which << 24;
2077         for (i = start; i < end; ++i)
2078             glyphs.glyphs[i] = hi | glyphs.glyphs[i];
2079 
2080         if (!(flags & QTextItem::RightToLeft)) {
2081             for (i = start; i < end; ++i)
2082                 x += glyphs.advances[i].toReal();
2083         }
2084 
2085         // change engine
2086         start = end;
2087         which = e;
2088     }
2089 
2090     if (flags & QTextItem::RightToLeft) {
2091         for (i = start; i < end; ++i)
2092             x -= glyphs.advances[i].toReal();
2093     }
2094 
2095     // set the high byte to zero
2096     for (i = start; i < end; ++i)
2097         glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
2098 
2099     engine(which)->addOutlineToPath(x, y, glyphs.mid(start, end - start), path, flags);
2100 
2101     // reset the high byte for all glyphs
2102     const int hi = which << 24;
2103     for (i = start; i < end; ++i)
2104         glyphs.glyphs[i] = hi | glyphs.glyphs[i];
2105 }
2106 
recalcAdvances(QGlyphLayout * glyphs,QFontEngine::ShaperFlags flags) const2107 void QFontEngineMulti::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
2108 {
2109     if (glyphs->numGlyphs <= 0)
2110         return;
2111 
2112     int which = highByte(glyphs->glyphs[0]);
2113     int start = 0;
2114     int end, i;
2115     for (end = 0; end < glyphs->numGlyphs; ++end) {
2116         const int e = highByte(glyphs->glyphs[end]);
2117         if (e == which)
2118             continue;
2119 
2120         // set the high byte to zero
2121         for (i = start; i < end; ++i)
2122             glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
2123 
2124         QGlyphLayout offs = glyphs->mid(start, end - start);
2125         engine(which)->recalcAdvances(&offs, flags);
2126 
2127         // reset the high byte for all glyphs and update x and y
2128         const int hi = which << 24;
2129         for (i = start; i < end; ++i)
2130             glyphs->glyphs[i] = hi | glyphs->glyphs[i];
2131 
2132         // change engine
2133         start = end;
2134         which = e;
2135     }
2136 
2137     // set the high byte to zero
2138     for (i = start; i < end; ++i)
2139         glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
2140 
2141     QGlyphLayout offs = glyphs->mid(start, end - start);
2142     engine(which)->recalcAdvances(&offs, flags);
2143 
2144     // reset the high byte for all glyphs
2145     const int hi = which << 24;
2146     for (i = start; i < end; ++i)
2147         glyphs->glyphs[i] = hi | glyphs->glyphs[i];
2148 }
2149 
doKerning(QGlyphLayout * glyphs,QFontEngine::ShaperFlags flags) const2150 void QFontEngineMulti::doKerning(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
2151 {
2152     if (glyphs->numGlyphs <= 0)
2153         return;
2154 
2155     int which = highByte(glyphs->glyphs[0]);
2156     int start = 0;
2157     int end, i;
2158     for (end = 0; end < glyphs->numGlyphs; ++end) {
2159         const int e = highByte(glyphs->glyphs[end]);
2160         if (e == which)
2161             continue;
2162 
2163         // set the high byte to zero
2164         for (i = start; i < end; ++i)
2165             glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
2166 
2167         QGlyphLayout offs = glyphs->mid(start, end - start);
2168         engine(which)->doKerning(&offs, flags);
2169 
2170         // reset the high byte for all glyphs and update x and y
2171         const int hi = which << 24;
2172         for (i = start; i < end; ++i)
2173             glyphs->glyphs[i] = hi | glyphs->glyphs[i];
2174 
2175         // change engine
2176         start = end;
2177         which = e;
2178     }
2179 
2180     // set the high byte to zero
2181     for (i = start; i < end; ++i)
2182         glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
2183 
2184     QGlyphLayout offs = glyphs->mid(start, end - start);
2185     engine(which)->doKerning(&offs, flags);
2186 
2187     // reset the high byte for all glyphs
2188     const int hi = which << 24;
2189     for (i = start; i < end; ++i)
2190         glyphs->glyphs[i] = hi | glyphs->glyphs[i];
2191 }
2192 
boundingBox(glyph_t glyph)2193 glyph_metrics_t QFontEngineMulti::boundingBox(glyph_t glyph)
2194 {
2195     const int which = highByte(glyph);
2196     return engine(which)->boundingBox(stripped(glyph));
2197 }
2198 
ascent() const2199 QFixed QFontEngineMulti::ascent() const
2200 { return engine(0)->ascent(); }
2201 
capHeight() const2202 QFixed QFontEngineMulti::capHeight() const
2203 { return engine(0)->capHeight(); }
2204 
descent() const2205 QFixed QFontEngineMulti::descent() const
2206 { return engine(0)->descent(); }
2207 
leading() const2208 QFixed QFontEngineMulti::leading() const
2209 {
2210     return engine(0)->leading();
2211 }
2212 
xHeight() const2213 QFixed QFontEngineMulti::xHeight() const
2214 {
2215     return engine(0)->xHeight();
2216 }
2217 
averageCharWidth() const2218 QFixed QFontEngineMulti::averageCharWidth() const
2219 {
2220     return engine(0)->averageCharWidth();
2221 }
2222 
lineThickness() const2223 QFixed QFontEngineMulti::lineThickness() const
2224 {
2225     return engine(0)->lineThickness();
2226 }
2227 
underlinePosition() const2228 QFixed QFontEngineMulti::underlinePosition() const
2229 {
2230     return engine(0)->underlinePosition();
2231 }
2232 
maxCharWidth() const2233 qreal QFontEngineMulti::maxCharWidth() const
2234 {
2235     return engine(0)->maxCharWidth();
2236 }
2237 
minLeftBearing() const2238 qreal QFontEngineMulti::minLeftBearing() const
2239 {
2240     return engine(0)->minLeftBearing();
2241 }
2242 
minRightBearing() const2243 qreal QFontEngineMulti::minRightBearing() const
2244 {
2245     return engine(0)->minRightBearing();
2246 }
2247 
canRender(const QChar * string,int len) const2248 bool QFontEngineMulti::canRender(const QChar *string, int len) const
2249 {
2250     if (engine(0)->canRender(string, len))
2251         return true;
2252 
2253     int nglyphs = len;
2254 
2255     QVarLengthArray<glyph_t> glyphs(nglyphs);
2256 
2257     QGlyphLayout g;
2258     g.numGlyphs = nglyphs;
2259     g.glyphs = glyphs.data();
2260     if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly))
2261         Q_UNREACHABLE();
2262 
2263     for (int i = 0; i < nglyphs; i++) {
2264         if (glyphs[i] == 0)
2265             return false;
2266     }
2267 
2268     return true;
2269 }
2270 
2271 /* Implement alphaMapForGlyph() which is called by QPA Windows code.
2272  * Ideally, that code should be fixed to correctly handle QFontEngineMulti. */
2273 
alphaMapForGlyph(glyph_t glyph)2274 QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph)
2275 {
2276     const int which = highByte(glyph);
2277     return engine(which)->alphaMapForGlyph(stripped(glyph));
2278 }
2279 
alphaMapForGlyph(glyph_t glyph,QFixed subPixelPosition)2280 QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition)
2281 {
2282     const int which = highByte(glyph);
2283     return engine(which)->alphaMapForGlyph(stripped(glyph), subPixelPosition);
2284 }
2285 
alphaMapForGlyph(glyph_t glyph,const QTransform & t)2286 QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, const QTransform &t)
2287 {
2288     const int which = highByte(glyph);
2289     return engine(which)->alphaMapForGlyph(stripped(glyph), t);
2290 }
2291 
alphaMapForGlyph(glyph_t glyph,QFixed subPixelPosition,const QTransform & t)2292 QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
2293 {
2294     const int which = highByte(glyph);
2295     return engine(which)->alphaMapForGlyph(stripped(glyph), subPixelPosition, t);
2296 }
2297 
alphaRGBMapForGlyph(glyph_t glyph,QFixed subPixelPosition,const QTransform & t)2298 QImage QFontEngineMulti::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
2299 {
2300     const int which = highByte(glyph);
2301     return engine(which)->alphaRGBMapForGlyph(stripped(glyph), subPixelPosition, t);
2302 }
2303 
2304 /*
2305   This is used indirectly by Qt WebKit when using QTextLayout::setRawFont
2306 
2307   The purpose of this is to provide the necessary font fallbacks when drawing complex
2308   text. Since Qt WebKit ends up repeatedly creating QTextLayout instances and passing them
2309   the same raw font over and over again, we want to cache the corresponding multi font engine
2310   as it may contain fallback font engines already.
2311 */
createMultiFontEngine(QFontEngine * fe,int script)2312 QFontEngine *QFontEngineMulti::createMultiFontEngine(QFontEngine *fe, int script)
2313 {
2314     QFontEngine *engine = nullptr;
2315     QFontCache::Key key(fe->fontDef, script, /*multi = */true);
2316     QFontCache *fc = QFontCache::instance();
2317     //  We can't rely on the fontDef (and hence the cache Key)
2318     //  alone to distinguish webfonts, since these should not be
2319     //  accidentally shared, even if the resulting fontcache key
2320     //  is strictly identical. See:
2321     //   http://www.w3.org/TR/css3-fonts/#font-face-rule
2322     const bool faceIsLocal = !fe->faceId().filename.isEmpty();
2323     QFontCache::EngineCache::Iterator it = fc->engineCache.find(key),
2324             end = fc->engineCache.end();
2325     while (it != end && it.key() == key) {
2326         Q_ASSERT(it.value().data->type() == QFontEngine::Multi);
2327         QFontEngineMulti *cachedEngine = static_cast<QFontEngineMulti *>(it.value().data);
2328         if (fe == cachedEngine->engine(0) || (faceIsLocal && fe->faceId().filename == cachedEngine->engine(0)->faceId().filename)) {
2329             engine = cachedEngine;
2330             fc->updateHitCountAndTimeStamp(it.value());
2331             break;
2332         }
2333         ++it;
2334     }
2335     if (!engine) {
2336         engine = QGuiApplicationPrivate::instance()->platformIntegration()->fontDatabase()->fontEngineMulti(fe, QChar::Script(script));
2337         fc->insertEngine(key, engine, /* insertMulti */ !faceIsLocal);
2338     }
2339     Q_ASSERT(engine);
2340     return engine;
2341 }
2342 
QTestFontEngine(int size)2343 QTestFontEngine::QTestFontEngine(int size)
2344     : QFontEngineBox(TestFontEngine, size)
2345 {}
2346 
2347 QT_END_NAMESPACE
2348