qfontengine.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/gui/text/qfontengine.cpp
Source codeSwitch to Preprocessed file
LineSourceCount
1/****************************************************************************-
2**-
3** Copyright (C) 2016 The Qt Company Ltd.-
4** Contact: https://www.qt.io/licensing/-
5**-
6** This file is part of the QtGui module of the Qt Toolkit.-
7**-
8** $QT_BEGIN_LICENSE:LGPL$-
9** Commercial License Usage-
10** Licensees holding valid commercial Qt licenses may use this file in-
11** accordance with the commercial license agreement provided with the-
12** Software or, alternatively, in accordance with the terms contained in-
13** a written agreement between you and The Qt Company. For licensing terms-
14** and conditions see https://www.qt.io/terms-conditions. For further-
15** information use the contact form at https://www.qt.io/contact-us.-
16**-
17** GNU Lesser General Public License Usage-
18** Alternatively, this file may be used under the terms of the GNU Lesser-
19** General Public License version 3 as published by the Free Software-
20** Foundation and appearing in the file LICENSE.LGPL3 included in the-
21** packaging of this file. Please review the following information to-
22** ensure the GNU Lesser General Public License version 3 requirements-
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.-
24**-
25** GNU General Public License Usage-
26** Alternatively, this file may be used under the terms of the GNU-
27** General Public License version 2.0 or (at your option) the GNU General-
28** Public license version 3 or any later version approved by the KDE Free-
29** Qt Foundation. The licenses are as published by the Free Software-
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3-
31** included in the packaging of this file. Please review the following-
32** information to ensure the GNU General Public License requirements will-
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and-
34** https://www.gnu.org/licenses/gpl-3.0.html.-
35**-
36** $QT_END_LICENSE$-
37**-
38****************************************************************************/-
39-
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#ifdef QT_ENABLE_HARFBUZZ_NG-
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#ifdef QT_ENABLE_HARFBUZZ_NG-
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_(0), font_destroy_func(0),(),-
250 face_(0), face_destroy_func(0),(),-
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)
enginesCollectorDescription
TRUEnever evaluated
FALSEnever evaluated
0
267 enginesCollector->append(this);
never executed: enginesCollector->append(this);
0
268#endif-
269}
never executed: end of block
0
270-
271QFontEngine::~QFontEngine()-
{
m_glyphCaches.clear();
if (font_ && font_destroy_func) {
font_destroy_func(font_);
font_ = 0;
}
if (face_ && face_destroy_func){
face_destroy_func(face_);
face_ = 0;
}#ifdef QT_BUILD_INTERNAL
274 if (enginesCollector)
enginesCollectorDescription
TRUEnever evaluated
FALSEnever evaluated
0
275 enginesCollector->removeOne(this);
never executed: enginesCollector->removeOne(this);
0
276#endif-
277}
never executed: end of block
0
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#ifdef QT_ENABLE_HARFBUZZ_NG-
301 if (qt_useHarfbuzzNG())
qt_useHarfbuzzNG()Description
TRUEnever evaluated
FALSEnever evaluated
0
302 return hb_qt_font_get_for_engine(const_cast<QFontEngine *>(this));
never executed: return hb_qt_font_get_for_engine(const_cast<QFontEngine *>(this));
0
303#endif-
304 if (!font_) {
!font_Description
TRUEnever evaluated
FALSEnever evaluated
0
305 HB_Face hbFace = (HB_Face)harfbuzzFace();-
306 if (hbFace->font_for_init) {
hbFace->font_for_initDescription
TRUEnever evaluated
FALSEnever evaluated
0
307 void *data = hbFace->font_for_init;-
308 q_check_ptr(qHBLoadFace(hbFace));-
309 free(data);-
310 }
never executed: end of block
0
311-
312 HB_FontRec *hbFont = (HB_FontRec *) malloc(sizeof(HB_FontRec));-
313 Q_CHECK_PTR(hbFont);
never executed: qt_check_pointer(__FILE__,313);
!(hbFont)Description
TRUEnever evaluated
FALSEnever evaluated
0
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)
emSquare == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
320 emSquare = 1000; // a fallback value suitable for Type1 fonts
never executed: emSquare = 1000;
0
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(void *)hbFont;-
font_destroy_func =, free;);
328 }
never executed: end of block
0
329 return font_;.get();
never executed: return font_.get();
0
330}-
331-
332void *QFontEngine::harfbuzzFace() const-
333{-
334 Q_ASSERT(type() != QFontEngine::Multi);-
335#ifdef QT_ENABLE_HARFBUZZ_NG-
336 if (qt_useHarfbuzzNG())
qt_useHarfbuzzNG()Description
TRUEnever evaluated
FALSEnever evaluated
0
337 return hb_qt_face_get_for_engine(const_cast<QFontEngine *>(this));
never executed: return hb_qt_face_get_for_engine(const_cast<QFontEngine *>(this));
0
338#endif-
339 if (!face_) {
!face_Description
TRUEnever evaluated
FALSEnever evaluated
0
340 QFontEngine::FaceData *data = (QFontEngine::FaceData *)malloc(sizeof(QFontEngine::FaceData));-
341 Q_CHECK_PTR(data);
never executed: qt_check_pointer(__FILE__,341);
!(data)Description
TRUEnever evaluated
FALSEnever evaluated
0
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);
never executed: qt_check_pointer(__FILE__,346);
!(hbFace)Description
TRUEnever evaluated
FALSEnever evaluated
0
347 hbFace->isSymbolFont = symbol;-
348-
349 face_ = Holder(void *)hbFace;-
face_destroy_func =, hb_freeFace;);
350 }
never executed: end of block
0
351 return face_;.get();
never executed: return face_.get();
0
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 (!((script >= QChar::Script_Syriac && script <= QChar::Script_Sinhala)-
363 || script == QChar::Script_Khmer || script == QChar::Script_Nko)) {-
364 return true;-
365 }-
366-
367#ifdef QT_ENABLE_HARFBUZZ_NG-
368 if (qt_useHarfbuzzNG()) {-
369#if defined(Q_OS_DARWIN)-
370 // in AAT fonts, 'gsub' table is effectively replaced by 'mort'/'morx' table-
371 uint len;-
372 if (getSfntTableData(MAKE_TAG('m','o','r','t'), 0, &len) || getSfntTableData(MAKE_TAG('m','o','r','x'), 0, &len))-
373 return true;-
374#endif-
375-
376 bool ret = false;-
377 if (hb_face_t *face = hb_qt_face_get_for_engine(const_cast<QFontEngine *>(this))) {-
378 hb_tag_t script_tag_1, script_tag_2;-
379 hb_ot_tags_from_script(hb_qt_script_to_script(script), &script_tag_1, &script_tag_2);-
380-
381 unsigned int script_index;-
382 ret = hb_ot_layout_table_find_script(face, HB_OT_TAG_GSUB, script_tag_1, &script_index);-
383 if (!ret) {-
384 ret = hb_ot_layout_table_find_script(face, HB_OT_TAG_GSUB, script_tag_2, &script_index);-
385 if (!ret && script_tag_2 != HB_OT_TAG_DEFAULT_SCRIPT)-
386 ret = hb_ot_layout_table_find_script(face, HB_OT_TAG_GSUB, HB_OT_TAG_DEFAULT_SCRIPT, &script_index);-
387 }-
388 }-
389 return ret;-
390 }-
391#endif-
392 HB_Face hbFace = (HB_Face)harfbuzzFace();-
393 if (hbFace->font_for_init) {-
394 void *data = hbFace->font_for_init;-
395 q_check_ptr(qHBLoadFace(hbFace));-
396 free(data);-
397 }-
398 return hbFace->supported_scripts[script_to_hbscript(script)];-
399}-
400-
401bool QFontEngine::canRender(const QChar *str, int len) const-
402{-
403 QStringIterator it(str, str + len);-
404 while (it.hasNext()) {-
405 if (glyphIndex(it.next()) == 0)-
406 return false;-
407 }-
408-
409 return true;-
410}-
411-
412glyph_metrics_t QFontEngine::boundingBox(glyph_t glyph, const QTransform &matrix)-
413{-
414 glyph_metrics_t metrics = boundingBox(glyph);-
415-
416 if (matrix.type() > QTransform::TxTranslate) {-
417 return metrics.transformed(matrix);-
418 }-
419 return metrics;-
420}-
421-
422QFixed QFontEngine::xHeight() const-
423{-
424 const glyph_t glyph = glyphIndex('x');-
425 glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph);-
426 return bb.height;-
427}-
428-
429QFixed QFontEngine::averageCharWidth() const-
430{-
431 const glyph_t glyph = glyphIndex('x');-
432 glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph);-
433 return bb.xoff;-
434}-
435-
436bool QFontEngine::supportsTransformation(const QTransform &transform) const-
437{-
438 return transform.type() < QTransform::TxProject;-
439}-
440-
441void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags,-
442 QVarLengthArray<glyph_t> &glyphs_out, QVarLengthArray<QFixedPoint> &positions)-
443{-
444 QFixed xpos;-
445 QFixed ypos;-
446-
447 const bool transform = matrix.m11() != 1.-
448 || matrix.m12() != 0.-
449 || matrix.m21() != 0.-
450 || matrix.m22() != 1.;-
451 if (!transform) {-
452 xpos = QFixed::fromReal(matrix.dx());-
453 ypos = QFixed::fromReal(matrix.dy());-
454 }-
455-
456 int current = 0;-
457 if (flags & QTextItem::RightToLeft) {-
458 int i = glyphs.numGlyphs;-
459 int totalKashidas = 0;-
460 while(i--) {-
461 if (glyphs.attributes[i].dontPrint)-
462 continue;-
463 xpos += glyphs.advances[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);-
464 totalKashidas += glyphs.justifications[i].nKashidas;-
465 }-
466 positions.resize(glyphs.numGlyphs+totalKashidas);-
467 glyphs_out.resize(glyphs.numGlyphs+totalKashidas);-
468-
469 i = 0;-
470 while(i < glyphs.numGlyphs) {-
471 if (glyphs.attributes[i].dontPrint) {-
472 ++i;-
473 continue;-
474 }-
475 xpos -= glyphs.advances[i];-
476-
477 QFixed gpos_x = xpos + glyphs.offsets[i].x;-
478 QFixed gpos_y = ypos + glyphs.offsets[i].y;-
479 if (transform) {-
480 QPointF gpos(gpos_x.toReal(), gpos_y.toReal());-
481 gpos = gpos * matrix;-
482 gpos_x = QFixed::fromReal(gpos.x());-
483 gpos_y = QFixed::fromReal(gpos.y());-
484 }-
485 positions[current].x = gpos_x;-
486 positions[current].y = gpos_y;-
487 glyphs_out[current] = glyphs.glyphs[i];-
488 ++current;-
489 if (glyphs.justifications[i].nKashidas) {-
490 QChar ch(0x640); // Kashida character-
491-
492 glyph_t kashidaGlyph = glyphIndex(ch.unicode());-
493 QFixed kashidaWidth;-
494-
495 QGlyphLayout g;-
496 g.numGlyphs = 1;-
497 g.glyphs = &kashidaGlyph;-
498 g.advances = &kashidaWidth;-
499 recalcAdvances(&g, 0);-
500-
501 for (uint k = 0; k < glyphs.justifications[i].nKashidas; ++k) {-
502 xpos -= kashidaWidth;-
503-
504 QFixed gpos_x = xpos + glyphs.offsets[i].x;-
505 QFixed gpos_y = ypos + glyphs.offsets[i].y;-
506 if (transform) {-
507 QPointF gpos(gpos_x.toReal(), gpos_y.toReal());-
508 gpos = gpos * matrix;-
509 gpos_x = QFixed::fromReal(gpos.x());-
510 gpos_y = QFixed::fromReal(gpos.y());-
511 }-
512 positions[current].x = gpos_x;-
513 positions[current].y = gpos_y;-
514 glyphs_out[current] = kashidaGlyph;-
515 ++current;-
516 }-
517 } else {-
518 xpos -= QFixed::fromFixed(glyphs.justifications[i].space_18d6);-
519 }-
520 ++i;-
521 }-
522 } else {-
523 positions.resize(glyphs.numGlyphs);-
524 glyphs_out.resize(glyphs.numGlyphs);-
525 int i = 0;-
526 if (!transform) {-
527 while (i < glyphs.numGlyphs) {-
528 if (!glyphs.attributes[i].dontPrint) {-
529 positions[current].x = xpos + glyphs.offsets[i].x;-
530 positions[current].y = ypos + glyphs.offsets[i].y;-
531 glyphs_out[current] = glyphs.glyphs[i];-
532 xpos += glyphs.advances[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);-
533 ++current;-
534 }-
535 ++i;-
536 }-
537 } else {-
538 while (i < glyphs.numGlyphs) {-
539 if (!glyphs.attributes[i].dontPrint) {-
540 QFixed gpos_x = xpos + glyphs.offsets[i].x;-
541 QFixed gpos_y = ypos + glyphs.offsets[i].y;-
542 QPointF gpos(gpos_x.toReal(), gpos_y.toReal());-
543 gpos = gpos * matrix;-
544 positions[current].x = QFixed::fromReal(gpos.x());-
545 positions[current].y = QFixed::fromReal(gpos.y());-
546 glyphs_out[current] = glyphs.glyphs[i];-
547 xpos += glyphs.advances[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);-
548 ++current;-
549 }-
550 ++i;-
551 }-
552 }-
553 }-
554 positions.resize(current);-
555 glyphs_out.resize(current);-
556 Q_ASSERT(positions.size() == glyphs_out.size());-
557}-
558-
559void QFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)-
560{-
561 glyph_metrics_t gi = boundingBox(glyph);-
562 if (leftBearing != 0)-
563 *leftBearing = gi.leftBearing().toReal();-
564 if (rightBearing != 0)-
565 *rightBearing = gi.rightBearing().toReal();-
566}-
567-
568qreal QFontEngine::minLeftBearing() const-
569{-
570 if (m_minLeftBearing == kBearingNotInitialized)-
571 minRightBearing(); // Initializes both (see below)-
572-
573 return m_minLeftBearing;-
574}-
575-
576#define q16Dot16ToFloat(i) ((i) / 65536.0)-
577-
578#define kMinLeftSideBearingOffset 12-
579#define kMinRightSideBearingOffset 14-
580-
581qreal QFontEngine::minRightBearing() const-
582{-
583 if (m_minRightBearing == kBearingNotInitialized) {-
584-
585 // Try the 'hhea' font table first, which covers the entire font-
586 QByteArray hheaTable = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a'));-
587 if (hheaTable.size() >= int(kMinRightSideBearingOffset + sizeof(qint16))) {-
588 const uchar *tableData = reinterpret_cast<const uchar *>(hheaTable.constData());-
589 Q_ASSERT(q16Dot16ToFloat(qFromBigEndian<quint32>(tableData)) == 1.0);-
590-
591 qint16 minLeftSideBearing = qFromBigEndian<qint16>(tableData + kMinLeftSideBearingOffset);-
592 qint16 minRightSideBearing = qFromBigEndian<qint16>(tableData + kMinRightSideBearingOffset);-
593-
594 // The table data is expressed as FUnits, meaning we have to take the number-
595 // of units per em into account. Since pixelSize already has taken DPI into-
596 // account we can use that directly instead of the point size.-
597 int unitsPerEm = emSquareSize().toInt();-
598 qreal funitToPixelFactor = fontDef.pixelSize / unitsPerEm;-
599-
600 // Some fonts on OS X (such as Gurmukhi Sangam MN, Khmer MN, Lao Sangam MN, etc.), have-
601 // invalid values for their NBSPACE left bearing, causing the 'hhea' minimum bearings to-
602 // be way off. We detect this by assuming that the minimum bearsings are within a certain-
603 // range of the em square size.-
604 static const int largestValidBearing = 4 * unitsPerEm;-
605-
606 if (qAbs(minLeftSideBearing) < largestValidBearing)-
607 m_minLeftBearing = minLeftSideBearing * funitToPixelFactor;-
608 if (qAbs(minRightSideBearing) < largestValidBearing)-
609 m_minRightBearing = minRightSideBearing * funitToPixelFactor;-
610 }-
611-
612 // Fallback in case of missing 'hhea' table (bitmap fonts e.g.) or broken 'hhea' values-
613 if (m_minLeftBearing == kBearingNotInitialized || m_minRightBearing == kBearingNotInitialized) {-
614-
615 // To balance performance and correctness we only look at a subset of the-
616 // possible glyphs in the font, based on which characters are more likely-
617 // to have a left or right bearing.-
618 static const ushort characterSubset[] = {-
619 '(', 'C', 'F', 'K', 'V', 'X', 'Y', ']', '_', 'f', 'r', '|',-
620 127, 205, 645, 884, 922, 1070, 12386-
621 };-
622-
623 // The font may have minimum bearings larger than 0, so we have to start at the max-
624 m_minLeftBearing = m_minRightBearing = std::numeric_limits<qreal>::max();-
625-
626 for (uint i = 0; i < (sizeof(characterSubset) / sizeof(ushort)); ++i) {-
627 const glyph_t glyph = glyphIndex(characterSubset[i]);-
628 if (!glyph)-
629 continue;-
630-
631 glyph_metrics_t glyphMetrics = const_cast<QFontEngine *>(this)->boundingBox(glyph);-
632-
633 // Glyphs with no contours shouldn't contribute to bearings-
634 if (!glyphMetrics.width || !glyphMetrics.height)-
635 continue;-
636-
637 m_minLeftBearing = qMin(m_minLeftBearing, glyphMetrics.leftBearing().toReal());-
638 m_minRightBearing = qMin(m_minRightBearing, glyphMetrics.rightBearing().toReal());-
639 }-
640 }-
641-
642 if (m_minLeftBearing == kBearingNotInitialized || m_minRightBearing == kBearingNotInitialized)-
643 qWarning() << "Failed to compute left/right minimum bearings for" << fontDef.family;-
644 }-
645-
646 return m_minRightBearing;-
647}-
648-
649glyph_metrics_t QFontEngine::tightBoundingBox(const QGlyphLayout &glyphs)-
650{-
651 glyph_metrics_t overall;-
652-
653 QFixed ymax = 0;-
654 QFixed xmax = 0;-
655 for (int i = 0; i < glyphs.numGlyphs; i++) {-
656 glyph_metrics_t bb = boundingBox(glyphs.glyphs[i]);-
657 QFixed x = overall.xoff + glyphs.offsets[i].x + bb.x;-
658 QFixed y = overall.yoff + glyphs.offsets[i].y + bb.y;-
659 overall.x = qMin(overall.x, x);-
660 overall.y = qMin(overall.y, y);-
661 xmax = qMax(xmax, x + bb.width);-
662 ymax = qMax(ymax, y + bb.height);-
663 overall.xoff += bb.xoff;-
664 overall.yoff += bb.yoff;-
665 }-
666 overall.height = qMax(overall.height, ymax - overall.y);-
667 overall.width = xmax - overall.x;-
668-
669 return overall;-
670}-
671-
672-
673void QFontEngine::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path,-
674 QTextItem::RenderFlags flags)-
675{-
676 if (!glyphs.numGlyphs)-
677 return;-
678-
679 QVarLengthArray<QFixedPoint> positions;-
680 QVarLengthArray<glyph_t> positioned_glyphs;-
681 QTransform matrix = QTransform::fromTranslate(x, y);-
682 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);-
683 addGlyphsToPath(positioned_glyphs.data(), positions.data(), positioned_glyphs.size(), path, flags);-
684}-
685-
686#define GRID(x, y) grid[(y)*(w+1) + (x)]-
687#define SET(x, y) (*(image_data + (y)*bpl + ((x) >> 3)) & (0x80 >> ((x) & 7)))-
688-
689enum { EdgeRight = 0x1,-
690 EdgeDown = 0x2,-
691 EdgeLeft = 0x4,-
692 EdgeUp = 0x8-
693};-
694-
695static void collectSingleContour(qreal x0, qreal y0, uint *grid, int x, int y, int w, int h, QPainterPath *path)-
696{-
697 Q_UNUSED(h);-
698-
699 path->moveTo(x + x0, y + y0);-
700 while (GRID(x, y)) {-
701 if (GRID(x, y) & EdgeRight) {-
702 while (GRID(x, y) & EdgeRight) {-
703 GRID(x, y) &= ~EdgeRight;-
704 ++x;-
705 }-
706 Q_ASSERT(x <= w);-
707 path->lineTo(x + x0, y + y0);-
708 continue;-
709 }-
710 if (GRID(x, y) & EdgeDown) {-
711 while (GRID(x, y) & EdgeDown) {-
712 GRID(x, y) &= ~EdgeDown;-
713 ++y;-
714 }-
715 Q_ASSERT(y <= h);-
716 path->lineTo(x + x0, y + y0);-
717 continue;-
718 }-
719 if (GRID(x, y) & EdgeLeft) {-
720 while (GRID(x, y) & EdgeLeft) {-
721 GRID(x, y) &= ~EdgeLeft;-
722 --x;-
723 }-
724 Q_ASSERT(x >= 0);-
725 path->lineTo(x + x0, y + y0);-
726 continue;-
727 }-
728 if (GRID(x, y) & EdgeUp) {-
729 while (GRID(x, y) & EdgeUp) {-
730 GRID(x, y) &= ~EdgeUp;-
731 --y;-
732 }-
733 Q_ASSERT(y >= 0);-
734 path->lineTo(x + x0, y + y0);-
735 continue;-
736 }-
737 }-
738 path->closeSubpath();-
739}-
740-
741Q_GUI_EXPORT void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path)-
742{-
743 uint *grid = new uint[(w+1)*(h+1)];-
744 // set up edges-
745 for (int y = 0; y <= h; ++y) {-
746 for (int x = 0; x <= w; ++x) {-
747 bool topLeft = (x == 0)|(y == 0) ? false : SET(x - 1, y - 1);-
748 bool topRight = (x == w)|(y == 0) ? false : SET(x, y - 1);-
749 bool bottomLeft = (x == 0)|(y == h) ? false : SET(x - 1, y);-
750 bool bottomRight = (x == w)|(y == h) ? false : SET(x, y);-
751-
752 GRID(x, y) = 0;-
753 if ((!topRight) & bottomRight)-
754 GRID(x, y) |= EdgeRight;-
755 if ((!bottomRight) & bottomLeft)-
756 GRID(x, y) |= EdgeDown;-
757 if ((!bottomLeft) & topLeft)-
758 GRID(x, y) |= EdgeLeft;-
759 if ((!topLeft) & topRight)-
760 GRID(x, y) |= EdgeUp;-
761 }-
762 }-
763-
764 // collect edges-
765 for (int y = 0; y < h; ++y) {-
766 for (int x = 0; x < w; ++x) {-
767 if (!GRID(x, y))-
768 continue;-
769 // found start of a contour, follow it-
770 collectSingleContour(x0, y0, grid, x, y, w, h, path);-
771 }-
772 }-
773 delete [] grid;-
774}-
775-
776#undef GRID-
777#undef SET-
778-
779-
780void QFontEngine::addBitmapFontToPath(qreal x, qreal y, const QGlyphLayout &glyphs,-
781 QPainterPath *path, QTextItem::RenderFlags flags)-
782{-
783// TODO what to do with 'flags' ??-
784 Q_UNUSED(flags);-
785 QFixed advanceX = QFixed::fromReal(x);-
786 QFixed advanceY = QFixed::fromReal(y);-
787 for (int i=0; i < glyphs.numGlyphs; ++i) {-
788 glyph_metrics_t metrics = boundingBox(glyphs.glyphs[i]);-
789 if (metrics.width.value() == 0 || metrics.height.value() == 0) {-
790 advanceX += glyphs.advances[i];-
791 continue;-
792 }-
793 const QImage alphaMask = alphaMapForGlyph(glyphs.glyphs[i]);-
794-
795 const int w = alphaMask.width();-
796 const int h = alphaMask.height();-
797 const int srcBpl = alphaMask.bytesPerLine();-
798 QImage bitmap;-
799 if (alphaMask.depth() == 1) {-
800 bitmap = alphaMask;-
801 } else {-
802 bitmap = QImage(w, h, QImage::Format_Mono);-
803 const uchar *imageData = alphaMask.bits();-
804 const int destBpl = bitmap.bytesPerLine();-
805 uchar *bitmapData = bitmap.bits();-
806-
807 for (int yi = 0; yi < h; ++yi) {-
808 const uchar *src = imageData + yi*srcBpl;-
809 uchar *dst = bitmapData + yi*destBpl;-
810 for (int xi = 0; xi < w; ++xi) {-
811 const int byte = xi / 8;-
812 const int bit = xi % 8;-
813 if (bit == 0)-
814 dst[byte] = 0;-
815 if (src[xi])-
816 dst[byte] |= 128 >> bit;-
817 }-
818 }-
819 }-
820 const uchar *bitmap_data = bitmap.constBits();-
821 QFixedPoint offset = glyphs.offsets[i];-
822 advanceX += offset.x;-
823 advanceY += offset.y;-
824 qt_addBitmapToPath((advanceX + metrics.x).toReal(), (advanceY + metrics.y).toReal(), bitmap_data, bitmap.bytesPerLine(), w, h, path);-
825 advanceX += glyphs.advances[i];-
826 }-
827}-
828-
829void QFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nGlyphs,-
830 QPainterPath *path, QTextItem::RenderFlags flags)-
831{-
832 qreal x = positions[0].x.toReal();-
833 qreal y = positions[0].y.toReal();-
834 QVarLengthGlyphLayoutArray g(nGlyphs);-
835-
836 for (int i = 0; i < nGlyphs - 1; ++i) {-
837 g.glyphs[i] = glyphs[i];-
838 g.advances[i] = positions[i + 1].x - positions[i].x;-
839 }-
840 g.glyphs[nGlyphs - 1] = glyphs[nGlyphs - 1];-
841 g.advances[nGlyphs - 1] = QFixed::fromReal(maxCharWidth());-
842-
843 addBitmapFontToPath(x, y, g, path, flags);-
844}-
845-
846QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed /*subPixelPosition*/)-
847{-
848 // For font engines don't support subpixel positioning-
849 return alphaMapForGlyph(glyph);-
850}-
851-
852QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &t)-
853{-
854 QImage i = alphaMapForGlyph(glyph);-
855 if (t.type() > QTransform::TxTranslate)-
856 i = i.transformed(t).convertToFormat(QImage::Format_Alpha8);-
857 Q_ASSERT(i.depth() <= 8); // To verify that transformed didn't change the format...-
858-
859 return i;-
860}-
861-
862QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)-
863{-
864 if (! supportsSubPixelPositions())-
865 return alphaMapForGlyph(glyph, t);-
866-
867 QImage i = alphaMapForGlyph(glyph, subPixelPosition);-
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-
875QImage QFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed /*subPixelPosition*/, const QTransform &t)-
876{-
877 const QImage alphaMask = alphaMapForGlyph(glyph, t);-
878 QImage rgbMask(alphaMask.width(), alphaMask.height(), QImage::Format_RGB32);-
879-
880 for (int y=0; y<alphaMask.height(); ++y) {-
881 uint *dst = (uint *) rgbMask.scanLine(y);-
882 const uchar *src = alphaMask.constScanLine(y);-
883 for (int x=0; x<alphaMask.width(); ++x) {-
884 int val = src[x];-
885 dst[x] = qRgb(val, val, val);-
886 }-
887 }-
888-
889 return rgbMask;-
890}-
891-
892QImage QFontEngine::bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform&)-
893{-
894 Q_UNUSED(subPixelPosition);-
895-
896 return QImage();-
897}-
898-
899QFixed QFontEngine::subPixelPositionForX(QFixed x) const-
900{-
901 if (m_subPixelPositionCount <= 1 || !supportsSubPixelPositions())-
902 return QFixed();-
903-
904 QFixed subPixelPosition;-
905 if (x != 0) {-
906 subPixelPosition = x - x.floor();-
907 QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor();-
908-
909 // Compensate for precision loss in fixed point to make sure we are always drawing at a subpixel position over-
910 // the lower boundary for the selected rasterization by adding 1/64.-
911 subPixelPosition = fraction / QFixed(m_subPixelPositionCount) + QFixed::fromReal(0.015625);-
912 }-
913 return subPixelPosition;-
914}-
915-
916QImage *QFontEngine::lockedAlphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition,-
917 QFontEngine::GlyphFormat neededFormat,-
918 const QTransform &t, QPoint *offset)-
919{-
920 Q_ASSERT(currentlyLockedAlphaMap.isNull());-
921 if (neededFormat == Format_None)-
922 neededFormat = Format_A32;-
923-
924 if (neededFormat != Format_A32)-
925 currentlyLockedAlphaMap = alphaMapForGlyph(glyph, subPixelPosition, t);-
926 else-
927 currentlyLockedAlphaMap = alphaRGBMapForGlyph(glyph, subPixelPosition, t);-
928-
929 if (offset != 0)-
930 *offset = QPoint(0, 0);-
931-
932 return &currentlyLockedAlphaMap;-
933}-
934-
935void QFontEngine::unlockAlphaMapForGlyph()-
936{-
937 Q_ASSERT(!currentlyLockedAlphaMap.isNull());-
938 currentlyLockedAlphaMap = QImage();-
939}-
940-
941QImage QFontEngine::alphaMapForGlyph(glyph_t glyph)-
942{-
943 glyph_metrics_t gm = boundingBox(glyph);-
944 int glyph_x = qFloor(gm.x.toReal());-
945 int glyph_y = qFloor(gm.y.toReal());-
946 int glyph_width = qCeil((gm.x + gm.width).toReal()) - glyph_x;-
947 int glyph_height = qCeil((gm.y + gm.height).toReal()) - glyph_y;-
948-
949 if (glyph_width <= 0 || glyph_height <= 0)-
950 return QImage();-
951 QFixedPoint pt;-
952 pt.x = -glyph_x;-
953 pt.y = -glyph_y; // the baseline-
954 QPainterPath path;-
955 path.setFillRule(Qt::WindingFill);-
956 QImage im(glyph_width, glyph_height, QImage::Format_ARGB32_Premultiplied);-
957 im.fill(Qt::transparent);-
958 QPainter p(&im);-
959 p.setRenderHint(QPainter::Antialiasing);-
960 addGlyphsToPath(&glyph, &pt, 1, &path, 0);-
961 p.setPen(Qt::NoPen);-
962 p.setBrush(Qt::black);-
963 p.drawPath(path);-
964 p.end();-
965-
966 QImage alphaMap(im.width(), im.height(), QImage::Format_Alpha8);-
967-
968 for (int y=0; y<im.height(); ++y) {-
969 uchar *dst = (uchar *) alphaMap.scanLine(y);-
970 const uint *src = reinterpret_cast<const uint *>(im.constScanLine(y));-
971 for (int x=0; x<im.width(); ++x)-
972 dst[x] = qAlpha(src[x]);-
973 }-
974-
975 return alphaMap;-
976}-
977-
978void QFontEngine::removeGlyphFromCache(glyph_t)-
979{-
980}-
981-
982QFontEngine::Properties QFontEngine::properties() const-
983{-
984 Properties p;-
985 QByteArray psname = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());-
986 psname += '-';-
987 psname += QByteArray::number(fontDef.style);-
988 psname += '-';-
989 psname += QByteArray::number(fontDef.weight);-
990-
991 p.postscriptName = psname;-
992 p.ascent = ascent();-
993 p.descent = descent();-
994 p.leading = leading();-
995 p.emSquare = p.ascent;-
996 p.boundingBox = QRectF(0, -p.ascent.toReal(), maxCharWidth(), (p.ascent + p.descent).toReal());-
997 p.italicAngle = 0;-
998 p.capHeight = p.ascent;-
999 p.lineWidth = lineThickness();-
1000 return p;-
1001}-
1002-
1003void QFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)-
1004{-
1005 *metrics = boundingBox(glyph);-
1006 QFixedPoint p;-
1007 p.x = 0;-
1008 p.y = 0;-
1009 addGlyphsToPath(&glyph, &p, 1, path, QFlag(0));-
1010}-
1011-
1012/*!-
1013 Returns \c true if the font table idetified by \a tag exists in the font;-
1014 returns \c false otherwise.-
1015-
1016 If \a buffer is NULL, stores the size of the buffer required for the font table data,-
1017 in bytes, in \a length. If \a buffer is not NULL and the capacity-
1018 of the buffer, passed in \a length, is sufficient to store the font table data,-
1019 also copies the font table data to \a buffer.-
1020-
1021 Note: returning \c false when the font table exists could lead to an undefined behavior.-
1022*/-
1023bool QFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const-
1024{-
1025 Q_UNUSED(tag)-
1026 Q_UNUSED(buffer)-
1027 Q_UNUSED(length)-
1028 return false;-
1029}-
1030-
1031QByteArray QFontEngine::getSfntTable(uint tag) const-
1032{-
1033 QByteArray table;-
1034 uint len = 0;-
1035 if (!getSfntTableData(tag, 0, &len))-
1036 return table;-
1037 table.resize(len);-
1038 if (!getSfntTableData(tag, reinterpret_cast<uchar *>(table.data()), &len))-
1039 return QByteArray();-
1040 return table;-
1041}-
1042-
1043void QFontEngine::clearGlyphCache(const void *context)-
1044{-
1045 m_glyphCaches.remove(context);-
1046}-
1047-
1048void QFontEngine::setGlyphCache(const void *context, QFontEngineGlyphCache *cache)-
1049{-
1050 Q_ASSERT(cache);-
1051-
1052 GlyphCaches &caches = m_glyphCaches[context];-
1053 for (GlyphCaches::const_iterator it = caches.constBegin(), end = caches.constEnd(); it != end; ++it) {-
1054 if (cache == it->cache.data())-
1055 return;-
1056 }-
1057-
1058 // Limit the glyph caches to 4 per context. This covers all 90 degree rotations,-
1059 // and limits memory use when there is continuous or random rotation-
1060 if (caches.size() == 4)-
1061 caches.removeLast();-
1062-
1063 GlyphCacheEntry entry;-
1064 entry.cache = cache;-
1065 caches.push_front(entry);-
1066-
1067}-
1068-
1069QFontEngineGlyphCache *QFontEngine::glyphCache(const void *context, GlyphFormat format, const QTransform &transform) const-
1070{-
1071 const QHash<const void*, GlyphCaches>::const_iterator caches = m_glyphCaches.constFind(context);-
1072 if (caches == m_glyphCaches.cend())-
1073 return Q_NULLPTR;-
1074-
1075 for (GlyphCaches::const_iterator it = caches->begin(), end = caches->end(); it != end; ++it) {-
1076 QFontEngineGlyphCache *cache = it->cache.data();-
1077 if (format == cache->glyphFormat() && qtransform_equals_no_translate(cache->m_transform, transform))-
1078 return cache;-
1079 }-
1080-
1081 return Q_NULLPTR;-
1082}-
1083-
1084static inline QFixed kerning(int left, int right, const QFontEngine::KernPair *pairs, int numPairs)-
1085{-
1086 uint left_right = (left << 16) + right;-
1087-
1088 left = 0, right = numPairs - 1;-
1089 while (left <= right) {-
1090 int middle = left + ( ( right - left ) >> 1 );-
1091-
1092 if(pairs[middle].left_right == left_right)-
1093 return pairs[middle].adjust;-
1094-
1095 if (pairs[middle].left_right < left_right)-
1096 left = middle + 1;-
1097 else-
1098 right = middle - 1;-
1099 }-
1100 return 0;-
1101}-
1102-
1103void QFontEngine::doKerning(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const-
1104{-
1105 int numPairs = kerning_pairs.size();-
1106 if(!numPairs)-
1107 return;-
1108-
1109 const KernPair *pairs = kerning_pairs.constData();-
1110-
1111 if (flags & DesignMetrics) {-
1112 for(int i = 0; i < glyphs->numGlyphs - 1; ++i)-
1113 glyphs->advances[i] += kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs);-
1114 } else {-
1115 for(int i = 0; i < glyphs->numGlyphs - 1; ++i)-
1116 glyphs->advances[i] += qRound(kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs));-
1117 }-
1118}-
1119-
1120void QFontEngine::loadKerningPairs(QFixed scalingFactor)-
1121{-
1122 kerning_pairs.clear();-
1123-
1124 QByteArray tab = getSfntTable(MAKE_TAG('k', 'e', 'r', 'n'));-
1125 if (tab.isEmpty())-
1126 return;-
1127-
1128 const uchar *table = reinterpret_cast<const uchar *>(tab.constData());-
1129 const uchar *end = table + tab.size();-
1130-
1131 quint16 version;-
1132 if (!qSafeFromBigEndian(table, end, &version))-
1133 return;-
1134-
1135 if (version != 0) {-
1136// qDebug("wrong version");-
1137 return;-
1138 }-
1139-
1140 quint16 numTables;-
1141 if (!qSafeFromBigEndian(table + 2, end, &numTables))-
1142 return;-
1143-
1144 {-
1145 int offset = 4;-
1146 for(int i = 0; i < numTables; ++i) {-
1147 const uchar *header = table + offset;-
1148-
1149 quint16 version;-
1150 if (!qSafeFromBigEndian(header, end, &version))-
1151 goto end;-
1152-
1153 quint16 length;-
1154 if (!qSafeFromBigEndian(header + 2, end, &length))-
1155 goto end;-
1156-
1157 quint16 coverage;-
1158 if (!qSafeFromBigEndian(header + 4, end, &coverage))-
1159 goto end;-
1160-
1161// qDebug("subtable: version=%d, coverage=%x",version, coverage);-
1162 if(version == 0 && coverage == 0x0001) {-
1163 if (offset + length > tab.size()) {-
1164// qDebug("length ouf ot bounds");-
1165 goto end;-
1166 }-
1167 const uchar *data = table + offset + 6;-
1168-
1169 quint16 nPairs;-
1170 if (!qSafeFromBigEndian(data, end, &nPairs))-
1171 goto end;-
1172-
1173 if(nPairs * 6 + 8 > length - 6) {-
1174// qDebug("corrupt table!");-
1175 // corrupt table-
1176 goto end;-
1177 }-
1178-
1179 int off = 8;-
1180 for(int i = 0; i < nPairs; ++i) {-
1181 QFontEngine::KernPair p;-
1182-
1183 quint16 tmp;-
1184 if (!qSafeFromBigEndian(data + off, end, &tmp))-
1185 goto end;-
1186-
1187 p.left_right = uint(tmp) << 16;-
1188 if (!qSafeFromBigEndian(data + off + 2, end, &tmp))-
1189 goto end;-
1190-
1191 p.left_right |= tmp;-
1192-
1193 if (!qSafeFromBigEndian(data + off + 4, end, &tmp))-
1194 goto end;-
1195-
1196 p.adjust = QFixed(int(short(tmp))) / scalingFactor;-
1197 kerning_pairs.append(p);-
1198 off += 6;-
1199 }-
1200 }-
1201 offset += length;-
1202 }-
1203 }-
1204end:-
1205 std::sort(kerning_pairs.begin(), kerning_pairs.end());-
1206// for (int i = 0; i < kerning_pairs.count(); ++i)-
1207// qDebug() << 'i' << i << "left_right" << hex << kerning_pairs.at(i).left_right;-
1208}-
1209-
1210-
1211int QFontEngine::glyphCount() const-
1212{-
1213 QByteArray maxpTable = getSfntTable(MAKE_TAG('m', 'a', 'x', 'p'));-
1214 if (maxpTable.size() < 6)-
1215 return 0;-
1216-
1217 const uchar *source = reinterpret_cast<const uchar *>(maxpTable.constData() + 4);-
1218 const uchar *end = source + maxpTable.size();-
1219-
1220 quint16 count = 0;-
1221 qSafeFromBigEndian(source, end, &count);-
1222 return count;-
1223}-
1224-
1225Qt::HANDLE QFontEngine::handle() const-
1226{-
1227 return Q_NULLPTR;-
1228}-
1229-
1230const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize)-
1231{-
1232 const uchar *header = table;-
1233 const uchar *endPtr = table + tableSize;-
1234-
1235 // version check-
1236 quint16 version;-
1237 if (!qSafeFromBigEndian(header, endPtr, &version) || version != 0)-
1238 return 0;-
1239-
1240 quint16 numTables;-
1241 if (!qSafeFromBigEndian(header + 2, endPtr, &numTables))-
1242 return 0;-
1243-
1244 const uchar *maps = table + 4;-
1245-
1246 enum {-
1247 Invalid,-
1248 AppleRoman,-
1249 Symbol,-
1250 Unicode11,-
1251 Unicode,-
1252 MicrosoftUnicode,-
1253 MicrosoftUnicodeExtended-
1254 };-
1255-
1256 int symbolTable = -1;-
1257 int tableToUse = -1;-
1258 int score = Invalid;-
1259 for (int n = 0; n < numTables; ++n) {-
1260 quint16 platformId;-
1261 if (!qSafeFromBigEndian(maps + 8 * n, endPtr, &platformId))-
1262 return 0;-
1263-
1264 quint16 platformSpecificId;-
1265 if (!qSafeFromBigEndian(maps + 8 * n + 2, endPtr, &platformSpecificId))-
1266 return 0;-
1267-
1268 switch (platformId) {-
1269 case 0: // Unicode-
1270 if (score < Unicode &&-
1271 (platformSpecificId == 0 ||-
1272 platformSpecificId == 2 ||-
1273 platformSpecificId == 3)) {-
1274 tableToUse = n;-
1275 score = Unicode;-
1276 } else if (score < Unicode11 && platformSpecificId == 1) {-
1277 tableToUse = n;-
1278 score = Unicode11;-
1279 }-
1280 break;-
1281 case 1: // Apple-
1282 if (score < AppleRoman && platformSpecificId == 0) { // Apple Roman-
1283 tableToUse = n;-
1284 score = AppleRoman;-
1285 }-
1286 break;-
1287 case 3: // Microsoft-
1288 switch (platformSpecificId) {-
1289 case 0:-
1290 symbolTable = n;-
1291 if (score < Symbol) {-
1292 tableToUse = n;-
1293 score = Symbol;-
1294 }-
1295 break;-
1296 case 1:-
1297 if (score < MicrosoftUnicode) {-
1298 tableToUse = n;-
1299 score = MicrosoftUnicode;-
1300 }-
1301 break;-
1302 case 0xa:-
1303 if (score < MicrosoftUnicodeExtended) {-
1304 tableToUse = n;-
1305 score = MicrosoftUnicodeExtended;-
1306 }-
1307 break;-
1308 default:-
1309 break;-
1310 }-
1311 default:-
1312 break;-
1313 }-
1314 }-
1315 if(tableToUse < 0)-
1316 return 0;-
1317-
1318resolveTable:-
1319 *isSymbolFont = (symbolTable > -1);-
1320-
1321 quint32 unicode_table;-
1322 if (!qSafeFromBigEndian(maps + 8 * tableToUse + 4, endPtr, &unicode_table))-
1323 return 0;-
1324-
1325 if (!unicode_table)-
1326 return 0;-
1327-
1328 // get the header of the unicode table-
1329 header = table + unicode_table;-
1330-
1331 quint16 format;-
1332 if (!qSafeFromBigEndian(header, endPtr, &format))-
1333 return 0;-
1334-
1335 quint32 length;-
1336 if (format < 8) {-
1337 quint16 tmp;-
1338 if (!qSafeFromBigEndian(header + 2, endPtr, &tmp))-
1339 return 0;-
1340 length = tmp;-
1341 } else {-
1342 if (!qSafeFromBigEndian(header + 4, endPtr, &length))-
1343 return 0;-
1344 }-
1345-
1346 if (table + unicode_table + length > endPtr)-
1347 return 0;-
1348 *cmapSize = length;-
1349-
1350 // To support symbol fonts that contain a unicode table for the symbol area-
1351 // we check the cmap tables and fall back to symbol font unless that would-
1352 // involve losing information from the unicode table-
1353 if (symbolTable > -1 && ((score == Unicode) || (score == Unicode11))) {-
1354 const uchar *selectedTable = table + unicode_table;-
1355-
1356 // Check that none of the latin1 range are in the unicode table-
1357 bool unicodeTableHasLatin1 = false;-
1358 for (int uc=0x00; uc<0x100; ++uc) {-
1359 if (getTrueTypeGlyphIndex(selectedTable, length, uc) != 0) {-
1360 unicodeTableHasLatin1 = true;-
1361 break;-
1362 }-
1363 }-
1364-
1365 // Check that at least one symbol char is in the unicode table-
1366 bool unicodeTableHasSymbols = false;-
1367 if (!unicodeTableHasLatin1) {-
1368 for (int uc=0xf000; uc<0xf100; ++uc) {-
1369 if (getTrueTypeGlyphIndex(selectedTable, length, uc) != 0) {-
1370 unicodeTableHasSymbols = true;-
1371 break;-
1372 }-
1373 }-
1374 }-
1375-
1376 // Fall back to symbol table-
1377 if (!unicodeTableHasLatin1 && unicodeTableHasSymbols) {-
1378 tableToUse = symbolTable;-
1379 score = Symbol;-
1380 goto resolveTable;-
1381 }-
1382 }-
1383-
1384 return table + unicode_table;-
1385}-
1386-
1387quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode)-
1388{-
1389 const uchar *end = cmap + cmapSize;-
1390 quint16 format;-
1391 if (!qSafeFromBigEndian(cmap, end, &format))-
1392 return 0;-
1393-
1394 if (format == 0) {-
1395 const uchar *ptr = cmap + 6 + unicode;-
1396 if (unicode < 256 && ptr < end)-
1397 return quint32(*ptr);-
1398 } else if (format == 4) {-
1399 /* some fonts come with invalid cmap tables, where the last segment-
1400 specified end = start = rangeoffset = 0xffff, delta = 0x0001-
1401 Since 0xffff is never a valid Unicode char anyway, we just get rid of the issue-
1402 by returning 0 for 0xffff-
1403 */-
1404 if(unicode >= 0xffff)-
1405 return 0;-
1406-
1407 quint16 segCountX2;-
1408 if (!qSafeFromBigEndian(cmap + 6, end, &segCountX2))-
1409 return 0;-
1410-
1411 const unsigned char *ends = cmap + 14;-
1412-
1413 int i = 0;-
1414 for (; i < segCountX2/2; ++i) {-
1415 quint16 codePoint;-
1416 if (!qSafeFromBigEndian(ends + 2 * i, end, &codePoint))-
1417 return 0;-
1418 if (codePoint >= unicode)-
1419 break;-
1420 }-
1421-
1422 const unsigned char *idx = ends + segCountX2 + 2 + 2*i;-
1423-
1424 quint16 startIndex;-
1425 if (!qSafeFromBigEndian(idx, end, &startIndex))-
1426 return 0;-
1427 if (startIndex > unicode)-
1428 return 0;-
1429-
1430 idx += segCountX2;-
1431-
1432 quint16 tmp;-
1433 if (!qSafeFromBigEndian(idx, end, &tmp))-
1434 return 0;-
1435 qint16 idDelta = qint16(tmp);-
1436-
1437 idx += segCountX2;-
1438-
1439 quint16 idRangeoffset_t;-
1440 if (!qSafeFromBigEndian(idx, end, &idRangeoffset_t))-
1441 return 0;-
1442-
1443 quint16 glyphIndex;-
1444 if (idRangeoffset_t) {-
1445 quint16 id;-
1446 if (!qSafeFromBigEndian(idRangeoffset_t + 2 * (unicode - startIndex) + idx, end, &id))-
1447 return 0;-
1448-
1449 if (id)-
1450 glyphIndex = (idDelta + id) % 0x10000;-
1451 else-
1452 glyphIndex = 0;-
1453 } else {-
1454 glyphIndex = (idDelta + unicode) % 0x10000;-
1455 }-
1456 return glyphIndex;-
1457 } else if (format == 6) {-
1458 quint16 tableSize;-
1459 if (!qSafeFromBigEndian(cmap + 2, end, &tableSize))-
1460 return 0;-
1461-
1462 quint16 firstCode6;-
1463 if (!qSafeFromBigEndian(cmap + 6, end, &firstCode6))-
1464 return 0;-
1465 if (unicode < firstCode6)-
1466 return 0;-
1467-
1468 quint16 entryCount6;-
1469 if (!qSafeFromBigEndian(cmap + 8, end, &entryCount6))-
1470 return 0;-
1471 if (entryCount6 * 2 + 10 > tableSize)-
1472 return 0;-
1473-
1474 quint16 sentinel6 = firstCode6 + entryCount6;-
1475 if (unicode >= sentinel6)-
1476 return 0;-
1477-
1478 quint16 entryIndex6 = unicode - firstCode6;-
1479-
1480 quint16 index = 0;-
1481 qSafeFromBigEndian(cmap + 10 + (entryIndex6 * 2), end, &index);-
1482 return index;-
1483 } else if (format == 12) {-
1484 quint32 nGroups;-
1485 if (!qSafeFromBigEndian(cmap + 12, end, &nGroups))-
1486 return 0;-
1487-
1488 cmap += 16; // move to start of groups-
1489-
1490 int left = 0, right = nGroups - 1;-
1491 while (left <= right) {-
1492 int middle = left + ( ( right - left ) >> 1 );-
1493-
1494 quint32 startCharCode;-
1495 if (!qSafeFromBigEndian(cmap + 12 * middle, end, &startCharCode))-
1496 return 0;-
1497-
1498 if(unicode < startCharCode)-
1499 right = middle - 1;-
1500 else {-
1501 quint32 endCharCode;-
1502 if (!qSafeFromBigEndian(cmap + 12 * middle + 4, end, &endCharCode))-
1503 return 0;-
1504-
1505 if (unicode <= endCharCode) {-
1506 quint32 index;-
1507 if (!qSafeFromBigEndian(cmap + 12 * middle + 8, end, &index))-
1508 return 0;-
1509-
1510 return index + unicode - startCharCode;-
1511 }-
1512 left = middle + 1;-
1513 }-
1514 }-
1515 } else {-
1516 qDebug("cmap table of format %d not implemented", format);-
1517 }-
1518-
1519 return 0;-
1520}-
1521-
1522QByteArray QFontEngine::convertToPostscriptFontFamilyName(const QByteArray &family)-
1523{-
1524 QByteArray f = family;-
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 f.replace('%', "");-
1536 return f;-
1537}-
1538-
1539// Allow font engines (e.g. Windows) that can not reliably create-
1540// outline paths for distance-field rendering to switch the scene-
1541// graph over to native text rendering.-
1542bool QFontEngine::hasUnreliableGlyphOutline() const-
1543{-
1544 // Color glyphs (Emoji) are generally not suited for outlining-
1545 return glyphFormat == QFontEngine::Format_ARGB;-
1546}-
1547-
1548QFixed QFontEngine::lastRightBearing(const QGlyphLayout &glyphs, bool round)-
1549{-
1550 if (glyphs.numGlyphs >= 1) {-
1551 glyph_t glyph = glyphs.glyphs[glyphs.numGlyphs - 1];-
1552 glyph_metrics_t gi = boundingBox(glyph);-
1553 if (gi.isValid())-
1554 return round ? qRound(gi.rightBearing()) : gi.rightBearing();-
1555 }-
1556 return 0;-
1557}-
1558-
1559-
1560QFontEngine::GlyphCacheEntry::GlyphCacheEntry()-
1561{-
1562}-
1563-
1564QFontEngine::GlyphCacheEntry::GlyphCacheEntry(const GlyphCacheEntry &o)-
1565 : cache(o.cache)-
1566{-
1567}-
1568-
1569QFontEngine::GlyphCacheEntry::~GlyphCacheEntry()-
1570{-
1571}-
1572-
1573QFontEngine::GlyphCacheEntry &QFontEngine::GlyphCacheEntry::operator=(const GlyphCacheEntry &o)-
1574{-
1575 cache = o.cache;-
1576 return *this;-
1577}-
1578-
1579// -------------------------------------------------------------------
1580// The box font engine-
1581// -------------------------------------------------------------------
1582-
1583QFontEngineBox::QFontEngineBox(int size)-
1584 : QFontEngine(Box),-
1585 _size(size)-
1586{-
1587 cache_cost = sizeof(QFontEngineBox);-
1588}-
1589-
1590QFontEngineBox::QFontEngineBox(Type type, int size)-
1591 : QFontEngine(type),-
1592 _size(size)-
1593{-
1594 cache_cost = sizeof(QFontEngineBox);-
1595}-
1596-
1597QFontEngineBox::~QFontEngineBox()-
1598{-
1599}-
1600-
1601glyph_t QFontEngineBox::glyphIndex(uint ucs4) const-
1602{-
1603 Q_UNUSED(ucs4)-
1604 return 0;-
1605}-
1606-
1607bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const-
1608{-
1609 Q_ASSERT(glyphs->numGlyphs >= *nglyphs);-
1610 if (*nglyphs < len) {-
1611 *nglyphs = len;-
1612 return false;-
1613 }-
1614-
1615 int ucs4Length = 0;-
1616 QStringIterator it(str, str + len);-
1617 while (it.hasNext()) {-
1618 it.advance();-
1619 glyphs->glyphs[ucs4Length++] = 0;-
1620 }-
1621-
1622 *nglyphs = ucs4Length;-
1623 glyphs->numGlyphs = ucs4Length;-
1624-
1625 if (!(flags & GlyphIndicesOnly))-
1626 recalcAdvances(glyphs, flags);-
1627-
1628 return true;-
1629}-
1630-
1631void QFontEngineBox::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const-
1632{-
1633 for (int i = 0; i < glyphs->numGlyphs; i++)-
1634 glyphs->advances[i] = _size;-
1635}-
1636-
1637void QFontEngineBox::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)-
1638{-
1639 if (!glyphs.numGlyphs)-
1640 return;-
1641-
1642 QVarLengthArray<QFixedPoint> positions;-
1643 QVarLengthArray<glyph_t> positioned_glyphs;-
1644 QTransform matrix = QTransform::fromTranslate(x, y - _size);-
1645 getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);-
1646-
1647 QSize s(_size - 3, _size - 3);-
1648 for (int k = 0; k < positions.size(); k++)-
1649 path->addRect(QRectF(positions[k].toPointF(), s));-
1650}-
1651-
1652glyph_metrics_t QFontEngineBox::boundingBox(const QGlyphLayout &glyphs)-
1653{-
1654 glyph_metrics_t overall;-
1655 overall.width = _size*glyphs.numGlyphs;-
1656 overall.height = _size;-
1657 overall.xoff = overall.width;-
1658 return overall;-
1659}-
1660-
1661void QFontEngineBox::draw(QPaintEngine *p, qreal x, qreal y, const QTextItemInt &ti)-
1662{-
1663 if (!ti.glyphs.numGlyphs)-
1664 return;-
1665-
1666 // any fixes here should probably also be done in QPaintEnginePrivate::drawBoxTextItem-
1667 QSize s(_size - 3, _size - 3);-
1668-
1669 QVarLengthArray<QFixedPoint> positions;-
1670 QVarLengthArray<glyph_t> glyphs;-
1671 QTransform matrix = QTransform::fromTranslate(x, y - _size);-
1672 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);-
1673 if (glyphs.size() == 0)-
1674 return;-
1675-
1676-
1677 QPainter *painter = p->painter();-
1678 painter->save();-
1679 painter->setBrush(Qt::NoBrush);-
1680 QPen pen = painter->pen();-
1681 pen.setWidthF(lineThickness().toReal());-
1682 painter->setPen(pen);-
1683 for (int k = 0; k < positions.size(); k++)-
1684 painter->drawRect(QRectF(positions[k].toPointF(), s));-
1685 painter->restore();-
1686}-
1687-
1688glyph_metrics_t QFontEngineBox::boundingBox(glyph_t)-
1689{-
1690 return glyph_metrics_t(0, -_size, _size, _size, _size, 0);-
1691}-
1692-
1693QFontEngine *QFontEngineBox::cloneWithSize(qreal pixelSize) const-
1694{-
1695 QFontEngineBox *fe = new QFontEngineBox(pixelSize);-
1696 return fe;-
1697}-
1698-
1699QFixed QFontEngineBox::ascent() const-
1700{-
1701 return _size;-
1702}-
1703-
1704QFixed QFontEngineBox::descent() const-
1705{-
1706 return 0;-
1707}-
1708-
1709QFixed QFontEngineBox::leading() const-
1710{-
1711 QFixed l = _size * QFixed::fromReal(qreal(0.15));-
1712 return l.ceil();-
1713}-
1714-
1715qreal QFontEngineBox::maxCharWidth() const-
1716{-
1717 return _size;-
1718}-
1719-
1720bool QFontEngineBox::canRender(const QChar *, int) const-
1721{-
1722 return true;-
1723}-
1724-
1725QImage QFontEngineBox::alphaMapForGlyph(glyph_t)-
1726{-
1727 QImage image(_size, _size, QImage::Format_Alpha8);-
1728 image.fill(0);-
1729-
1730 // FIXME: use qpainter-
1731 for (int i=2; i <= _size-3; ++i) {-
1732 image.setPixel(i, 2, 255);-
1733 image.setPixel(i, _size-3, 255);-
1734 image.setPixel(2, i, 255);-
1735 image.setPixel(_size-3, i, 255);-
1736 }-
1737 return image;-
1738}-
1739-
1740// -------------------------------------------------------------------
1741// Multi engine-
1742// -------------------------------------------------------------------
1743-
1744static inline uchar highByte(glyph_t glyph)-
1745{ return glyph >> 24; }-
1746-
1747// strip high byte from glyph-
1748static inline glyph_t stripped(glyph_t glyph)-
1749{ return glyph & 0x00ffffff; }-
1750-
1751QFontEngineMulti::QFontEngineMulti(QFontEngine *engine, int script, const QStringList &fallbackFamilies)-
1752 : QFontEngine(Multi),-
1753 m_fallbackFamilies(fallbackFamilies),-
1754 m_script(script),-
1755 m_fallbackFamiliesQueried(!m_fallbackFamilies.isEmpty())-
1756{-
1757 Q_ASSERT(engine && engine->type() != QFontEngine::Multi);-
1758-
1759 if (m_fallbackFamilies.isEmpty()) {-
1760 // defer obtaining the fallback families until loadEngine(1)-
1761 m_fallbackFamilies << QString();-
1762 }-
1763-
1764 m_engines.resize(m_fallbackFamilies.size() + 1);-
1765-
1766 engine->ref.ref();-
1767 m_engines[0] = engine;-
1768-
1769 fontDef = engine->fontDef;-
1770 cache_cost = engine->cache_cost;-
1771}-
1772-
1773QFontEngineMulti::~QFontEngineMulti()-
1774{-
1775 for (int i = 0; i < m_engines.size(); ++i) {-
1776 QFontEngine *fontEngine = m_engines.at(i);-
1777 if (fontEngine && !fontEngine->ref.deref())-
1778 delete fontEngine;-
1779 }-
1780}-
1781-
1782QStringList qt_fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script);-
1783-
1784void QFontEngineMulti::ensureFallbackFamiliesQueried()-
1785{-
1786 QFont::StyleHint styleHint = QFont::StyleHint(fontDef.styleHint);-
1787 if (styleHint == QFont::AnyStyle && fontDef.fixedPitch)-
1788 styleHint = QFont::TypeWriter;-
1789-
1790 setFallbackFamiliesList(qt_fallbacksForFamily(fontDef.family, QFont::Style(fontDef.style), styleHint, QChar::Script(m_script)));-
1791}-
1792-
1793void QFontEngineMulti::setFallbackFamiliesList(const QStringList &fallbackFamilies)-
1794{-
1795 Q_ASSERT(!m_fallbackFamiliesQueried);-
1796-
1797 m_fallbackFamilies = fallbackFamilies;-
1798 if (m_fallbackFamilies.isEmpty()) {-
1799 // turns out we lied about having any fallback at all-
1800 Q_ASSERT(m_engines.size() == 2); // see c-tor for details-
1801 QFontEngine *engine = m_engines.at(0);-
1802 engine->ref.ref();-
1803 m_engines[1] = engine;-
1804 m_fallbackFamilies << fontDef.family;-
1805 } else {-
1806 m_engines.resize(m_fallbackFamilies.size() + 1);-
1807 }-
1808-
1809 m_fallbackFamiliesQueried = true;-
1810}-
1811-
1812void QFontEngineMulti::ensureEngineAt(int at)-
1813{-
1814 if (!m_fallbackFamiliesQueried)-
1815 ensureFallbackFamiliesQueried();-
1816 Q_ASSERT(at < m_engines.size());-
1817 if (!m_engines.at(at)) {-
1818 QFontEngine *engine = loadEngine(at);-
1819 if (!engine)-
1820 engine = new QFontEngineBox(fontDef.pixelSize);-
1821 Q_ASSERT(engine && engine->type() != QFontEngine::Multi);-
1822 engine->ref.ref();-
1823 m_engines[at] = engine;-
1824 }-
1825}-
1826-
1827QFontEngine *QFontEngineMulti::loadEngine(int at)-
1828{-
1829 QFontDef request(fontDef);-
1830 request.styleStrategy |= QFont::NoFontMerging;-
1831 request.family = fallbackFamilyAt(at - 1);-
1832-
1833 if (QFontEngine *engine = QFontDatabase::findFont(request, m_script)) {-
1834 engine->fontDef.weight = request.weight;-
1835 if (request.style > QFont::StyleNormal)-
1836 engine->fontDef.style = request.style;-
1837 return engine;-
1838 }-
1839-
1840 return 0;-
1841}-
1842-
1843glyph_t QFontEngineMulti::glyphIndex(uint ucs4) const-
1844{-
1845 glyph_t glyph = engine(0)->glyphIndex(ucs4);-
1846 if (glyph == 0 && ucs4 != QChar::LineSeparator) {-
1847 if (!m_fallbackFamiliesQueried)-
1848 const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();-
1849 for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) {-
1850 QFontEngine *engine = m_engines.at(x);-
1851 if (!engine) {-
1852 if (!shouldLoadFontEngineForCharacter(x, ucs4))-
1853 continue;-
1854 const_cast<QFontEngineMulti *>(this)->ensureEngineAt(x);-
1855 engine = m_engines.at(x);-
1856 }-
1857 Q_ASSERT(engine != 0);-
1858 if (engine->type() == Box)-
1859 continue;-
1860-
1861 glyph = engine->glyphIndex(ucs4);-
1862 if (glyph != 0) {-
1863 // set the high byte to indicate which engine the glyph came from-
1864 glyph |= (x << 24);-
1865 break;-
1866 }-
1867 }-
1868 }-
1869-
1870 return glyph;-
1871}-
1872-
1873bool QFontEngineMulti::stringToCMap(const QChar *str, int len,-
1874 QGlyphLayout *glyphs, int *nglyphs,-
1875 QFontEngine::ShaperFlags flags) const-
1876{-
1877 if (!engine(0)->stringToCMap(str, len, glyphs, nglyphs, flags))-
1878 return false;-
1879-
1880 int glyph_pos = 0;-
1881 QStringIterator it(str, str + len);-
1882 while (it.hasNext()) {-
1883 const uint ucs4 = it.peekNext();-
1884 if (glyphs->glyphs[glyph_pos] == 0 && ucs4 != QChar::LineSeparator) {-
1885 if (!m_fallbackFamiliesQueried)-
1886 const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();-
1887 for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) {-
1888 QFontEngine *engine = m_engines.at(x);-
1889 if (!engine) {-
1890 if (!shouldLoadFontEngineForCharacter(x, ucs4))-
1891 continue;-
1892 const_cast<QFontEngineMulti *>(this)->ensureEngineAt(x);-
1893 engine = m_engines.at(x);-
1894 if (!engine)-
1895 continue;-
1896 }-
1897 Q_ASSERT(engine != 0);-
1898 if (engine->type() == Box)-
1899 continue;-
1900-
1901 glyph_t glyph = engine->glyphIndex(ucs4);-
1902 if (glyph != 0) {-
1903 glyphs->glyphs[glyph_pos] = glyph;-
1904 if (!(flags & GlyphIndicesOnly)) {-
1905 QGlyphLayout g = glyphs->mid(glyph_pos, 1);-
1906 engine->recalcAdvances(&g, flags);-
1907 }-
1908 // set the high byte to indicate which engine the glyph came from-
1909 glyphs->glyphs[glyph_pos] |= (x << 24);-
1910 break;-
1911 }-
1912 }-
1913 }-
1914-
1915 it.advance();-
1916 ++glyph_pos;-
1917 }-
1918-
1919 *nglyphs = glyph_pos;-
1920 glyphs->numGlyphs = glyph_pos;-
1921-
1922 return true;-
1923}-
1924-
1925bool QFontEngineMulti::shouldLoadFontEngineForCharacter(int at, uint ucs4) const-
1926{-
1927 Q_UNUSED(at);-
1928 Q_UNUSED(ucs4);-
1929 return true;-
1930}-
1931-
1932glyph_metrics_t QFontEngineMulti::boundingBox(const QGlyphLayout &glyphs)-
1933{-
1934 if (glyphs.numGlyphs <= 0)-
1935 return glyph_metrics_t();-
1936-
1937 glyph_metrics_t overall;-
1938-
1939 int which = highByte(glyphs.glyphs[0]);-
1940 int start = 0;-
1941 int end, i;-
1942 for (end = 0; end < glyphs.numGlyphs; ++end) {-
1943 const int e = highByte(glyphs.glyphs[end]);-
1944 if (e == which)-
1945 continue;-
1946-
1947 // set the high byte to zero-
1948 for (i = start; i < end; ++i)-
1949 glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);-
1950-
1951 // merge the bounding box for this run-
1952 const glyph_metrics_t gm = engine(which)->boundingBox(glyphs.mid(start, end - start));-
1953-
1954 overall.x = qMin(overall.x, gm.x);-
1955 overall.y = qMin(overall.y, gm.y);-
1956 overall.width = overall.xoff + gm.width;-
1957 overall.height = qMax(overall.height + overall.y, gm.height + gm.y) --
1958 qMin(overall.y, gm.y);-
1959 overall.xoff += gm.xoff;-
1960 overall.yoff += gm.yoff;-
1961-
1962 // reset the high byte for all glyphs-
1963 const int hi = which << 24;-
1964 for (i = start; i < end; ++i)-
1965 glyphs.glyphs[i] = hi | glyphs.glyphs[i];-
1966-
1967 // change engine-
1968 start = end;-
1969 which = e;-
1970 }-
1971-
1972 // set the high byte to zero-
1973 for (i = start; i < end; ++i)-
1974 glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);-
1975-
1976 // merge the bounding box for this run-
1977 const glyph_metrics_t gm = engine(which)->boundingBox(glyphs.mid(start, end - start));-
1978-
1979 overall.x = qMin(overall.x, gm.x);-
1980 overall.y = qMin(overall.y, gm.y);-
1981 overall.width = overall.xoff + gm.width;-
1982 overall.height = qMax(overall.height + overall.y, gm.height + gm.y) --
1983 qMin(overall.y, gm.y);-
1984 overall.xoff += gm.xoff;-
1985 overall.yoff += gm.yoff;-
1986-
1987 // reset the high byte for all glyphs-
1988 const int hi = which << 24;-
1989 for (i = start; i < end; ++i)-
1990 glyphs.glyphs[i] = hi | glyphs.glyphs[i];-
1991-
1992 return overall;-
1993}-
1994-
1995void QFontEngineMulti::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)-
1996{-
1997 int which = highByte(glyph);-
1998 ensureEngineAt(which);-
1999 engine(which)->getGlyphBearings(stripped(glyph), leftBearing, rightBearing);-
2000}-
2001-
2002void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,-
2003 QPainterPath *path, QTextItem::RenderFlags flags)-
2004{-
2005 if (glyphs.numGlyphs <= 0)-
2006 return;-
2007-
2008 int which = highByte(glyphs.glyphs[0]);-
2009 int start = 0;-
2010 int end, i;-
2011 if (flags & QTextItem::RightToLeft) {-
2012 for (int gl = 0; gl < glyphs.numGlyphs; gl++)-
2013 x += glyphs.advances[gl].toReal();-
2014 }-
2015 for (end = 0; end < glyphs.numGlyphs; ++end) {-
2016 const int e = highByte(glyphs.glyphs[end]);-
2017 if (e == which)-
2018 continue;-
2019-
2020 if (flags & QTextItem::RightToLeft) {-
2021 for (i = start; i < end; ++i)-
2022 x -= glyphs.advances[i].toReal();-
2023 }-
2024-
2025 // set the high byte to zero-
2026 for (i = start; i < end; ++i)-
2027 glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);-
2028 engine(which)->addOutlineToPath(x, y, glyphs.mid(start, end - start), path, flags);-
2029 // reset the high byte for all glyphs and update x and y-
2030 const int hi = which << 24;-
2031 for (i = start; i < end; ++i)-
2032 glyphs.glyphs[i] = hi | glyphs.glyphs[i];-
2033-
2034 if (!(flags & QTextItem::RightToLeft)) {-
2035 for (i = start; i < end; ++i)-
2036 x += glyphs.advances[i].toReal();-
2037 }-
2038-
2039 // change engine-
2040 start = end;-
2041 which = e;-
2042 }-
2043-
2044 if (flags & QTextItem::RightToLeft) {-
2045 for (i = start; i < end; ++i)-
2046 x -= glyphs.advances[i].toReal();-
2047 }-
2048-
2049 // set the high byte to zero-
2050 for (i = start; i < end; ++i)-
2051 glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);-
2052-
2053 engine(which)->addOutlineToPath(x, y, glyphs.mid(start, end - start), path, flags);-
2054-
2055 // reset the high byte for all glyphs-
2056 const int hi = which << 24;-
2057 for (i = start; i < end; ++i)-
2058 glyphs.glyphs[i] = hi | glyphs.glyphs[i];-
2059}-
2060-
2061void QFontEngineMulti::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const-
2062{-
2063 if (glyphs->numGlyphs <= 0)-
2064 return;-
2065-
2066 int which = highByte(glyphs->glyphs[0]);-
2067 int start = 0;-
2068 int end, i;-
2069 for (end = 0; end < glyphs->numGlyphs; ++end) {-
2070 const int e = highByte(glyphs->glyphs[end]);-
2071 if (e == which)-
2072 continue;-
2073-
2074 // set the high byte to zero-
2075 for (i = start; i < end; ++i)-
2076 glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);-
2077-
2078 QGlyphLayout offs = glyphs->mid(start, end - start);-
2079 engine(which)->recalcAdvances(&offs, flags);-
2080-
2081 // reset the high byte for all glyphs and update x and y-
2082 const int hi = which << 24;-
2083 for (i = start; i < end; ++i)-
2084 glyphs->glyphs[i] = hi | glyphs->glyphs[i];-
2085-
2086 // change engine-
2087 start = end;-
2088 which = e;-
2089 }-
2090-
2091 // set the high byte to zero-
2092 for (i = start; i < end; ++i)-
2093 glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);-
2094-
2095 QGlyphLayout offs = glyphs->mid(start, end - start);-
2096 engine(which)->recalcAdvances(&offs, flags);-
2097-
2098 // reset the high byte for all glyphs-
2099 const int hi = which << 24;-
2100 for (i = start; i < end; ++i)-
2101 glyphs->glyphs[i] = hi | glyphs->glyphs[i];-
2102}-
2103-
2104void QFontEngineMulti::doKerning(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const-
2105{-
2106 if (glyphs->numGlyphs <= 0)-
2107 return;-
2108-
2109 int which = highByte(glyphs->glyphs[0]);-
2110 int start = 0;-
2111 int end, i;-
2112 for (end = 0; end < glyphs->numGlyphs; ++end) {-
2113 const int e = highByte(glyphs->glyphs[end]);-
2114 if (e == which)-
2115 continue;-
2116-
2117 // set the high byte to zero-
2118 for (i = start; i < end; ++i)-
2119 glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);-
2120-
2121 QGlyphLayout offs = glyphs->mid(start, end - start);-
2122 engine(which)->doKerning(&offs, flags);-
2123-
2124 // reset the high byte for all glyphs and update x and y-
2125 const int hi = which << 24;-
2126 for (i = start; i < end; ++i)-
2127 glyphs->glyphs[i] = hi | glyphs->glyphs[i];-
2128-
2129 // change engine-
2130 start = end;-
2131 which = e;-
2132 }-
2133-
2134 // set the high byte to zero-
2135 for (i = start; i < end; ++i)-
2136 glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);-
2137-
2138 QGlyphLayout offs = glyphs->mid(start, end - start);-
2139 engine(which)->doKerning(&offs, flags);-
2140-
2141 // reset the high byte for all glyphs-
2142 const int hi = which << 24;-
2143 for (i = start; i < end; ++i)-
2144 glyphs->glyphs[i] = hi | glyphs->glyphs[i];-
2145}-
2146-
2147glyph_metrics_t QFontEngineMulti::boundingBox(glyph_t glyph)-
2148{-
2149 const int which = highByte(glyph);-
2150 return engine(which)->boundingBox(stripped(glyph));-
2151}-
2152-
2153QFixed QFontEngineMulti::ascent() const-
2154{ return engine(0)->ascent(); }-
2155-
2156QFixed QFontEngineMulti::descent() const-
2157{ return engine(0)->descent(); }-
2158-
2159QFixed QFontEngineMulti::leading() const-
2160{-
2161 return engine(0)->leading();-
2162}-
2163-
2164QFixed QFontEngineMulti::xHeight() const-
2165{-
2166 return engine(0)->xHeight();-
2167}-
2168-
2169QFixed QFontEngineMulti::averageCharWidth() const-
2170{-
2171 return engine(0)->averageCharWidth();-
2172}-
2173-
2174QFixed QFontEngineMulti::lineThickness() const-
2175{-
2176 return engine(0)->lineThickness();-
2177}-
2178-
2179QFixed QFontEngineMulti::underlinePosition() const-
2180{-
2181 return engine(0)->underlinePosition();-
2182}-
2183-
2184qreal QFontEngineMulti::maxCharWidth() const-
2185{-
2186 return engine(0)->maxCharWidth();-
2187}-
2188-
2189qreal QFontEngineMulti::minLeftBearing() const-
2190{-
2191 return engine(0)->minLeftBearing();-
2192}-
2193-
2194qreal QFontEngineMulti::minRightBearing() const-
2195{-
2196 return engine(0)->minRightBearing();-
2197}-
2198-
2199bool QFontEngineMulti::canRender(const QChar *string, int len) const-
2200{-
2201 if (engine(0)->canRender(string, len))-
2202 return true;-
2203-
2204 int nglyphs = len;-
2205-
2206 QVarLengthArray<glyph_t> glyphs(nglyphs);-
2207-
2208 QGlyphLayout g;-
2209 g.numGlyphs = nglyphs;-
2210 g.glyphs = glyphs.data();-
2211 if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly))-
2212 Q_UNREACHABLE();-
2213-
2214 for (int i = 0; i < nglyphs; i++) {-
2215 if (glyphs[i] == 0)-
2216 return false;-
2217 }-
2218-
2219 return true;-
2220}-
2221-
2222/* Implement alphaMapForGlyph() which is called by Lighthouse/Windows code.-
2223 * Ideally, that code should be fixed to correctly handle QFontEngineMulti. */-
2224-
2225QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph)-
2226{-
2227 const int which = highByte(glyph);-
2228 return engine(which)->alphaMapForGlyph(stripped(glyph));-
2229}-
2230-
2231QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition)-
2232{-
2233 const int which = highByte(glyph);-
2234 return engine(which)->alphaMapForGlyph(stripped(glyph), subPixelPosition);-
2235}-
2236-
2237QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, const QTransform &t)-
2238{-
2239 const int which = highByte(glyph);-
2240 return engine(which)->alphaMapForGlyph(stripped(glyph), t);-
2241}-
2242-
2243QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)-
2244{-
2245 const int which = highByte(glyph);-
2246 return engine(which)->alphaMapForGlyph(stripped(glyph), subPixelPosition, t);-
2247}-
2248-
2249QImage QFontEngineMulti::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)-
2250{-
2251 const int which = highByte(glyph);-
2252 return engine(which)->alphaRGBMapForGlyph(stripped(glyph), subPixelPosition, t);-
2253}-
2254-
2255/*-
2256 This is used indirectly by Qt WebKit when using QTextLayout::setRawFont-
2257-
2258 The purpose of this is to provide the necessary font fallbacks when drawing complex-
2259 text. Since Qt WebKit ends up repeatedly creating QTextLayout instances and passing them-
2260 the same raw font over and over again, we want to cache the corresponding multi font engine-
2261 as it may contain fallback font engines already.-
2262*/-
2263QFontEngine *QFontEngineMulti::createMultiFontEngine(QFontEngine *fe, int script)-
2264{-
2265 QFontEngine *engine = 0;-
2266 QFontCache::Key key(fe->fontDef, script, /*multi = */true);-
2267 QFontCache *fc = QFontCache::instance();-
2268 // We can't rely on the fontDef (and hence the cache Key)-
2269 // alone to distinguish webfonts, since these should not be-
2270 // accidentally shared, even if the resulting fontcache key-
2271 // is strictly identical. See:-
2272 // http://www.w3.org/TR/css3-fonts/#font-face-rule-
2273 const bool faceIsLocal = !fe->faceId().filename.isEmpty();-
2274 QFontCache::EngineCache::Iterator it = fc->engineCache.find(key),-
2275 end = fc->engineCache.end();-
2276 while (it != end && it.key() == key) {-
2277 Q_ASSERT(it.value().data->type() == QFontEngine::Multi);-
2278 QFontEngineMulti *cachedEngine = static_cast<QFontEngineMulti *>(it.value().data);-
2279 if (fe == cachedEngine->engine(0) || (faceIsLocal && fe->faceId().filename == cachedEngine->engine(0)->faceId().filename)) {-
2280 engine = cachedEngine;-
2281 fc->updateHitCountAndTimeStamp(it.value());-
2282 break;-
2283 }-
2284 ++it;-
2285 }-
2286 if (!engine) {-
2287 engine = QGuiApplicationPrivate::instance()->platformIntegration()->fontDatabase()->fontEngineMulti(fe, QChar::Script(script));-
2288 fc->insertEngine(key, engine, /* insertMulti */ !faceIsLocal);-
2289 }-
2290 Q_ASSERT(engine);-
2291 return engine;-
2292}-
2293-
2294QTestFontEngine::QTestFontEngine(int size)-
2295 : QFontEngineBox(TestFontEngine, size)-
2296{}-
2297-
2298QT_END_NAMESPACE-
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9