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
65QT_BEGIN_NAMESPACE
66
67static 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
84template<typename T>
85static 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)
97Q_GLOBAL_STATIC_WITH_ARGS(bool, useHarfbuzzNG,(qgetenv("QT_HARFBUZZ") != "old"))
98
99bool qt_useHarfbuzzNG()
100{
101 return *useHarfbuzzNG();
102}
103#endif
104
105Q_STATIC_ASSERT(sizeof(HB_Glyph) == sizeof(glyph_t));
106Q_STATIC_ASSERT(sizeof(HB_Fixed) == sizeof(QFixed));
107
108static 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
135static 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(0));
145}
146
147static 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
153static 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
165static 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
174int 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
185static 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
191static const HB_FontClass hb_fontClass = {
192 hb_stringToGlyphs, hb_getAdvances, hb_canRender, hb_getPointInOutline,
193 hb_getGlyphMetrics, hb_getFontMetric
194};
195
196static 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
209static void hb_freeFace(void *face)
210{
211 qHBFreeFace((HB_Face)face);
212}
213
214
215static 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!
224static QList<QFontEngine *> *enginesCollector = 0;
225
226Q_AUTOTEST_EXPORT void QFontEngine_startCollectingEngines()
227{
228 delete enginesCollector;
229 enginesCollector = new QList<QFontEngine *>();
230}
231
232Q_AUTOTEST_EXPORT QList<QFontEngine *> QFontEngine_stopCollectingEngines()
233{
234 Q_ASSERT(enginesCollector);
235 QList<QFontEngine *> ret = *enginesCollector;
236 delete enginesCollector;
237 enginesCollector = 0;
238 return ret;
239}
240#endif // QT_BUILD_INTERNAL
241
242
243// QFontEngine
244
245#define kBearingNotInitialized std::numeric_limits<qreal>::max()
246
247QFontEngine::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
271QFontEngine::~QFontEngine()
272{
273#ifdef QT_BUILD_INTERNAL
274 if (enginesCollector)
275 enginesCollector->removeOne(this);
276#endif
277}
278
279QFixed 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
292QFixed QFontEngine::underlinePosition() const
293{
294 return ((lineThickness() * 2) + 3) / 6;
295}
296
297void *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
332void *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
354bool 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 len;
370 if (getSfntTableData(MAKE_TAG('m','o','r','t'), 0, &len) || getSfntTableData(MAKE_TAG('m','o','r','x'), 0, &len))
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
399bool 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
410glyph_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
420QFixed 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
427QFixed 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
434QFixed 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
441bool QFontEngine::supportsTransformation(const QTransform &transform) const
442{
443 return transform.type() < QTransform::TxProject;
444}
445
446bool QFontEngine::expectsGammaCorrectedBlending() const
447{
448 return true;
449}
450
451void 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, 0);
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
569void QFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
570{
571 glyph_metrics_t gi = boundingBox(glyph);
572 if (leftBearing != 0)
573 *leftBearing = gi.leftBearing().toReal();
574 if (rightBearing != 0)
575 *rightBearing = gi.rightBearing().toReal();
576}
577
578qreal 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
591qreal 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
659glyph_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 glyph_metrics_t bb = boundingBox(glyphs.glyphs[i]);
667 QFixed x = overall.xoff + glyphs.offsets[i].x + bb.x;
668 QFixed y = overall.yoff + glyphs.offsets[i].y + bb.y;
669 overall.x = qMin(overall.x, x);
670 overall.y = qMin(overall.y, y);
671 xmax = qMax(xmax, x + bb.width);
672 ymax = qMax(ymax, y + bb.height);
673 overall.xoff += bb.xoff;
674 overall.yoff += bb.yoff;
675 }
676 overall.height = qMax(overall.height, ymax - overall.y);
677 overall.width = xmax - overall.x;
678
679 return overall;
680}
681
682
683void QFontEngine::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path,
684 QTextItem::RenderFlags flags)
685{
686 if (!glyphs.numGlyphs)
687 return;
688
689 QVarLengthArray<QFixedPoint> positions;
690 QVarLengthArray<glyph_t> positioned_glyphs;
691 QTransform matrix = QTransform::fromTranslate(x, y);
692 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
693 addGlyphsToPath(positioned_glyphs.data(), positions.data(), positioned_glyphs.size(), path, flags);
694}
695
696#define GRID(x, y) grid[(y)*(w+1) + (x)]
697#define SET(x, y) (*(image_data + (y)*bpl + ((x) >> 3)) & (0x80 >> ((x) & 7)))
698
699enum { EdgeRight = 0x1,
700 EdgeDown = 0x2,
701 EdgeLeft = 0x4,
702 EdgeUp = 0x8
703};
704
705static void collectSingleContour(qreal x0, qreal y0, uint *grid, int x, int y, int w, int h, QPainterPath *path)
706{
707 Q_UNUSED(h);
708
709 path->moveTo(x + x0, y + y0);
710 while (GRID(x, y)) {
711 if (GRID(x, y) & EdgeRight) {
712 while (GRID(x, y) & EdgeRight) {
713 GRID(x, y) &= ~EdgeRight;
714 ++x;
715 }
716 Q_ASSERT(x <= w);
717 path->lineTo(x + x0, y + y0);
718 continue;
719 }
720 if (GRID(x, y) & EdgeDown) {
721 while (GRID(x, y) & EdgeDown) {
722 GRID(x, y) &= ~EdgeDown;
723 ++y;
724 }
725 Q_ASSERT(y <= h);
726 path->lineTo(x + x0, y + y0);
727 continue;
728 }
729 if (GRID(x, y) & EdgeLeft) {
730 while (GRID(x, y) & EdgeLeft) {
731 GRID(x, y) &= ~EdgeLeft;
732 --x;
733 }
734 Q_ASSERT(x >= 0);
735 path->lineTo(x + x0, y + y0);
736 continue;
737 }
738 if (GRID(x, y) & EdgeUp) {
739 while (GRID(x, y) & EdgeUp) {
740 GRID(x, y) &= ~EdgeUp;
741 --y;
742 }
743 Q_ASSERT(y >= 0);
744 path->lineTo(x + x0, y + y0);
745 continue;
746 }
747 }
748 path->closeSubpath();
749}
750
751Q_GUI_EXPORT void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path)
752{
753 uint *grid = new uint[(w+1)*(h+1)];
754 // set up edges
755 for (int y = 0; y <= h; ++y) {
756 for (int x = 0; x <= w; ++x) {
757 bool topLeft = (x == 0)|(y == 0) ? false : SET(x - 1, y - 1);
758 bool topRight = (x == w)|(y == 0) ? false : SET(x, y - 1);
759 bool bottomLeft = (x == 0)|(y == h) ? false : SET(x - 1, y);
760 bool bottomRight = (x == w)|(y == h) ? false : SET(x, y);
761
762 GRID(x, y) = 0;
763 if ((!topRight) & bottomRight)
764 GRID(x, y) |= EdgeRight;
765 if ((!bottomRight) & bottomLeft)
766 GRID(x, y) |= EdgeDown;
767 if ((!bottomLeft) & topLeft)
768 GRID(x, y) |= EdgeLeft;
769 if ((!topLeft) & topRight)
770 GRID(x, y) |= EdgeUp;
771 }
772 }
773
774 // collect edges
775 for (int y = 0; y < h; ++y) {
776 for (int x = 0; x < w; ++x) {
777 if (!GRID(x, y))
778 continue;
779 // found start of a contour, follow it
780 collectSingleContour(x0, y0, grid, x, y, w, h, path);
781 }
782 }
783 delete [] grid;
784}
785
786#undef GRID
787#undef SET
788
789
790void QFontEngine::addBitmapFontToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
791 QPainterPath *path, QTextItem::RenderFlags flags)
792{
793// TODO what to do with 'flags' ??
794 Q_UNUSED(flags);
795 QFixed advanceX = QFixed::fromReal(x);
796 QFixed advanceY = QFixed::fromReal(y);
797 for (int i=0; i < glyphs.numGlyphs; ++i) {
798 glyph_metrics_t metrics = boundingBox(glyphs.glyphs[i]);
799 if (metrics.width.value() == 0 || metrics.height.value() == 0) {
800 advanceX += glyphs.advances[i];
801 continue;
802 }
803 const QImage alphaMask = alphaMapForGlyph(glyphs.glyphs[i]);
804
805 const int w = alphaMask.width();
806 const int h = alphaMask.height();
807 const int srcBpl = alphaMask.bytesPerLine();
808 QImage bitmap;
809 if (alphaMask.depth() == 1) {
810 bitmap = alphaMask;
811 } else {
812 bitmap = QImage(w, h, QImage::Format_Mono);
813 const uchar *imageData = alphaMask.bits();
814 const int destBpl = bitmap.bytesPerLine();
815 uchar *bitmapData = bitmap.bits();
816
817 for (int yi = 0; yi < h; ++yi) {
818 const uchar *src = imageData + yi*srcBpl;
819 uchar *dst = bitmapData + yi*destBpl;
820 for (int xi = 0; xi < w; ++xi) {
821 const int byte = xi / 8;
822 const int bit = xi % 8;
823 if (bit == 0)
824 dst[byte] = 0;
825 if (src[xi])
826 dst[byte] |= 128 >> bit;
827 }
828 }
829 }
830 const uchar *bitmap_data = bitmap.constBits();
831 QFixedPoint offset = glyphs.offsets[i];
832 advanceX += offset.x;
833 advanceY += offset.y;
834 qt_addBitmapToPath((advanceX + metrics.x).toReal(), (advanceY + metrics.y).toReal(), bitmap_data, bitmap.bytesPerLine(), w, h, path);
835 advanceX += glyphs.advances[i];
836 }
837}
838
839void QFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nGlyphs,
840 QPainterPath *path, QTextItem::RenderFlags flags)
841{
842 qreal x = positions[0].x.toReal();
843 qreal y = positions[0].y.toReal();
844 QVarLengthGlyphLayoutArray g(nGlyphs);
845
846 for (int i = 0; i < nGlyphs - 1; ++i) {
847 g.glyphs[i] = glyphs[i];
848 g.advances[i] = positions[i + 1].x - positions[i].x;
849 }
850 g.glyphs[nGlyphs - 1] = glyphs[nGlyphs - 1];
851 g.advances[nGlyphs - 1] = QFixed::fromReal(maxCharWidth());
852
853 addBitmapFontToPath(x, y, g, path, flags);
854}
855
856QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed /*subPixelPosition*/)
857{
858 // For font engines don't support subpixel positioning
859 return alphaMapForGlyph(glyph);
860}
861
862QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &t)
863{
864 QImage i = alphaMapForGlyph(glyph);
865 if (t.type() > QTransform::TxTranslate)
866 i = i.transformed(t).convertToFormat(QImage::Format_Alpha8);
867 Q_ASSERT(i.depth() <= 8); // To verify that transformed didn't change the format...
868
869 return i;
870}
871
872QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
873{
874 if (! supportsSubPixelPositions())
875 return alphaMapForGlyph(glyph, t);
876
877 QImage i = alphaMapForGlyph(glyph, subPixelPosition);
878 if (t.type() > QTransform::TxTranslate)
879 i = i.transformed(t).convertToFormat(QImage::Format_Alpha8);
880 Q_ASSERT(i.depth() <= 8); // To verify that transformed didn't change the format...
881
882 return i;
883}
884
885QImage QFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed /*subPixelPosition*/, const QTransform &t)
886{
887 const QImage alphaMask = alphaMapForGlyph(glyph, t);
888 QImage rgbMask(alphaMask.width(), alphaMask.height(), QImage::Format_RGB32);
889
890 for (int y=0; y<alphaMask.height(); ++y) {
891 uint *dst = (uint *) rgbMask.scanLine(y);
892 const uchar *src = alphaMask.constScanLine(y);
893 for (int x=0; x<alphaMask.width(); ++x) {
894 int val = src[x];
895 dst[x] = qRgb(val, val, val);
896 }
897 }
898
899 return rgbMask;
900}
901
902QImage QFontEngine::bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform&, const QColor &)
903{
904 Q_UNUSED(subPixelPosition);
905
906 return QImage();
907}
908
909QFixed QFontEngine::subPixelPositionForX(QFixed x) const
910{
911 if (m_subPixelPositionCount <= 1 || !supportsSubPixelPositions())
912 return QFixed();
913
914 QFixed subPixelPosition;
915 if (x != 0) {
916 subPixelPosition = x - x.floor();
917 QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor();
918
919 // Compensate for precision loss in fixed point to make sure we are always drawing at a subpixel position over
920 // the lower boundary for the selected rasterization by adding 1/64.
921 subPixelPosition = fraction / QFixed(m_subPixelPositionCount) + QFixed::fromReal(0.015625);
922 }
923 return subPixelPosition;
924}
925
926QImage *QFontEngine::lockedAlphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition,
927 QFontEngine::GlyphFormat neededFormat,
928 const QTransform &t, QPoint *offset)
929{
930 Q_ASSERT(currentlyLockedAlphaMap.isNull());
931 if (neededFormat == Format_None)
932 neededFormat = Format_A32;
933
934 if (neededFormat != Format_A32)
935 currentlyLockedAlphaMap = alphaMapForGlyph(glyph, subPixelPosition, t);
936 else
937 currentlyLockedAlphaMap = alphaRGBMapForGlyph(glyph, subPixelPosition, t);
938
939 if (offset != 0)
940 *offset = QPoint(0, 0);
941
942 return &currentlyLockedAlphaMap;
943}
944
945void QFontEngine::unlockAlphaMapForGlyph()
946{
947 Q_ASSERT(!currentlyLockedAlphaMap.isNull());
948 currentlyLockedAlphaMap = QImage();
949}
950
951QImage QFontEngine::alphaMapForGlyph(glyph_t glyph)
952{
953 glyph_metrics_t gm = boundingBox(glyph);
954 int glyph_x = qFloor(gm.x.toReal());
955 int glyph_y = qFloor(gm.y.toReal());
956 int glyph_width = qCeil((gm.x + gm.width).toReal()) - glyph_x;
957 int glyph_height = qCeil((gm.y + gm.height).toReal()) - glyph_y;
958
959 if (glyph_width <= 0 || glyph_height <= 0)
960 return QImage();
961 QFixedPoint pt;
962 pt.x = -glyph_x;
963 pt.y = -glyph_y; // the baseline
964 QPainterPath path;
965 path.setFillRule(Qt::WindingFill);
966 QImage im(glyph_width, glyph_height, QImage::Format_ARGB32_Premultiplied);
967 im.fill(Qt::transparent);
968 QPainter p(&im);
969 p.setRenderHint(QPainter::Antialiasing);
970 addGlyphsToPath(&glyph, &pt, 1, &path, 0);
971 p.setPen(Qt::NoPen);
972 p.setBrush(Qt::black);
973 p.drawPath(path);
974 p.end();
975
976 QImage alphaMap(im.width(), im.height(), QImage::Format_Alpha8);
977
978 for (int y=0; y<im.height(); ++y) {
979 uchar *dst = (uchar *) alphaMap.scanLine(y);
980 const uint *src = reinterpret_cast<const uint *>(im.constScanLine(y));
981 for (int x=0; x<im.width(); ++x)
982 dst[x] = qAlpha(src[x]);
983 }
984
985 return alphaMap;
986}
987
988void QFontEngine::removeGlyphFromCache(glyph_t)
989{
990}
991
992QFontEngine::Properties QFontEngine::properties() const
993{
994 Properties p;
995 p.postscriptName
996 = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8())
997 + '-'
998 + QByteArray::number(fontDef.style)
999 + '-'
1000 + QByteArray::number(fontDef.weight);
1001 p.ascent = ascent();
1002 p.descent = descent();
1003 p.leading = leading();
1004 p.emSquare = p.ascent;
1005 p.boundingBox = QRectF(0, -p.ascent.toReal(), maxCharWidth(), (p.ascent + p.descent).toReal());
1006 p.italicAngle = 0;
1007 p.capHeight = p.ascent;
1008 p.lineWidth = lineThickness();
1009 return p;
1010}
1011
1012void QFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
1013{
1014 *metrics = boundingBox(glyph);
1015 QFixedPoint p;
1016 p.x = 0;
1017 p.y = 0;
1018 addGlyphsToPath(&glyph, &p, 1, path, QFlag(0));
1019}
1020
1021/*!
1022 Returns \c true if the font table idetified by \a tag exists in the font;
1023 returns \c false otherwise.
1024
1025 If \a buffer is \nullptr, stores the size of the buffer required for the font table data,
1026 in bytes, in \a length. If \a buffer is not \nullptr and the capacity
1027 of the buffer, passed in \a length, is sufficient to store the font table data,
1028 also copies the font table data to \a buffer.
1029
1030 Note: returning \c false when the font table exists could lead to an undefined behavior.
1031*/
1032bool QFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const
1033{
1034 Q_UNUSED(tag)
1035 Q_UNUSED(buffer)
1036 Q_UNUSED(length)
1037 return false;
1038}
1039
1040QByteArray QFontEngine::getSfntTable(uint tag) const
1041{
1042 QByteArray table;
1043 uint len = 0;
1044 if (!getSfntTableData(tag, 0, &len))
1045 return table;
1046 table.resize(len);
1047 if (!getSfntTableData(tag, reinterpret_cast<uchar *>(table.data()), &len))
1048 return QByteArray();
1049 return table;
1050}
1051
1052void QFontEngine::clearGlyphCache(const void *context)
1053{
1054 m_glyphCaches.remove(context);
1055}
1056
1057void QFontEngine::setGlyphCache(const void *context, QFontEngineGlyphCache *cache)
1058{
1059 Q_ASSERT(cache);
1060
1061 GlyphCaches &caches = m_glyphCaches[context];
1062 for (auto & e : caches) {
1063 if (cache == e.cache.data())
1064 return;
1065 }
1066
1067 // Limit the glyph caches to 4 per context. This covers all 90 degree rotations,
1068 // and limits memory use when there is continuous or random rotation
1069 if (caches.size() == 4)
1070 caches.pop_back();
1071
1072 GlyphCacheEntry entry;
1073 entry.cache = cache;
1074 caches.push_front(entry);
1075
1076}
1077
1078QFontEngineGlyphCache *QFontEngine::glyphCache(const void *context,
1079 GlyphFormat format,
1080 const QTransform &transform,
1081 const QColor &color) const
1082{
1083 const QHash<const void*, GlyphCaches>::const_iterator caches = m_glyphCaches.constFind(context);
1084 if (caches == m_glyphCaches.cend())
1085 return nullptr;
1086
1087 for (auto &e : *caches) {
1088 QFontEngineGlyphCache *cache = e.cache.data();
1089 if (format == cache->glyphFormat()
1090 && (format != Format_ARGB || color == cache->color())
1091 && qtransform_equals_no_translate(cache->m_transform, transform)) {
1092 return cache;
1093 }
1094 }
1095
1096 return nullptr;
1097}
1098
1099static inline QFixed kerning(int left, int right, const QFontEngine::KernPair *pairs, int numPairs)
1100{
1101 uint left_right = (left << 16) + right;
1102
1103 left = 0, right = numPairs - 1;
1104 while (left <= right) {
1105 int middle = left + ( ( right - left ) >> 1 );
1106
1107 if(pairs[middle].left_right == left_right)
1108 return pairs[middle].adjust;
1109
1110 if (pairs[middle].left_right < left_right)
1111 left = middle + 1;
1112 else
1113 right = middle - 1;
1114 }
1115 return 0;
1116}
1117
1118void QFontEngine::doKerning(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
1119{
1120 int numPairs = kerning_pairs.size();
1121 if(!numPairs)
1122 return;
1123
1124 const KernPair *pairs = kerning_pairs.constData();
1125
1126 if (flags & DesignMetrics) {
1127 for(int i = 0; i < glyphs->numGlyphs - 1; ++i)
1128 glyphs->advances[i] += kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs);
1129 } else {
1130 for(int i = 0; i < glyphs->numGlyphs - 1; ++i)
1131 glyphs->advances[i] += qRound(kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs));
1132 }
1133}
1134
1135void QFontEngine::loadKerningPairs(QFixed scalingFactor)
1136{
1137 kerning_pairs.clear();
1138
1139 QByteArray tab = getSfntTable(MAKE_TAG('k', 'e', 'r', 'n'));
1140 if (tab.isEmpty())
1141 return;
1142
1143 const uchar *table = reinterpret_cast<const uchar *>(tab.constData());
1144 const uchar *end = table + tab.size();
1145
1146 quint16 version;
1147 if (!qSafeFromBigEndian(table, end, &version))
1148 return;
1149
1150 if (version != 0) {
1151// qDebug("wrong version");
1152 return;
1153 }
1154
1155 quint16 numTables;
1156 if (!qSafeFromBigEndian(table + 2, end, &numTables))
1157 return;
1158
1159 {
1160 int offset = 4;
1161 for(int i = 0; i < numTables; ++i) {
1162 const uchar *header = table + offset;
1163
1164 quint16 version;
1165 if (!qSafeFromBigEndian(header, end, &version))
1166 goto end;
1167
1168 quint16 length;
1169 if (!qSafeFromBigEndian(header + 2, end, &length))
1170 goto end;
1171
1172 quint16 coverage;
1173 if (!qSafeFromBigEndian(header + 4, end, &coverage))
1174 goto end;
1175
1176// qDebug("subtable: version=%d, coverage=%x",version, coverage);
1177 if(version == 0 && coverage == 0x0001) {
1178 if (offset + length > tab.size()) {
1179// qDebug("length ouf ot bounds");
1180 goto end;
1181 }
1182 const uchar *data = table + offset + 6;
1183
1184 quint16 nPairs;
1185 if (!qSafeFromBigEndian(data, end, &nPairs))
1186 goto end;
1187
1188 if(nPairs * 6 + 8 > length - 6) {
1189// qDebug("corrupt table!");
1190 // corrupt table
1191 goto end;
1192 }
1193
1194 int off = 8;
1195 for(int i = 0; i < nPairs; ++i) {
1196 QFontEngine::KernPair p;
1197
1198 quint16 tmp;
1199 if (!qSafeFromBigEndian(data + off, end, &tmp))
1200 goto end;
1201
1202 p.left_right = uint(tmp) << 16;
1203 if (!qSafeFromBigEndian(data + off + 2, end, &tmp))
1204 goto end;
1205
1206 p.left_right |= tmp;
1207
1208 if (!qSafeFromBigEndian(data + off + 4, end, &tmp))
1209 goto end;
1210
1211 p.adjust = QFixed(int(short(tmp))) / scalingFactor;
1212 kerning_pairs.append(p);
1213 off += 6;
1214 }
1215 }
1216 offset += length;
1217 }
1218 }
1219end:
1220 std::sort(kerning_pairs.begin(), kerning_pairs.end());
1221// for (int i = 0; i < kerning_pairs.count(); ++i)
1222// qDebug() << 'i' << i << "left_right" << Qt::hex << kerning_pairs.at(i).left_right;
1223}
1224
1225
1226int QFontEngine::glyphCount() const
1227{
1228 QByteArray maxpTable = getSfntTable(MAKE_TAG('m', 'a', 'x', 'p'));
1229 if (maxpTable.size() < 6)
1230 return 0;
1231
1232 const uchar *source = reinterpret_cast<const uchar *>(maxpTable.constData() + 4);
1233 const uchar *end = source + maxpTable.size();
1234
1235 quint16 count = 0;
1236 qSafeFromBigEndian(source, end, &count);
1237 return count;
1238}
1239
1240Qt::HANDLE QFontEngine::handle() const
1241{
1242 return nullptr;
1243}
1244
1245const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize)
1246{
1247 const uchar *header = table;
1248 const uchar *endPtr = table + tableSize;
1249
1250 // version check
1251 quint16 version;
1252 if (!qSafeFromBigEndian(header, endPtr, &version) || version != 0)
1253 return 0;
1254
1255 quint16 numTables;
1256 if (!qSafeFromBigEndian(header + 2, endPtr, &numTables))
1257 return 0;
1258
1259 const uchar *maps = table + 4;
1260
1261 enum {
1262 Invalid,
1263 AppleRoman,
1264 Symbol,
1265 Unicode11,
1266 Unicode,
1267 MicrosoftUnicode,
1268 MicrosoftUnicodeExtended
1269 };
1270
1271 int symbolTable = -1;
1272 int tableToUse = -1;
1273 int score = Invalid;
1274 for (int n = 0; n < numTables; ++n) {
1275 quint16 platformId;
1276 if (!qSafeFromBigEndian(maps + 8 * n, endPtr, &platformId))
1277 return 0;
1278
1279 quint16 platformSpecificId = 0;
1280 if (!qSafeFromBigEndian(maps + 8 * n + 2, endPtr, &platformSpecificId))
1281 return 0;
1282
1283 switch (platformId) {
1284 case 0: // Unicode
1285 if (score < Unicode &&
1286 (platformSpecificId == 0 ||
1287 platformSpecificId == 2 ||
1288 platformSpecificId == 3)) {
1289 tableToUse = n;
1290 score = Unicode;
1291 } else if (score < Unicode11 && platformSpecificId == 1) {
1292 tableToUse = n;
1293 score = Unicode11;
1294 }
1295 break;
1296 case 1: // Apple
1297 if (score < AppleRoman && platformSpecificId == 0) { // Apple Roman
1298 tableToUse = n;
1299 score = AppleRoman;
1300 }
1301 break;
1302 case 3: // Microsoft
1303 switch (platformSpecificId) {
1304 case 0:
1305 symbolTable = n;
1306 if (score < Symbol) {
1307 tableToUse = n;
1308 score = Symbol;
1309 }
1310 break;
1311 case 1:
1312 if (score < MicrosoftUnicode) {
1313 tableToUse = n;
1314 score = MicrosoftUnicode;
1315 }
1316 break;
1317 case 0xa:
1318 if (score < MicrosoftUnicodeExtended) {
1319 tableToUse = n;
1320 score = MicrosoftUnicodeExtended;
1321 }
1322 break;
1323 default:
1324 break;
1325 }
1326 default:
1327 break;
1328 }
1329 }
1330 if(tableToUse < 0)
1331 return 0;
1332
1333resolveTable:
1334 *isSymbolFont = (symbolTable > -1);
1335
1336 quint32 unicode_table = 0;
1337 if (!qSafeFromBigEndian(maps + 8 * tableToUse + 4, endPtr, &unicode_table))
1338 return 0;
1339
1340 if (!unicode_table)
1341 return 0;
1342
1343 // get the header of the unicode table
1344 header = table + unicode_table;
1345
1346 quint16 format;
1347 if (!qSafeFromBigEndian(header, endPtr, &format))
1348 return 0;
1349
1350 quint32 length;
1351 if (format < 8) {
1352 quint16 tmp;
1353 if (!qSafeFromBigEndian(header + 2, endPtr, &tmp))
1354 return 0;
1355 length = tmp;
1356 } else {
1357 if (!qSafeFromBigEndian(header + 4, endPtr, &length))
1358 return 0;
1359 }
1360
1361 if (table + unicode_table + length > endPtr)
1362 return 0;
1363 *cmapSize = length;
1364
1365 // To support symbol fonts that contain a unicode table for the symbol area
1366 // we check the cmap tables and fall back to symbol font unless that would
1367 // involve losing information from the unicode table
1368 if (symbolTable > -1 && ((score == Unicode) || (score == Unicode11))) {
1369 const uchar *selectedTable = table + unicode_table;
1370
1371 // Check that none of the latin1 range are in the unicode table
1372 bool unicodeTableHasLatin1 = false;
1373 for (int uc=0x00; uc<0x100; ++uc) {
1374 if (getTrueTypeGlyphIndex(selectedTable, length, uc) != 0) {
1375 unicodeTableHasLatin1 = true;
1376 break;
1377 }
1378 }
1379
1380 // Check that at least one symbol char is in the unicode table
1381 bool unicodeTableHasSymbols = false;
1382 if (!unicodeTableHasLatin1) {
1383 for (int uc=0xf000; uc<0xf100; ++uc) {
1384 if (getTrueTypeGlyphIndex(selectedTable, length, uc) != 0) {
1385 unicodeTableHasSymbols = true;
1386 break;
1387 }
1388 }
1389 }
1390
1391 // Fall back to symbol table
1392 if (!unicodeTableHasLatin1 && unicodeTableHasSymbols) {
1393 tableToUse = symbolTable;
1394 score = Symbol;
1395 goto resolveTable;
1396 }
1397 }
1398
1399 return table + unicode_table;
1400}
1401
1402quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode)
1403{
1404 const uchar *end = cmap + cmapSize;
1405 quint16 format;
1406 if (!qSafeFromBigEndian(cmap, end, &format))
1407 return 0;
1408
1409 if (format == 0) {
1410 const uchar *ptr = cmap + 6 + unicode;
1411 if (unicode < 256 && ptr < end)
1412 return quint32(*ptr);
1413 } else if (format == 4) {
1414 /* some fonts come with invalid cmap tables, where the last segment
1415 specified end = start = rangeoffset = 0xffff, delta = 0x0001
1416 Since 0xffff is never a valid Unicode char anyway, we just get rid of the issue
1417 by returning 0 for 0xffff
1418 */
1419 if(unicode >= 0xffff)
1420 return 0;
1421
1422 quint16 segCountX2;
1423 if (!qSafeFromBigEndian(cmap + 6, end, &segCountX2))
1424 return 0;
1425
1426 const unsigned char *ends = cmap + 14;
1427
1428 int i = 0;
1429 for (; i < segCountX2/2; ++i) {
1430 quint16 codePoint;
1431 if (!qSafeFromBigEndian(ends + 2 * i, end, &codePoint))
1432 return 0;
1433 if (codePoint >= unicode)
1434 break;
1435 }
1436
1437 const unsigned char *idx = ends + segCountX2 + 2 + 2*i;
1438
1439 quint16 startIndex;
1440 if (!qSafeFromBigEndian(idx, end, &startIndex))
1441 return 0;
1442 if (startIndex > unicode)
1443 return 0;
1444
1445 idx += segCountX2;
1446
1447 quint16 tmp;
1448 if (!qSafeFromBigEndian(idx, end, &tmp))
1449 return 0;
1450 qint16 idDelta = qint16(tmp);
1451
1452 idx += segCountX2;
1453
1454 quint16 idRangeoffset_t;
1455 if (!qSafeFromBigEndian(idx, end, &idRangeoffset_t))
1456 return 0;
1457
1458 quint16 glyphIndex;
1459 if (idRangeoffset_t) {
1460 quint16 id;
1461 if (!qSafeFromBigEndian(idRangeoffset_t + 2 * (unicode - startIndex) + idx, end, &id))
1462 return 0;
1463
1464 if (id)
1465 glyphIndex = (idDelta + id) % 0x10000;
1466 else
1467 glyphIndex = 0;
1468 } else {
1469 glyphIndex = (idDelta + unicode) % 0x10000;
1470 }
1471 return glyphIndex;
1472 } else if (format == 6) {
1473 quint16 tableSize;
1474 if (!qSafeFromBigEndian(cmap + 2, end, &tableSize))
1475 return 0;
1476
1477 quint16 firstCode6;
1478 if (!qSafeFromBigEndian(cmap + 6, end, &firstCode6))
1479 return 0;
1480 if (unicode < firstCode6)
1481 return 0;
1482
1483 quint16 entryCount6;
1484 if (!qSafeFromBigEndian(cmap + 8, end, &entryCount6))
1485 return 0;
1486 if (entryCount6 * 2 + 10 > tableSize)
1487 return 0;
1488
1489 quint16 sentinel6 = firstCode6 + entryCount6;
1490 if (unicode >= sentinel6)
1491 return 0;
1492
1493 quint16 entryIndex6 = unicode - firstCode6;
1494
1495 quint16 index = 0;
1496 qSafeFromBigEndian(cmap + 10 + (entryIndex6 * 2), end, &index);
1497 return index;
1498 } else if (format == 12) {
1499 quint32 nGroups;
1500 if (!qSafeFromBigEndian(cmap + 12, end, &nGroups))
1501 return 0;
1502
1503 cmap += 16; // move to start of groups
1504
1505 int left = 0, right = nGroups - 1;
1506 while (left <= right) {
1507 int middle = left + ( ( right - left ) >> 1 );
1508
1509 quint32 startCharCode;
1510 if (!qSafeFromBigEndian(cmap + 12 * middle, end, &startCharCode))
1511 return 0;
1512
1513 if(unicode < startCharCode)
1514 right = middle - 1;
1515 else {
1516 quint32 endCharCode;
1517 if (!qSafeFromBigEndian(cmap + 12 * middle + 4, end, &endCharCode))
1518 return 0;
1519
1520 if (unicode <= endCharCode) {
1521 quint32 index;
1522 if (!qSafeFromBigEndian(cmap + 12 * middle + 8, end, &index))
1523 return 0;
1524
1525 return index + unicode - startCharCode;
1526 }
1527 left = middle + 1;
1528 }
1529 }
1530 } else {
1531 qDebug("cmap table of format %d not implemented", format);
1532 }
1533
1534 return 0;
1535}
1536
1537QByteArray QFontEngine::convertToPostscriptFontFamilyName(const QByteArray &family)
1538{
1539 QByteArray f = family;
1540 f.replace(' ', "");
1541 f.replace('(', "");
1542 f.replace(')', "");
1543 f.replace('<', "");
1544 f.replace('>', "");
1545 f.replace('[', "");
1546 f.replace(']', "");
1547 f.replace('{', "");
1548 f.replace('}', "");
1549 f.replace('/', "");
1550 f.replace('%', "");
1551 return f;
1552}
1553
1554// Allow font engines (e.g. Windows) that can not reliably create
1555// outline paths for distance-field rendering to switch the scene
1556// graph over to native text rendering.
1557bool QFontEngine::hasUnreliableGlyphOutline() const
1558{
1559 // Color glyphs (Emoji) are generally not suited for outlining
1560 return glyphFormat == QFontEngine::Format_ARGB;
1561}
1562
1563QFixed QFontEngine::lastRightBearing(const QGlyphLayout &glyphs, bool round)
1564{
1565 if (glyphs.numGlyphs >= 1) {
1566 glyph_t glyph = glyphs.glyphs[glyphs.numGlyphs - 1];
1567 glyph_metrics_t gi = boundingBox(glyph);
1568 if (gi.isValid())
1569 return round ? qRound(gi.rightBearing()) : gi.rightBearing();
1570 }
1571 return 0;
1572}
1573
1574
1575QFontEngine::GlyphCacheEntry::GlyphCacheEntry()
1576{
1577}
1578
1579QFontEngine::GlyphCacheEntry::GlyphCacheEntry(const GlyphCacheEntry &o)
1580 : cache(o.cache)
1581{
1582}
1583
1584QFontEngine::GlyphCacheEntry::~GlyphCacheEntry()
1585{
1586}
1587
1588QFontEngine::GlyphCacheEntry &QFontEngine::GlyphCacheEntry::operator=(const GlyphCacheEntry &o)
1589{
1590 cache = o.cache;
1591 return *this;
1592}
1593
1594// ------------------------------------------------------------------
1595// The box font engine
1596// ------------------------------------------------------------------
1597
1598QFontEngineBox::QFontEngineBox(int size)
1599 : QFontEngine(Box),
1600 _size(size)
1601{
1602 cache_cost = sizeof(QFontEngineBox);
1603}
1604
1605QFontEngineBox::QFontEngineBox(Type type, int size)
1606 : QFontEngine(type),
1607 _size(size)
1608{
1609 cache_cost = sizeof(QFontEngineBox);
1610}
1611
1612QFontEngineBox::~QFontEngineBox()
1613{
1614}
1615
1616glyph_t QFontEngineBox::glyphIndex(uint ucs4) const
1617{
1618 Q_UNUSED(ucs4)
1619 return 0;
1620}
1621
1622bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
1623{
1624 Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
1625 if (*nglyphs < len) {
1626 *nglyphs = len;
1627 return false;
1628 }
1629
1630 int ucs4Length = 0;
1631 QStringIterator it(str, str + len);
1632 while (it.hasNext()) {
1633 it.advance();
1634 glyphs->glyphs[ucs4Length++] = 0;
1635 }
1636
1637 *nglyphs = ucs4Length;
1638 glyphs->numGlyphs = ucs4Length;
1639
1640 if (!(flags & GlyphIndicesOnly))
1641 recalcAdvances(glyphs, flags);
1642
1643 return true;
1644}
1645
1646void QFontEngineBox::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const
1647{
1648 for (int i = 0; i < glyphs->numGlyphs; i++)
1649 glyphs->advances[i] = _size;
1650}
1651
1652void QFontEngineBox::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1653{
1654 if (!glyphs.numGlyphs)
1655 return;
1656
1657 QVarLengthArray<QFixedPoint> positions;
1658 QVarLengthArray<glyph_t> positioned_glyphs;
1659 QTransform matrix = QTransform::fromTranslate(x, y - _size);
1660 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1661
1662 QSize s(_size - 3, _size - 3);
1663 for (int k = 0; k < positions.size(); k++)
1664 path->addRect(QRectF(positions[k].toPointF(), s));
1665}
1666
1667glyph_metrics_t QFontEngineBox::boundingBox(const QGlyphLayout &glyphs)
1668{
1669 glyph_metrics_t overall;
1670 overall.width = _size*glyphs.numGlyphs;
1671 overall.height = _size;
1672 overall.xoff = overall.width;
1673 return overall;
1674}
1675
1676void QFontEngineBox::draw(QPaintEngine *p, qreal x, qreal y, const QTextItemInt &ti)
1677{
1678 if (!ti.glyphs.numGlyphs)
1679 return;
1680
1681 // any fixes here should probably also be done in QPaintEnginePrivate::drawBoxTextItem
1682 QSize s(_size - 3, _size - 3);
1683
1684 QVarLengthArray<QFixedPoint> positions;
1685 QVarLengthArray<glyph_t> glyphs;
1686 QTransform matrix = QTransform::fromTranslate(x, y - _size);
1687 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
1688 if (glyphs.size() == 0)
1689 return;
1690
1691
1692 QPainter *painter = p->painter();
1693 painter->save();
1694 painter->setBrush(Qt::NoBrush);
1695 QPen pen = painter->pen();
1696 pen.setWidthF(lineThickness().toReal());
1697 painter->setPen(pen);
1698 for (int k = 0; k < positions.size(); k++)
1699 painter->drawRect(QRectF(positions[k].toPointF(), s));
1700 painter->restore();
1701}
1702
1703glyph_metrics_t QFontEngineBox::boundingBox(glyph_t)
1704{
1705 return glyph_metrics_t(0, -_size, _size, _size, _size, 0);
1706}
1707
1708QFontEngine *QFontEngineBox::cloneWithSize(qreal pixelSize) const
1709{
1710 QFontEngineBox *fe = new QFontEngineBox(pixelSize);
1711 return fe;
1712}
1713
1714QFixed QFontEngineBox::ascent() const
1715{
1716 return _size;
1717}
1718
1719QFixed QFontEngineBox::capHeight() const
1720{
1721 return _size;
1722}
1723
1724QFixed QFontEngineBox::descent() const
1725{
1726 return 0;
1727}
1728
1729QFixed QFontEngineBox::leading() const
1730{
1731 QFixed l = _size * QFixed::fromReal(qreal(0.15));
1732 return l.ceil();
1733}
1734
1735qreal QFontEngineBox::maxCharWidth() const
1736{
1737 return _size;
1738}
1739
1740bool QFontEngineBox::canRender(const QChar *, int) const
1741{
1742 return true;
1743}
1744
1745QImage QFontEngineBox::alphaMapForGlyph(glyph_t)
1746{
1747 QImage image(_size, _size, QImage::Format_Alpha8);
1748 image.fill(0);
1749
1750 // FIXME: use qpainter
1751 for (int i=2; i <= _size-3; ++i) {
1752 image.setPixel(i, 2, 255);
1753 image.setPixel(i, _size-3, 255);
1754 image.setPixel(2, i, 255);
1755 image.setPixel(_size-3, i, 255);
1756 }
1757 return image;
1758}
1759
1760// ------------------------------------------------------------------
1761// Multi engine
1762// ------------------------------------------------------------------
1763
1764uchar QFontEngineMulti::highByte(glyph_t glyph)
1765{ return glyph >> 24; }
1766
1767// strip high byte from glyph
1768static inline glyph_t stripped(glyph_t glyph)
1769{ return glyph & 0x00ffffff; }
1770
1771QFontEngineMulti::QFontEngineMulti(QFontEngine *engine, int script, const QStringList &fallbackFamilies)
1772 : QFontEngine(Multi),
1773 m_fallbackFamilies(fallbackFamilies),
1774 m_script(script),
1775 m_fallbackFamiliesQueried(!m_fallbackFamilies.isEmpty())
1776{
1777 Q_ASSERT(engine && engine->type() != QFontEngine::Multi);
1778
1779 if (m_fallbackFamilies.isEmpty()) {
1780 // defer obtaining the fallback families until loadEngine(1)
1781 m_fallbackFamilies << QString();
1782 }
1783
1784 m_engines.resize(m_fallbackFamilies.size() + 1);
1785
1786 engine->ref.ref();
1787 m_engines[0] = engine;
1788
1789 fontDef = engine->fontDef;
1790 cache_cost = engine->cache_cost;
1791}
1792
1793QFontEngineMulti::~QFontEngineMulti()
1794{
1795 for (int i = 0; i < m_engines.size(); ++i) {
1796 QFontEngine *fontEngine = m_engines.at(i);
1797 if (fontEngine && !fontEngine->ref.deref())
1798 delete fontEngine;
1799 }
1800}
1801
1802QStringList qt_fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script);
1803
1804void QFontEngineMulti::ensureFallbackFamiliesQueried()
1805{
1806 QFont::StyleHint styleHint = QFont::StyleHint(fontDef.styleHint);
1807 if (styleHint == QFont::AnyStyle && fontDef.fixedPitch)
1808 styleHint = QFont::TypeWriter;
1809
1810 setFallbackFamiliesList(qt_fallbacksForFamily(fontDef.family, QFont::Style(fontDef.style), styleHint, QChar::Script(m_script)));
1811}
1812
1813void QFontEngineMulti::setFallbackFamiliesList(const QStringList &fallbackFamilies)
1814{
1815 Q_ASSERT(!m_fallbackFamiliesQueried);
1816
1817 m_fallbackFamilies = fallbackFamilies;
1818 if (m_fallbackFamilies.isEmpty()) {
1819 // turns out we lied about having any fallback at all
1820 Q_ASSERT(m_engines.size() == 2); // see c-tor for details
1821 QFontEngine *engine = m_engines.at(0);
1822 engine->ref.ref();
1823 m_engines[1] = engine;
1824 m_fallbackFamilies << fontDef.family;
1825 } else {
1826 m_engines.resize(m_fallbackFamilies.size() + 1);
1827 }
1828
1829 m_fallbackFamiliesQueried = true;
1830}
1831
1832void QFontEngineMulti::ensureEngineAt(int at)
1833{
1834 if (!m_fallbackFamiliesQueried)
1835 ensureFallbackFamiliesQueried();
1836 Q_ASSERT(at < m_engines.size());
1837 if (!m_engines.at(at)) {
1838 QFontEngine *engine = loadEngine(at);
1839 if (!engine)
1840 engine = new QFontEngineBox(fontDef.pixelSize);
1841 Q_ASSERT(engine && engine->type() != QFontEngine::Multi);
1842 engine->ref.ref();
1843 m_engines[at] = engine;
1844 }
1845}
1846
1847QFontEngine *QFontEngineMulti::loadEngine(int at)
1848{
1849 QFontDef request(fontDef);
1850 request.styleStrategy |= QFont::NoFontMerging;
1851 request.family = fallbackFamilyAt(at - 1);
1852 request.families = QStringList(request.family);
1853
1854 // At this point, the main script of the text has already been considered
1855 // when fetching the list of fallback families from the database, and the
1856 // info about the actual script of the characters may have been discarded,
1857 // so we do not check for writing system support, but instead just load
1858 // the family indiscriminately.
1859 if (QFontEngine *engine = QFontDatabase::findFont(request, QChar::Script_Common)) {
1860 engine->fontDef.weight = request.weight;
1861 if (request.style > QFont::StyleNormal)
1862 engine->fontDef.style = request.style;
1863 return engine;
1864 }
1865
1866 return 0;
1867}
1868
1869glyph_t QFontEngineMulti::glyphIndex(uint ucs4) const
1870{
1871 glyph_t glyph = engine(0)->glyphIndex(ucs4);
1872 if (glyph == 0
1873 && ucs4 != QChar::LineSeparator
1874 && ucs4 != QChar::LineFeed
1875 && ucs4 != QChar::CarriageReturn
1876 && ucs4 != QChar::ParagraphSeparator) {
1877 if (!m_fallbackFamiliesQueried)
1878 const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
1879 for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
1880 QFontEngine *engine = m_engines.at(x);
1881 if (!engine) {
1882 if (!shouldLoadFontEngineForCharacter(x, ucs4))
1883 continue;
1884 const_cast<QFontEngineMulti *>(this)->ensureEngineAt(x);
1885 engine = m_engines.at(x);
1886 }
1887 Q_ASSERT(engine != 0);
1888 if (engine->type() == Box)
1889 continue;
1890
1891 glyph = engine->glyphIndex(ucs4);
1892 if (glyph != 0) {
1893 // set the high byte to indicate which engine the glyph came from
1894 glyph |= (x << 24);
1895 break;
1896 }
1897 }
1898 }
1899
1900 return glyph;
1901}
1902
1903bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
1904 QGlyphLayout *glyphs, int *nglyphs,
1905 QFontEngine::ShaperFlags flags) const
1906{
1907 if (!engine(0)->stringToCMap(str, len, glyphs, nglyphs, flags))
1908 return false;
1909
1910 int glyph_pos = 0;
1911 QStringIterator it(str, str + len);
1912
1913 int lastFallback = -1;
1914 while (it.hasNext()) {
1915 const uint ucs4 = it.peekNext();
1916
1917 // If we applied a fallback font to previous glyph, and the current is either
1918 // ZWJ or ZWNJ, we should also try applying the same fallback font to that, in order
1919 // to get the correct shaping rules applied.
1920 if (lastFallback >= 0 && (ucs4 == QChar(0x200d) || ucs4 == QChar(0x200c))) {
1921 QFontEngine *engine = m_engines.at(lastFallback);
1922 glyph_t glyph = engine->glyphIndex(ucs4);
1923 if (glyph != 0) {
1924 glyphs->glyphs[glyph_pos] = glyph;
1925 if (!(flags & GlyphIndicesOnly)) {
1926 QGlyphLayout g = glyphs->mid(glyph_pos, 1);
1927 engine->recalcAdvances(&g, flags);
1928 }
1929
1930 // set the high byte to indicate which engine the glyph came from
1931 glyphs->glyphs[glyph_pos] |= (lastFallback << 24);
1932 } else {
1933 lastFallback = -1;
1934 }
1935 } else {
1936 lastFallback = -1;
1937 }
1938
1939 if (glyphs->glyphs[glyph_pos] == 0
1940 && ucs4 != QChar::LineSeparator
1941 && ucs4 != QChar::LineFeed
1942 && ucs4 != QChar::CarriageReturn
1943 && ucs4 != QChar::ParagraphSeparator) {
1944 if (!m_fallbackFamiliesQueried)
1945 const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
1946 for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
1947 QFontEngine *engine = m_engines.at(x);
1948 if (!engine) {
1949 if (!shouldLoadFontEngineForCharacter(x, ucs4))
1950 continue;
1951 const_cast<QFontEngineMulti *>(this)->ensureEngineAt(x);
1952 engine = m_engines.at(x);
1953 if (!engine)
1954 continue;
1955 }
1956 Q_ASSERT(engine != 0);
1957 if (engine->type() == Box)
1958 continue;
1959
1960 glyph_t glyph = engine->glyphIndex(ucs4);
1961 if (glyph != 0) {
1962 glyphs->glyphs[glyph_pos] = glyph;
1963 if (!(flags & GlyphIndicesOnly)) {
1964 QGlyphLayout g = glyphs->mid(glyph_pos, 1);
1965 engine->recalcAdvances(&g, flags);
1966 }
1967
1968 lastFallback = x;
1969
1970 // set the high byte to indicate which engine the glyph came from
1971 glyphs->glyphs[glyph_pos] |= (x << 24);
1972 break;
1973 }
1974 }
1975 }
1976
1977 it.advance();
1978 ++glyph_pos;
1979 }
1980
1981 *nglyphs = glyph_pos;
1982 glyphs->numGlyphs = glyph_pos;
1983
1984 return true;
1985}
1986
1987bool QFontEngineMulti::shouldLoadFontEngineForCharacter(int at, uint ucs4) const
1988{
1989 Q_UNUSED(at);
1990 Q_UNUSED(ucs4);
1991 return true;
1992}
1993
1994glyph_metrics_t QFontEngineMulti::boundingBox(const QGlyphLayout &glyphs)
1995{
1996 if (glyphs.numGlyphs <= 0)
1997 return glyph_metrics_t();
1998
1999 glyph_metrics_t overall;
2000
2001 int which = highByte(glyphs.glyphs[0]);
2002 int start = 0;
2003 int end, i;
2004 for (end = 0; end < glyphs.numGlyphs; ++end) {
2005 const int e = highByte(glyphs.glyphs[end]);
2006 if (e == which)
2007 continue;
2008
2009 // set the high byte to zero
2010 for (i = start; i < end; ++i)
2011 glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
2012
2013 // merge the bounding box for this run
2014 const glyph_metrics_t gm = engine(which)->boundingBox(glyphs.mid(start, end - start));
2015
2016 overall.x = qMin(overall.x, gm.x);
2017 overall.y = qMin(overall.y, gm.y);
2018 overall.width = overall.xoff + gm.width;
2019 overall.height = qMax(overall.height + overall.y, gm.height + gm.y) -
2020 qMin(overall.y, gm.y);
2021 overall.xoff += gm.xoff;
2022 overall.yoff += gm.yoff;
2023
2024 // reset the high byte for all glyphs
2025 const int hi = which << 24;
2026 for (i = start; i < end; ++i)
2027 glyphs.glyphs[i] = hi | glyphs.glyphs[i];
2028
2029 // change engine
2030 start = end;
2031 which = e;
2032 }
2033
2034 // set the high byte to zero
2035 for (i = start; i < end; ++i)
2036 glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
2037
2038 // merge the bounding box for this run
2039 const glyph_metrics_t gm = engine(which)->boundingBox(glyphs.mid(start, end - start));
2040
2041 overall.x = qMin(overall.x, gm.x);
2042 overall.y = qMin(overall.y, gm.y);
2043 overall.width = overall.xoff + gm.width;
2044 overall.height = qMax(overall.height + overall.y, gm.height + gm.y) -
2045 qMin(overall.y, gm.y);
2046 overall.xoff += gm.xoff;
2047 overall.yoff += gm.yoff;
2048
2049 // reset the high byte for all glyphs
2050 const int hi = which << 24;
2051 for (i = start; i < end; ++i)
2052 glyphs.glyphs[i] = hi | glyphs.glyphs[i];
2053
2054 return overall;
2055}
2056
2057void QFontEngineMulti::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
2058{
2059 int which = highByte(glyph);
2060 ensureEngineAt(which);
2061 engine(which)->getGlyphBearings(stripped(glyph), leftBearing, rightBearing);
2062}
2063
2064void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
2065 QPainterPath *path, QTextItem::RenderFlags flags)
2066{
2067 if (glyphs.numGlyphs <= 0)
2068 return;
2069
2070 int which = highByte(glyphs.glyphs[0]);
2071 int start = 0;
2072 int end, i;
2073 if (flags & QTextItem::RightToLeft) {
2074 for (int gl = 0; gl < glyphs.numGlyphs; gl++)
2075 x += glyphs.advances[gl].toReal();
2076 }
2077 for (end = 0; end < glyphs.numGlyphs; ++end) {
2078 const int e = highByte(glyphs.glyphs[end]);
2079 if (e == which)
2080 continue;
2081
2082 if (flags & QTextItem::RightToLeft) {
2083 for (i = start; i < end; ++i)
2084 x -= glyphs.advances[i].toReal();
2085 }
2086
2087 // set the high byte to zero
2088 for (i = start; i < end; ++i)
2089 glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
2090 engine(which)->addOutlineToPath(x, y, glyphs.mid(start, end - start), path, flags);
2091 // reset the high byte for all glyphs and update x and y
2092 const int hi = which << 24;
2093 for (i = start; i < end; ++i)
2094 glyphs.glyphs[i] = hi | glyphs.glyphs[i];
2095
2096 if (!(flags & QTextItem::RightToLeft)) {
2097 for (i = start; i < end; ++i)
2098 x += glyphs.advances[i].toReal();
2099 }
2100
2101 // change engine
2102 start = end;
2103 which = e;
2104 }
2105
2106 if (flags & QTextItem::RightToLeft) {
2107 for (i = start; i < end; ++i)
2108 x -= glyphs.advances[i].toReal();
2109 }
2110
2111 // set the high byte to zero
2112 for (i = start; i < end; ++i)
2113 glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
2114
2115 engine(which)->addOutlineToPath(x, y, glyphs.mid(start, end - start), path, flags);
2116
2117 // reset the high byte for all glyphs
2118 const int hi = which << 24;
2119 for (i = start; i < end; ++i)
2120 glyphs.glyphs[i] = hi | glyphs.glyphs[i];
2121}
2122
2123void QFontEngineMulti::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
2124{
2125 if (glyphs->numGlyphs <= 0)
2126 return;
2127
2128 int which = highByte(glyphs->glyphs[0]);
2129 int start = 0;
2130 int end, i;
2131 for (end = 0; end < glyphs->numGlyphs; ++end) {
2132 const int e = highByte(glyphs->glyphs[end]);
2133 if (e == which)
2134 continue;
2135
2136 // set the high byte to zero
2137 for (i = start; i < end; ++i)
2138 glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
2139
2140 QGlyphLayout offs = glyphs->mid(start, end - start);
2141 engine(which)->recalcAdvances(&offs, flags);
2142
2143 // reset the high byte for all glyphs and update x and y
2144 const int hi = which << 24;
2145 for (i = start; i < end; ++i)
2146 glyphs->glyphs[i] = hi | glyphs->glyphs[i];
2147
2148 // change engine
2149 start = end;
2150 which = e;
2151 }
2152
2153 // set the high byte to zero
2154 for (i = start; i < end; ++i)
2155 glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
2156
2157 QGlyphLayout offs = glyphs->mid(start, end - start);
2158 engine(which)->recalcAdvances(&offs, flags);
2159
2160 // reset the high byte for all glyphs
2161 const int hi = which << 24;
2162 for (i = start; i < end; ++i)
2163 glyphs->glyphs[i] = hi | glyphs->glyphs[i];
2164}
2165
2166void QFontEngineMulti::doKerning(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
2167{
2168 if (glyphs->numGlyphs <= 0)
2169 return;
2170
2171 int which = highByte(glyphs->glyphs[0]);
2172 int start = 0;
2173 int end, i;
2174 for (end = 0; end < glyphs->numGlyphs; ++end) {
2175 const int e = highByte(glyphs->glyphs[end]);
2176 if (e == which)
2177 continue;
2178
2179 // set the high byte to zero
2180 for (i = start; i < end; ++i)
2181 glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
2182
2183 QGlyphLayout offs = glyphs->mid(start, end - start);
2184 engine(which)->doKerning(&offs, flags);
2185
2186 // reset the high byte for all glyphs and update x and y
2187 const int hi = which << 24;
2188 for (i = start; i < end; ++i)
2189 glyphs->glyphs[i] = hi | glyphs->glyphs[i];
2190
2191 // change engine
2192 start = end;
2193 which = e;
2194 }
2195
2196 // set the high byte to zero
2197 for (i = start; i < end; ++i)
2198 glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
2199
2200 QGlyphLayout offs = glyphs->mid(start, end - start);
2201 engine(which)->doKerning(&offs, flags);
2202
2203 // reset the high byte for all glyphs
2204 const int hi = which << 24;
2205 for (i = start; i < end; ++i)
2206 glyphs->glyphs[i] = hi | glyphs->glyphs[i];
2207}
2208
2209glyph_metrics_t QFontEngineMulti::boundingBox(glyph_t glyph)
2210{
2211 const int which = highByte(glyph);
2212 return engine(which)->boundingBox(stripped(glyph));
2213}
2214
2215QFixed QFontEngineMulti::ascent() const
2216{ return engine(0)->ascent(); }
2217
2218QFixed QFontEngineMulti::capHeight() const
2219{ return engine(0)->capHeight(); }
2220
2221QFixed QFontEngineMulti::descent() const
2222{ return engine(0)->descent(); }
2223
2224QFixed QFontEngineMulti::leading() const
2225{
2226 return engine(0)->leading();
2227}
2228
2229QFixed QFontEngineMulti::xHeight() const
2230{
2231 return engine(0)->xHeight();
2232}
2233
2234QFixed QFontEngineMulti::averageCharWidth() const
2235{
2236 return engine(0)->averageCharWidth();
2237}
2238
2239QFixed QFontEngineMulti::lineThickness() const
2240{
2241 return engine(0)->lineThickness();
2242}
2243
2244QFixed QFontEngineMulti::underlinePosition() const
2245{
2246 return engine(0)->underlinePosition();
2247}
2248
2249qreal QFontEngineMulti::maxCharWidth() const
2250{
2251 return engine(0)->maxCharWidth();
2252}
2253
2254qreal QFontEngineMulti::minLeftBearing() const
2255{
2256 return engine(0)->minLeftBearing();
2257}
2258
2259qreal QFontEngineMulti::minRightBearing() const
2260{
2261 return engine(0)->minRightBearing();
2262}
2263
2264bool QFontEngineMulti::canRender(const QChar *string, int len) const
2265{
2266 if (engine(0)->canRender(string, len))
2267 return true;
2268
2269 int nglyphs = len;
2270
2271 QVarLengthArray<glyph_t> glyphs(nglyphs);
2272
2273 QGlyphLayout g;
2274 g.numGlyphs = nglyphs;
2275 g.glyphs = glyphs.data();
2276 if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly))
2277 Q_UNREACHABLE();
2278
2279 for (int i = 0; i < nglyphs; i++) {
2280 if (glyphs[i] == 0)
2281 return false;
2282 }
2283
2284 return true;
2285}
2286
2287/* Implement alphaMapForGlyph() which is called by Lighthouse/Windows code.
2288 * Ideally, that code should be fixed to correctly handle QFontEngineMulti. */
2289
2290QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph)
2291{
2292 const int which = highByte(glyph);
2293 return engine(which)->alphaMapForGlyph(stripped(glyph));
2294}
2295
2296QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition)
2297{
2298 const int which = highByte(glyph);
2299 return engine(which)->alphaMapForGlyph(stripped(glyph), subPixelPosition);
2300}
2301
2302QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, const QTransform &t)
2303{
2304 const int which = highByte(glyph);
2305 return engine(which)->alphaMapForGlyph(stripped(glyph), t);
2306}
2307
2308QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
2309{
2310 const int which = highByte(glyph);
2311 return engine(which)->alphaMapForGlyph(stripped(glyph), subPixelPosition, t);
2312}
2313
2314QImage QFontEngineMulti::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
2315{
2316 const int which = highByte(glyph);
2317 return engine(which)->alphaRGBMapForGlyph(stripped(glyph), subPixelPosition, t);
2318}
2319
2320/*
2321 This is used indirectly by Qt WebKit when using QTextLayout::setRawFont
2322
2323 The purpose of this is to provide the necessary font fallbacks when drawing complex
2324 text. Since Qt WebKit ends up repeatedly creating QTextLayout instances and passing them
2325 the same raw font over and over again, we want to cache the corresponding multi font engine
2326 as it may contain fallback font engines already.
2327*/
2328QFontEngine *QFontEngineMulti::createMultiFontEngine(QFontEngine *fe, int script)
2329{
2330 QFontEngine *engine = 0;
2331 QFontCache::Key key(fe->fontDef, script, /*multi = */true);
2332 QFontCache *fc = QFontCache::instance();
2333 // We can't rely on the fontDef (and hence the cache Key)
2334 // alone to distinguish webfonts, since these should not be
2335 // accidentally shared, even if the resulting fontcache key
2336 // is strictly identical. See:
2337 // http://www.w3.org/TR/css3-fonts/#font-face-rule
2338 const bool faceIsLocal = !fe->faceId().filename.isEmpty();
2339 QFontCache::EngineCache::Iterator it = fc->engineCache.find(key),
2340 end = fc->engineCache.end();
2341 while (it != end && it.key() == key) {
2342 Q_ASSERT(it.value().data->type() == QFontEngine::Multi);
2343 QFontEngineMulti *cachedEngine = static_cast<QFontEngineMulti *>(it.value().data);
2344 if (fe == cachedEngine->engine(0) || (faceIsLocal && fe->faceId().filename == cachedEngine->engine(0)->faceId().filename)) {
2345 engine = cachedEngine;
2346 fc->updateHitCountAndTimeStamp(it.value());
2347 break;
2348 }
2349 ++it;
2350 }
2351 if (!engine) {
2352 engine = QGuiApplicationPrivate::instance()->platformIntegration()->fontDatabase()->fontEngineMulti(fe, QChar::Script(script));
2353 fc->insertEngine(key, engine, /* insertMulti */ !faceIsLocal);
2354 }
2355 Q_ASSERT(engine);
2356 return engine;
2357}
2358
2359QTestFontEngine::QTestFontEngine(int size)
2360 : QFontEngineBox(TestFontEngine, size)
2361{}
2362
2363QT_END_NAMESPACE
2364