source: trunk/src/gui/text/qfontengine_qws.cpp@ 561

Last change on this file since 561 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

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