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