src/gui/text/qfontengine_qws.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    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 
       
    81 QT_BEGIN_NAMESPACE
       
    82 
       
    83 #ifndef QT_NO_QWS_QPF
       
    84 QT_BEGIN_INCLUDE_NAMESPACE
       
    85 #include "qplatformdefs.h"
       
    86 QT_END_INCLUDE_NAMESPACE
       
    87 
       
    88 static 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 
       
   104 class Q_PACKED QPFGlyphMetrics {
       
   105 
       
   106 public:
       
   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 
       
   125 class QPFGlyph {
       
   126 public:
       
   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 
       
   136 struct 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 
       
   148 class QPFGlyphTree {
       
   149 public:
       
   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;
       
   163 public:
       
   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 
       
   235 private:
       
   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 
       
   379 class QFontEngineQPF1Data
       
   380 {
       
   381 public:
       
   382     QPFFontMetrics fm;
       
   383     QPFGlyphTree *tree;
       
   384     void *mmapStart;
       
   385     size_t mmapLength;
       
   386 };
       
   387 
       
   388 
       
   389 QFontEngineQPF1::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 
       
   436 QFontEngineQPF1::~QFontEngineQPF1()
       
   437 {
       
   438     if (d->mmapStart)
       
   439         munmap(d->mmapStart, d->mmapLength);
       
   440     delete d->tree;
       
   441     delete d;
       
   442 }
       
   443 
       
   444 
       
   445 bool 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 
       
   472 void 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 
       
   485 void 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 
       
   518 QImage 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 
       
   547 void QFontEngineQPF1::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
       
   548 {
       
   549     addBitmapFontToPath(x, y, glyphs, path, flags);
       
   550 }
       
   551 
       
   552 glyph_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 
       
   563 glyph_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 
       
   574 QFixed QFontEngineQPF1::ascent() const
       
   575 {
       
   576     return d->fm.ascent;
       
   577 }
       
   578 
       
   579 QFixed QFontEngineQPF1::descent() const
       
   580 {
       
   581     return d->fm.descent;
       
   582 }
       
   583 
       
   584 QFixed QFontEngineQPF1::leading() const
       
   585 {
       
   586     return d->fm.leading;
       
   587 }
       
   588 
       
   589 qreal QFontEngineQPF1::maxCharWidth() const
       
   590 {
       
   591     return d->fm.maxwidth;
       
   592 }
       
   593 /*
       
   594 const char *QFontEngineQPF1::name() const
       
   595 {
       
   596     return "qt";
       
   597 }
       
   598 */
       
   599 bool 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 
       
   607 QFontEngine::Type QFontEngineQPF1::type() const
       
   608 {
       
   609     return QPF1;
       
   610 }
       
   611 
       
   612 qreal QFontEngineQPF1::minLeftBearing() const
       
   613 {
       
   614     return d->fm.leftbearing;
       
   615 }
       
   616 
       
   617 qreal QFontEngineQPF1::minRightBearing() const
       
   618 {
       
   619     return d->fm.rightbearing;
       
   620 }
       
   621 
       
   622 QFixed QFontEngineQPF1::underlinePosition() const
       
   623 {
       
   624     return d->fm.underlinepos;
       
   625 }
       
   626 
       
   627 QFixed QFontEngineQPF1::lineThickness() const
       
   628 {
       
   629     return d->fm.underlinewidth;
       
   630 }
       
   631 
       
   632 #endif //QT_NO_QWS_QPF
       
   633 
       
   634 QT_END_NAMESPACE