1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://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 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qfontengine_p.h"
43 #include <qwsdisplay_qws.h>
44 #include <qvarlengtharray.h>
45 #include <private/qpainter_p.h>
46 #include <private/qpaintengine_raster_p.h>
47 #include <private/qpdf_p.h>
48 #include "qtextengine_p.h"
49 #include "private/qcore_unix_p.h" // overrides QT_OPEN
50
51 #include <qdebug.h>
52
53 #ifndef QT_NO_QWS_QPF
54
55 #include "qplatformdefs.h"
56 #include "qfile.h"
57
58 #include <stdlib.h>
59
60 #if !defined(Q_OS_INTEGRITY)
61 #define QT_USE_MMAP
62 #endif
63
64 #ifdef QT_USE_MMAP
65 // for mmap
66 #include <unistd.h>
67 #include <sys/types.h>
68 #include <sys/stat.h>
69 #include <sys/mman.h>
70 #include <fcntl.h>
71 #include <errno.h>
72
73 #ifndef MAP_FILE
74 # define MAP_FILE 0
75 #endif
76 #ifndef MAP_FAILED
77 # define MAP_FAILED (void *)-1
78 #endif
79
80 #endif // QT_USE_MMAP
81
82 QT_BEGIN_NAMESPACE
83
getChar(const QChar * str,int & i,const int len)84 static inline unsigned int getChar(const QChar *str, int &i, const int len)
85 {
86 uint ucs4 = str[i].unicode();
87 if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
88 ++i;
89 ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
90 }
91 return ucs4;
92 }
93
94 #define FM_SMOOTH 1
95
96
97 class Q_PACKED QPFGlyphMetrics {
98
99 public:
100 quint8 linestep;
101 quint8 width;
102 quint8 height;
103 quint8 flags;
104
105 qint8 bearingx; // Difference from pen position to glyph's left bbox
106 quint8 advance; // Difference between pen positions
107 qint8 bearingy; // Used for putting characters on baseline
108
109 qint8 reserved; // Do not use
110
111 // Flags:
112 // RendererOwnsData - the renderer is responsible for glyph data
113 // memory deletion otherwise QPFGlyphTree must
114 // delete [] the data when the glyph is deleted.
115 enum Flags { RendererOwnsData=0x01 };
116 };
117
118 class QPFGlyph {
119 public:
QPFGlyph()120 QPFGlyph() { metrics=0; data=0; }
QPFGlyph(QPFGlyphMetrics * m,uchar * d)121 QPFGlyph(QPFGlyphMetrics* m, uchar* d) :
122 metrics(m), data(d) { }
~QPFGlyph()123 ~QPFGlyph() {}
124
125 QPFGlyphMetrics* metrics;
126 uchar* data;
127 };
128
129 struct Q_PACKED QPFFontMetrics{
130 qint8 ascent,descent;
131 qint8 leftbearing,rightbearing;
132 quint8 maxwidth;
133 qint8 leading;
134 quint8 flags;
135 quint8 underlinepos;
136 quint8 underlinewidth;
137 quint8 reserved3;
138 };
139
140
141 class QPFGlyphTree {
142 public:
143 /* reads in a tree like this:
144
145 A-Z
146 / \
147 0-9 a-z
148
149 etc.
150
151 */
152 glyph_t min,max;
153 QPFGlyphTree* less;
154 QPFGlyphTree* more;
155 QPFGlyph* glyph;
156 public:
QPFGlyphTree(uchar * & data)157 QPFGlyphTree(uchar*& data)
158 {
159 read(data);
160 }
161
~QPFGlyphTree()162 ~QPFGlyphTree()
163 {
164 // NOTE: does not delete glyph[*].metrics or .data.
165 // the caller does this (only they know who owns
166 // the data). See clear().
167 delete less;
168 delete more;
169 delete [] glyph;
170 }
171
inFont(glyph_t g) const172 bool inFont(glyph_t g) const
173 {
174 if ( g < min ) {
175 if ( !less )
176 return false;
177 return less->inFont(g);
178 } else if ( g > max ) {
179 if ( !more )
180 return false;
181 return more->inFont(g);
182 }
183 return true;
184 }
185
get(glyph_t g)186 QPFGlyph* get(glyph_t g)
187 {
188 if ( g < min ) {
189 if ( !less )
190 return 0;
191 return less->get(g);
192 } else if ( g > max ) {
193 if ( !more )
194 return 0;
195 return more->get(g);
196 }
197 return &glyph[g - min];
198 }
totalChars() const199 int totalChars() const
200 {
201 if ( !this ) return 0;
202 return max-min+1 + less->totalChars() + more->totalChars();
203 }
weight() const204 int weight() const
205 {
206 if ( !this ) return 0;
207 return 1 + less->weight() + more->weight();
208 }
209
dump(int indent=0)210 void dump(int indent=0)
211 {
212 for (int i=0; i<indent; i++) printf(" ");
213 printf("%d..%d",min,max);
214 //if ( indent == 0 )
215 printf(" (total %d)",totalChars());
216 printf("\n");
217 if ( less ) less->dump(indent+1);
218 if ( more ) more->dump(indent+1);
219 }
220
221 private:
QPFGlyphTree()222 QPFGlyphTree()
223 {
224 }
225
read(uchar * & data)226 void read(uchar*& data)
227 {
228 // All node data first
229 readNode(data);
230 // Then all non-video data
231 readMetrics(data);
232 // Then all video data
233 readData(data);
234 }
235
readNode(uchar * & data)236 void readNode(uchar*& data)
237 {
238 uchar rw = *data++;
239 uchar cl = *data++;
240 min = (rw << 8) | cl;
241 rw = *data++;
242 cl = *data++;
243 max = (rw << 8) | cl;
244 int flags = *data++;
245 if ( flags & 1 )
246 less = new QPFGlyphTree;
247 else
248 less = 0;
249 if ( flags & 2 )
250 more = new QPFGlyphTree;
251 else
252 more = 0;
253 int n = max-min+1;
254 glyph = new QPFGlyph[n];
255
256 if ( less )
257 less->readNode(data);
258 if ( more )
259 more->readNode(data);
260 }
261
readMetrics(uchar * & data)262 void readMetrics(uchar*& data)
263 {
264 int n = max-min+1;
265 for (int i=0; i<n; i++) {
266 glyph[i].metrics = (QPFGlyphMetrics*)data;
267 data += sizeof(QPFGlyphMetrics);
268 }
269 if ( less )
270 less->readMetrics(data);
271 if ( more )
272 more->readMetrics(data);
273 }
274
readData(uchar * & data)275 void readData(uchar*& data)
276 {
277 int n = max-min+1;
278 for (int i=0; i<n; i++) {
279 QSize s( glyph[i].metrics->width, glyph[i].metrics->height );
280 //######### s = qt_screen->mapToDevice( s );
281 uint datasize = glyph[i].metrics->linestep * s.height();
282 glyph[i].data = data; data += datasize;
283 }
284 if ( less )
285 less->readData(data);
286 if ( more )
287 more->readData(data);
288 }
289 };
290
291 class QFontEngineQPF1Data
292 {
293 public:
294 QPFFontMetrics fm;
295 QPFGlyphTree *tree;
296 uchar *mmapStart;
297 size_t mmapLength;
298 #ifdef QT_USE_MMAP
299 bool used_mmap;
300 #endif
301 };
302
QFontEngineQPF1(const QFontDef &,const QString & fn)303 QFontEngineQPF1::QFontEngineQPF1(const QFontDef&, const QString &fn)
304 {
305 cache_cost = 1;
306
307 int fd = QT_OPEN(QFile::encodeName(fn).constData(), O_RDONLY, 0);
308 if (fd == -1)
309 qFatal("Failed to open '%s'", QFile::encodeName(fn).constData());
310
311 QT_STATBUF st;
312 if (QT_FSTAT(fd, &st) != 0)
313 qFatal("Failed to stat '%s'", QFile::encodeName(fn).constData());
314
315 d = new QFontEngineQPF1Data;
316 d->mmapStart = 0;
317 d->mmapLength = st.st_size;
318
319 #ifdef QT_USE_MMAP
320 d->used_mmap = true;
321 d->mmapStart = (uchar *)::mmap(0, st.st_size, // any address, whole file
322 PROT_READ, // read-only memory
323 MAP_FILE | MAP_PRIVATE, // swap-backed map from file
324 fd, 0); // from offset 0 of fd
325 if (d->mmapStart == (uchar *)MAP_FAILED)
326 d->mmapStart = 0;
327 #endif
328
329 if (!d->mmapStart) {
330 #ifdef QT_USE_MMAP
331 d->used_mmap = false;
332 #endif
333 d->mmapStart = new uchar[d->mmapLength];
334 if (QT_READ(fd, d->mmapStart, d->mmapLength) != (qint64)d->mmapLength)
335 qFatal("Failed to read '%s'", QFile::encodeName(fn).constData());
336 }
337 QT_CLOSE(fd);
338
339 if (d->mmapStart) {
340 uchar* data = d->mmapStart;
341
342 memcpy(reinterpret_cast<char*>(&d->fm), data, sizeof(d->fm));
343 data += sizeof(d->fm);
344
345 d->tree = new QPFGlyphTree(data);
346 glyphFormat = (d->fm.flags & FM_SMOOTH) ? QFontEngineGlyphCache::Raster_A8
347 : QFontEngineGlyphCache::Raster_Mono;
348 #if 0
349 qDebug() << "font file" << fn
350 << "ascent" << d->fm.ascent << "descent" << d->fm.descent
351 << "leftbearing" << d->fm.leftbearing
352 << "rightbearing" << d->fm.rightbearing
353 << "maxwidth" << d->fm.maxwidth
354 << "leading" << d->fm.leading
355 << "flags" << d->fm.flags
356 << "underlinepos" << d->fm.underlinepos
357 << "underlinewidth" << d->fm.underlinewidth;
358 #endif
359 }
360 }
361
~QFontEngineQPF1()362 QFontEngineQPF1::~QFontEngineQPF1()
363 {
364 if (d->mmapStart) {
365 #if defined(QT_USE_MMAP)
366 if (d->used_mmap)
367 ::munmap(d->mmapStart, d->mmapLength);
368 else
369 #endif
370 delete [] d->mmapStart;
371 }
372 delete d->tree;
373 delete d;
374 }
375
376
stringToCMap(const QChar * str,int len,QGlyphLayout * glyphs,int * nglyphs,QTextEngine::ShaperFlags flags) const377 bool QFontEngineQPF1::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
378 {
379 if(*nglyphs < len) {
380 *nglyphs = len;
381 return false;
382 }
383 *nglyphs = 0;
384
385 bool mirrored = flags & QTextEngine::RightToLeft;
386 for(int i = 0; i < len; i++) {
387 unsigned int uc = getChar(str, i, len);
388 if (mirrored)
389 uc = QChar::mirroredChar(uc);
390 glyphs->glyphs[*nglyphs] = uc < 0x10000 ? uc : 0;
391 ++*nglyphs;
392 }
393
394 glyphs->numGlyphs = *nglyphs;
395
396 if (flags & QTextEngine::GlyphIndicesOnly)
397 return true;
398
399 recalcAdvances(glyphs, flags);
400
401 return true;
402 }
403
recalcAdvances(QGlyphLayout * glyphs,QTextEngine::ShaperFlags) const404 void QFontEngineQPF1::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const
405 {
406 for(int i = 0; i < glyphs->numGlyphs; i++) {
407 QPFGlyph *glyph = d->tree->get(glyphs->glyphs[i]);
408
409 glyphs->advances_x[i] = glyph ? glyph->metrics->advance : 0;
410 glyphs->advances_y[i] = 0;
411
412 if (!glyph)
413 glyphs->glyphs[i] = 0;
414 }
415 }
416
draw(QPaintEngine * p,qreal _x,qreal _y,const QTextItemInt & si)417 void QFontEngineQPF1::draw(QPaintEngine *p, qreal _x, qreal _y, const QTextItemInt &si)
418 {
419 QPaintEngineState *pState = p->state;
420 QRasterPaintEngine *paintEngine = static_cast<QRasterPaintEngine*>(p);
421
422 QTransform matrix = pState->transform();
423 matrix.translate(_x, _y);
424 QFixed x = QFixed::fromReal(matrix.dx());
425 QFixed y = QFixed::fromReal(matrix.dy());
426
427 QVarLengthArray<QFixedPoint> positions;
428 QVarLengthArray<glyph_t> glyphs;
429 getGlyphPositions(si.glyphs, matrix, si.flags, glyphs, positions);
430 if (glyphs.size() == 0)
431 return;
432
433 int depth = (d->fm.flags & FM_SMOOTH) ? 8 : 1;
434 for(int i = 0; i < glyphs.size(); i++) {
435 const QPFGlyph *glyph = d->tree->get(glyphs[i]);
436 if (!glyph)
437 continue;
438
439 int bpl = glyph->metrics->linestep;
440
441 if(glyph->data)
442 paintEngine->alphaPenBlt(glyph->data, bpl, depth,
443 qRound(positions[i].x) + glyph->metrics->bearingx,
444 qRound(positions[i].y) - glyph->metrics->bearingy,
445 glyph->metrics->width,glyph->metrics->height);
446 }
447 }
448
449
alphaMapForGlyph(glyph_t g)450 QImage QFontEngineQPF1::alphaMapForGlyph(glyph_t g)
451 {
452 const QPFGlyph *glyph = d->tree->get(g);
453 if (!glyph)
454 return QImage();
455
456 int mono = !(d->fm.flags & FM_SMOOTH);
457
458 const uchar *bits = glyph->data;//((const uchar *) glyph);
459
460 QImage image;
461 if (mono) {
462 image = QImage((glyph->metrics->width+7)&~7, glyph->metrics->height, QImage::Format_Mono);
463 image.setColor(0, qRgba(0, 0, 0, 0));
464 image.setColor(1, qRgba(0, 0, 0, 255));
465 } else {
466 image = QImage(glyph->metrics->width, glyph->metrics->height, QImage::Format_Indexed8);
467 for (int j=0; j<256; ++j)
468 image.setColor(j, qRgba(0, 0, 0, j));
469 }
470 for (int i=0; i<glyph->metrics->height; ++i) {
471 memcpy(image.scanLine(i), bits, glyph->metrics->linestep);
472 bits += glyph->metrics->linestep;
473 }
474 return image;
475 }
476
477
478
addOutlineToPath(qreal x,qreal y,const QGlyphLayout & glyphs,QPainterPath * path,QTextItem::RenderFlags flags)479 void QFontEngineQPF1::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
480 {
481 addBitmapFontToPath(x, y, glyphs, path, flags);
482 }
483
boundingBox(const QGlyphLayout & glyphs)484 glyph_metrics_t QFontEngineQPF1::boundingBox(const QGlyphLayout &glyphs)
485 {
486 if (glyphs.numGlyphs == 0)
487 return glyph_metrics_t();
488
489 QFixed w = 0;
490 for (int i = 0; i < glyphs.numGlyphs; ++i)
491 w += glyphs.effectiveAdvance(i);
492 return glyph_metrics_t(0, -ascent(), w - lastRightBearing(glyphs), ascent()+descent()+1, w, 0);
493 }
494
boundingBox(glyph_t glyph)495 glyph_metrics_t QFontEngineQPF1::boundingBox(glyph_t glyph)
496 {
497 const QPFGlyph *g = d->tree->get(glyph);
498 if (!g)
499 return glyph_metrics_t();
500 Q_ASSERT(g);
501 return glyph_metrics_t(g->metrics->bearingx, -g->metrics->bearingy,
502 g->metrics->width, g->metrics->height,
503 g->metrics->advance, 0);
504 }
505
ascent() const506 QFixed QFontEngineQPF1::ascent() const
507 {
508 return d->fm.ascent;
509 }
510
descent() const511 QFixed QFontEngineQPF1::descent() const
512 {
513 return d->fm.descent;
514 }
515
leading() const516 QFixed QFontEngineQPF1::leading() const
517 {
518 return d->fm.leading;
519 }
520
maxCharWidth() const521 qreal QFontEngineQPF1::maxCharWidth() const
522 {
523 return d->fm.maxwidth;
524 }
525 /*
526 const char *QFontEngineQPF1::name() const
527 {
528 return "qt";
529 }
530 */
canRender(const QChar * str,int len)531 bool QFontEngineQPF1::canRender(const QChar *str, int len)
532 {
533 for(int i = 0; i < len; i++)
534 if (!d->tree->inFont(str[i].unicode()))
535 return false;
536 return true;
537 }
538
type() const539 QFontEngine::Type QFontEngineQPF1::type() const
540 {
541 return QPF1;
542 }
543
minLeftBearing() const544 qreal QFontEngineQPF1::minLeftBearing() const
545 {
546 return d->fm.leftbearing;
547 }
548
minRightBearing() const549 qreal QFontEngineQPF1::minRightBearing() const
550 {
551 return d->fm.rightbearing;
552 }
553
underlinePosition() const554 QFixed QFontEngineQPF1::underlinePosition() const
555 {
556 return d->fm.underlinepos;
557 }
558
lineThickness() const559 QFixed QFontEngineQPF1::lineThickness() const
560 {
561 return d->fm.underlinewidth;
562 }
563
564 #endif //QT_NO_QWS_QPF
565
566 QT_END_NAMESPACE
567