📄 qfontengine_qws.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtGui module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qfontengine_p.h"#include <private/qunicodetables_p.h>#include <qwsdisplay_qws.h>#include <qvarlengtharray.h>#include <private/qpainter_p.h>#include <private/qpaintengine_raster_p.h>#include <private/qpdf_p.h>#include "qtextengine_p.h"#include "qopentype_p.h"#include <qdebug.h>#ifndef QT_NO_QWS_QPF#include "qfile.h"#include "qdir.h"#define QT_USE_MMAP#include <stdlib.h>#ifdef QT_USE_MMAP// for mmap#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/mman.h>#include <fcntl.h>#include <errno.h>#endif#endif // QT_NO_QWS_QPF#ifndef QT_NO_QWS_QPF#include "qplatformdefs.h"static inline unsigned int getChar(const QChar *str, int &i, const int len){ unsigned int uc = str[i].unicode(); if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) { uint low = str[i+1].unicode(); if (low >= 0xdc00 && low < 0xe000) { uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000; ++i; } } return uc;}#define FM_SMOOTH 1class Q_PACKED QPFGlyphMetrics {public: quint8 linestep; quint8 width; quint8 height; quint8 flags; qint8 bearingx; // Difference from pen position to glyph's left bbox quint8 advance; // Difference between pen positions qint8 bearingy; // Used for putting characters on baseline qint8 reserved; // Do not use // Flags: // RendererOwnsData - the renderer is responsible for glyph data // memory deletion otherwise QPFGlyphTree must // delete [] the data when the glyph is deleted. enum Flags { RendererOwnsData=0x01 };};class QPFGlyph {public: QPFGlyph() { metrics=0; data=0; } QPFGlyph(QPFGlyphMetrics* m, uchar* d) : metrics(m), data(d) { } ~QPFGlyph() {} QPFGlyphMetrics* metrics; uchar* data;};struct Q_PACKED QPFFontMetrics{ qint8 ascent,descent; qint8 leftbearing,rightbearing; quint8 maxwidth; qint8 leading; quint8 flags; quint8 underlinepos; quint8 underlinewidth; quint8 reserved3;};class QPFGlyphTree {public: /* reads in a tree like this: A-Z / \ 0-9 a-z etc. */ glyph_t min,max; QPFGlyphTree* less; QPFGlyphTree* more; QPFGlyph* glyph;public:#ifdef QT_USE_MMAP QPFGlyphTree(uchar*& data) { read(data); }#else QPFGlyphTree(QIODevice& f) { read(f); }#endif ~QPFGlyphTree() { // NOTE: does not delete glyph[*].metrics or .data. // the caller does this (only they know who owns // the data). See clear(). delete less; delete more; delete [] glyph; } bool inFont(glyph_t g) const { if ( g < min ) { if ( !less ) return false; return less->inFont(g); } else if ( g > max ) { if ( !more ) return false; return more->inFont(g); } return true; } QPFGlyph* get(glyph_t g) { if ( g < min ) { if ( !less ) return 0; return less->get(g); } else if ( g > max ) { if ( !more ) return 0; return more->get(g); } return &glyph[g - min]; } int totalChars() const { if ( !this ) return 0; return max-min+1 + less->totalChars() + more->totalChars(); } int weight() const { if ( !this ) return 0; return 1 + less->weight() + more->weight(); } void dump(int indent=0) { for (int i=0; i<indent; i++) printf(" "); printf("%d..%d",min,max); //if ( indent == 0 ) printf(" (total %d)",totalChars()); printf("\n"); if ( less ) less->dump(indent+1); if ( more ) more->dump(indent+1); }private: QPFGlyphTree() { }#ifdef QT_USE_MMAP void read(uchar*& data) { // All node data first readNode(data); // Then all non-video data readMetrics(data); // Then all video data readData(data); }#else void read(QIODevice& f) { // All node data first readNode(f); // Then all non-video data readMetrics(f); // Then all video data readData(f); }#endif#ifdef QT_USE_MMAP void readNode(uchar*& data) { uchar rw = *data++; uchar cl = *data++; min = (rw << 8) | cl; rw = *data++; cl = *data++; max = (rw << 8) | cl; int flags = *data++; if ( flags & 1 ) less = new QPFGlyphTree; else less = 0; if ( flags & 2 ) more = new QPFGlyphTree; else more = 0; int n = max-min+1; glyph = new QPFGlyph[n]; if ( less ) less->readNode(data); if ( more ) more->readNode(data); }#else void readNode(QIODevice& f) { uchar rw = f.getch(); uchar cl = f.getch(); min = (rw << 8) | cl; rw = f.getch(); cl = f.getch(); max = (rw << 8) | cl; int flags = f.getch(); if ( flags & 1 ) less = new QPFGlyphTree; else less = 0; if ( flags & 2 ) more = new QPFGlyphTree; else more = 0; int n = max-min+1; glyph = new QPFGlyph[n]; if ( less ) less->readNode(f); if ( more ) more->readNode(f); }#endif#ifdef QT_USE_MMAP void readMetrics(uchar*& data) { int n = max-min+1; for (int i=0; i<n; i++) { glyph[i].metrics = (QPFGlyphMetrics*)data; data += sizeof(QPFGlyphMetrics); } if ( less ) less->readMetrics(data); if ( more ) more->readMetrics(data); }#else void readMetrics(QIODevice& f) { int n = max-min+1; for (int i=0; i<n; i++) { glyph[i].metrics = new QPFGlyphMetrics; f.readBlock((char*)glyph[i].metrics, sizeof(QPFGlyphMetrics)); } if ( less ) less->readMetrics(f); if ( more ) more->readMetrics(f); }#endif#ifdef QT_USE_MMAP void readData(uchar*& data) { int n = max-min+1; for (int i=0; i<n; i++) { QSize s( glyph[i].metrics->width, glyph[i].metrics->height ); //######### s = qt_screen->mapToDevice( s ); uint datasize = glyph[i].metrics->linestep * s.height(); glyph[i].data = data; data += datasize; } if ( less ) less->readData(data); if ( more ) more->readData(data); }#else void readData(QIODevice& f) { int n = max-min+1; for (int i=0; i<n; i++) { QSize s( glyph[i].metrics->width, glyph[i].metrics->height ); //############### s = qt_screen->mapToDevice( s ); uint datasize = glyph[i].metrics->linestep * s.height(); glyph[i].data = new uchar[datasize]; // ### deleted? f.readBlock((char*)glyph[i].data, datasize); } if ( less ) less->readData(f); if ( more ) more->readData(f); }#endif};class QFontEngineQPF1Data{public: QPFFontMetrics fm; QPFGlyphTree *tree;};QFontEngineQPF1::QFontEngineQPF1(const QFontDef&, const QString &fn){ cache_cost = 1; int f = ::open( QFile::encodeName(fn), O_RDONLY ); Q_ASSERT(f>=0); QT_STATBUF st; if ( QT_FSTAT( f, &st ) ) qFatal("Failed to stat %s",QFile::encodeName(fn).data()); uchar* data = (uchar*)mmap( 0, // any address st.st_size, // whole file PROT_READ, // read-only memory#if !defined(Q_OS_SOLARIS) && !defined(Q_OS_QNX4) && !defined(QT_LSB) && !defined(Q_OS_INTEGRITY) MAP_FILE | MAP_PRIVATE, // swap-backed map from file#else MAP_PRIVATE,#endif f, 0 ); // from offset 0 of f#if defined(Q_OS_QNX4) && !defined(MAP_FAILED)#define MAP_FAILED ((void *)-1)#endif if ( !data || data == (uchar*)MAP_FAILED ) qFatal("Failed to mmap %s",QFile::encodeName(fn).data()); ::close(f); d = new QFontEngineQPF1Data; memcpy(reinterpret_cast<char*>(&d->fm),data,sizeof(d->fm)); data += sizeof(d->fm); d->tree = new QPFGlyphTree(data);#if 0 qDebug() << "font file" << fn << "ascent" << d->fm.ascent << "descent" << d->fm.descent << "leftbearing" << d->fm.leftbearing << "rightbearing" << d->fm.rightbearing << "maxwidth" << d->fm.maxwidth << "leading" << d->fm.leading << "flags" << d->fm.flags << "underlinepos" << d->fm.underlinepos << "underlinewidth" << d->fm.underlinewidth;#endif}QFontEngineQPF1::~QFontEngineQPF1(){ delete d->tree; delete d;}bool QFontEngineQPF1::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags) const{ if(*nglyphs < len) { *nglyphs = len; return false; } *nglyphs = 0; for(int i = 0; i < len; i++) { unsigned int uc = getChar(str, i, len); glyphs[*nglyphs].glyph = uc < 0x10000 ? uc : 0; ++*nglyphs; } for(int i = 0; i < len; i++) { QGlyphLayout &g=glyphs[i]; QPFGlyph *glyph = d->tree->get(g.glyph); g.advance.x = glyph ? glyph->metrics->advance : 0; g.advance.y = 0; if (!glyph) g.glyph = 0; } return true;}void QFontEngineQPF1::draw(QPaintEngine *p, qreal _x, qreal _y, const QTextItemInt &si){ QPaintEngineState *pState = p->state; QRasterPaintEngine *paintEngine = static_cast<QRasterPaintEngine*>(p); QTransform matrix = pState->transform(); matrix.translate(_x, _y); QFixed x = QFixed::fromReal(matrix.dx()); QFixed y = QFixed::fromReal(matrix.dy()); QVarLengthArray<QFixedPoint> positions; QVarLengthArray<glyph_t> glyphs; getGlyphPositions(si.glyphs, si.num_glyphs, matrix, si.flags, glyphs, positions); if (glyphs.size() == 0) return; for(int i = 0; i < glyphs.size(); i++) { const QPFGlyph *glyph = d->tree->get(glyphs[i]); if (!glyph) continue; int mono = !(d->fm.flags & FM_SMOOTH); int bpl = glyph->metrics->linestep; if(glyph->data) paintEngine->alphaPenBlt(glyph->data, bpl, mono, qRound(positions[i].x) + glyph->metrics->bearingx, qRound(positions[i].y) - glyph->metrics->bearingy, glyph->metrics->width,glyph->metrics->height); }}void QFontEngineQPF1::addOutlineToPath(qreal x, qreal y, const QGlyphLayout *glyphs, int numGlyphs, QPainterPath *path, QTextItem::RenderFlags flags){ addBitmapFontToPath(x, y, glyphs, numGlyphs, path, flags);}glyph_metrics_t QFontEngineQPF1::boundingBox(const QGlyphLayout *glyphs, int numGlyphs){ if (numGlyphs == 0) return glyph_metrics_t(); QFixed w = 0; const QGlyphLayout *end = glyphs + numGlyphs; while(end > glyphs) w += (--end)->advance.x; return glyph_metrics_t(0, -ascent(), w, ascent()+descent()+1, w, 0);}glyph_metrics_t QFontEngineQPF1::boundingBox(glyph_t glyph){ const QPFGlyph *g = d->tree->get(glyph); if (!g) return glyph_metrics_t(); Q_ASSERT(g); return glyph_metrics_t(g->metrics->bearingx, -g->metrics->bearingy, g->metrics->width, g->metrics->height, g->metrics->advance, 0);}QFixed QFontEngineQPF1::ascent() const{ return d->fm.ascent;}QFixed QFontEngineQPF1::descent() const{ return d->fm.descent;}QFixed QFontEngineQPF1::leading() const{ return d->fm.leading;}qreal QFontEngineQPF1::maxCharWidth() const{ return d->fm.maxwidth;}/*const char *QFontEngineQPF1::name() const{ return "qt";}*/bool QFontEngineQPF1::canRender(const QChar *str, int len){ for(int i = 0; i < len; i++) if (!d->tree->inFont(str[i].unicode())) return false; return true;}QFontEngine::Type QFontEngineQPF1::type() const{ return QPF1;}qreal QFontEngineQPF1::minLeftBearing() const{ return d->fm.leftbearing;}qreal QFontEngineQPF1::minRightBearing() const{ return d->fm.rightbearing;}QFixed QFontEngineQPF1::underlinePosition() const{ return d->fm.underlinepos;}QFixed QFontEngineQPF1::lineThickness() const{ return d->fm.underlinewidth;}#endif //QT_NO_QWS_QPF
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -