Changeset 846 for trunk/src/gui/text


Ignore:
Timestamp:
May 5, 2011, 5:36:53 AM (14 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

Location:
trunk
Files:
95 edited
3 copied

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/gui/text/qabstractfontengine_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qabstractfontengine_qws.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qabstractfontengine_qws.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qabstracttextdocumentlayout.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qabstracttextdocumentlayout.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qabstracttextdocumentlayout_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qcssparser.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qcssparser_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qcssscanner.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qfont.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    7878#endif
    7979#ifdef Q_OS_SYMBIAN
    80 #include "qt_s60_p.h"
     80#include <private/qt_s60_p.h>
    8181#endif
    8282
     
    12831283    \value Decorative is a synonym for \c OldEnglish.
    12841284
     1285    \value Monospace the font matcher prefers fonts that map to the
     1286    CSS generic font-family 'monospace'.
     1287
     1288    \value Fantasy the font matcher prefers fonts that map to the
     1289    CSS generic font-family 'fantasy'.
     1290
     1291    \value Cursive the font matcher prefers fonts that map to the
     1292    CSS generic font-family 'cursive'.
     1293
    12851294    \value System the font matcher prefers system fonts.
    12861295*/
     
    13061315    \value OpenGLCompatible forces the use of OpenGL compatible
    13071316           fonts.
    1308     \value NoFontMerging If a font does not contain a character requested
    1309            to draw then Qt automatically chooses a similar looking for that contains
    1310            the character. This flag disables this feature.
     1317    \value NoFontMerging If the font selected for a certain writing system
     1318           does not contain a character requested to draw, then Qt automatically chooses a similar
     1319           looking font that contains the character. The NoFontMerging flag disables this feature.
     1320           Please note that enabling this flag will not prevent Qt from automatically picking a
     1321           suitable font when the selected font does not support the writing system of the text.
    13111322
    13121323    Any of these may be OR-ed with one of these flags:
     
    13171328           will use the nearest standard point size that the font
    13181329           supports.
     1330    \value ForceIntegerMetrics forces the use of integer values in font engines that support fractional
     1331           font metrics.
    13191332*/
    13201333
  • trunk/src/gui/text/qfont.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    7373        OldEnglish, Decorative = OldEnglish,
    7474        System,
    75         AnyStyle
     75        AnyStyle,
     76        Cursive,
     77        Monospace,
     78        Fantasy
    7679    };
    7780
    7881    enum StyleStrategy {
    79         PreferDefault    = 0x0001,
    80         PreferBitmap     = 0x0002,
    81         PreferDevice     = 0x0004,
    82         PreferOutline    = 0x0008,
    83         ForceOutline     = 0x0010,
    84         PreferMatch      = 0x0020,
    85         PreferQuality    = 0x0040,
    86         PreferAntialias  = 0x0080,
    87         NoAntialias      = 0x0100,
    88         OpenGLCompatible = 0x0200,
    89         NoFontMerging    = 0x8000
     82        PreferDefault       = 0x0001,
     83        PreferBitmap        = 0x0002,
     84        PreferDevice        = 0x0004,
     85        PreferOutline       = 0x0008,
     86        ForceOutline        = 0x0010,
     87        PreferMatch         = 0x0020,
     88        PreferQuality       = 0x0040,
     89        PreferAntialias     = 0x0080,
     90        NoAntialias         = 0x0100,
     91        OpenGLCompatible    = 0x0200,
     92        ForceIntegerMetrics = 0x0400,
     93        NoFontMerging       = 0x8000
    9094    };
    9195
     
    292296    friend class QFontInfo;
    293297    friend class QPainter;
     298    friend class QPainterPrivate;
    294299    friend class QPSPrintEngineFont;
    295300    friend class QApplication;
  • trunk/src/gui/text/qfont_mac.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    137137        case QFont::Courier:
    138138            return QString::fromLatin1("Courier New");
     139        case QFont::Monospace:
     140            return QString::fromLatin1("Courier");
    139141        case QFont::Decorative:
    140142            return QString::fromLatin1("Bookman Old Style");
     143        case QFont::Cursive:
     144            return QString::fromLatin1("Apple Chancery");
     145        case QFont::Fantasy:
     146            return QString::fromLatin1("Papyrus");
    141147        case QFont::Helvetica:
    142148        case QFont::System:
  • trunk/src/gui/text/qfont_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qfont_qws.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    109109            return QString::fromLatin1("times");
    110110        case QFont::Courier:
     111        case QFont::Monospace:
    111112            return QString::fromLatin1("courier");
    112113        case QFont::Decorative:
  • trunk/src/gui/text/qfont_s60.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4141
    4242#include "qfont.h"
    43 #include "qt_s60_p.h"
    44 #include "qpixmap_s60_p.h"
     43#include "qfont_p.h"
     44#include <private/qt_s60_p.h>
     45#include <private/qpixmap_s60_p.h>
    4546#include "qmutex.h"
    4647
    4748QT_BEGIN_NAMESPACE
    4849
    49 #if 1
    5050#ifdef QT_NO_FREETYPE
    5151Q_GLOBAL_STATIC(QMutex, lastResortFamilyMutex);
     52extern QStringList qt_symbian_fontFamiliesOnFontServer(); // qfontdatabase_s60.cpp
     53Q_GLOBAL_STATIC_WITH_INITIALIZER(QStringList, fontFamiliesOnFontServer, {
     54    // We are only interested in the initial font families. No Application fonts.
     55    // Therefore, we are allowed to cache the list.
     56    x->append(qt_symbian_fontFamiliesOnFontServer());
     57});
    5258#endif // QT_NO_FREETYPE
     59
     60QString QFont::lastResortFont() const
     61{
     62    // Symbian's font Api does not distinguish between font and family.
     63    // Therefore we try to get a "Family" first, then fall back to "Sans".
     64    static QString font = lastResortFamily();
     65    if (font.isEmpty())
     66        font = QLatin1String("Sans");
     67    return font;
     68}
    5369
    5470QString QFont::lastResortFamily() const
     
    7187    }
    7288    return family;
    73 #else
     89#else // QT_NO_FREETYPE
    7490    // For the FreeType case we just hard code the face name, since otherwise on
    7591    // East Asian systems we may get a name for a stroke based (non-ttf) font.
     
    8399#endif // QT_NO_FREETYPE
    84100}
    85 #else // 0
    86 QString QFont::lastResortFamily() const
    87 {
    88     return QLatin1String("Series 60 Sans");
    89 }
    90 #endif // 0
    91101
    92102QString QFont::defaultFamily() const
    93103{
     104#ifdef QT_NO_FREETYPE
     105    switch(d->request.styleHint) {
     106        case QFont::SansSerif: {
     107            static const char* const preferredSansSerif[] = {"Nokia Sans S60", "Series 60 Sans"};
     108            for (int i = 0; i < sizeof preferredSansSerif / sizeof preferredSansSerif[0]; ++i) {
     109                const QString sansSerif = QLatin1String(preferredSansSerif[i]);
     110                if (fontFamiliesOnFontServer()->contains(sansSerif))
     111                    return sansSerif;
     112            }
     113        }
     114        // No break. Intentional fall through.
     115        default:
     116            return lastResortFamily();
     117    }
     118#endif // QT_NO_FREETYPE
    94119    return lastResortFamily();
    95120}
  • trunk/src/gui/text/qfont_win.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    149149            return QString::fromLatin1("Times New Roman");
    150150        case QFont::Courier:
     151        case QFont::Monospace:
    151152            return QString::fromLatin1("Courier New");
    152153        case QFont::Decorative:
    153154            return QString::fromLatin1("Bookman Old Style");
     155        case QFont::Cursive:
     156            return QString::fromLatin1("Comic Sans MS");
     157        case QFont::Fantasy:
     158            return QString::fromLatin1("Impact");
    154159        case QFont::Helvetica:
    155160            return QString::fromLatin1("Arial");
  • trunk/src/gui/text/qfont_x11.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    281281    case QFont::Courier:
    282282        return QString::fromLatin1("Courier");
     283
     284    case QFont::Monospace:
     285        return QString::fromLatin1("Courier New");
     286
     287    case QFont::Cursive:
     288        return QString::fromLatin1("Comic Sans MS");
     289
     290    case QFont::Fantasy:
     291        return QString::fromLatin1("Impact");
    283292
    284293    case QFont::Decorative:
  • trunk/src/gui/text/qfontdatabase.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    149149struct QtFontSize
    150150{
    151     unsigned short pixelSize;
    152 
    153151#ifdef Q_WS_X11
    154     int count;
    155152    QtFontEncoding *encodings;
    156153    QtFontEncoding *encodingID(int id, uint xpoint = 0, uint xres = 0,
    157154                                uint yres = 0, uint avgwidth = 0, bool add = false);
     155    unsigned short count : 16;
    158156#endif // Q_WS_X11
    159157#ifdef Q_WS_PM
     
    164162    int fileIndex;
    165163#endif // defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)
     164
     165    unsigned short pixelSize : 16;
    166166};
    167167
     
    294294        return 0;
    295295
    296     if (!(count % 8)) {
     296    if (!pixelSizes) {
     297        // Most style have only one font size, we avoid waisting memory
     298        QtFontSize *newPixelSizes = (QtFontSize *)malloc(sizeof(QtFontSize));
     299        Q_CHECK_PTR(newPixelSizes);
     300        pixelSizes = newPixelSizes;
     301    } else if (!(count % 8) || count == 1) {
    297302        QtFontSize *newPixelSizes = (QtFontSize *)
    298303                     realloc(pixelSizes,
     
    421426#endif
    422427#ifdef Q_WS_X11
    423     bool symbol_checked;
     428    bool symbol_checked : 1;
    424429#endif
    425430
     
    635640    ~QFontDatabasePrivate() {
    636641        free();
     642#if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
     643        if (symbianExtras)
     644            delete symbianExtras;
     645#endif
    637646    }
    638647    QtFontFamily *family(const QString &f, bool = false);
     
    643652        families = 0;
    644653        count = 0;
    645 #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
    646         if (symbianExtras) {
    647             delete symbianExtras;
    648             symbianExtras = 0;
    649         }
    650 #endif
    651654        // don't clear the memory fonts!
    652655    }
     
    664667#elif defined(Q_WS_MAC)
    665668        ATSFontContainerRef handle;
     669#elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
     670        QString temporaryFileName;
     671        TInt screenDeviceFontFileId;
     672        TUid fontStoreFontFileUid;
    666673#endif
    667674        QStringList families;
     
    691698    QStringList fallbackFamilies;
    692699#elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
    693     const QSymbianFontDatabaseExtras *symbianExtras;
     700    QSymbianFontDatabaseExtras *symbianExtras;
    694701#endif
    695702
     
    25922599    currently not supported.
    25932600
     2601    \note On Symbian, the font family names get truncated to a length of 20 characters.
     2602
    25942603    \sa addApplicationFontFromData(), applicationFontFamilies(), removeApplicationFont()
    25952604*/
     
    26222631    currently not supported.
    26232632
     2633    \note On Symbian, the font family names get truncated to a length of 20 characters.
     2634
    26242635    \sa addApplicationFont(), applicationFontFamilies(), removeApplicationFont()
    26252636*/
  • trunk/src/gui/text/qfontdatabase.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qfontdatabase_mac.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qfontdatabase_qws.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    633633
    634634            QScopedPointer<QFontEngineFT> fte(new QFontEngineFT(def));
    635             if (fte->init(faceId, style->antialiased,
    636                           style->antialiased ? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono)) {
     635            bool antialias = style->antialiased && !(request.styleStrategy & QFont::NoAntialias);
     636            if (fte->init(faceId, antialias,
     637                          antialias ? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono)) {
    637638#ifdef QT_NO_QWS_QPF2
    638639                return fte.take();
     
    794795             "    weight: %d, style: %d\n"
    795796             "    stretch: %d\n"
    796              "    pixelSize: %d\n"
     797             "    pixelSize: %g\n"
    797798             "    pitch: %c",
    798799             family_name.isEmpty() ? "-- first in script --" : family_name.toLatin1().constData(),
  • trunk/src/gui/text/qfontdatabase_s60.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4646#include "qabstractfileengine.h"
    4747#include "qdesktopservices.h"
    48 #include "qpixmap_s60_p.h"
    49 #include "qt_s60_p.h"
     48#include "qtemporaryfile.h"
     49#include "qtextcodec.h"
     50#include <private/qpixmap_s60_p.h>
     51#include <private/qt_s60_p.h>
    5052#include "qendian.h"
    5153#include <private/qcore_symbian_p.h>
    52 #if defined(QT_NO_FREETYPE)
     54#ifdef QT_NO_FREETYPE
    5355#include <openfont.h>
    5456#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
    5557#include <graphics/openfontrasterizer.h> // COpenFontRasterizer has moved to a new header file
    5658#endif // SYMBIAN_ENABLE_SPLIT_HEADERS
    57 #endif
     59#endif // QT_NO_FREETYPE
    5860
    5961QT_BEGIN_NAMESPACE
     62
     63QStringList qt_symbian_fontFamiliesOnFontServer() // Also used in qfont_s60.cpp
     64{
     65    QStringList result;
     66    QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
     67    const int numTypeFaces = S60->screenDevice()->NumTypefaces();
     68    for (int i = 0; i < numTypeFaces; i++) {
     69        TTypefaceSupport typefaceSupport;
     70        S60->screenDevice()->TypefaceSupport(typefaceSupport, i);
     71        const QString familyName((const QChar *)typefaceSupport.iTypeface.iName.Ptr(), typefaceSupport.iTypeface.iName.Length());
     72        result.append(familyName);
     73    }
     74    lock.relock();
     75    return result;
     76}
    6077
    6178QFileInfoList alternativeFilePaths(const QString &path, const QStringList &nameFilters,
     
    92109}
    93110
    94 #if defined(QT_NO_FREETYPE)
     111#ifdef QT_NO_FREETYPE
    95112class QSymbianFontDatabaseExtrasImplementation : public QSymbianFontDatabaseExtras
    96113{
     
    100117
    101118    const QSymbianTypeFaceExtras *extras(const QString &typeface, bool bold, bool italic) const;
    102 
    103 private:
     119    void removeAppFontData(QFontDatabasePrivate::ApplicationFont *fnt);
     120    static inline bool appFontLimitReached();
     121    TUid addFontFileToFontStore(const QFileInfo &fontFileInfo);
     122    static void clear();
     123
     124    static inline QString tempAppFontFolder();
     125    static const QString appFontMarkerPrefix;
     126    static QString appFontMarker(); // 'qaf<shortUid[+shortPid]>'
     127
     128    struct CFontFromFontStoreReleaser {
     129        static inline void cleanup(CFont *font)
     130        {
     131            if (!font)
     132                return;
     133            const QSymbianFontDatabaseExtrasImplementation *dbExtras =
     134                    static_cast<const QSymbianFontDatabaseExtrasImplementation*>(privateDb()->symbianExtras);
     135            dbExtras->m_store->ReleaseFont(font);
     136        }
     137    };
     138
     139    struct CFontFromScreenDeviceReleaser {
     140        static inline void cleanup(CFont *font)
     141        {
     142            if (!font)
     143                return;
     144            S60->screenDevice()->ReleaseFont(font);
     145        }
     146    };
     147
     148// m_heap, m_store, m_rasterizer and m_extras are used if Symbian
     149// does not provide the Font Table API
    104150    RHeap* m_heap;
    105151    CFontStore *m_store;
    106152    COpenFontRasterizer *m_rasterizer;
    107153    mutable QList<const QSymbianTypeFaceExtras *> m_extras;
     154
    108155    mutable QHash<QString, const QSymbianTypeFaceExtras *> m_extrasHash;
     156    mutable QSet<QString> m_applicationFontFamilies;
    109157};
    110158
     159const QString QSymbianFontDatabaseExtrasImplementation::appFontMarkerPrefix =
     160        QLatin1String("Q");
     161
     162inline QString QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder()
     163{
     164    return QDir::toNativeSeparators(QDir::tempPath()) + QLatin1Char('\\');
     165}
     166
     167QString QSymbianFontDatabaseExtrasImplementation::appFontMarker()
     168{
     169    static QString result;
     170    if (result.isEmpty()) {
     171        quint16 id = 0;
     172        if (QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) {
     173            // We are allowed to load app fonts even from previous, crashed runs
     174            // of this application, since we can access the font tables.
     175            const quint32 uid = RProcess().Type().MostDerived().iUid;
     176            id = static_cast<quint16>(uid + (uid >> 16));
     177        } else {
     178            // If no font table Api is available, we must not even load a font
     179            // from a previous (crashed) run of this application. Reason: we
     180            // won't get the font tables, they are not in the CFontStore.
     181            // So, we use the pid, for more uniqueness.
     182            id = static_cast<quint16>(RProcess().Id().Id());
     183        }
     184        result = appFontMarkerPrefix + QString::fromLatin1("%1").arg(id & 0x7fff, 3, 32, QLatin1Char('0'));
     185        Q_ASSERT(appFontMarkerPrefix.length() == 1 && result.length() == 4);
     186    }
     187    return result;
     188}
     189
     190static inline bool qt_symbian_fontNameHasAppFontMarker(const QString &fontName)
     191{
     192    const int idLength = 3; // Keep in sync with id length in appFontMarker().
     193    const QString &prefix = QSymbianFontDatabaseExtrasImplementation::appFontMarkerPrefix;
     194    if (fontName.length() < prefix.length() + idLength
     195            || fontName.mid(fontName.length() - idLength - prefix.length(), prefix.length()) != prefix)
     196        return false;
     197    // Testing if the the id is base32 data
     198    for (int i = fontName.length() - idLength; i < fontName.length(); ++i) {
     199        const QChar &c = fontName.at(i);
     200        if (!(c >= QLatin1Char('0') && c <= QLatin1Char('9')
     201              || c >= QLatin1Char('a') && c <= QLatin1Char('v')))
     202            return false;
     203    }
     204    return true;
     205}
     206
     207// If fontName is an application font of this app, prepend the app font marker
     208QString qt_symbian_fontNameWithAppFontMarker(const QString &fontName)
     209{
     210    QFontDatabasePrivate *db = privateDb();
     211    Q_ASSERT(db);
     212    const QSymbianFontDatabaseExtrasImplementation *dbExtras =
     213            static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
     214    return dbExtras->m_applicationFontFamilies.contains(fontName) ?
     215                fontName + QSymbianFontDatabaseExtrasImplementation::appFontMarker()
     216              : fontName;
     217}
     218
     219static inline QString qt_symbian_appFontNameWithoutMarker(const QString &markedFontName)
     220{
     221    return markedFontName.left(markedFontName.length()
     222                               - QSymbianFontDatabaseExtrasImplementation::appFontMarker().length());
     223}
     224
    111225QSymbianFontDatabaseExtrasImplementation::QSymbianFontDatabaseExtrasImplementation()
    112226{
    113     QStringList filters;
    114     filters.append(QLatin1String("*.ttf"));
    115     filters.append(QLatin1String("*.ccc"));
    116     filters.append(QLatin1String("*.ltt"));
    117     const QFileInfoList fontFiles = alternativeFilePaths(QLatin1String("resource\\Fonts"), filters);
    118 
    119     const TInt heapMinLength = 0x1000;
    120     const TInt heapMaxLength = qMax(0x20000 * fontFiles.count(), heapMinLength);
    121     m_heap = User::ChunkHeap(NULL, heapMinLength, heapMaxLength);
    122     QT_TRAP_THROWING(
    123         m_store = CFontStore::NewL(m_heap);
    124         m_rasterizer = COpenFontRasterizer::NewL(TUid::Uid(0x101F7F5E));
    125         CleanupStack::PushL(m_rasterizer);
    126         m_store->InstallRasterizerL(m_rasterizer);
    127         CleanupStack::Pop(m_rasterizer););
    128 
    129     foreach (const QFileInfo &fontFileInfo, fontFiles) {
    130         const QString fontFile = QDir::toNativeSeparators(fontFileInfo.absoluteFilePath());
    131         TPtrC fontFilePtr(qt_QString2TPtrC(fontFile));
    132         QT_TRAP_THROWING(m_store->AddFileL(fontFilePtr));
     227    if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) {
     228        QStringList filters;
     229        filters.append(QLatin1String("*.ttf"));
     230        filters.append(QLatin1String("*.ccc"));
     231        filters.append(QLatin1String("*.ltt"));
     232        const QFileInfoList fontFiles = alternativeFilePaths(QLatin1String("resource\\Fonts"), filters);
     233
     234        const TInt heapMinLength = 0x1000;
     235        const TInt heapMaxLength = qMax(0x20000 * fontFiles.count(), heapMinLength);
     236        m_heap = User::ChunkHeap(NULL, heapMinLength, heapMaxLength);
     237        QT_TRAP_THROWING(
     238            m_store = CFontStore::NewL(m_heap);
     239            m_rasterizer = COpenFontRasterizer::NewL(TUid::Uid(0x101F7F5E));
     240            CleanupStack::PushL(m_rasterizer);
     241            m_store->InstallRasterizerL(m_rasterizer);
     242            CleanupStack::Pop(m_rasterizer););
     243
     244        foreach (const QFileInfo &fontFileInfo, fontFiles)
     245            addFontFileToFontStore(fontFileInfo);
     246    }
     247}
     248
     249void QSymbianFontDatabaseExtrasImplementation::clear()
     250{
     251    QFontDatabasePrivate *db = privateDb();
     252    if (!db)
     253        return;
     254    const QSymbianFontDatabaseExtrasImplementation *dbExtras =
     255            static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
     256    if (!dbExtras)
     257        return; // initializeDb() has never been called
     258    if (QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) {
     259        qDeleteAll(dbExtras->m_extrasHash);
     260    } else {
     261        typedef QList<const QSymbianTypeFaceExtras *>::iterator iterator;
     262        for (iterator p = dbExtras->m_extras.begin(); p != dbExtras->m_extras.end(); ++p) {
     263            dbExtras->m_store->ReleaseFont((*p)->fontOwner());
     264            delete *p;
     265        }
     266        dbExtras->m_extras.clear();
     267    }
     268    dbExtras->m_extrasHash.clear();
     269}
     270
     271void qt_cleanup_symbianFontDatabase()
     272{
     273    QFontDatabasePrivate *db = privateDb();
     274    if (!db)
     275        return;
     276
     277    QSymbianFontDatabaseExtrasImplementation::clear();
     278
     279    if (!db->applicationFonts.isEmpty()) {
     280        QFontDatabase::removeAllApplicationFonts();
     281        // We remove the left over temporary font files of Qt application.
     282        // Active fonts are undeletable since the font server holds a handle
     283        // on them, so we do not need to worry to delete other running
     284        // applications' fonts.
     285        const QDir dir(QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder());
     286        const QStringList filter(
     287                QSymbianFontDatabaseExtrasImplementation::appFontMarkerPrefix + QLatin1String("*.ttf"));
     288        foreach (const QFileInfo &ttfFile, dir.entryInfoList(filter))
     289            QFile(ttfFile.absoluteFilePath()).remove();
     290        db->applicationFonts.clear();
    133291    }
    134292}
     
    136294QSymbianFontDatabaseExtrasImplementation::~QSymbianFontDatabaseExtrasImplementation()
    137295{
    138     typedef QList<const QSymbianTypeFaceExtras *>::iterator iterator;
    139     for (iterator p = m_extras.begin(); p != m_extras.end(); ++p) {
    140         m_store->ReleaseFont((*p)->fontOwner());
    141         delete *p;
    142     }
    143 
    144     delete m_store;
    145     m_heap->Close();
     296    qt_cleanup_symbianFontDatabase();
     297    if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) {
     298        delete m_store;
     299        m_heap->Close();
     300    }
    146301}
    147302
     
    163318#endif // FNTSTORE_H_INLINES_SUPPORT_FMM
    164319
    165 const QSymbianTypeFaceExtras *QSymbianFontDatabaseExtrasImplementation::extras(const QString &typeface,
     320const QSymbianTypeFaceExtras *QSymbianFontDatabaseExtrasImplementation::extras(const QString &aTypeface,
    166321                                                                               bool bold, bool italic) const
    167322{
     323    const QString typeface = qt_symbian_fontNameWithAppFontMarker(aTypeface);
    168324    const QString searchKey = typeface + QString::number(int(bold)) + QString::number(int(italic));
    169325    if (!m_extrasHash.contains(searchKey)) {
    170         CFont* font = NULL;
    171326        TFontSpec searchSpec(qt_QString2TPtrC(typeface), 1);
    172327        if (bold)
     
    174329        if (italic)
    175330            searchSpec.iFontStyle.SetPosture(EPostureItalic);
    176         const TInt err = m_store->GetNearestFontToDesignHeightInPixels(font, searchSpec);
    177         Q_ASSERT(err == KErrNone && font);
    178         const CBitmapFont *bitmapFont = static_cast<CBitmapFont*>(font);
    179         COpenFont *openFont =
     331
     332        CFont* font = NULL;
     333        if (QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) {
     334            const TInt err = S60->screenDevice()->GetNearestFontToDesignHeightInPixels(font, searchSpec);
     335            Q_ASSERT(err == KErrNone && font);
     336            QScopedPointer<CFont, CFontFromScreenDeviceReleaser> sFont(font);
     337            QSymbianTypeFaceExtras *extras = new QSymbianTypeFaceExtras(font);
     338            sFont.take();
     339            m_extrasHash.insert(searchKey, extras);
     340        } else {
     341            const TInt err = m_store->GetNearestFontToDesignHeightInPixels(font, searchSpec);
     342            Q_ASSERT(err == KErrNone && font);
     343            const CBitmapFont *bitmapFont = static_cast<CBitmapFont*>(font);
     344            COpenFont *openFont =
    180345#ifdef FNTSTORE_H_INLINES_SUPPORT_FMM
    181             bitmapFont->openFont();
    182 #else
    183             OpenFontFromBitmapFont(bitmapFont);
     346                bitmapFont->OpenFont();
     347#else // FNTSTORE_H_INLINES_SUPPORT_FMM
     348                OpenFontFromBitmapFont(bitmapFont);
    184349#endif // FNTSTORE_H_INLINES_SUPPORT_FMM
    185         const TOpenFontFaceAttrib* const attrib = openFont->FaceAttrib();
    186         const QString foundKey =
    187                 QString((const QChar*)attrib->FullName().Ptr(), attrib->FullName().Length());
    188         if (!m_extrasHash.contains(foundKey)) {
    189             QSymbianTypeFaceExtras *extras = new QSymbianTypeFaceExtras(font, openFont);
    190             m_extras.append(extras);
    191             m_extrasHash.insert(searchKey, extras);
    192             m_extrasHash.insert(foundKey, extras);
    193         } else {
    194             m_store->ReleaseFont(font);
    195             m_extrasHash.insert(searchKey, m_extrasHash.value(foundKey));
     350            const TOpenFontFaceAttrib* const attrib = openFont->FaceAttrib();
     351            const QString foundKey =
     352                    QString((const QChar*)attrib->FullName().Ptr(), attrib->FullName().Length());
     353            if (!m_extrasHash.contains(foundKey)) {
     354                QScopedPointer<CFont, CFontFromFontStoreReleaser> sFont(font);
     355                QSymbianTypeFaceExtras *extras = new QSymbianTypeFaceExtras(font, openFont);
     356                sFont.take();
     357                m_extras.append(extras);
     358                m_extrasHash.insert(searchKey, extras);
     359                m_extrasHash.insert(foundKey, extras);
     360            } else {
     361                m_store->ReleaseFont(font);
     362                m_extrasHash.insert(searchKey, m_extrasHash.value(foundKey));
     363            }
    196364        }
    197365    }
    198366    return m_extrasHash.value(searchKey);
    199367}
    200 #else
     368
     369void QSymbianFontDatabaseExtrasImplementation::removeAppFontData(
     370    QFontDatabasePrivate::ApplicationFont *fnt)
     371{
     372    clear();
     373    if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable()
     374            && fnt->fontStoreFontFileUid.iUid != 0)
     375        m_store->RemoveFile(fnt->fontStoreFontFileUid);
     376    if (!fnt->families.isEmpty())
     377        m_applicationFontFamilies.remove(fnt->families.first());
     378    if (fnt->screenDeviceFontFileId != 0)
     379        S60->screenDevice()->RemoveFile(fnt->screenDeviceFontFileId);
     380    QFile::remove(fnt->temporaryFileName);
     381    *fnt = QFontDatabasePrivate::ApplicationFont();
     382}
     383
     384bool QSymbianFontDatabaseExtrasImplementation::appFontLimitReached()
     385{
     386    QFontDatabasePrivate *db = privateDb();
     387    if (!db)
     388        return false;
     389    const int maxAppFonts = 5;
     390    int registeredAppFonts = 0;
     391    foreach (const QFontDatabasePrivate::ApplicationFont &appFont, db->applicationFonts)
     392        if (!appFont.families.isEmpty() && ++registeredAppFonts == maxAppFonts)
     393            return true;
     394    return false;
     395}
     396
     397TUid QSymbianFontDatabaseExtrasImplementation::addFontFileToFontStore(const QFileInfo &fontFileInfo)
     398{
     399    Q_ASSERT(!QSymbianTypeFaceExtras::symbianFontTableApiAvailable());
     400    const QString fontFile = QDir::toNativeSeparators(fontFileInfo.absoluteFilePath());
     401    const TPtrC fontFilePtr(qt_QString2TPtrC(fontFile));
     402    TUid fontUid = {0};
     403    TRAP_IGNORE(fontUid = m_store->AddFileL(fontFilePtr));
     404    return fontUid;
     405}
     406
     407#else // QT_NO_FREETYPE
    201408class QFontEngineFTS60 : public QFontEngineFT
    202409{
     
    210417    default_hint_style = HintFull;
    211418}
    212 #endif // defined(QT_NO_FREETYPE)
     419#endif // QT_NO_FREETYPE
    213420
    214421/*
     
    219426qreal QFontEngineS60::pixelsToPoints(qreal pixels, Qt::Orientation orientation)
    220427{
     428    CWsScreenDevice* device = S60->screenDevice();
    221429    return (orientation == Qt::Horizontal?
    222         S60->screenDevice()->HorizontalPixelsToTwips(pixels)
    223         :S60->screenDevice()->VerticalPixelsToTwips(pixels)) / KTwipsPerPoint;
     430        device->HorizontalPixelsToTwips(pixels)
     431        :device->VerticalPixelsToTwips(pixels)) / KTwipsPerPoint;
    224432}
    225433
    226434qreal QFontEngineS60::pointsToPixels(qreal points, Qt::Orientation orientation)
    227435{
     436    CWsScreenDevice* device = S60->screenDevice();
    228437    const int twips = points * KTwipsPerPoint;
    229438    return orientation == Qt::Horizontal?
    230         S60->screenDevice()->HorizontalTwipsToPixels(twips)
    231         :S60->screenDevice()->VerticalTwipsToPixels(twips);
     439        device->HorizontalTwipsToPixels(twips)
     440        :device->VerticalTwipsToPixels(twips);
    232441}
    233442
     
    256465}
    257466
     467static bool registerScreenDeviceFont(int screenDeviceFontIndex,
     468                                     const QSymbianFontDatabaseExtrasImplementation *dbExtras)
     469{
     470    TTypefaceSupport typefaceSupport;
     471        S60->screenDevice()->TypefaceSupport(typefaceSupport, screenDeviceFontIndex);
     472
     473    QString familyName((const QChar*)typefaceSupport.iTypeface.iName.Ptr(), typefaceSupport.iTypeface.iName.Length());
     474    if (qt_symbian_fontNameHasAppFontMarker(familyName)) {
     475        const QString &marker = QSymbianFontDatabaseExtrasImplementation::appFontMarker();
     476        if (familyName.endsWith(marker)) {
     477            familyName = qt_symbian_appFontNameWithoutMarker(familyName);
     478            dbExtras->m_applicationFontFamilies.insert(familyName);
     479        } else {
     480            return false; // This was somebody else's application font. Skip it.
     481        }
     482    }
     483
     484    CFont *font; // We have to get a font instance in order to know all the details
     485    TFontSpec fontSpec(typefaceSupport.iTypeface.iName, 11);
     486    if (S60->screenDevice()->GetNearestFontInPixels(font, fontSpec) != KErrNone)
     487        return false;
     488    QScopedPointer<CFont, QSymbianFontDatabaseExtrasImplementation::CFontFromScreenDeviceReleaser> sFont(font);
     489    if (font->TypeUid() != KCFbsFontUid)
     490        return false;
     491    TOpenFontFaceAttrib faceAttrib;
     492    const CFbsFont *cfbsFont = static_cast<const CFbsFont *>(font);
     493    cfbsFont->GetFaceAttrib(faceAttrib);
     494
     495    QtFontStyle::Key styleKey;
     496    styleKey.style = faceAttrib.IsItalic()?QFont::StyleItalic:QFont::StyleNormal;
     497    styleKey.weight = faceAttrib.IsBold()?QFont::Bold:QFont::Normal;
     498
     499    QtFontFamily *family = privateDb()->family(familyName, true);
     500    family->fixedPitch = faceAttrib.IsMonoWidth();
     501    QtFontFoundry *foundry = family->foundry(QString(), true);
     502    QtFontStyle *style = foundry->style(styleKey, true);
     503    style->smoothScalable = typefaceSupport.iIsScalable;
     504    style->pixelSize(0, true);
     505
     506    const QSymbianTypeFaceExtras *typeFaceExtras =
     507            dbExtras->extras(familyName, faceAttrib.IsBold(), faceAttrib.IsItalic());
     508    const QByteArray os2Table = typeFaceExtras->getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
     509    const unsigned char* data = reinterpret_cast<const unsigned char*>(os2Table.constData());
     510    const unsigned char* ulUnicodeRange = data + 42;
     511    quint32 unicodeRange[4] = {
     512        qFromBigEndian<quint32>(ulUnicodeRange),
     513        qFromBigEndian<quint32>(ulUnicodeRange + 4),
     514        qFromBigEndian<quint32>(ulUnicodeRange + 8),
     515        qFromBigEndian<quint32>(ulUnicodeRange + 12)
     516    };
     517    const unsigned char* ulCodePageRange = data + 78;
     518    quint32 codePageRange[2] = {
     519        qFromBigEndian<quint32>(ulCodePageRange),
     520        qFromBigEndian<quint32>(ulCodePageRange + 4)
     521    };
     522    const QList<QFontDatabase::WritingSystem> writingSystems =
     523        determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
     524    foreach (const QFontDatabase::WritingSystem system, writingSystems)
     525        family->writingSystems[system] = QtFontFamily::Supported;
     526    return true;
     527}
     528
    258529static void initializeDb()
    259530{
     
    262533        return;
    263534
    264 #if defined(QT_NO_FREETYPE)
     535#ifdef QT_NO_FREETYPE
    265536    if (!db->symbianExtras)
    266537        db->symbianExtras = new QSymbianFontDatabaseExtrasImplementation;
    267538
    268539    QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
    269    
    270     const int numTypeFaces = QS60Data::screenDevice()->NumTypefaces();
     540
     541    const int numTypeFaces = S60->screenDevice()->NumTypefaces();
    271542    const QSymbianFontDatabaseExtrasImplementation *dbExtras =
    272543            static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
    273     bool fontAdded = false;
    274     for (int i = 0; i < numTypeFaces; i++) {
    275         TTypefaceSupport typefaceSupport;
    276         QS60Data::screenDevice()->TypefaceSupport(typefaceSupport, i);
    277         CFont *font; // We have to get a font instance in order to know all the details
    278         TFontSpec fontSpec(typefaceSupport.iTypeface.iName, 11);
    279         if (QS60Data::screenDevice()->GetNearestFontInPixels(font, fontSpec) != KErrNone)
    280             continue;
    281         if (font->TypeUid() == KCFbsFontUid) {
    282             TOpenFontFaceAttrib faceAttrib;
    283             const CFbsFont *cfbsFont = static_cast<const CFbsFont *>(font);
    284             cfbsFont->GetFaceAttrib(faceAttrib);
    285 
    286             QtFontStyle::Key styleKey;
    287             styleKey.style = faceAttrib.IsItalic()?QFont::StyleItalic:QFont::StyleNormal;
    288             styleKey.weight = faceAttrib.IsBold()?QFont::Bold:QFont::Normal;
    289 
    290             QString familyName((const QChar *)typefaceSupport.iTypeface.iName.Ptr(), typefaceSupport.iTypeface.iName.Length());
    291             QtFontFamily *family = db->family(familyName, true);
    292             family->fixedPitch = faceAttrib.IsMonoWidth();
    293             QtFontFoundry *foundry = family->foundry(QString(), true);
    294             QtFontStyle *style = foundry->style(styleKey, true);
    295             style->smoothScalable = typefaceSupport.iIsScalable;
    296             style->pixelSize(0, true);
    297 
    298             const QSymbianTypeFaceExtras *typeFaceExtras =
    299                     dbExtras->extras(familyName, faceAttrib.IsBold(), faceAttrib.IsItalic());
    300             const QByteArray os2Table = typeFaceExtras->getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
    301             const unsigned char* data = reinterpret_cast<const unsigned char*>(os2Table.constData());
    302             const unsigned char* ulUnicodeRange = data + 42;
    303             quint32 unicodeRange[4] = {
    304                 qFromBigEndian<quint32>(ulUnicodeRange),
    305                 qFromBigEndian<quint32>(ulUnicodeRange + 4),
    306                 qFromBigEndian<quint32>(ulUnicodeRange + 8),
    307                 qFromBigEndian<quint32>(ulUnicodeRange + 12)
    308             };
    309             const unsigned char* ulCodePageRange = data + 78;
    310             quint32 codePageRange[2] = {
    311                 qFromBigEndian<quint32>(ulCodePageRange),
    312                 qFromBigEndian<quint32>(ulCodePageRange + 4)
    313             };
    314             const QList<QFontDatabase::WritingSystem> writingSystems =
    315                 determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
    316             foreach (const QFontDatabase::WritingSystem system, writingSystems)
    317                 family->writingSystems[system] = QtFontFamily::Supported;
    318 
    319             fontAdded = true;
    320         }
    321         QS60Data::screenDevice()->ReleaseFont(font);
    322     }
    323 
    324     Q_ASSERT(fontAdded);
    325    
    326         lock.relock();
    327 
    328 #else // defined(QT_NO_FREETYPE)
     544    for (int i = 0; i < numTypeFaces; i++)
     545        registerScreenDeviceFont(i, dbExtras);
     546
     547    // We have to clear/release all CFonts, here, in case one of the fonts is
     548    // an application font of another running Qt app. Otherwise the other Qt app
     549    // cannot remove it's application font, anymore -> "Zombie Font".
     550    QSymbianFontDatabaseExtrasImplementation::clear();
     551
     552    lock.relock();
     553
     554#else // QT_NO_FREETYPE
    329555    QDir dir(QDesktopServices::storageLocation(QDesktopServices::FontsLocation));
    330556    dir.setNameFilters(QStringList() << QLatin1String("*.ttf")
     
    335561        db->addTTFile(file);
    336562    }
    337 #endif // defined(QT_NO_FREETYPE)
     563#endif // QT_NO_FREETYPE
    338564}
    339565
     
    345571}
    346572
     573struct OffsetTable {
     574    quint32 sfntVersion;
     575    quint16 numTables, searchRange, entrySelector, rangeShift;
     576};
     577
     578struct TableRecord {
     579    quint32 tag, checkSum, offset, length;
     580};
     581
     582struct NameTableHead {
     583    quint16 format, count, stringOffset;
     584};
     585
     586struct NameRecord {
     587    quint16 platformID, encodingID, languageID, nameID, length, offset;
     588};
     589
     590static quint32 ttfCalcChecksum(const char *data, quint32 bytesCount)
     591{
     592    quint32 result = 0;
     593    const quint32 *ptr = reinterpret_cast<const quint32*>(data);
     594    const quint32 *endPtr =
     595            ptr + (bytesCount + sizeof(quint32) - 1) / sizeof(quint32);
     596    while (ptr < endPtr) {
     597        const quint32 unit32Value = *ptr++;
     598        result += qFromBigEndian(unit32Value);
     599    }
     600    return result;
     601}
     602
     603static inline quint32 toDWordBoundary(quint32 value)
     604{
     605    return (value + 3) & ~3;
     606}
     607
     608static inline quint32 dWordPadding(quint32 value)
     609{
     610    return (4 - (value & 3)) & 3;
     611}
     612
     613static inline bool ttfMarkNameTable(QByteArray &table, const QString &marker)
     614{
     615    const quint32 tableLength = static_cast<quint32>(table.size());
     616
     617    if (tableLength > 50000 // hard limit
     618            || tableLength < sizeof(NameTableHead)) // corrupt name table
     619        return false;
     620
     621    const NameTableHead *head = reinterpret_cast<const NameTableHead*>(table.constData());
     622    const quint16 count = qFromBigEndian(head->count);
     623    const quint16 stringOffset = qFromBigEndian(head->stringOffset);
     624    if (count > 200 // hard limit
     625            || stringOffset >= tableLength // corrupt name table
     626            || sizeof(NameTableHead) + count * sizeof(NameRecord) >= tableLength) // corrupt name table
     627        return false;
     628
     629    QTextEncoder encoder(QTextCodec::codecForName("UTF-16BE"), QTextCodec::IgnoreHeader);
     630    const QByteArray markerUtf16BE = encoder.fromUnicode(marker);
     631    const QByteArray markerAscii = marker.toAscii();
     632
     633    QByteArray markedTable;
     634    markedTable.reserve(tableLength + marker.length() * 20); // Original size plus some extra
     635    markedTable.append(table, stringOffset);
     636    QByteArray markedStrings;
     637    quint32 stringDataCount = stringOffset;
     638    for (quint16 i = 0; i < count; ++i) {
     639        const quint32 nameRecordOffset = sizeof(NameTableHead) + sizeof(NameRecord) * i;
     640        NameRecord *nameRecord =
     641                reinterpret_cast<NameRecord*>(markedTable.data() + nameRecordOffset);
     642        const quint16 nameID = qFromBigEndian(nameRecord->nameID);
     643        const quint16 platformID = qFromBigEndian(nameRecord->platformID);
     644        const quint16 encodingID = qFromBigEndian(nameRecord->encodingID);
     645        const quint16 offset = qFromBigEndian(nameRecord->offset);
     646        const quint16 length = qFromBigEndian(nameRecord->length);
     647        stringDataCount += length;
     648        if (stringDataCount > 80000 // hard limit. String data may be > name table size. Multiple records can reference the same string.
     649                || static_cast<quint32>(stringOffset + offset + length) > tableLength) // String outside bounds
     650            return false;
     651        const bool needsMarker =
     652                nameID == 1 || nameID == 3 || nameID == 4 || nameID == 16 || nameID == 21;
     653        const bool isUnicode =
     654                platformID == 0 || platformID == 3 && encodingID == 1;
     655        const QByteArray originalString =
     656                QByteArray::fromRawData(table.constData() + stringOffset + offset, length);
     657        QByteArray markedString;
     658        if (needsMarker) {
     659            const int maxBytesLength = (KMaxTypefaceNameLength - marker.length()) * (isUnicode ? 2 : 1);
     660            markedString = originalString.left(maxBytesLength) + (isUnicode ? markerUtf16BE : markerAscii);
     661        } else {
     662            markedString = originalString;
     663        }
     664        nameRecord->offset = qToBigEndian(static_cast<quint16>(markedStrings.length()));
     665        nameRecord->length = qToBigEndian(static_cast<quint16>(markedString.length()));
     666        markedStrings.append(markedString);
     667    }
     668    markedTable.append(markedStrings);
     669    table = markedTable;
     670    return true;
     671}
     672
     673const quint32 ttfMaxFileSize = 3500000;
     674
     675static inline bool ttfMarkAppFont(QByteArray &ttf, const QString &marker)
     676{
     677    const quint32 ttfChecksumNumber = 0xb1b0afba;
     678    const quint32 alignment = 4;
     679    const quint32 ttfLength = static_cast<quint32>(ttf.size());
     680    if (ttfLength > ttfMaxFileSize // hard limit
     681            || ttfLength % alignment != 0 // ttf sizes are always factors of 4
     682            || ttfLength <= sizeof(OffsetTable) // ttf too short
     683            || ttfCalcChecksum(ttf.constData(), ttf.size()) != ttfChecksumNumber) // ttf checksum is invalid
     684        return false;
     685
     686    const OffsetTable *offsetTable = reinterpret_cast<const OffsetTable*>(ttf.constData());
     687    const quint16 numTables = qFromBigEndian(offsetTable->numTables);
     688    const quint32 recordsLength =
     689            toDWordBoundary(sizeof(OffsetTable) + numTables * sizeof(TableRecord));
     690    if (numTables > 30 // hard limit
     691            || recordsLength + numTables * alignment > ttfLength) // Corrupt ttf. Tables would not fit, even if empty.
     692        return false;
     693
     694    QByteArray markedTtf;
     695    markedTtf.reserve(ttfLength + marker.length() * 20); // Original size plus some extra
     696    markedTtf.append(ttf.constData(), recordsLength);
     697
     698    const quint32 ttfCheckSumAdjustmentOffset = 8; // Offset from the start of 'head'
     699    int indexOfHeadTable = -1;
     700    quint32 ttfDataSize = recordsLength;
     701    typedef QPair<quint32, quint32> Range;
     702    QList<Range> memoryRanges;
     703    memoryRanges.reserve(numTables);
     704    for (int i = 0; i < numTables; ++i) {
     705        TableRecord *tableRecord =
     706                reinterpret_cast<TableRecord*>(markedTtf.data() + sizeof(OffsetTable) + i * sizeof(TableRecord));
     707        const quint32 offset = qFromBigEndian(tableRecord->offset);
     708        const quint32 length = qFromBigEndian(tableRecord->length);
     709        const quint32 lengthAligned = toDWordBoundary(length);
     710        ttfDataSize += lengthAligned;
     711        if (offset < recordsLength // must not intersect ttf header/records
     712                || offset % alignment != 0 // must be aligned
     713                || offset > ttfLength - alignment // table out of bounds
     714                || offset + lengthAligned > ttfLength // table out of bounds
     715                || ttfDataSize > ttfLength) // tables would not fit into the ttf
     716            return false;
     717
     718        foreach (const Range &range, memoryRanges)
     719            if (offset < range.first + range.second && offset + lengthAligned > range.first)
     720                return false; // Overlaps with another table
     721        memoryRanges.append(Range(offset, lengthAligned));
     722
     723        quint32 checkSum = qFromBigEndian(tableRecord->checkSum);
     724        if (tableRecord->tag == qToBigEndian(static_cast<quint32>('head'))) {
     725            if (length < ttfCheckSumAdjustmentOffset + sizeof(quint32))
     726                return false; // Invalid 'head' table
     727            const quint32 *checkSumAdjustmentTag =
     728                    reinterpret_cast<const quint32*>(ttf.constData() + offset + ttfCheckSumAdjustmentOffset);
     729            const quint32 checkSumAdjustment = qFromBigEndian(*checkSumAdjustmentTag);
     730            checkSum += checkSumAdjustment;
     731            indexOfHeadTable = i; // For the ttf checksum re-calculation, later
     732        }
     733        if (checkSum != ttfCalcChecksum(ttf.constData() + offset, length))
     734            return false; // Table checksum is invalid
     735
     736        bool updateTableChecksum = false;
     737        QByteArray table;
     738        if (tableRecord->tag == qToBigEndian(static_cast<quint32>('name'))) {
     739            table = QByteArray(ttf.constData() + offset, length);
     740            if (!ttfMarkNameTable(table, marker))
     741                return false; // Name table was not markable.
     742            updateTableChecksum = true;
     743        } else {
     744            table = QByteArray::fromRawData(ttf.constData() + offset, length);
     745        }
     746
     747        tableRecord->offset = qToBigEndian(markedTtf.size());
     748        tableRecord->length = qToBigEndian(table.size());
     749        markedTtf.append(table);
     750        markedTtf.append(QByteArray(dWordPadding(table.size()), 0)); // 0-padding
     751        if (updateTableChecksum) {
     752            TableRecord *tableRecord = // Need to recalculate, since markedTtf changed
     753                    reinterpret_cast<TableRecord*>(markedTtf.data() + sizeof(OffsetTable) + i * sizeof(TableRecord));
     754            const quint32 offset = qFromBigEndian(tableRecord->offset);
     755            const quint32 length = qFromBigEndian(tableRecord->length);
     756            tableRecord->checkSum = qToBigEndian(ttfCalcChecksum(markedTtf.constData() + offset, length));
     757        }
     758    }
     759    if (indexOfHeadTable == -1 // 'head' table is mandatory
     760            || ttfDataSize != ttfLength) // We do not allow ttf data "holes". Neither does Symbian.
     761        return false;
     762    TableRecord *headRecord =
     763            reinterpret_cast<TableRecord*>(markedTtf.data() + sizeof(OffsetTable) + indexOfHeadTable * sizeof(TableRecord));
     764    quint32 *checkSumAdjustmentTag =
     765            reinterpret_cast<quint32*>(markedTtf.data() + qFromBigEndian(headRecord->offset) + ttfCheckSumAdjustmentOffset);
     766    *checkSumAdjustmentTag = 0;
     767    const quint32 ttfChecksum = ttfCalcChecksum(markedTtf.constData(), markedTtf.count());
     768    *checkSumAdjustmentTag = qToBigEndian(ttfChecksumNumber - ttfChecksum);
     769    ttf = markedTtf;
     770    return true;
     771}
     772
     773static inline bool ttfCanSymbianLoadFont(const QByteArray &data, const QString &fileName)
     774{
     775    bool result = false;
     776    QString ttfFileName;
     777    QFile tempFileGuard;
     778    QFileInfo info(fileName);
     779    if (!data.isEmpty()) {
     780        QTemporaryFile tempfile(QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder()
     781                                + QSymbianFontDatabaseExtrasImplementation::appFontMarker()
     782                                + QLatin1String("XXXXXX.ttf"));
     783        if (!tempfile.open() || tempfile.write(data) == -1)
     784            return false;
     785        ttfFileName = QDir::toNativeSeparators(QFileInfo(tempfile).canonicalFilePath());
     786        tempfile.setAutoRemove(false);
     787        tempfile.close();
     788        tempFileGuard.setFileName(ttfFileName);
     789        if (!tempFileGuard.open(QIODevice::ReadOnly))
     790            return false;
     791    } else if (info.isFile()) {
     792        ttfFileName = QDir::toNativeSeparators(info.canonicalFilePath());
     793    } else {
     794        return false;
     795    }
     796
     797    CFontStore *store = 0;
     798    RHeap* heap = User::ChunkHeap(NULL, 0x1000, 0x20000);
     799    if (heap) {
     800        QT_TRAP_THROWING(
     801            CleanupClosePushL(*heap);
     802            store = CFontStore::NewL(heap);
     803            CleanupStack::PushL(store);
     804            COpenFontRasterizer *rasterizer = COpenFontRasterizer::NewL(TUid::Uid(0x101F7F5E));
     805            CleanupStack::PushL(rasterizer);
     806            store->InstallRasterizerL(rasterizer);
     807            CleanupStack::Pop(rasterizer);
     808            TUid fontUid = {-1};
     809            TRAP_IGNORE(fontUid = store->AddFileL(qt_QString2TPtrC(ttfFileName)));
     810            if (fontUid.iUid != -1)
     811                result = true;
     812            CleanupStack::PopAndDestroy(2, heap); // heap, store
     813        );
     814    }
     815
     816    if (tempFileGuard.isOpen())
     817        tempFileGuard.remove();
     818
     819    return result;
     820}
     821
    347822static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
    348823{
    349     Q_UNUSED(fnt);
     824    if (QSymbianFontDatabaseExtrasImplementation::appFontLimitReached()
     825            || fnt->data.size() > ttfMaxFileSize // hard limit
     826            || fnt->data.isEmpty() && (!fnt->fileName.endsWith(QLatin1String(".ttf"), Qt::CaseInsensitive) // Only buffer or .ttf
     827                                       || QFileInfo(fnt->fileName).size() > ttfMaxFileSize)) // hard limit
     828        return;
     829
     830//    Using ttfCanSymbianLoadFont() causes crashes on app destruction (Symbian^3|PR1 and lower).
     831//    Therefore, not using it for now, but eventually in a later version.
     832//    if (!ttfCanSymbianLoadFont(fnt->data, fnt->fileName))
     833//        return;
     834
     835    QFontDatabasePrivate *db = privateDb();
     836    if (!db)
     837        return;
     838
     839    if (!db->count)
     840        initializeDb();
     841
     842    QSymbianFontDatabaseExtrasImplementation *dbExtras =
     843            static_cast<QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
     844    if (!dbExtras)
     845        return;
     846
     847    const QString &marker = QSymbianFontDatabaseExtrasImplementation::appFontMarker();
     848
     849    // The QTemporaryFile object being used in the following section must be
     850    // destructed before letting Symbian load the TTF file. Symbian would not
     851    // load it otherwise, because QTemporaryFile will still keep some handle
     852    // on it. The scope is used to reduce the life time of the QTemporaryFile.
     853    // In order to prevent other processes from modifying the file between the
     854    // moment where the QTemporaryFile is destructed and the file is loaded by
     855    // Symbian, we have a QFile "tempFileGuard" outside the scope which opens
     856    // the file in ReadOnly mode while the QTemporaryFile is still alive.
     857    QFile tempFileGuard;
     858    {
     859        QTemporaryFile tempfile(QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder()
     860                                + marker + QLatin1String("XXXXXX.ttf"));
     861        if (!tempfile.open())
     862            return;
     863        const QString tempFileName = QFileInfo(tempfile).canonicalFilePath();
     864        if (fnt->data.isEmpty()) {
     865            QFile sourceFile(fnt->fileName);
     866            if (!sourceFile.open(QIODevice::ReadOnly))
     867                return;
     868            fnt->data = sourceFile.readAll();
     869        }
     870        if (!ttfMarkAppFont(fnt->data, marker) || tempfile.write(fnt->data) == -1)
     871            return;
     872        tempfile.setAutoRemove(false);
     873        tempfile.close(); // Tempfile still keeps a file handle, forbidding write access
     874        fnt->data.clear(); // The TTF data was marked and saved. Not needed in memory, anymore.
     875        tempFileGuard.setFileName(tempFileName);
     876        if (!tempFileGuard.open(QIODevice::ReadOnly))
     877            return;
     878        fnt->temporaryFileName = tempFileName;
     879    }
     880
     881    const QString fullFileName = QDir::toNativeSeparators(fnt->temporaryFileName);
     882    QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
     883    const QStringList fontsOnServerBefore = qt_symbian_fontFamiliesOnFontServer();
     884    const TInt err =
     885            S60->screenDevice()->AddFile(qt_QString2TPtrC(fullFileName), fnt->screenDeviceFontFileId);
     886    tempFileGuard.close(); // Did its job
     887    const QStringList fontsOnServerAfter = qt_symbian_fontFamiliesOnFontServer();
     888    if (err == KErrNone && fontsOnServerBefore.count() < fontsOnServerAfter.count()) { // Added to screen device?
     889        int fontOnServerIndex = fontsOnServerAfter.count() - 1;
     890        for (int i = 0; i < fontsOnServerBefore.count(); i++) {
     891            if (fontsOnServerBefore.at(i) != fontsOnServerAfter.at(i)) {
     892                fontOnServerIndex = i;
     893                break;
     894            }
     895        }
     896
     897        // Must remove all font engines with their CFonts, first.
     898        QFontCache::instance()->clear();
     899        db->free();
     900        QSymbianFontDatabaseExtrasImplementation::clear();
     901
     902        if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable())
     903            fnt->fontStoreFontFileUid = dbExtras->addFontFileToFontStore(QFileInfo(fullFileName));
     904
     905        const QString &appFontName = fontsOnServerAfter.at(fontOnServerIndex);
     906        fnt->families.append(qt_symbian_appFontNameWithoutMarker(appFontName));
     907        if (!qt_symbian_fontNameHasAppFontMarker(appFontName)
     908                || !registerScreenDeviceFont(fontOnServerIndex, dbExtras))
     909            dbExtras->removeAppFontData(fnt);
     910    } else {
     911        if (fnt->screenDeviceFontFileId > 0)
     912            S60->screenDevice()->RemoveFile(fnt->screenDeviceFontFileId); // May still have the file open!
     913        QFile::remove(fnt->temporaryFileName);
     914        *fnt = QFontDatabasePrivate::ApplicationFont();
     915    }
     916    lock.relock();
    350917}
    351918
    352919bool QFontDatabase::removeApplicationFont(int handle)
    353920{
    354     Q_UNUSED(handle);
    355     return false;
     921    QMutexLocker locker(fontDatabaseMutex());
     922
     923    QFontDatabasePrivate *db = privateDb();
     924    if (!db || handle < 0 || handle >= db->applicationFonts.count())
     925        return false;
     926    QSymbianFontDatabaseExtrasImplementation *dbExtras =
     927            static_cast<QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
     928    if (!dbExtras)
     929        return false;
     930
     931    QFontDatabasePrivate::ApplicationFont *fnt = &db->applicationFonts[handle];
     932    if (fnt->families.isEmpty())
     933        return true; // Nothing to remove. Return peacefully.
     934
     935    // Must remove all font engines with their CFonts, first
     936    QFontCache::instance()->clear();
     937    db->free();
     938    dbExtras->removeAppFontData(fnt);
     939
     940    db->invalidate(); // This will just emit 'fontDatabaseChanged()'
     941    return true;
    356942}
    357943
    358944bool QFontDatabase::removeAllApplicationFonts()
    359945{
    360     return false;
     946    QMutexLocker locker(fontDatabaseMutex());
     947
     948    const int applicationFontsCount = privateDb()->applicationFonts.count();
     949    for (int i = 0; i < applicationFontsCount; ++i)
     950        if (!removeApplicationFont(i))
     951            return false;
     952    return true;
    361953}
    362954
     
    377969}
    378970
    379 QFontEngine *QFontDatabase::findFont(int script, const QFontPrivate *, const QFontDef &req)
     971QFontEngine *QFontDatabase::findFont(int script, const QFontPrivate *d, const QFontDef &req)
    380972{
    381973    const QFontCache::Key key(cleanedFontDef(req), script);
     
    391983        QtFontDesc desc;
    392984        QList<int> blacklistedFamilies;
    393         match(script, req, req.family, QString(), -1, &desc, blacklistedFamilies);
     985        match(script, key.def, key.def.family, QString(), -1, &desc, blacklistedFamilies);
    394986        if (!desc.family) // falling back to application font
    395987            desc.family = db->family(QApplication::font().defaultFamily());
     
    4171009        QFontDef request = req;
    4181010        request.family = fontFamily;
    419 #if defined(QT_NO_FREETYPE)
     1011#ifdef QT_NO_FREETYPE
    4201012        const QSymbianFontDatabaseExtrasImplementation *dbExtras =
    4211013                static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras);
    4221014        const QSymbianTypeFaceExtras *typeFaceExtras =
    4231015                dbExtras->extras(fontFamily, request.weight > QFont::Normal, request.style != QFont::StyleNormal);
     1016
     1017        // We need a valid pixelSize, e.g. for lineThickness()
     1018        if (request.pixelSize < 0)
     1019            request.pixelSize = request.pointSize * d->dpi / 72;
     1020
    4241021        fe = new QFontEngineS60(request, typeFaceExtras);
    425 #else
     1022#else // QT_NO_FREETYPE
     1023        Q_UNUSED(d)
    4261024        QFontEngine::FaceId faceId;
    4271025        const QtFontFamily * const reqQtFontFamily = db->family(fontFamily);
     
    4341032        else
    4351033            delete fte;
    436 #endif
     1034#endif // QT_NO_FREETYPE
    4371035
    4381036        Q_ASSERT(fe);
  • trunk/src/gui/text/qfontdatabase_win.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4646#include "qfontengine_p.h"
    4747#include "qpaintdevice.h"
    48 #include "qlibrary.h"
     48#include <private/qsystemlibrary_p.h>
    4949#include "qabstractfileengine.h"
    5050#include "qendian.h"
     
    10501050    if(!fnt->data.isEmpty()) {
    10511051#ifndef Q_OS_WINCE
    1052         PtrAddFontMemResourceEx ptrAddFontMemResourceEx = (PtrAddFontMemResourceEx)QLibrary::resolve(QLatin1String("gdi32"),
     1052        PtrAddFontMemResourceEx ptrAddFontMemResourceEx = (PtrAddFontMemResourceEx)QSystemLibrary::resolve(QLatin1String("gdi32"),
    10531053                                                                                                     "AddFontMemResourceEx");
    10541054        if (!ptrAddFontMemResourceEx)
     
    11121112            return;
    11131113#else
    1114         // supported from 2000 on, so no need to deal with the *A variant
    1115         PtrAddFontResourceExW ptrAddFontResourceExW = (PtrAddFontResourceExW)QLibrary::resolve(QLatin1String("gdi32"),
     1114        PtrAddFontResourceExW ptrAddFontResourceExW = (PtrAddFontResourceExW)QSystemLibrary::resolve(QLatin1String("gdi32"),
    11161115                                                                                               "AddFontResourceExW");
    11171116        if (!ptrAddFontResourceExW
     
    11421141            return false;
    11431142#else
    1144         PtrRemoveFontMemResourceEx ptrRemoveFontMemResourceEx = (PtrRemoveFontMemResourceEx)QLibrary::resolve(QLatin1String("gdi32"),
     1143        PtrRemoveFontMemResourceEx ptrRemoveFontMemResourceEx = (PtrRemoveFontMemResourceEx)QSystemLibrary::resolve(QLatin1String("gdi32"),
    11451144                                                                                                              "RemoveFontMemResourceEx");
    11461145        if (!ptrRemoveFontMemResourceEx
     
    11531152            return false;
    11541153#else
    1155         PtrRemoveFontResourceExW ptrRemoveFontResourceExW = (PtrRemoveFontResourceExW)QLibrary::resolve(QLatin1String("gdi32"),
     1154        PtrRemoveFontResourceExW ptrRemoveFontResourceExW = (PtrRemoveFontResourceExW)QSystemLibrary::resolve(QLatin1String("gdi32"),
    11561155                                                                                                        "RemoveFontResourceExW");
    11571156        if (!ptrRemoveFontResourceExW
  • trunk/src/gui/text/qfontdatabase_x11.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4242#include <qplatformdefs.h>
    4343
    44 #include <qdatetime.h>
    4544#include <qdebug.h>
    4645#include <qpaintdevice.h>
     46#include <qelapsedtimer.h>
    4747
    4848#include <private/qt_x11_p.h>
     
    7878extern double qt_pointSize(double pixelSize, int dpi);
    7979extern double qt_pixelSize(double pointSize, int dpi);
     80
     81// from qapplication.cpp
     82extern bool qt_is_gui_used;
    8083
    8184static inline void capitalize (char *s)
     
    12191222
    12201223#ifdef QFONTDATABASE_DEBUG
    1221     QTime t;
     1224    QElapsedTimer t;
    12221225    t.start();
    12231226#endif
     
    13021305        return;
    13031306
    1304     QTime t;
     1307    QElapsedTimer t;
    13051308    t.start();
    13061309
     
    13151318
    13161319    loadFontConfig();
    1317     FD_DEBUG("QFontDatabase: loaded FontConfig: %d ms", t.elapsed());
     1320    FD_DEBUG("QFontDatabase: loaded FontConfig: %d ms", int(t.elapsed()));
    13181321#endif
    13191322
     
    18891892}
    18901893
     1894#if (defined(QT_ARCH_ARM) || defined(QT_ARCH_ARMV6)) && defined(Q_CC_GNU) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
     1895#define NEEDS_GCC_BUG_WORKAROUND
     1896#endif
     1897
     1898#ifdef NEEDS_GCC_BUG_WORKAROUND
     1899static inline void gccBugWorkaround(const QFontDef &req)
     1900{
     1901    char buffer[8];
     1902    snprintf(buffer, 8, "%f", req.pixelSize);
     1903}
     1904#endif
     1905
    18911906/*! \internal
    18921907  Loads a QFontEngine for the specified \a script that matches the
     
    19001915    QFontDef req = d->request;
    19011916    if (req.pixelSize <= 0)
    1902         req.pixelSize = floor(qt_pixelSize(req.pointSize, d->dpi) * 100 + 0.5) / 100;
     1917        req.pixelSize = qFloor(qt_pixelSize(req.pointSize, d->dpi) * 100.0 + 0.5) * 0.01;
    19031918    if (req.pixelSize < 1)
    19041919        req.pixelSize = 1;
     1920
     1921#ifdef NEEDS_GCC_BUG_WORKAROUND
     1922    // req.pixelSize ends up with a bogus value unless this workaround is called
     1923    gccBugWorkaround(req);
     1924#endif
     1925
    19051926    if (req.weight == 0)
    19061927        req.weight = QFont::Normal;
     
    19381959        } else if (X11->has_fontconfig) {
    19391960            fe = loadFc(d, script, req);
    1940 
    1941             if (fe != 0 && fe->fontDef.pixelSize != req.pixelSize) {
    1942                 delete fe;
    1943                 fe = loadXlfd(d->screen, script, req);
     1961            if (fe != 0 && fe->fontDef.pixelSize != req.pixelSize && mainThread && qt_is_gui_used) {
     1962                QFontEngine *xlfdFontEngine = loadXlfd(d->screen, script, req);
     1963                if (xlfdFontEngine->fontDef.family == fe->fontDef.family) {
     1964                    delete fe;
     1965                    fe = xlfdFontEngine;
     1966                } else {
     1967                    delete xlfdFontEngine;
     1968                }
    19441969            }
    19451970
    19461971
    19471972#endif
    1948         } else if (mainThread) {
     1973        } else if (mainThread && qt_is_gui_used) {
    19491974            fe = loadXlfd(d->screen, script, req);
    19501975        }
     
    19822007    FcFontSet *set = FcConfigGetFonts(config, FcSetApplication);
    19832008    if (!set) {
    1984         FcConfigAppFontAddFile(config, (const FcChar8 *)":/non-existant");
     2009        FcConfigAppFontAddFile(config, (const FcChar8 *)":/non-existent");
    19852010        set = FcConfigGetFonts(config, FcSetApplication); // try again
    19862011        if (!set)
  • trunk/src/gui/text/qfontengine.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4747#include "qpainterpath.h"
    4848#include "qvarlengtharray.h"
    49 #include <private/qpdf_p.h>
    5049#include <qmath.h>
    5150#include <qendian.h>
     
    597596    QImage i = alphaMapForGlyph(glyph);
    598597    if (t.type() > QTransform::TxTranslate)
    599         i = i.transformed(t);
     598        i = i.transformed(t).convertToFormat(QImage::Format_Indexed8);
    600599    Q_ASSERT(i.depth() <= 8); // To verify that transformed didn't change the format...
     600
    601601    return i;
    602602}
     
    607607    QImage rgbMask(alphaMask.width(), alphaMask.height(), QImage::Format_RGB32);
    608608
     609    QVector<QRgb> colorTable = alphaMask.colorTable();
    609610    for (int y=0; y<alphaMask.height(); ++y) {
    610611        uint *dst = (uint *) rgbMask.scanLine(y);
    611612        uchar *src = (uchar *) alphaMask.scanLine(y);
    612         for (int x=0; x<alphaMask.width(); ++x)
    613             dst[x] = qRgb(src[x], src[x], src[x]);
     613        for (int x=0; x<alphaMask.width(); ++x) {
     614            int val = qAlpha(colorTable.at(src[x]));
     615            dst[x] = qRgb(val, val, val);
     616        }
    614617    }
    615618
     
    628631        return QImage();
    629632    QFixedPoint pt;
    630     pt.x = 0;
     633    pt.x = -glyph_x;
    631634    pt.y = -glyph_y; // the baseline
    632635    QPainterPath path;
    633     QImage im(glyph_width + qAbs(glyph_x) + 4, glyph_height, QImage::Format_ARGB32_Premultiplied);
     636    QImage im(glyph_width + 4, glyph_height, QImage::Format_ARGB32_Premultiplied);
    634637    im.fill(Qt::transparent);
    635638    QPainter p(&im);
     
    664667{
    665668    Properties p;
    666 #ifndef QT_NO_PRINTER
    667     QByteArray psname = QPdf::stripSpecialCharacters(fontDef.family.toUtf8());
    668 #else
    669     QByteArray psname = fontDef.family.toUtf8();
    670 #endif
     669    QByteArray psname = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
    671670    psname += '-';
    672671    psname += QByteArray::number(fontDef.style);
     
    718717
    719718    // Limit the glyph caches to 4. This covers all 90 degree rotations and limits
    720     // memory use when there is continous or random rotation
     719    // memory use when there is continuous or random rotation
    721720    if (m_glyphCaches.size() == 4)
    722721        delete m_glyphCaches.takeLast().cache;
     
    871870    enum {
    872871        Invalid,
     872        AppleRoman,
    873873        Symbol,
    874         AppleRoman,
    875874        Unicode11,
    876875        Unicode,
     
    936935
    937936resolveTable:
    938     *isSymbolFont = (score == Symbol);
     937    *isSymbolFont = (symbolTable > -1);
    939938
    940939    unsigned int unicode_table = qFromBigEndian<quint32>(maps + 8*tableToUse + 4);
     
    10781077}
    10791078
     1079QByteArray QFontEngine::convertToPostscriptFontFamilyName(const QByteArray &family)
     1080{
     1081    QByteArray f = family;
     1082    f.replace(' ', "");
     1083    f.replace('(', "");
     1084    f.replace(')', "");
     1085    f.replace('<', "");
     1086    f.replace('>', "");
     1087    f.replace('[', "");
     1088    f.replace(']', "");
     1089    f.replace('{', "");
     1090    f.replace('}', "");
     1091    f.replace('/', "");
     1092    f.replace('%', "");
     1093    return f;
     1094}
     1095
    10801096Q_GLOBAL_STATIC_WITH_INITIALIZER(QVector<QRgb>, qt_grayPalette, {
    10811097    x->resize(256);
     
    10881104{
    10891105    return *qt_grayPalette();
     1106}
     1107
     1108QFixed QFontEngine::lastRightBearing(const QGlyphLayout &glyphs, bool round)
     1109{
     1110    if (glyphs.numGlyphs >= 1) {
     1111        glyph_t glyph = glyphs.glyphs[glyphs.numGlyphs - 1];
     1112        glyph_metrics_t gi = boundingBox(glyph);
     1113        if (gi.isValid())
     1114            return round ? QFixed(qRound(gi.xoff - gi.x - gi.width))
     1115                         : QFixed(gi.xoff - gi.x - gi.width);
     1116    }
     1117    return 0;
    10901118}
    10911119
  • trunk/src/gui/text/qfontengine_ft.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    5252#include "qthreadstorage.h"
    5353#include <qmath.h>
    54 #include <private/qpdf_p.h>
    5554#include <private/qharfbuzz_p.h>
    5655
     
    5958#include FT_FREETYPE_H
    6059#include FT_OUTLINE_H
     60#include FT_SYNTHESIS_H
    6161#include FT_TRUETYPE_TABLES_H
    6262#include FT_TYPE1_TABLES_H
     
    9292#define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
    9393#define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
     94#endif
     95
     96/* FreeType 2.1.10 starts to provide FT_GlyphSlot_Embolden */
     97#if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20110
     98#define Q_FT_GLYPHSLOT_EMBOLDEN(slot)   FT_GlyphSlot_Embolden(slot)
     99#else
     100#define Q_FT_GLYPHSLOT_EMBOLDEN(slot)
    94101#endif
    95102
     
    618625    kerning_pairs_loaded = false;
    619626    transform = false;
     627    embolden = false;
    620628    antialias = true;
    621629    freetype = 0;
    622     default_load_flags = 0;
     630    default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
    623631    default_hint_style = HintNone;
    624632    subpixelType = Subpixel_None;
     
    680688    FT_Face face = lockFace();
    681689
    682     //underline metrics
    683690    if (FT_IS_SCALABLE(face)) {
    684         line_thickness =  QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
    685         underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
    686691        bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
    687692        if (fake_oblique)
     
    691696        if (fake_oblique)
    692697            transform = true;
     698        // fake bold
     699        if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
     700            embolden = true;
     701        // underline metrics
     702        line_thickness =  QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
     703        underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
    693704    } else {
    694705        // copied from QFontEngineQPF
     
    747758QFontEngineFT::Glyph *QFontEngineFT::loadGlyphMetrics(QGlyphSet *set, uint glyph) const
    748759{
    749     Glyph *g = set->glyph_data.value(glyph);
     760    Glyph *g = set->getGlyph(glyph);
    750761    if (g)
    751762        return g;
     
    790801
    791802    FT_GlyphSlot slot = face->glyph;
     803    if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
    792804    int left  = slot->metrics.horiBearingX;
    793805    int right = slot->metrics.horiBearingX + slot->metrics.width;
     
    859871    }
    860872
    861     Glyph *g = set->glyph_data.value(glyph);
     873    Glyph *g = set->getGlyph(glyph);
    862874    if (g && g->format == format) {
    863875        if (uploadToServer && !g->uploadedToServer) {
    864             set->glyph_data[glyph] = 0;
     876            set->setGlyph(glyph, 0);
    865877            delete g;
    866878            g = 0;
     
    935947
    936948    FT_GlyphSlot slot = face->glyph;
     949    if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
    937950    FT_Library library = qt_getFreetype();
    938951
     
    11591172    }
    11601173
    1161     set->glyph_data[glyph] = g;
     1174    set->setGlyph(glyph, g);
    11621175
    11631176    return g;
     
    11831196    Properties p = freetype->properties();
    11841197    if (p.postscriptName.isEmpty()) {
    1185         p.postscriptName = fontDef.family.toUtf8();
    1186 #ifndef QT_NO_PRINTER
    1187         p.postscriptName = QPdf::stripSpecialCharacters(p.postscriptName);
    1188 #endif
     1198        p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
    11891199    }
    11901200
     
    12101220    if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
    12111221        s = SynthesizedItalic;
     1222    if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
     1223        s |= SynthesizedBold;
    12121224    if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
    12131225        s |= SynthesizedStretch;
     
    13691381    if (!gs) {
    13701382        // don't try to load huge fonts
    1371         bool draw_as_outline = fontDef.pixelSize * qSqrt(matrix.det()) >= 64;
     1383        bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= 64;
    13721384        if (draw_as_outline)
    13731385            return 0;
     
    13821394        gs = &transformedGlyphSets[0];
    13831395
    1384         qDeleteAll(gs->glyph_data);
    1385         gs->glyph_data.clear();
     1396        gs->clear();
    13861397
    13871398        gs->id = allocateServerGlyphSet();
     
    13991410
    14001411    for (int i = 0; i < num_glyphs; ++i) {
    1401         Glyph *glyph = gs->glyph_data.value(glyphs[i]);
     1412        Glyph *glyph = gs->getGlyph(glyphs[i]);
    14021413        if (glyph == 0 || glyph->format != format) {
    14031414            if (!face) {
     
    15511562        for ( int i = 0; i < len; ++i ) {
    15521563            unsigned int uc = getChar(str, i, len);
    1553             if (mirrored)
    1554                 uc = QChar::mirroredChar(uc);
    15551564            glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
    15561565            if ( !glyphs->glyphs[glyph_pos] ) {
     
    16361645    if (flags & QTextEngine::DesignMetrics) {
    16371646        for (int i = 0; i < glyphs->numGlyphs; i++) {
    1638             Glyph *g = defaultGlyphSet.glyph_data.value(glyphs->glyphs[i]);
     1647            Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]);
    16391648            if (g) {
    16401649                glyphs->advances_x[i] = QFixed::fromFixed(g->linearAdvance);
     
    16491658    } else {
    16501659        for (int i = 0; i < glyphs->numGlyphs; i++) {
    1651             Glyph *g = defaultGlyphSet.glyph_data.value(glyphs->glyphs[i]);
     1660            Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]);
    16521661            if (g) {
    16531662                glyphs->advances_x[i] = QFixed(g->advance);
     
    16781687    QFixed xmax = 0;
    16791688    for (int i = 0; i < glyphs.numGlyphs; i++) {
    1680         Glyph *g = defaultGlyphSet.glyph_data.value(glyphs.glyphs[i]);
     1689        Glyph *g = defaultGlyphSet.getGlyph(glyphs.glyphs[i]);
    16811690        if (!g) {
    16821691            if (!face)
     
    17201729    FT_Face face = 0;
    17211730    glyph_metrics_t overall;
    1722     Glyph *g = defaultGlyphSet.glyph_data.value(glyph);
     1731    Glyph *g = defaultGlyphSet.getGlyph(glyph);
    17231732    if (!g) {
    17241733        face = lockFace();
     
    17841793            }
    17851794            glyphSet = &transformedGlyphSets[0];
    1786             qDeleteAll(glyphSet->glyph_data);
    1787             glyphSet->glyph_data.clear();
     1795            glyphSet->clear();
    17881796            glyphSet->id = allocateServerGlyphSet();
    17891797            glyphSet->transformationMatrix = m;
     
    17931801        glyphSet = &defaultGlyphSet;
    17941802    }
    1795     Glyph * g = glyphSet->glyph_data.value(glyph);
     1803    Glyph * g = glyphSet->getGlyph(glyph);
    17961804    if (!g) {
    17971805        face = lockFace();
     
    18821890void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
    18831891{
    1884     delete defaultGlyphSet.glyph_data.take(glyph);
     1892    defaultGlyphSet.removeGlyphFromCache(glyph);
    18851893}
    18861894
     
    19381946    transformationMatrix.xy = 0;
    19391947    transformationMatrix.yx = 0;
     1948    memset(fast_glyph_data, 0, sizeof(fast_glyph_data));
     1949    fast_glyph_count = 0;
    19401950}
    19411951
    19421952QFontEngineFT::QGlyphSet::~QGlyphSet()
    19431953{
     1954    clear();
     1955}
     1956
     1957void QFontEngineFT::QGlyphSet::clear()
     1958{
     1959    if (fast_glyph_count > 0) {
     1960        for (int i = 0; i < 256; ++i) {
     1961            if (fast_glyph_data[i]) {
     1962                delete fast_glyph_data[i];
     1963                fast_glyph_data[i] = 0;
     1964            }
     1965        }
     1966        fast_glyph_count = 0;
     1967    }
    19441968    qDeleteAll(glyph_data);
     1969    glyph_data.clear();
     1970}
     1971
     1972void QFontEngineFT::QGlyphSet::removeGlyphFromCache(int index)
     1973{
     1974    if (index < 256) {
     1975        if (fast_glyph_data[index]) {
     1976            delete fast_glyph_data[index];
     1977            fast_glyph_data[index] = 0;
     1978            if (fast_glyph_count > 0)
     1979                --fast_glyph_count;
     1980        }
     1981    } else {
     1982        delete glyph_data.take(index);
     1983    }
     1984}
     1985
     1986void QFontEngineFT::QGlyphSet::setGlyph(int index, Glyph *glyph)
     1987{
     1988    if (index < 256) {
     1989        if (!fast_glyph_data[index])
     1990            ++fast_glyph_count;
     1991        fast_glyph_data[index] = glyph;
     1992    } else {
     1993        glyph_data.insert(index, glyph);
     1994    }
    19451995}
    19461996
  • trunk/src/gui/text/qfontengine_ft_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    181181        unsigned long id; // server sided id, GlyphSet for X11
    182182        bool outline_drawing;
     183
     184        void removeGlyphFromCache(int index);
     185        void clear();
     186        inline Glyph *getGlyph(int index) const
     187        {
     188            if (index < 256)
     189                return fast_glyph_data[index];
     190            return glyph_data.value(index);
     191        }
     192        void setGlyph(int index, Glyph *glyph);
     193
     194private:
    183195        mutable QHash<int, Glyph *> glyph_data; // maps from glyph index to glyph data
     196        mutable Glyph *fast_glyph_data[256]; // for fast lookup of glyphs < 256
     197        mutable int fast_glyph_count;
    184198    };
    185199
     
    253267    GlyphFormat defaultGlyphFormat() const { return defaultFormat; }
    254268
    255     inline Glyph *cachedGlyph(glyph_t g) const { return defaultGlyphSet.glyph_data.value(g); }
     269    inline Glyph *cachedGlyph(glyph_t g) const { return defaultGlyphSet.getGlyph(g); }
    256270
    257271    QGlyphSet *loadTransformedGlyphSet(const QTransform &matrix);
     
    291305    bool antialias;
    292306    bool transform;
     307    bool embolden;
    293308    SubpixelAntialiasingType subpixelType;
    294309    int lcdFilterType;
  • trunk/src/gui/text/qfontengine_mac.mm

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4747#include <private/qpaintengine_mac_p.h>
    4848#include <private/qprintengine_mac_p.h>
    49 #include <private/qpdf_p.h>
    5049#include <qglobal.h>
    5150#include <qpixmap.h>
     
    5453#include <qdebug.h>
    5554#include <qendian.h>
     55#include <qmath.h>
    5656
    5757#include <ApplicationServices/ApplicationServices.h>
     
    162162    ATSFontGetName(atsFontRef, kATSOptionFlagsDefault, &name);
    163163
     164    transform = CGAffineTransformIdentity;
     165    if (fontDef.stretch != 100) {
     166        transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1);
     167    }
     168
    164169    QCFType<CTFontDescriptorRef> descriptor = CTFontDescriptorCreateWithNameAndSize(name, fontDef.pixelSize);
    165     QCFType<CTFontRef> baseFont = CTFontCreateWithFontDescriptor(descriptor, fontDef.pixelSize, 0);
    166     ctfont = CTFontCreateCopyWithSymbolicTraits(baseFont, fontDef.pixelSize, 0, symbolicTraits, symbolicTraits);
     170    QCFType<CTFontRef> baseFont = CTFontCreateWithFontDescriptor(descriptor, fontDef.pixelSize, &transform);
     171    ctfont = CTFontCreateCopyWithSymbolicTraits(baseFont, fontDef.pixelSize, &transform, symbolicTraits, symbolicTraits);
    167172
    168173    // CTFontCreateCopyWithSymbolicTraits returns NULL if we ask for a trait that does
     
    226231    glyph_t *initialGlyph = outGlyphs;
    227232
    228     if (arraySize == 0)
    229         return false;
     233    if (arraySize == 0) {
     234        // CoreText failed to shape the text we gave it, so we assume one glyph
     235        // per character and build a list of invalid glyphs with zero advance
     236        *nglyphs = len;
     237        for (int i = 0; i < len; ++i) {
     238            outGlyphs[i] = 0;
     239            if (logClusters)
     240                logClusters[i] = i;
     241            outAdvances_x[i] = QFixed();
     242            outAdvances_y[i] = QFixed();
     243            outAttributes[i].clusterStart = true;
     244        }
     245        return true;
     246    }
    230247
    231248    const bool rtl = (CTRunGetStatus(static_cast<CTRunRef>(CFArrayGetValueAtIndex(array, 0))) & kCTRunStatusRightToLeft);
     
    304321                outAdvances_x[idx] = QFixed::fromReal(tmpPoints[i + 1].x - tmpPoints[i].x);
    305322                outAdvances_y[idx] = QFixed::fromReal(tmpPoints[i + 1].y - tmpPoints[i].y);
     323               
     324                if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
     325                    outAdvances_x[idx] = outAdvances_x[idx].round();
     326                    outAdvances_y[idx] = outAdvances_y[idx].round();
     327                }
    306328            }
    307329            CGSize lastGlyphAdvance;
     
    309331
    310332            outGlyphs[rtl ? 0 : (glyphCount - 1)] = tmpGlyphs[glyphCount - 1] | fontIndex;
    311             outAdvances_x[rtl ? 0 : (glyphCount - 1)] = QFixed::fromReal(lastGlyphAdvance.width).ceil();
     333            outAdvances_x[rtl ? 0 : (glyphCount - 1)] =
     334                    (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
     335                    ? QFixed::fromReal(lastGlyphAdvance.width).round()
     336                    : QFixed::fromReal(lastGlyphAdvance.width);
    312337        }
    313338        outGlyphs += glyphCount;
     
    323348                                            int *nglyphs, QTextEngine::ShaperFlags flags) const
    324349{
    325     return stringToCMap(str, len, glyphs, nglyphs, flags, 0, 0);
     350    *nglyphs = len;
     351    QCFType<CFStringRef> cfstring;
     352
     353    QVarLengthArray<CGGlyph> cgGlyphs(len);
     354    CTFontGetGlyphsForCharacters(ctfont, (const UniChar*)str, cgGlyphs.data(), len);
     355
     356    for (int i = 0; i < len; ++i) {
     357        if (cgGlyphs[i]) {
     358            glyphs->glyphs[i] = cgGlyphs[i];
     359        } else {
     360            if (!cfstring)
     361                cfstring = CFStringCreateWithCharactersNoCopy(0, reinterpret_cast<const UniChar *>(str), len, kCFAllocatorNull);
     362            QCFType<CTFontRef> substituteFont = CTFontCreateForString(ctfont, cfstring, CFRangeMake(i, 1));
     363            CGGlyph substituteGlyph = 0;
     364            CTFontGetGlyphsForCharacters(substituteFont, (const UniChar*)str + i, &substituteGlyph, 1);
     365            if (substituteGlyph) {
     366                const uint fontIndex = (fontIndexForFont(substituteFont) << 24);
     367                glyphs->glyphs[i] = substituteGlyph | fontIndex;
     368                if (!(flags & QTextEngine::GlyphIndicesOnly)) {
     369                    CGSize advance;
     370                    CTFontGetAdvancesForGlyphs(substituteFont, kCTFontHorizontalOrientation, &substituteGlyph, &advance, 1);
     371                    glyphs->advances_x[i] = QFixed::fromReal(advance.width);
     372                    glyphs->advances_y[i] = QFixed::fromReal(advance.height);
     373                }
     374            }
     375        }
     376    }
     377
     378    if (flags & QTextEngine::GlyphIndicesOnly)
     379        return true;
     380
     381    QVarLengthArray<CGSize> advances(len);
     382    CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, cgGlyphs.data(), advances.data(), len);
     383
     384    for (int i = 0; i < len; ++i) {
     385        if (glyphs->glyphs[i] & 0xff000000)
     386            continue;
     387        glyphs->advances_x[i] = QFixed::fromReal(advances[i].width);
     388        glyphs->advances_y[i] = QFixed::fromReal(advances[i].height);
     389    }
     390
     391    if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
     392        for (int i = 0; i < len; ++i) {
     393            glyphs->advances_x[i] = glyphs->advances_x[i].round();
     394            glyphs->advances_y[i] = glyphs->advances_y[i].round();
     395        }
     396    }
     397
     398    return true;
    326399}
    327400
     
    359432        synthesisFlags |= SynthesizedItalic;
    360433    }
    361 
     434    transform = CGAffineTransformIdentity;
     435    if (fontDef.stretch != 100) {
     436        transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1);
     437    }
    362438    QByteArray os2Table = getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
    363439    if (os2Table.size() >= 10)
     
    379455{
    380456    QFixed w;
    381     for (int i = 0; i < glyphs.numGlyphs; ++i)
    382         w += glyphs.effectiveAdvance(i);
    383     return glyph_metrics_t(0, -(ascent()), w, ascent()+descent(), w, 0);
     457    bool round = fontDef.styleStrategy & QFont::ForceIntegerMetrics;
     458
     459    for (int i = 0; i < glyphs.numGlyphs; ++i) {
     460        w += round ? glyphs.effectiveAdvance(i).round()
     461                   : glyphs.effectiveAdvance(i);
     462    }
     463    return glyph_metrics_t(0, -(ascent()), w - lastRightBearing(glyphs, round), ascent()+descent(), w, 0);
    384464}
    385465glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph)
     
    394474    CGSize advances[1];
    395475    CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, &g, advances, 1);
    396     ret.xoff = QFixed::fromReal(advances[0].width).ceil();
    397     ret.yoff = QFixed::fromReal(advances[0].height).ceil();
     476    ret.xoff = QFixed::fromReal(advances[0].width);
     477    ret.yoff = QFixed::fromReal(advances[0].height);
     478
     479    if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
     480        ret.xoff = ret.xoff.round();
     481        ret.yoff = ret.yoff.round();
     482    }
     483
    398484    return ret;
    399485}
     
    401487QFixed QCoreTextFontEngine::ascent() const
    402488{
    403     return QFixed::fromReal(CTFontGetAscent(ctfont)).ceil();
     489    return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
     490            ? QFixed::fromReal(CTFontGetAscent(ctfont)).round()
     491            : QFixed::fromReal(CTFontGetAscent(ctfont));
    404492}
    405493QFixed QCoreTextFontEngine::descent() const
    406494{
     495    QFixed d = QFixed::fromReal(CTFontGetDescent(ctfont));
     496    if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
     497        d = d.round();
     498
    407499    // subtract a pixel to even out the historical +1 in QFontMetrics::height().
    408500    // Fix in Qt 5.
    409     return QFixed::fromReal(CTFontGetDescent(ctfont)).ceil() - 1;
     501    return d - 1;
    410502}
    411503QFixed QCoreTextFontEngine::leading() const
    412504{
    413     return QFixed::fromReal(CTFontGetLeading(ctfont)).ceil();
     505    return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
     506            ? QFixed::fromReal(CTFontGetLeading(ctfont)).round()
     507            : QFixed::fromReal(CTFontGetLeading(ctfont));
    414508}
    415509QFixed QCoreTextFontEngine::xHeight() const
    416510{
    417     return QFixed::fromReal(CTFontGetXHeight(ctfont)).ceil();
     511    return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
     512            ? QFixed::fromReal(CTFontGetXHeight(ctfont)).round()
     513            : QFixed::fromReal(CTFontGetXHeight(ctfont));
    418514}
    419515QFixed QCoreTextFontEngine::averageCharWidth() const
    420516{
    421517    // ### Need to implement properly and get the information from the OS/2 Table.
    422     return QFontEngine::averageCharWidth();
     518    return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
     519            ? QFontEngine::averageCharWidth().round()
     520            : QFontEngine::averageCharWidth();
    423521}
    424522
     
    463561        cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -tanf(14 * acosf(0) / 90), 1, 0, 0));
    464562
    465 // ###    cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
     563    cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
    466564
    467565    CGContextSetTextMatrix(ctx, cgMatrix);
     
    586684        cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, tanf(14 * acosf(0) / 90), 1, 0, 0));
    587685
    588 // ###    cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
     686    cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
    589687
    590688    CGContextSetTextMatrix(ctx, cgMatrix);
     
    788886    QTextEngine::ShaperFlags flags;
    789887    QFontEngineMacMulti::ShaperItem *shaperItem;
     888    unsigned int styleStrategy;
    790889};
    791890
     
    856955        QFixed yAdvance = FixedToQFixed(baselineDeltas[glyphIdx]);
    857956        QFixed xAdvance = FixedToQFixed(layoutData[glyphIdx + 1].realPos - layoutData[glyphIdx].realPos);
     957
     958        if (nfo->styleStrategy & QFont::ForceIntegerMetrics) {
     959            yAdvance = yAdvance.round();
     960            xAdvance = xAdvance.round();
     961        }
    858962
    859963        if (glyphId != 0xffff || i == 0) {
     
    10331137    nfo.flags = flags;
    10341138    nfo.shaperItem = shaperItem;
     1139    nfo.styleStrategy = fontDef.styleStrategy;
    10351140
    10361141    int prevNumGlyphs = *nglyphs;
     
    10611166                                       | kATSLineDisableAllJustification
    10621167                                       ;
    1063 
    1064         layopts |= kATSLineUseDeviceMetrics;
    10651168
    10661169        if (fontDef.styleStrategy & QFont::NoAntialias)
     
    13671470        glyphs->advances_x[i] = QFixed::fromReal(metrics[i].deviceAdvance.x);
    13681471        glyphs->advances_y[i] = QFixed::fromReal(metrics[i].deviceAdvance.y);
     1472
     1473        if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
     1474            glyphs->advances_x[i] = glyphs->advances_x[i].round();
     1475            glyphs->advances_y[i] = glyphs->advances_y[i].round();
     1476        }
    13691477    }
    13701478}
     
    13731481{
    13741482    QFixed w;
    1375     for (int i = 0; i < glyphs.numGlyphs; ++i)
    1376         w += glyphs.effectiveAdvance(i);
    1377     return glyph_metrics_t(0, -(ascent()), w, ascent()+descent(), w, 0);
     1483    bool round = fontDef.styleStrategy & QFont::ForceIntegerMetrics;
     1484    for (int i = 0; i < glyphs.numGlyphs; ++i) {
     1485        w += round ? glyphs.effectiveAdvance(i).round()
     1486                   : glyphs.effectiveAdvance(i);
     1487    }
     1488    return glyph_metrics_t(0, -(ascent()), w - lastRightBearing(glyphs, round), ascent()+descent(), w, 0);
    13781489}
    13791490
     
    13991510    gm.yoff = QFixed::fromReal(metrics.deviceAdvance.y);
    14001511
     1512    if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
     1513        gm.x = gm.x.floor();
     1514        gm.y = gm.y.floor();
     1515        gm.xoff = gm.xoff.round();
     1516        gm.yoff = gm.yoff.round();
     1517    }
     1518
    14011519    return gm;
    14021520}
     
    14041522QFixed QFontEngineMac::ascent() const
    14051523{
    1406     return m_ascent;
     1524    return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
     1525            ? m_ascent.round()
     1526            : m_ascent;
    14071527}
    14081528
     
    14111531    // subtract a pixel to even out the historical +1 in QFontMetrics::height().
    14121532    // Fix in Qt 5.
    1413     return m_descent - 1;
     1533    return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
     1534            ? m_descent.round() - 1
     1535            : m_descent;
    14141536}
    14151537
    14161538QFixed QFontEngineMac::leading() const
    14171539{
    1418     return m_leading;
     1540    return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
     1541            ? m_leading.round()
     1542            : m_leading;
    14191543}
    14201544
    14211545qreal QFontEngineMac::maxCharWidth() const
    14221546{
    1423     return m_maxCharWidth;
     1547    return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
     1548            ? qRound(m_maxCharWidth)
     1549            : m_maxCharWidth;
    14241550}
    14251551
    14261552QFixed QFontEngineMac::xHeight() const
    14271553{
    1428     return m_xHeight;
     1554    return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
     1555            ? m_xHeight.round()
     1556            : m_xHeight;
    14291557}
    14301558
    14311559QFixed QFontEngineMac::averageCharWidth() const
    14321560{
    1433     return m_averageCharWidth;
     1561    return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
     1562            ? m_averageCharWidth.round()
     1563            : m_averageCharWidth;
    14341564}
    14351565
     
    17231853    if (ATSFontGetPostScriptName(FMGetATSFontRefFromFont(fontID), kATSOptionFlagsDefault, &psName) == noErr)
    17241854        props.postscriptName = QString(psName).toUtf8();
    1725     props.postscriptName = QPdf::stripSpecialCharacters(props.postscriptName);
     1855    props.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(props.postscriptName);
    17261856    return props;
    17271857}
  • trunk/src/gui/text/qfontengine_p.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    159159    virtual QFixed emSquareSize() const { return ascent(); }
    160160
    161     /* returns 0 as glyph index for non existant glyphs */
     161    /* returns 0 as glyph index for non existent glyphs */
    162162    virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const = 0;
    163163
     
    181181    /**
    182182     * Create a qimage with the alpha values for the glyph.
    183      * Returns an image indexed_8 with index values ranging from 0=fully transparant to 255=opaque
     183     * Returns an image indexed_8 with index values ranging from 0=fully transparent to 255=opaque
    184184     */
    185185    virtual QImage alphaMapForGlyph(glyph_t);
     
    227227    static const uchar *getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize);
    228228    static quint32 getTrueTypeGlyphIndex(const uchar *cmap, uint unicode);
     229
     230    static QByteArray convertToPostscriptFontFamilyName(const QByteArray &fontFamily);
    229231
    230232    QAtomicInt ref;
     
    254256protected:
    255257    static const QVector<QRgb> &grayPalette();
     258    QFixed lastRightBearing(const QGlyphLayout &glyphs, bool round = false);
    256259
    257260private:
     
    463466    QCoreTextFontEngineMulti *parentEngine;
    464467    int synthesisFlags;
     468    CGAffineTransform transform;
    465469    friend class QCoreTextFontEngineMulti;
    466470};
     
    494498    CTFontRef ctfont;
    495499    mutable QCFType<CFMutableDictionaryRef> attributeDict;
    496 
     500    CGAffineTransform transform;
    497501    friend class QFontDialogPrivate;
    498502};
  • trunk/src/gui/text/qfontengine_qpf.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    579579        for (int i = 0; i < len; ++i) {
    580580            unsigned int uc = getChar(str, i, len);
    581             if (mirrored)
    582                 uc = QChar::mirroredChar(uc);
    583581            glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
    584582            if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
     
    921919    if (!renderingFontEngine)
    922920        return;
    923 
    924     QImage img = renderingFontEngine->alphaMapForGlyph(glyph).convertToFormat(QImage::Format_Indexed8);
     921    QImage img = renderingFontEngine->alphaMapForGlyph(glyph);
     922    if (img.format() != QImage::Format_Indexed8) {
     923        bool mono = img.depth() == 1;
     924        img = img.convertToFormat(QImage::Format_Indexed8);
     925        if (mono) {
     926            //### we know that 1 is opaque and 0 is transparent
     927            uchar *byte = img.bits();
     928            int count = img.byteCount();
     929            while (count--)
     930                *byte++ *= 0xff;
     931        }
     932    }
    925933    glyph_metrics_t metrics = renderingFontEngine->boundingBox(glyph);
    926934    renderingFontEngine->removeGlyphFromCache(glyph);
  • trunk/src/gui/text/qfontengine_qpf_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qfontengine_qws.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    558558    for (int i = 0; i < glyphs.numGlyphs; ++i)
    559559        w += glyphs.effectiveAdvance(i);
    560     return glyph_metrics_t(0, -ascent(), w, ascent()+descent()+1, w, 0);
     560    return glyph_metrics_t(0, -ascent(), w - lastRightBearing(glyphs), ascent()+descent()+1, w, 0);
    561561}
    562562
  • trunk/src/gui/text/qfontengine_s60.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4242#include "qfontengine_s60_p.h"
    4343#include "qtextengine_p.h"
     44#include "qendian.h"
    4445#include "qglobal.h"
    4546#include <private/qapplication_p.h>
    4647#include "qimage.h"
    4748#include <private/qt_s60_p.h>
     49#include <private/qpixmap_s60_p.h>
    4850
    4951#include <e32base.h>
     
    5153#include <eikenv.h>
    5254#include <gdi.h>
     55#if defined(Q_SYMBIAN_HAS_GLYPHOUTLINE_API)
     56#include <graphics/gdi/gdiplatapi.h>
     57#endif // Q_SYMBIAN_HAS_GLYPHOUTLINE_API
     58
     59// Replication of TGetFontTableParam & friends.
     60// There is unfortunately no compile time flag like SYMBIAN_FONT_TABLE_API
     61// that would help us to only replicate these things for Symbian versions
     62// that do not yet have the font table Api. Symbian's public SDK does
     63// generally not define any usable macros.
     64class QSymbianTGetFontTableParam
     65{
     66public:
     67    TUint32 iTag;
     68    TAny *iContent;
     69    TInt iLength;
     70};
     71const TUid QSymbianKFontGetFontTable      = {0x102872C1};
     72const TUid QSymbianKFontReleaseFontTable  = {0x2002AC24};
    5373
    5474QT_BEGIN_NAMESPACE
    5575
    56 QSymbianTypeFaceExtras::QSymbianTypeFaceExtras(CFont* fontOwner, COpenFont *font)
    57     : m_font(font)
    58     , m_cmap(0)
     76QSymbianTypeFaceExtras::QSymbianTypeFaceExtras(CFont* cFont, COpenFont *openFont)
     77    : m_cFont(cFont)
    5978    , m_symbolCMap(false)
    60     , m_fontOwner(fontOwner)
    61 {
    62     TAny *trueTypeExtension = NULL;
    63     m_font->ExtendedInterface(KUidOpenFontTrueTypeExtension, trueTypeExtension);
    64     m_trueTypeExtension = static_cast<MOpenFontTrueTypeExtension*>(trueTypeExtension);
    65     Q_ASSERT(m_trueTypeExtension);
     79    , m_openFont(openFont)
     80{
     81    if (!symbianFontTableApiAvailable()) {
     82        TAny *trueTypeExtension = NULL;
     83        m_openFont->ExtendedInterface(KUidOpenFontTrueTypeExtension, trueTypeExtension);
     84        m_trueTypeExtension = static_cast<MOpenFontTrueTypeExtension*>(trueTypeExtension);
     85        Q_ASSERT(m_trueTypeExtension);
     86    }
     87}
     88
     89QSymbianTypeFaceExtras::~QSymbianTypeFaceExtras()
     90{
     91    if (symbianFontTableApiAvailable())
     92        S60->screenDevice()->ReleaseFont(m_cFont);
    6693}
    6794
    6895QByteArray QSymbianTypeFaceExtras::getSfntTable(uint tag) const
    6996{
    70     Q_ASSERT(m_trueTypeExtension->HasTrueTypeTable(tag));
    71     TInt error = KErrNone;
    72     TInt tableByteLength = 0;
    73     TAny *table = q_check_ptr(m_trueTypeExtension->GetTrueTypeTable(error, tag, &tableByteLength));
    74     QByteArray result(static_cast<const char*>(table), tableByteLength);
    75     m_trueTypeExtension->ReleaseTrueTypeTable(table);
     97    if (symbianFontTableApiAvailable()) {
     98        QSymbianTGetFontTableParam fontTableParams = { tag, 0, 0 };
     99        if (m_cFont->ExtendedFunction(QSymbianKFontGetFontTable, &fontTableParams) == KErrNone) {
     100            const char* const fontTableContent =
     101                    static_cast<const char *>(fontTableParams.iContent);
     102            const QByteArray fontTable(fontTableContent, fontTableParams.iLength);
     103            m_cFont->ExtendedFunction(QSymbianKFontReleaseFontTable, &fontTableParams);
     104            return fontTable;
     105        }
     106        return QByteArray();
     107    } else {
     108        Q_ASSERT(m_trueTypeExtension->HasTrueTypeTable(tag));
     109        TInt error = KErrNone;
     110        TInt tableByteLength = 0;
     111        TAny *table = q_check_ptr(m_trueTypeExtension->GetTrueTypeTable(error, tag, &tableByteLength));
     112        const QByteArray result(static_cast<const char*>(table), tableByteLength);
     113        m_trueTypeExtension->ReleaseTrueTypeTable(table);
     114        return result;
     115    }
     116}
     117
     118bool QSymbianTypeFaceExtras::getSfntTableData(uint tag, uchar *buffer, uint *length) const
     119{
     120    bool result = true;
     121    if (symbianFontTableApiAvailable()) {
     122        QSymbianTGetFontTableParam fontTableParams = { tag, 0, 0 };
     123        if (m_cFont->ExtendedFunction(QSymbianKFontGetFontTable, &fontTableParams) == KErrNone) {
     124            if (*length > 0 && *length < fontTableParams.iLength) {
     125                result = false; // Caller did not allocate enough memory
     126            } else {
     127                *length = fontTableParams.iLength;
     128                if (buffer)
     129                    memcpy(buffer, fontTableParams.iContent, fontTableParams.iLength);
     130            }
     131            m_cFont->ExtendedFunction(QSymbianKFontReleaseFontTable, &fontTableParams);
     132        } else {
     133            result = false;
     134        }
     135    } else {
     136        if (!m_trueTypeExtension->HasTrueTypeTable(tag))
     137            return false;
     138
     139        TInt error = KErrNone;
     140        TInt tableByteLength;
     141        TAny *table =
     142                q_check_ptr(m_trueTypeExtension->GetTrueTypeTable(error, tag, &tableByteLength));
     143
     144        if (error != KErrNone) {
     145            return false;
     146        } else if (*length > 0 && *length < tableByteLength) {
     147            result = false; // Caller did not allocate enough memory
     148        } else {
     149            *length = tableByteLength;
     150            if (buffer)
     151                memcpy(buffer, table, tableByteLength);
     152        }
     153
     154        m_trueTypeExtension->ReleaseTrueTypeTable(table);
     155    }
    76156    return result;
    77157}
    78158
    79 bool QSymbianTypeFaceExtras::getSfntTableData(uint tag, uchar *buffer, uint *length) const
    80 {
    81     if (!m_trueTypeExtension->HasTrueTypeTable(tag))
    82         return false;
    83 
    84     bool result = true;
    85     TInt error = KErrNone;
    86     TInt tableByteLength;
    87     TAny *table =
    88         q_check_ptr(m_trueTypeExtension->GetTrueTypeTable(error, tag, &tableByteLength));
    89 
    90     if (error != KErrNone) {
    91         return false;
    92     } else if (*length > 0 && *length < tableByteLength) {
    93         result = false; // Caller did not allocate enough memory
     159const uchar *QSymbianTypeFaceExtras::cmap() const
     160{
     161    if (m_cmapTable.isNull()) {
     162        const QByteArray cmapTable = getSfntTable(MAKE_TAG('c', 'm', 'a', 'p'));
     163        int size = 0;
     164        const uchar *cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>
     165                (cmapTable.constData()), cmapTable.size(), &m_symbolCMap, &size);
     166        m_cmapTable = QByteArray(reinterpret_cast<const char *>(cmap), size);
     167    }
     168    return reinterpret_cast<const uchar *>(m_cmapTable.constData());
     169}
     170
     171bool QSymbianTypeFaceExtras::isSymbolCMap() const
     172{
     173    return m_symbolCMap;
     174}
     175
     176CFont *QSymbianTypeFaceExtras::fontOwner() const
     177{
     178    return m_cFont;
     179}
     180
     181QFixed QSymbianTypeFaceExtras::unitsPerEm() const
     182{
     183    if (m_unitsPerEm.value() != 0)
     184        return m_unitsPerEm;
     185    const QByteArray head = getSfntTable(MAKE_TAG('h', 'e', 'a', 'd'));
     186    const int unitsPerEmOffset = 18;
     187    if (head.size() > unitsPerEmOffset + sizeof(quint16)) {
     188        const uchar* tableData = reinterpret_cast<const uchar*>(head.constData());
     189        const uchar* unitsPerEm = tableData + unitsPerEmOffset;
     190        m_unitsPerEm = qFromBigEndian<quint16>(unitsPerEm);
    94191    } else {
    95         *length = tableByteLength;
    96         if (buffer)
    97             qMemCopy(buffer, table, tableByteLength);
    98     }
    99 
    100     m_trueTypeExtension->ReleaseTrueTypeTable(table);
    101     return result;
    102 }
    103 
    104 const unsigned char *QSymbianTypeFaceExtras::cmap() const
    105 {
    106     if (!m_cmap) {
    107         m_cmapTable = getSfntTable(MAKE_TAG('c', 'm', 'a', 'p'));
    108         int size = 0;
    109         m_cmap = QFontEngineS60::getCMap(reinterpret_cast<const uchar *>(m_cmapTable.constData()), m_cmapTable.size(), &m_symbolCMap, &size);
    110     }
    111     return m_cmap;
    112 }
    113 
    114 CFont *QSymbianTypeFaceExtras::fontOwner() const
    115 {
    116     return m_fontOwner;
    117 }
    118 
     192        // Bitmap font? Corrupt font?
     193        // We return -1 and let the QFontEngineS60 return the pixel size.
     194        m_unitsPerEm = -1;
     195    }
     196    return m_unitsPerEm;
     197}
     198
     199bool QSymbianTypeFaceExtras::symbianFontTableApiAvailable()
     200{
     201    enum FontTableApiAvailability {
     202        Unknown,
     203        Available,
     204        Unavailable
     205    };
     206    static FontTableApiAvailability availability =
     207            QSysInfo::symbianVersion() < QSysInfo::SV_SF_3 ?
     208                Unavailable : Unknown;
     209    if (availability == Unknown) {
     210        // Actually, we should ask CFeatureDiscovery::IsFeatureSupportedL()
     211        // with FfFontTable here. But since at the time of writing, the
     212        // FfFontTable flag check either gave false positives or false
     213        // negatives. Here comes an implicit check via CFont::ExtendedFunction.
     214        QSymbianTGetFontTableParam fontTableParams = {
     215            MAKE_TAG('O', 'S', '/', '2'), 0, 0 };
     216        QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
     217        CFont *font;
     218        const TInt getFontErr = S60->screenDevice()->GetNearestFontInTwips(font, TFontSpec());
     219        Q_ASSERT(getFontErr == KErrNone);
     220        if (font->ExtendedFunction(QSymbianKFontGetFontTable, &fontTableParams) == KErrNone) {
     221            font->ExtendedFunction(QSymbianKFontReleaseFontTable, &fontTableParams);
     222            availability = Available;
     223        } else {
     224            availability = Unavailable;
     225        }
     226        S60->screenDevice()->ReleaseFont(font);
     227        lock.relock();
     228    }
     229    return availability == Available;
     230}
    119231
    120232// duplicated from qfontengine_xyz.cpp
     
    132244}
    133245
     246extern QString qt_symbian_fontNameWithAppFontMarker(const QString &fontName); // qfontdatabase_s60.cpp
     247
    134248CFont *QFontEngineS60::fontWithSize(qreal size) const
    135249{
    136250    CFont *result = 0;
    137     TFontSpec fontSpec(qt_QString2TPtrC(QFontEngine::fontDef.family), TInt(size));
     251    const QString family = qt_symbian_fontNameWithAppFontMarker(QFontEngine::fontDef.family);
     252    TFontSpec fontSpec(qt_QString2TPtrC(family), TInt(size));
    138253    fontSpec.iFontStyle.SetBitmapType(EAntiAliasedGlyphBitmap);
    139254    fontSpec.iFontStyle.SetPosture(QFontEngine::fontDef.style == QFont::StyleNormal?EPostureUpright:EPostureItalic);
     
    190305}
    191306
     307QFixed QFontEngineS60::emSquareSize() const
     308{
     309    const QFixed unitsPerEm = m_extras->unitsPerEm();
     310    return unitsPerEm.toInt() == -1 ?
     311                QFixed::fromReal(m_originalFontSizeInPixels) : unitsPerEm;
     312}
     313
    192314bool QFontEngineS60::stringToCMap(const QChar *characters, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
    193315{
     
    203325        const unsigned int uc = getChar(characters, i, len);
    204326        *g++ = QFontEngine::getTrueTypeGlyphIndex(cmap,
    205                         isRtl ? QChar::mirroredChar(uc) : uc);
     327                        (isRtl && !m_extras->isSymbolCMap()) ? QChar::mirroredChar(uc) : uc);
    206328    }
    207329
     
    219341{
    220342    Q_UNUSED(flags);
     343    TOpenFontCharMetrics metrics;
     344    const TUint8 *glyphBitmapBytes;
     345    TSize glyphBitmapSize;
    221346    for (int i = 0; i < glyphs->numGlyphs; i++) {
    222         const glyph_metrics_t bbox = boundingBox_const(glyphs->glyphs[i]);
    223         glyphs->advances_x[i] = bbox.xoff;
    224         glyphs->advances_y[i] = bbox.yoff;
    225     }
     347        getCharacterData(glyphs->glyphs[i], metrics, glyphBitmapBytes, glyphBitmapSize);
     348        glyphs->advances_x[i] = metrics.HorizAdvance();
     349        glyphs->advances_y[i] = 0;
     350    }
     351}
     352
     353#ifdef Q_SYMBIAN_HAS_GLYPHOUTLINE_API
     354static bool parseGlyphPathData(const char *dataStr, const char *dataEnd, QPainterPath &path,
     355                               qreal fontPixelSize, const QPointF &offset, bool hinted);
     356#endif //Q_SYMBIAN_HAS_GLYPHOUTLINE_API
     357
     358void QFontEngineS60::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions,
     359                                     int nglyphs, QPainterPath *path,
     360                                     QTextItem::RenderFlags flags)
     361{
     362#ifdef Q_SYMBIAN_HAS_GLYPHOUTLINE_API
     363    Q_UNUSED(flags)
     364    RGlyphOutlineIterator iterator;
     365    const TInt error = iterator.Open(*m_activeFont, glyphs, nglyphs);
     366    if (KErrNone != error)
     367        return;
     368    const qreal fontSizeInPixels = qreal(m_activeFont->HeightInPixels());
     369    int count = 0;
     370    do {
     371        const TUint8* outlineUint8 = iterator.Outline();
     372        const char* const outlineChar = reinterpret_cast<const char*>(outlineUint8);
     373        const char* const outlineEnd = outlineChar + iterator.OutlineLength();
     374        parseGlyphPathData(outlineChar, outlineEnd, *path, fontSizeInPixels,
     375                positions[count++].toPointF(), false);
     376    } while(KErrNone == iterator.Next() && count <= nglyphs);
     377    iterator.Close();
     378#else // Q_SYMBIAN_HAS_GLYPHOUTLINE_API
     379    QFontEngine::addGlyphsToPath(glyphs, positions, nglyphs, path, flags);
     380#endif //Q_SYMBIAN_HAS_GLYPHOUTLINE_API
    226381}
    227382
    228383QImage QFontEngineS60::alphaMapForGlyph(glyph_t glyph)
    229384{
     385    // Note: On some Symbian versions (apparently <= Symbian^1), this
     386    // function will return gray values 0x00, 0x10 ... 0xe0, 0xf0 due
     387    // to a bug. The glyphs are nowhere perfectly opaque.
     388    // This has been fixed for Symbian^3.
     389
    230390    TOpenFontCharMetrics metrics;
    231391    const TUint8 *glyphBitmapBytes;
     
    234394    QImage result(glyphBitmapBytes, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight, glyphBitmapSize.iWidth, QImage::Format_Indexed8);
    235395    result.setColorTable(grayPalette());
    236 
    237     // The above setColorTable() call detached the image data anyway, so why not shape tha data a bit, while we can.
    238     // CFont::GetCharacterData() returns 8-bit data that obviously was 4-bit data before, and converted to 8-bit incorrectly.
    239     // The data values are 0x00, 0x10 ... 0xe0, 0xf0. So, a real opaque 0xff is never reached, which we get punished
    240     // for every time we want to blit this glyph in the raster paint engine.
    241     // "Fix" is to convert all 0xf0 to 0xff. Is fine, quality wise, and I assume faster than correcting all values.
    242     // Blitting is however, evidentially faster now.
    243     const int bpl = result.bytesPerLine();
    244     for (int row = 0; row < result.height(); ++row) {
    245         uchar *scanLine = result.scanLine(row);
    246         for (int column = 0; column < bpl; ++column) {
    247             if (*scanLine == 0xf0)
    248                 *scanLine = 0xff;
    249             scanLine++;
    250         }
    251     }
    252 
    253396    return result;
    254397}
     
    263406        w += glyphs.effectiveAdvance(i);
    264407
    265     return glyph_metrics_t(0, -ascent(), w, ascent()+descent()+1, w, 0);
     408    return glyph_metrics_t(0, -ascent(), w - lastRightBearing(glyphs), ascent()+descent()+1, w, 0);
    266409}
    267410
     
    272415    TSize glyphBitmapSize;
    273416    getCharacterData(glyph, metrics, glyphBitmapBytes, glyphBitmapSize);
    274     TRect glyphBounds;
    275     metrics.GetHorizBounds(glyphBounds);
    276417    const glyph_metrics_t result(
    277         glyphBounds.iTl.iX,
    278         glyphBounds.iTl.iY,
    279         glyphBounds.Width(),
    280         glyphBounds.Height(),
     418        metrics.HorizBearingX(),
     419        -metrics.HorizBearingY(),
     420        metrics.Width(),
     421        metrics.Height(),
    281422        metrics.HorizAdvance(),
    282423        0
     
    292433QFixed QFontEngineS60::ascent() const
    293434{
    294     return m_originalFont->FontMaxAscent();
     435    // Workaround for QTBUG-8013
     436    // Stroke based fonts may return an incorrect FontMaxAscent of 0.
     437    const QFixed ascent = m_originalFont->FontMaxAscent();
     438    return (ascent > 0) ? ascent : QFixed::fromReal(m_originalFontSizeInPixels) - descent();
    295439}
    296440
     
    357501}
    358502
     503#ifdef Q_SYMBIAN_HAS_GLYPHOUTLINE_API
     504static inline void skipSpacesAndComma(const char* &str, const char* const strEnd)
     505{
     506    while (str <= strEnd && (*str == ' ' || *str == ','))
     507        ++str;
     508}
     509
     510static bool parseGlyphPathData(const char *svgPath, const char *svgPathEnd, QPainterPath &path,
     511                               qreal fontPixelSize, const QPointF &offset, bool hinted)
     512{
     513    Q_UNUSED(hinted)
     514    QPointF p1, p2, firstSubPathPoint;
     515    qreal *elementValues[] =
     516        {&p1.rx(), &p1.ry(), &p2.rx(), &p2.ry()};
     517    const int unitsPerEm = 2048; // See: http://en.wikipedia.org/wiki/Em_%28typography%29
     518    const qreal resizeFactor = fontPixelSize / unitsPerEm;
     519
     520    while (svgPath < svgPathEnd) {
     521        skipSpacesAndComma(svgPath, svgPathEnd);
     522        const char pathElem = *svgPath++;
     523        skipSpacesAndComma(svgPath, svgPathEnd);
     524
     525        if (pathElem != 'Z') {
     526            char *endStr = 0;
     527            int elementValuesCount = 0;
     528            for (int i = 0; i < 4; ++i) { // 4 = size of elementValues[]
     529                qreal coordinateValue = strtod(svgPath, &endStr);
     530                if (svgPath == endStr)
     531                    break;
     532                if (i % 2) // Flip vertically
     533                    coordinateValue = -coordinateValue;
     534                *elementValues[i] = coordinateValue * resizeFactor;
     535                elementValuesCount++;
     536                svgPath = endStr;
     537                skipSpacesAndComma(svgPath, svgPathEnd);
     538            }
     539            p1 += offset;
     540            if (elementValuesCount == 2)
     541                p2 = firstSubPathPoint;
     542            else
     543                p2 += offset;
     544        }
     545
     546        switch (pathElem) {
     547        case 'M':
     548            firstSubPathPoint = p1;
     549            path.moveTo(p1);
     550            break;
     551        case 'Z':
     552            path.closeSubpath();
     553            break;
     554        case 'L':
     555            path.lineTo(p1);
     556            break;
     557        case 'Q':
     558            path.quadTo(p1, p2);
     559            break;
     560        default:
     561            return false;
     562        }
     563    }
     564    return true;
     565}
     566#endif // Q_SYMBIAN_HAS_GLYPHOUTLINE_API
     567
    359568QT_END_NAMESPACE
  • trunk/src/gui/text/qfontengine_s60_p.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    5555
    5656#include "qconfig.h"
    57 #include "qfontengine_p.h"
     57#include <private/qfontengine_p.h>
    5858#include "qsize.h"
    5959#include <openfont.h>
     60
     61// The glyph outline code is intentionally disabled. It will be reactivated as
     62// soon as the glyph outline API is backported from Symbian(^4) to Symbian(^3).
     63#if 0
     64#define Q_SYMBIAN_HAS_GLYPHOUTLINE_API
     65#endif
    6066
    6167class CFont;
     
    6773{
    6874public:
    69     QSymbianTypeFaceExtras(CFont* fontOwner, COpenFont *font);
     75    QSymbianTypeFaceExtras(CFont* cFont, COpenFont *openFont = 0);
     76    ~QSymbianTypeFaceExtras();
    7077
    7178    QByteArray getSfntTable(uint tag) const;
    7279    bool getSfntTableData(uint tag, uchar *buffer, uint *length) const;
    73     const unsigned char *cmap() const;
     80    const uchar *cmap() const;
    7481    CFont *fontOwner() const;
     82    bool isSymbolCMap() const;
     83    QFixed unitsPerEm() const;
     84    static bool symbianFontTableApiAvailable();
    7585
    7686private:
    77     COpenFont *m_font;
    78     mutable MOpenFontTrueTypeExtension *m_trueTypeExtension;
    79     mutable const unsigned char *m_cmap;
     87    CFont* m_cFont;
    8088    mutable bool m_symbolCMap;
    8189    mutable QByteArray m_cmapTable;
    82     CFont* m_fontOwner;
     90    mutable QFixed m_unitsPerEm;
     91
     92    // m_openFont and m_openFont are used if Symbian does not provide
     93    // the Font Table API
     94    COpenFont *m_openFont;
     95    mutable MOpenFontTrueTypeExtension *m_trueTypeExtension;
    8396};
    8497
     
    89102    ~QFontEngineS60();
    90103
     104    QFixed emSquareSize() const;
    91105    bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const;
    92106    void recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const;
     107
     108    void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
     109                         QPainterPath *path, QTextItem::RenderFlags flags);
    93110
    94111    QImage alphaMapForGlyph(glyph_t glyph);
     
    122139private:
    123140    friend class QFontPrivate;
     141    friend class QSymbianVGFontGlyphCache;
    124142
    125143    QFixed glyphAdvance(HB_Glyph glyph) const;
  • trunk/src/gui/text/qfontengine_win.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    5151#include <private/qapplication_p.h>
    5252
    53 #include <qlibrary.h>
     53#include <private/qsystemlibrary_p.h>
    5454#include <qpaintdevice.h>
    5555#include <qpainter.h>
     
    6464
    6565#include <private/qpainter_p.h>
    66 #include <private/qpdf_p.h>
    6766#include "qpaintengine.h"
    6867#include "qvarlengtharray.h"
     
    141140        return;
    142141    resolvedGetCharWidthI = true;
    143     ptrGetCharWidthI = (PtrGetCharWidthI)QLibrary::resolve(QLatin1String("gdi32"), "GetCharWidthI");
     142    ptrGetCharWidthI = (PtrGetCharWidthI)QSystemLibrary::resolve(QLatin1String("gdi32"), "GetCharWidthI");
    144143}
    145144#endif // !defined(Q_WS_WINCE)
     
    214213        x_height = (int)otm->otmsXHeight;
    215214        loadKerningPairs(designToDevice);
    216         _faceId.filename = QString::fromWCharArray((wchar_t *)((char *)otm + (int)otm->otmpFullName)).toLatin1();
     215        _faceId.filename = QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpFullName)).toLatin1();
    217216        lineWidth = otm->otmsUnderscoreSize;
    218217        fsType = otm->otmfsType;
     
    488487        w += glyphs.effectiveAdvance(i);
    489488
    490     return glyph_metrics_t(0, -tm.tmAscent, w, tm.tmHeight, w, 0);
     489    return glyph_metrics_t(0, -tm.tmAscent, w - lastRightBearing(glyphs), tm.tmHeight, w, 0);
    491490}
    492491
     
    10381037    p.emSquare = unitsPerEm;
    10391038    p.italicAngle = otm->otmItalicAngle;
    1040     p.postscriptName = QString::fromWCharArray((wchar_t *)((char *)otm + (int)otm->otmpFamilyName)).toLatin1();
    1041     p.postscriptName += QString::fromWCharArray((wchar_t *)((char *)otm + (int)otm->otmpStyleName)).toLatin1();
    1042 #ifndef QT_NO_PRINTER
    1043     p.postscriptName = QPdf::stripSpecialCharacters(p.postscriptName);
    1044 #endif
     1039    p.postscriptName = QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpFamilyName)).toLatin1();
     1040    p.postscriptName += QString::fromWCharArray((wchar_t *)((char *)otm + (quintptr)otm->otmpStyleName)).toLatin1();
     1041    p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(p.postscriptName);
    10451042    p.boundingBox = QRectF(otm->otmrcFontBox.left, -otm->otmrcFontBox.top,
    10461043                           otm->otmrcFontBox.right - otm->otmrcFontBox.left,
     
    12131210    QImage indexed(mask->width(), mask->height(), QImage::Format_Indexed8);
    12141211
    1215     // ### This part is kinda pointless, but we'll crash later if we dont because some
     1212    // ### This part is kinda pointless, but we'll crash later if we don't because some
    12161213    // code paths expects there to be colortables for index8-bit...
    12171214    QVector<QRgb> colors(256);
     
    12971294    first->ref.ref();
    12981295    fontDef = engines[0]->fontDef;
     1296    cache_cost = first->cache_cost;
    12991297}
    13001298
     
    13181316    engines[at]->ref.ref();
    13191317    engines[at]->fontDef = fontDef;
     1318
     1319    // TODO: increase cost in QFontCache for the font engine loaded here
    13201320}
    13211321
  • trunk/src/gui/text/qfontengine_win_p.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qfontengine_x11.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    430430    int i = glyphs->numGlyphs;
    431431    XCharStruct *xcs;
    432     // inlined for better perfomance
     432    // inlined for better performance
    433433    if (!_fs->per_char) {
    434434        xcs = &_fs->min_bounds;
  • trunk/src/gui/text/qfontengine_x11_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qfontengineglyphcache_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qfontinfo.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qfontmetrics.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    329329    QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
    330330    Q_ASSERT(engine != 0);
    331     return qRound(engine->ascent() + engine->descent()) + 1;
     331    return qRound(engine->ascent()) + qRound(engine->descent()) + 1;
    332332}
    333333
     
    357357    QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
    358358    Q_ASSERT(engine != 0);
    359     return qRound(engine->leading() + engine->ascent() + engine->descent()) + 1;
     359    return qRound(engine->leading()) + qRound(engine->ascent()) + qRound(engine->descent()) + 1;
    360360}
    361361
     
    526526*/
    527527int QFontMetrics::width(const QString &text, int len) const
     528{
     529    return width(text, len, 0);
     530}
     531
     532/*!
     533    \internal
     534*/
     535int QFontMetrics::width(const QString &text, int len, int flags) const
    528536{
    529537    int pos = text.indexOf(QLatin1Char('\x9c'));
     
    536544        return 0;
    537545
    538     QTextEngine layout(text, d.data());
     546    if (flags & Qt::TextBypassShaping) {
     547        // Skip harfbuzz complex shaping, only use advances
     548        int numGlyphs = len;
     549        QVarLengthGlyphLayoutArray glyphs(numGlyphs);
     550        QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
     551        if (!engine->stringToCMap(text.data(), len, &glyphs, &numGlyphs, 0)) {
     552            glyphs.resize(numGlyphs);
     553            if (!engine->stringToCMap(text.data(), len, &glyphs, &numGlyphs, 0))
     554                Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice");
     555        }
     556
     557        QFixed width;
     558        for (int i = 0; i < numGlyphs; ++i)
     559            width += glyphs.advances_x[i];
     560        return qRound(width);
     561    }
     562
     563    QStackTextEngine layout(text, d.data());
    539564    layout.ignoreBidi = true;
    540565    return qRound(layout.width(0, len));
     
    612637        int to = qMin(text.length(), pos + 8);
    613638        QString cstr = QString::fromRawData(text.unicode() + from, to - from);
    614         QTextEngine layout(cstr, d.data());
     639        QStackTextEngine layout(cstr, d.data());
    615640        layout.ignoreBidi = true;
    616641        layout.itemize();
     
    661686        return QRect();
    662687
    663     QTextEngine layout(text, d.data());
     688    QStackTextEngine layout(text, d.data());
    664689    layout.ignoreBidi = true;
    665690    layout.itemize();
     
    831856        return QRect();
    832857
    833     QTextEngine layout(text, d.data());
     858    QStackTextEngine layout(text, d.data());
    834859    layout.ignoreBidi = true;
    835860    layout.itemize();
     
    13761401    int len = (pos != -1) ? pos : text.length();
    13771402
    1378     QTextEngine layout(text, d.data());
     1403    QStackTextEngine layout(text, d.data());
    13791404    layout.ignoreBidi = true;
    13801405    layout.itemize();
     
    14531478        return QRectF();
    14541479
    1455     QTextEngine layout(text, d.data());
     1480    QStackTextEngine layout(text, d.data());
    14561481    layout.ignoreBidi = true;
    14571482    layout.itemize();
     
    16261651        return QRect();
    16271652
    1628     QTextEngine layout(text, d.data());
     1653    QStackTextEngine layout(text, d.data());
    16291654    layout.ignoreBidi = true;
    16301655    layout.itemize();
  • trunk/src/gui/text/qfontmetrics.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    9090    int rightBearing(QChar) const;
    9191    int width(const QString &, int len = -1) const;
     92    int width(const QString &, int len, int flags) const;
    9293
    9394    int width(QChar) const;
  • trunk/src/gui/text/qfontsubset.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    698698// Bit 11: Font data is 'lossless,' as a result of having been compressed and decompressed with the Agfa MicroType Express engine.
    699699// Bit 12: Font converted (produce compatible metrics)
    700 // Bit 13: Font optimised for ClearType
     700// Bit 13: Font optimized for ClearType
    701701// Bit 14: Reserved, set to 0
    702702// Bit 15: Reserved, set to 0
     
    10091009                    np.y = (i1_y + i2_y) >> 1;
    10101010                    if (try_reduce) {
    1011                         // see if we can optimise out the last onCurve point
     1011                        // see if we can optimize out the last onCurve point
    10121012                        int mx = (points->at(points->size() - 2).x + base[2].x) >> 1;
    10131013                        int my = (points->at(points->size() - 2).y + base[2].y) >> 1;
  • trunk/src/gui/text/qfontsubset_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qfragmentmap.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qfragmentmap_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qpfutil.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qsyntaxhighlighter.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    6060    Q_DECLARE_PUBLIC(QSyntaxHighlighter)
    6161public:
    62     inline QSyntaxHighlighterPrivate() : rehighlightPending(false) {}
     62    inline QSyntaxHighlighterPrivate()
     63        : rehighlightPending(false), inReformatBlocks(false)
     64    {}
    6365
    6466    QPointer<QTextDocument> doc;
    6567
    6668    void _q_reformatBlocks(int from, int charsRemoved, int charsAdded);
    67     void reformatBlock(QTextBlock block);
    68    
     69    void reformatBlocks(int from, int charsRemoved, int charsAdded);
     70    void reformatBlock(const QTextBlock &block);
     71
    6972    inline void rehighlight(QTextCursor &cursor, QTextCursor::MoveOperation operation) {
    70         QObject::disconnect(doc, SIGNAL(contentsChange(int,int,int)),
    71                             q_func(), SLOT(_q_reformatBlocks(int,int,int)));
     73        inReformatBlocks = true;
    7274        cursor.beginEditBlock();
    7375        int from = cursor.position();
    7476        cursor.movePosition(operation);
    75         _q_reformatBlocks(from, 0, cursor.position() - from);
     77        reformatBlocks(from, 0, cursor.position() - from);
    7678        cursor.endEditBlock();
    77         QObject::connect(doc, SIGNAL(contentsChange(int,int,int)),
    78                          q_func(), SLOT(_q_reformatBlocks(int,int,int)));
     79        inReformatBlocks = false;
    7980    }
    8081
     
    8485        rehighlightPending = false;
    8586        q_func()->rehighlight();
    86         return;
    8787    }
    8888
     
    9191    QTextBlock currentBlock;
    9292    bool rehighlightPending;
     93    bool inReformatBlocks;
    9394};
    9495
    9596void QSyntaxHighlighterPrivate::applyFormatChanges()
    9697{
     98    bool formatsChanged = false;
     99
    97100    QTextLayout *layout = currentBlock.layout();
    98101
     
    102105    const int preeditAreaLength = layout->preeditAreaText().length();
    103106
    104     QList<QTextLayout::FormatRange>::Iterator it = ranges.begin();
    105     while (it != ranges.end()) {
    106         if (it->start >= preeditAreaStart
    107             && it->start + it->length <= preeditAreaStart + preeditAreaLength)
    108             ++it;
    109         else
    110             it = ranges.erase(it);
     107    if (preeditAreaLength != 0) {
     108        QList<QTextLayout::FormatRange>::Iterator it = ranges.begin();
     109        while (it != ranges.end()) {
     110            if (it->start >= preeditAreaStart
     111                && it->start + it->length <= preeditAreaStart + preeditAreaLength) {
     112                ++it;
     113            } else {
     114                it = ranges.erase(it);
     115                formatsChanged = true;
     116            }
     117        }
     118    } else if (!ranges.isEmpty()) {
     119        ranges.clear();
     120        formatsChanged = true;
    111121    }
    112122
     
    114124
    115125    QTextLayout::FormatRange r;
    116     r.start = r.length = -1;
     126    r.start = -1;
    117127
    118128    int i = 0;
     
    136146        r.length = i - r.start;
    137147
    138         if (r.start >= preeditAreaStart) {
    139             r.start += preeditAreaLength;
    140         } else if (r.start + r.length >= preeditAreaStart) {
    141             r.length += preeditAreaLength;
     148        if (preeditAreaLength != 0) {
     149            if (r.start >= preeditAreaStart)
     150                r.start += preeditAreaLength;
     151            else if (r.start + r.length >= preeditAreaStart)
     152                r.length += preeditAreaLength;
    142153        }
    143154
    144155        ranges << r;
    145         r.start = r.length = -1;
     156        formatsChanged = true;
     157        r.start = -1;
    146158    }
    147159
     
    149161        r.length = formatChanges.count() - r.start;
    150162
    151         if (r.start >= preeditAreaStart) {
    152             r.start += preeditAreaLength;
    153         } else if (r.start + r.length >= preeditAreaStart) {
    154             r.length += preeditAreaLength;
     163        if (preeditAreaLength != 0) {
     164            if (r.start >= preeditAreaStart)
     165                r.start += preeditAreaLength;
     166            else if (r.start + r.length >= preeditAreaStart)
     167                r.length += preeditAreaLength;
    155168        }
    156169
    157170        ranges << r;
    158     }
    159 
    160     layout->setAdditionalFormats(ranges);
     171        formatsChanged = true;
     172    }
     173
     174    if (formatsChanged) {
     175        layout->setAdditionalFormats(ranges);
     176        doc->markContentsDirty(currentBlock.position(), currentBlock.length());
     177    }
    161178}
    162179
    163180void QSyntaxHighlighterPrivate::_q_reformatBlocks(int from, int charsRemoved, int charsAdded)
    164181{
    165     Q_UNUSED(charsRemoved);
     182    if (!inReformatBlocks)
     183        reformatBlocks(from, charsRemoved, charsAdded);
     184}
     185
     186void QSyntaxHighlighterPrivate::reformatBlocks(int from, int charsRemoved, int charsAdded)
     187{
    166188    rehighlightPending = false;
    167189
     
    192214}
    193215
    194 void QSyntaxHighlighterPrivate::reformatBlock(QTextBlock block)
     216void QSyntaxHighlighterPrivate::reformatBlock(const QTextBlock &block)
    195217{
    196218    Q_Q(QSyntaxHighlighter);
     
    199221
    200222    currentBlock = block;
    201     QTextBlock previous = block.previous();
    202223
    203224    formatChanges.fill(QTextCharFormat(), block.length() - 1);
    204225    q->highlightBlock(block.text());
    205226    applyFormatChanges();
    206 
    207     doc->markContentsDirty(block.position(), block.length());
    208227
    209228    currentBlock = QTextBlock();
     
    350369        connect(d->doc, SIGNAL(contentsChange(int,int,int)),
    351370                this, SLOT(_q_reformatBlocks(int,int,int)));
     371        d->rehighlightPending = true;
    352372        QTimer::singleShot(0, this, SLOT(_q_delayedRehighlight()));
    353         d->rehighlightPending = true;
    354373    }
    355374}
     
    392411{
    393412    Q_D(QSyntaxHighlighter);
    394     if (!d->doc)
     413    if (!d->doc || !block.isValid() || block.document() != d->doc)
    395414        return;
     415
     416    const bool rehighlightPending = d->rehighlightPending;
    396417
    397418    QTextCursor cursor(block);
    398419    d->rehighlight(cursor, QTextCursor::EndOfBlock);
     420
     421    if (rehighlightPending)
     422        d->rehighlightPending = rehighlightPending;
    399423}
    400424
     
    461485{
    462486    Q_D(QSyntaxHighlighter);
    463 
    464487    if (start < 0 || start >= d->formatChanges.count())
    465488        return;
     
    629652
    630653    Returns the current text block.
    631  */
     654*/
    632655QTextBlock QSyntaxHighlighter::currentBlock() const
    633656{
  • trunk/src/gui/text/qsyntaxhighlighter.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qtextcontrol.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    9292
    9393#ifndef QT_NO_CONTEXTMENU
    94 #if defined(Q_WS_WIN)
     94#if defined(Q_WS_WIN) || defined(Q_WS_X11)
    9595extern bool qt_use_rtl_extensions;
    9696#endif
     
    405405    setContent(format, text, document);
    406406
    407     QWidget *parentWidget = qobject_cast<QWidget*>(parent);
    408     if (parentWidget) {
    409         QTextOption opt = doc->defaultTextOption();
    410         opt.setTextDirection(parentWidget->layoutDirection());
    411         doc->setDefaultTextOption(opt);
    412     }
    413407    doc->setUndoRedoEnabled(interactionFlags & Qt::TextEditable);
    414408    q->setCursorWidth(-1);
     
    442436
    443437        // convenience signal forwards
    444         QObject::connect(doc, SIGNAL(contentsChanged()), q, SIGNAL(textChanged()));
    445438        QObject::connect(doc, SIGNAL(undoAvailable(bool)), q, SIGNAL(undoAvailable(bool)));
    446439        QObject::connect(doc, SIGNAL(redoAvailable(bool)), q, SIGNAL(redoAvailable(bool)));
     
    453446        doc->setUndoRedoEnabled(false);
    454447
     448    //Saving the index save some time.
     449    static int contentsChangedIndex = QTextDocument::staticMetaObject.indexOfSignal("contentsChanged()");
     450    static int textChangedIndex = QTextControl::staticMetaObject.indexOfSignal("textChanged()");
    455451    // avoid multiple textChanged() signals being emitted
    456     QObject::disconnect(doc, SIGNAL(contentsChanged()), q, SIGNAL(textChanged()));
     452    QMetaObject::disconnect(doc, contentsChangedIndex, q, textChangedIndex);
    457453
    458454    if (!text.isEmpty()) {
     
    489485    cursor.setCharFormat(charFormatForInsertion);
    490486
    491     QObject::connect(doc, SIGNAL(contentsChanged()), q, SIGNAL(textChanged()));
     487    QMetaObject::connect(doc, contentsChangedIndex, q, textChangedIndex);
    492488    emit q->textChanged();
    493489    if (!document)
     
    746742    Q_D(QTextControl);
    747743    d->repaintSelection();
     744    const int oldCursorPos = d->cursor.position();
    748745    d->doc->undo(&d->cursor);
     746    if (d->cursor.position() != oldCursorPos)
     747        emit cursorPositionChanged();
     748    emit microFocusChanged();
    749749    ensureCursorVisible();
    750750}
     
    754754    Q_D(QTextControl);
    755755    d->repaintSelection();
     756    const int oldCursorPos = d->cursor.position();
    756757    d->doc->redo(&d->cursor);
     758        if (d->cursor.position() != oldCursorPos)
     759        emit cursorPositionChanged();
     760    emit microFocusChanged();
    757761    ensureCursorVisible();
    758762}
     
    847851}
    848852
    849 void QTextControl::paste()
    850 {
    851     const QMimeData *md = QApplication::clipboard()->mimeData();
     853void QTextControl::paste(QClipboard::Mode mode)
     854{
     855    const QMimeData *md = QApplication::clipboard()->mimeData(mode);
    852856    if (md)
    853857        insertFromMimeData(md);
     
    884888{
    885889    Q_D(QTextControl);
    886     if (d->interactionFlags & Qt::NoTextInteraction)
    887         return;
     890    if (d->interactionFlags == Qt::NoTextInteraction) {
     891        e->ignore();
     892        return;
     893    }
    888894
    889895    d->contextWidget = contextWidget;
     
    10901096            }
    10911097            break;
    1092         case QEvent::LayoutDirectionChange: {
    1093             if (contextWidget) {
    1094                 QTextOption opt = document()->defaultTextOption();
    1095                 opt.setTextDirection(contextWidget->layoutDirection());
    1096                 document()->setDefaultTextOption(opt);
    1097             }
    1098         }
    1099             // FALL THROUGH
    11001098        default:
    11011099            break;
     
    12301228    }
    12311229    else if (e == QKeySequence::Paste) {
    1232            q->paste();
     1230        QClipboard::Mode mode = QClipboard::Clipboard;
     1231#ifdef Q_WS_X11
     1232        if (e->modifiers() == (Qt::CTRL | Qt::SHIFT) && e->key() == Qt::Key_Insert)
     1233            mode = QClipboard::Selection;
     1234#endif
     1235        q->paste(mode);
    12331236    }
    12341237#endif
     
    17651768    if (!menu)
    17661769        return;
    1767     menu->exec(screenPos);
    1768     delete menu;
     1770    menu->setAttribute(Qt::WA_DeleteOnClose);
     1771    menu->popup(screenPos);
    17691772#endif
    17701773}
     
    20762079#endif
    20772080
    2078 #if defined(Q_WS_WIN)
     2081#if defined(Q_WS_WIN) || defined(Q_WS_X11)
    20792082    if ((d->interactionFlags & Qt::TextEditable) && qt_use_rtl_extensions) {
    20802083#else
  • trunk/src/gui/text/qtextcontrol_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    6363#include <QtGui/qabstracttextdocumentlayout.h>
    6464#include <QtGui/qtextdocumentfragment.h>
     65#include <QtGui/qclipboard.h>
    6566
    6667#ifdef QT3_SUPPORT
     
    192193    void cut();
    193194    void copy();
    194     void paste();
     195    void paste(QClipboard::Mode mode = QClipboard::Clipboard);
    195196#endif
    196197
  • trunk/src/gui/text/qtextcontrol_p_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qtextcursor.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    6565QTextCursorPrivate::QTextCursorPrivate(QTextDocumentPrivate *p)
    6666    : priv(p), x(0), position(0), anchor(0), adjusted_anchor(0),
    67       currentCharFormat(-1), visualNavigation(false)
     67      currentCharFormat(-1), visualNavigation(false), keepPositionOnInsert(false),
     68      changed(false)
    6869{
    6970    priv->addCursor(this);
     
    8081    currentCharFormat = rhs.currentCharFormat;
    8182    visualNavigation = rhs.visualNavigation;
     83    keepPositionOnInsert = rhs.keepPositionOnInsert;
     84    changed = rhs.changed;
    8285    priv->addCursor(this);
    8386}
     
    9699        || (position == positionOfChange
    97100            && (op == QTextUndoCommand::KeepCursor
    98                 || anchor < position)
     101                || keepPositionOnInsert)
    99102            )
    100103         ) {
     
    361364    QTextBlock blockIt = block();
    362365
     366    if (!blockIt.isValid())
     367        return false;
     368
    363369    if (op >= QTextCursor::Left && op <= QTextCursor::WordRight
    364         && blockIt.blockFormat().layoutDirection() == Qt::RightToLeft) {
     370        && blockIt.textDirection() == Qt::RightToLeft) {
    365371        if (op == QTextCursor::Left)
    366372            op = QTextCursor::NextCharacter;
     
    11461152    The cursor is positioned between characters.
    11471153
    1148     \sa setPosition() movePosition() anchor()
     1154    \sa setPosition() movePosition() anchor() positionInBlock()
    11491155*/
    11501156int QTextCursor::position() const
     
    11531159        return -1;
    11541160    return d->position;
     1161}
     1162
     1163/*!
     1164    \since 4.7
     1165    Returns the relative position of the cursor within the block.
     1166    The cursor is positioned between characters.
     1167
     1168    This is equivalent to \c{ position() - block().position()}.
     1169
     1170    \sa position()
     1171*/
     1172int QTextCursor::positionInBlock() const
     1173{
     1174    if (!d || !d->priv)
     1175        return 0;
     1176    return d->position - d->block().position();
    11551177}
    11561178
     
    12611283}
    12621284
     1285
     1286/*!
     1287  \since 4.7
     1288
     1289  Sets the visual x position for vertical cursor movements to \a x.
     1290
     1291  The vertical movement x position is cleared automatically when the cursor moves horizontally, and kept
     1292  unchanged when the cursor moves vertically. The mechanism allows the cursor to move up and down on a
     1293  visually straight line with proportional fonts, and to gently "jump" over short lines.
     1294
     1295  A value of -1 indicates no predefined x position. It will then be set automatically the next time the
     1296  cursor moves up or down.
     1297
     1298  \sa verticalMovementX()
     1299  */
     1300void QTextCursor::setVerticalMovementX(int x)
     1301{
     1302    if (d)
     1303        d->x = x;
     1304}
     1305
     1306/*! \since 4.7
     1307
     1308  Returns the visual x position for vertical cursor movements.
     1309
     1310  A value of -1 indicates no predefined x position. It will then be set automatically the next time the
     1311  cursor moves up or down.
     1312
     1313  \sa setVerticalMovementX()
     1314  */
     1315int QTextCursor::verticalMovementX() const
     1316{
     1317    return d ? d->x : -1;
     1318}
     1319
     1320/*!
     1321  \since 4.7
     1322
     1323  Returns whether the cursor should keep its current position when text gets inserted at the position of the
     1324  cursor.
     1325
     1326  The default is false;
     1327
     1328  \sa setKeepPositionOnInsert()
     1329 */
     1330bool QTextCursor::keepPositionOnInsert() const
     1331{
     1332    return d ? d->keepPositionOnInsert : false;
     1333}
     1334
     1335/*!
     1336  \since 4.7
     1337
     1338  Defines whether the cursor should keep its current position when text gets inserted at the current position of the
     1339  cursor.
     1340
     1341  If \a b is true, the cursor keeps its current position when text gets inserted at the positing of the cursor.
     1342  If \a b is false, the cursor moves along with the inserted text.
     1343
     1344  The default is false.
     1345
     1346  Note that a cursor always moves when text is inserted before the current position of the cursor, and it
     1347  always keeps its position when text is inserted after the current position of the cursor.
     1348
     1349  \sa keepPositionOnInsert()
     1350 */
     1351void QTextCursor::setKeepPositionOnInsert(bool b)
     1352{
     1353    if (d)
     1354        d->keepPositionOnInsert = b;
     1355}
     1356
     1357
     1358
    12631359/*!
    12641360    Inserts \a text at the current position, using the current
     
    13931489    if (!d || !d->priv)
    13941490        return;
    1395    
     1491
    13961492    if (d->position != d->anchor) {
    13971493        removeSelectedText();
    13981494        return;
    13991495    }
    1400    
     1496
    14011497    if (d->anchor < 1 || !d->canDelete(d->anchor-1))
    14021498        return;
    14031499    d->anchor--;
    1404    
     1500
    14051501    QTextDocumentPrivate::FragmentIterator fragIt = d->priv->find(d->anchor);
    14061502    const QTextFragmentData * const frag = fragIt.value();
     
    14141510            --d->anchor;
    14151511    }
    1416    
     1512
    14171513    d->adjusted_anchor = d->anchor;
    14181514    d->remove();
     
    23472443        return;
    23482444
     2445    if (d->priv->editBlock == 0) // we are the initial edit block, store current cursor position for undo
     2446        d->priv->editBlockCursorPosition = d->position;
     2447
    23492448    d->priv->beginEditBlock();
    23502449}
     
    24152514}
    24162515
     2516
    24172517/*!
    24182518    \since 4.2
    24192519    Returns the position of the cursor within its containing line.
     2520
     2521    Note that this is the column number relative to a wrapped line,
     2522    not relative to the block (i.e. the paragraph).
     2523
     2524    You probably want to call positionInBlock() instead.
     2525
     2526    \sa positionInBlock()
    24202527*/
    24212528int QTextCursor::columnNumber() const
  • trunk/src/gui/text/qtextcursor.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    9090    void setPosition(int pos, MoveMode mode = MoveAnchor);
    9191    int position() const;
     92    int positionInBlock() const;
    9293
    9394    int anchor() const;
     
    132133    void setVisualNavigation(bool b);
    133134
     135    void setVerticalMovementX(int x);
     136    int verticalMovementX() const;
     137
     138    void setKeepPositionOnInsert(bool b);
     139    bool keepPositionOnInsert() const;
     140
    134141    void deleteChar();
    135142    void deletePreviousChar();
  • trunk/src/gui/text/qtextcursor_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    113113    int adjusted_anchor;
    114114    int currentCharFormat;
    115     bool visualNavigation;
     115    uint visualNavigation : 1;
     116    uint keepPositionOnInsert : 1;
     117    uint changed : 1;
    116118};
    117119
  • trunk/src/gui/text/qtextdocument.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    6262#include "qtextcontrol_p.h"
    6363#include "private/qtextedit_p.h"
     64#include "private/qdataurl_p.h"
    6465
    6566#include "qtextdocument_p.h"
     
    126127                    tag += text[i];
    127128                else if (!tag.isEmpty() && text[i].isSpace())
     129                    break;
     130                else if (!tag.isEmpty() && text[i] == QLatin1Char('/') && i + 1 == close)
    128131                    break;
    129132                else if (!text[i].isSpace() && (!tag.isEmpty() || text[i] != QLatin1Char('!')))
     
    289292    provides contentsChanged(), undoAvailable(), and redoAvailable() signals
    290293    that inform connected editor widgets about the state of the undo/redo
    291     system.
     294    system. The following are the undo/redo operations of a QTextDocument:
     295
     296    \list
     297        \o Insertion or removal of characters. A sequence of insertions or removals
     298           within the same text block are regarded as a single undo/redo operation.
     299        \o Insertion or removal of text blocks. Sequences of insertion or removals
     300           in a single operation (e.g., by selecting and then deleting text) are
     301           regarded as a single undo/redo operation.
     302        \o Text character format changes.
     303        \o Text block format changes.
     304        \o Text block group format changes.
     305    \endlist
    292306
    293307    \sa QTextCursor, QTextEdit, \link richtext.html Rich Text Processing\endlink , {Text Object Example}
     
    435449}
    436450
     451/*! \enum QTextDocument::Stacks
     452 
     453  \value UndoStack              The undo stack.
     454  \value RedoStack              The redo stack.
     455  \value UndoAndRedoStacks      Both the undo and redo stacks.
     456*/
     457       
     458/*!
     459    \since 4.7
     460    Clears the stacks specified by \a stacksToClear.
     461
     462    This method clears any commands on the undo stack, the redo stack,
     463    or both (the default). If commands are cleared, the appropriate
     464    signals are emitted, QTextDocument::undoAvailable() or
     465    QTextDocument::redoAvailable().
     466
     467    \sa QTextDocument::undoAvailable() QTextDocument::redoAvailable()
     468*/
     469void QTextDocument::clearUndoRedoStacks(Stacks stacksToClear)
     470{
     471    Q_D(QTextDocument);
     472    d->clearUndoRedoStacks(stacksToClear, true);
     473}
     474
    437475/*!
    438476    \overload
     
    557595{
    558596    Q_D(QTextDocument);
    559     if (!d->inContentsChange)
    560         d->beginEditBlock();
    561597    d->documentChange(from, length);
    562     if (!d->inContentsChange)
    563         d->endEditBlock();
     598    if (!d->inContentsChange) {
     599        if (d->lout) {
     600            d->lout->documentChanged(d->docChangeFrom, d->docChangeOldLength, d->docChangeLength);
     601            d->docChangeFrom = -1;
     602        }
     603    }
    564604}
    565605
     
    17501790    if (printer->collateCopies() == true){
    17511791        docCopies = 1;
    1752         pageCopies = printer->numCopies();
     1792        pageCopies = printer->supportsMultipleCopies() ? 1 : printer->copyCount();
    17531793    } else {
    1754         docCopies = printer->numCopies();
     1794        docCopies = printer->supportsMultipleCopies() ? 1 : printer->copyCount();
    17551795        pageCopies = 1;
    17561796    }
     
    19211961    }
    19221962#endif
     1963
     1964    // handle data: URLs
     1965    if (r.isNull() && name.scheme().compare(QLatin1String("data"), Qt::CaseInsensitive) == 0)
     1966        r = qDecodeDataUrl(name).second;
    19231967
    19241968    // if resource was not loaded try to load it here
     
    24682512    emitAlignment(format.alignment());
    24692513
    2470     Qt::LayoutDirection dir = format.layoutDirection();
    2471     if (dir == Qt::LeftToRight) {
    2472         // assume default to not bloat the html too much
    2473         // html += QLatin1String(" dir='ltr'");
    2474     } else {
     2514    // assume default to not bloat the html too much
     2515    // html += QLatin1String(" dir='ltr'");
     2516    if (block.textDirection() == Qt::RightToLeft)
    24752517        html += QLatin1String(" dir='rtl'");
    2476     }
    24772518
    24782519    QLatin1String style(" style=\"");
  • trunk/src/gui/text/qtextdocument.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    257257    void redo(QTextCursor *cursor);
    258258
     259    enum Stacks {
     260        UndoStack = 0x01,
     261        RedoStack = 0x02,
     262        UndoAndRedoStacks = UndoStack | RedoStack
     263    };
     264    void clearUndoRedoStacks(Stacks historyToClear = UndoAndRedoStacks);
     265
    259266    int maximumBlockCount() const;
    260267    void setMaximumBlockCount(int maximum);
  • trunk/src/gui/text/qtextdocument_p.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    6464#if !defined(Q_CC_DIAB)
    6565#  define QT_INIT_TEXTUNDOCOMMAND(c, a1, a2, a3, a4, a5, a6, a7, a8) \
    66           QTextUndoCommand c = { a1, a2, 0, 0, a3, a4, a5, a6, { a7 }, a8 }
     66          QTextUndoCommand c = { a1, a2, 0, 0, quint8(a3), a4, a5, a6, { a7 }, a8 }
    6767#else
    6868#  define QT_INIT_TEXTUNDOCOMMAND(c, a1, a2, a3, a4, a5, a6, a7, a8) \
     
    9292
    9393  Lists are not in here, as they are treated specially. A list is just
    94   a collection of (not neccessarily connected) blocks, that share the
     94  a collection of (not necessarily connected) blocks, that share the
    9595  same objectIndex() in the format that refers to the list format and
    9696  object.
     
    193193{
    194194    editBlock = 0;
     195    editBlockCursorPosition = -1;
    195196    docChangeFrom = -1;
    196197
     
    205206    undoEnabled = true;
    206207    inContentsChange = false;
     208    blockCursorAdjustment = false;
    207209
    208210    defaultTextOption.setTabStop(80); // same as in qtextengine.cpp
     
    234236{
    235237    Q_Q(QTextDocument);
    236     for (int i = 0; i < cursors.count(); ++i) {
    237         cursors.at(i)->setPosition(0);
    238         cursors.at(i)->currentCharFormat = -1;
    239         cursors.at(i)->anchor = 0;
    240         cursors.at(i)->adjusted_anchor = 0;
     238
     239    foreach (QTextCursorPrivate *curs, cursors) {
     240        curs->setPosition(0);
     241        curs->currentCharFormat = -1;
     242        curs->anchor = 0;
     243        curs->adjusted_anchor = 0;
    241244    }
    242245
     
    244247    QT_TRY{
    245248        cursors.clear();
    246         changedCursors.clear();
    247249
    248250        QMap<int, QTextObject *>::Iterator objectIt = objects.begin();
     
    260262
    261263        title.clear();
    262         undoState = 0;
    263         truncateUndoStack();
     264        clearUndoRedoStacks(QTextDocument::UndoAndRedoStacks);
    264265        text = QString();
    265266        unreachableCharacterCount = 0;
     
    288289QTextDocumentPrivate::~QTextDocumentPrivate()
    289290{
    290     for (int i = 0; i < cursors.count(); ++i)
    291         cursors.at(i)->priv = 0;
     291    foreach (QTextCursorPrivate *curs, cursors)
     292        curs->priv = 0;
    292293    cursors.clear();
    293294    undoState = 0;
    294295    undoEnabled = true;
    295     truncateUndoStack();
     296    clearUndoRedoStacks(QTextDocument::RedoStack);
    296297}
    297298
     
    320321void QTextDocumentPrivate::insert_string(int pos, uint strPos, uint length, int format, QTextUndoCommand::Operation op)
    321322{
    322     // ##### optimise when only appending to the fragment!
     323    // ##### optimize when only appending to the fragment!
    323324    Q_ASSERT(noBlockInString(text.mid(strPos, length)));
    324325
     
    663664    Q_ASSERT(blocks.length() == fragments.length());
    664665
    665     finishEdit();
     666    if (!blockCursorAdjustment)
     667        finishEdit();
    666668}
    667669
     
    670672    if (length == 0)
    671673        return;
     674    blockCursorAdjustment = true;
    672675    move(pos, -1, length, op);
     676    blockCursorAdjustment = false;
     677    foreach (QTextCursorPrivate *curs, cursors) {
     678        if (curs->adjustPosition(pos, -length, op) == QTextCursorPrivate::CursorMoved) {
     679            curs->changed = true;
     680        }
     681    }
     682    finishEdit();
    673683}
    674684
     
    872882    beginEditBlock();
    873883    int editPos = -1;
     884    int editLength = -1;
    874885    while (1) {
    875886        if (undo)
     
    884895            c.command = QTextUndoCommand::Removed;
    885896            editPos = c.pos;
     897            editLength = 0;
    886898            break;
    887899        case QTextUndoCommand::Removed:
     
    889901            insert_string(c.pos, c.strPos, c.length, c.format, (QTextUndoCommand::Operation)c.operation);
    890902            c.command = QTextUndoCommand::Inserted;
    891             editPos = c.pos + c.length;
     903            if (editPos != (int)c.pos)
     904                editLength = 0;
     905            editPos = c.pos;
     906            editLength += c.length;
    892907            break;
    893908        case QTextUndoCommand::BlockInserted:
     
    900915                c.command = QTextUndoCommand::BlockDeleted;
    901916            editPos = c.pos;
     917            editLength = 0;
    902918            break;
    903919        case QTextUndoCommand::BlockRemoved:
     
    910926            else
    911927                c.command = QTextUndoCommand::BlockAdded;
    912             editPos = c.pos + 1;
     928            if (editPos != (int)c.pos)
     929                editLength = 0;
     930            editPos = c.pos;
     931            editLength += 1;
    913932            break;
    914933        case QTextUndoCommand::CharFormatChanged: {
     
    921940            setCharFormat(c.pos, c.length, formats.charFormat(c.format));
    922941            c.format = oldFormat;
    923             editPos = c.pos + c.length;
     942            if (editPos != (int)c.pos)
     943                editLength = 0;
     944            editPos = c.pos;
     945            editLength += c.length;
    924946            break;
    925947        }
     
    957979            break;
    958980        }
     981        case QTextUndoCommand::CursorMoved:
     982            editPos = c.pos;
     983            editLength = 0;
     984            break;
    959985        case QTextUndoCommand::Custom:
    960986            resetBlockRevision = -1; // ## TODO
     
    9891015    }
    9901016    undoEnabled = true;
    991     if (editPos < 0 && docChangeFrom >= 0) {
    992         editPos = qMin(docChangeFrom + docChangeLength, length() - 1);
    993     }
     1017
     1018    int newCursorPos = -1;
     1019
     1020    if (editPos >=0)
     1021        newCursorPos = editPos + editLength;
     1022    else if (docChangeFrom >= 0)
     1023        newCursorPos= qMin(docChangeFrom + docChangeLength, length() - 1);
     1024
    9941025    endEditBlock();
    9951026    emitUndoAvailable(isUndoAvailable());
    9961027    emitRedoAvailable(isRedoAvailable());
    997     return editPos;
     1028
     1029    return newCursorPos;
    9981030}
    9991031
     
    10281060        return;
    10291061    if (undoState < undoStack.size())
    1030         truncateUndoStack();
     1062        clearUndoRedoStacks(QTextDocument::RedoStack);
     1063
     1064    if (editBlock != 0 && editBlockCursorPosition >= 0) { // we had a beginEditBlock() with a cursor position
     1065        if (c.pos != (quint32) editBlockCursorPosition) { // and that cursor position is different from the command
     1066            // generate a CursorMoved undo item
     1067            QT_INIT_TEXTUNDOCOMMAND(cc, QTextUndoCommand::CursorMoved, true, QTextUndoCommand::MoveCursor,
     1068                                    0, 0, editBlockCursorPosition, 0, 0);
     1069            undoStack.append(cc);
     1070            undoState++;
     1071            editBlockCursorPosition = -1;
     1072        }
     1073    }
     1074
    10311075
    10321076    if (!undoStack.isEmpty() && modified) {
     
    10511095}
    10521096
    1053 void QTextDocumentPrivate::truncateUndoStack()
    1054 {
    1055     if (undoState == undoStack.size())
    1056         return;
    1057 
    1058     for (int i = undoState; i < undoStack.size(); ++i) {
    1059         QTextUndoCommand c = undoStack[i];
    1060         if (c.command & QTextUndoCommand::Removed) {
    1061             // ########
    1062 //             QTextFragment *f = c.fragment_list;
    1063 //             while (f) {
    1064 //                 QTextFragment *n = f->right;
    1065 //                 delete f;
    1066 //                 f = n;
    1067 //             }
    1068         } else if (c.command & QTextUndoCommand::Custom) {
    1069             delete c.custom;
    1070         }
    1071     }
    1072     undoStack.resize(undoState);
     1097void QTextDocumentPrivate::clearUndoRedoStacks(QTextDocument::Stacks stacksToClear,
     1098                                               bool emitSignals)
     1099{
     1100    bool undoCommandsAvailable = undoState != 0;
     1101    bool redoCommandsAvailable = undoState != undoStack.size();
     1102    if (stacksToClear == QTextDocument::UndoStack && undoCommandsAvailable) {
     1103        for (int i = 0; i < undoState; ++i) {
     1104            QTextUndoCommand c = undoStack[undoState];
     1105            if (c.command & QTextUndoCommand::Custom)
     1106                delete c.custom;
     1107        }
     1108        undoStack.remove(0, undoState);
     1109        undoStack.resize(undoStack.size() - undoState);
     1110        undoState = 0;
     1111        if (emitSignals)
     1112            emitUndoAvailable(false);
     1113    } else if (stacksToClear == QTextDocument::RedoStack
     1114               && redoCommandsAvailable) {
     1115        for (int i = undoState; i < undoStack.size(); ++i) {
     1116            QTextUndoCommand c = undoStack[i];
     1117            if (c.command & QTextUndoCommand::Custom)
     1118                delete c.custom;
     1119        }
     1120        undoStack.resize(undoState);
     1121        if (emitSignals)
     1122            emitRedoAvailable(false);
     1123    } else if (stacksToClear == QTextDocument::UndoAndRedoStacks
     1124               && !undoStack.isEmpty()) {
     1125        for (int i = 0; i < undoStack.size(); ++i) {
     1126            QTextUndoCommand c = undoStack[i];
     1127            if (c.command & QTextUndoCommand::Custom)
     1128                delete c.custom;
     1129        }
     1130        undoState = 0;
     1131        undoStack.resize(0);
     1132        if (emitSignals && undoCommandsAvailable)
     1133            emitUndoAvailable(false);
     1134        if (emitSignals && redoCommandsAvailable)
     1135            emitRedoAvailable(false);
     1136    }
    10731137}
    10741138
     
    10981162    if (!enable) {
    10991163        undoState = 0;
    1100         truncateUndoStack();
     1164        clearUndoRedoStacks(QTextDocument::RedoStack);
    11011165        emitUndoAvailable(false);
    11021166        emitRedoAvailable(false);
     
    11301194        }
    11311195    }
     1196
     1197    editBlockCursorPosition = -1;
    11321198
    11331199    finishEdit();
     
    11661232    }
    11671233
    1168     while (!changedCursors.isEmpty()) {
    1169         QTextCursorPrivate *curs = changedCursors.takeFirst();
    1170         emit q->cursorPositionChanged(QTextCursor(curs));
    1171     }
     1234    QList<QTextCursor> changedCursors;
     1235    foreach (QTextCursorPrivate *curs, cursors) {
     1236        if (curs->changed) {
     1237            curs->changed = false;
     1238            changedCursors.append(QTextCursor(curs));
     1239        }
     1240    }
     1241    foreach (const QTextCursor &cursor, changedCursors)
     1242        emit q->cursorPositionChanged(cursor);
    11721243
    11731244    contentsChanged();
     
    12111282        ++revision;
    12121283
    1213     for (int i = 0; i < cursors.size(); ++i) {
    1214         QTextCursorPrivate *curs = cursors.at(i);
    1215         if (curs->adjustPosition(from, addedOrRemoved, op) == QTextCursorPrivate::CursorMoved) {
    1216             if (!changedCursors.contains(curs))
    1217                 changedCursors.append(curs);
     1284    if (blockCursorAdjustment)  {
     1285        ; // postpone, will be called again from QTextDocumentPrivate::remove()
     1286    } else {
     1287        foreach (QTextCursorPrivate *curs, cursors) {
     1288            if (curs->adjustPosition(from, addedOrRemoved, op) == QTextCursorPrivate::CursorMoved) {
     1289                curs->changed = true;
     1290            }
    12181291        }
    12191292    }
     
    13761449void QTextDocumentPrivate::scan_frames(int pos, int charsRemoved, int charsAdded)
    13771450{
    1378     // ###### optimise
     1451    // ###### optimize
    13791452    Q_UNUSED(pos);
    13801453    Q_UNUSED(charsRemoved);
     
    15791652
    15801653    for (FragmentMap::Iterator it = fragments.begin(); !it.atEnd(); ++it) {
    1581         qMemCopy(newTextPtr, text.constData() + it->stringPosition, it->size_array[0] * sizeof(QChar));
     1654        memcpy(newTextPtr, text.constData() + it->stringPosition, it->size_array[0] * sizeof(QChar));
    15821655        it->stringPosition = newLen;
    15831656        newTextPtr += it->size_array[0];
     
    16381711{
    16391712    Q_ASSERT(from <= to);
    1640     for (int i = 0; i < cursors.size(); ++i)
    1641         cursors.at(i)->aboutToRemoveCell(from, to);
     1713    foreach (QTextCursorPrivate *curs, cursors)
     1714        curs->aboutToRemoveCell(from, to);
    16421715}
    16431716
  • trunk/src/gui/text/qtextdocument_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    133133        BlockDeleted = 7,
    134134        GroupFormatChange = 8,
     135        CursorMoved = 9,
    135136        Custom = 256
    136137    };
     
    253254    inline void setDefaultFont(const QFont &f) { formats.setDefaultFont(f); }
    254255
     256    void clearUndoRedoStacks(QTextDocument::Stacks stacksToClear, bool emitSignals = false);
     257
    255258private:
    256259    bool split(int pos);
    257260    bool unite(uint f);
    258     void truncateUndoStack();
    259261
    260262    void insert_string(int pos, uint strPos, uint length, int format, QTextUndoCommand::Operation op);
     
    276278
    277279    inline void addCursor(QTextCursorPrivate *c) { cursors.append(c); }
    278     inline void removeCursor(QTextCursorPrivate *c) { cursors.removeAll(c); changedCursors.removeAll(c); }
     280    inline void removeCursor(QTextCursorPrivate *c) { cursors.removeAll(c); }
    279281
    280282    QTextFrame *frameAt(int pos) const;
     
    315317
    316318    int editBlock;
     319    int editBlockCursorPosition;
    317320    int docChangeFrom;
    318321    int docChangeOldLength;
     
    327330    int initialBlockCharFormatIndex;
    328331
    329     QList<QTextCursorPrivate*> cursors;
    330     QList<QTextCursorPrivate*> changedCursors;
     332    QList<QTextCursorPrivate *> cursors;
    331333    QMap<int, QTextObject *> objects;
    332334    QMap<QUrl, QVariant> resources;
     
    344346    uint needsEnsureMaximumBlockCount : 1;
    345347    uint inContentsChange : 1;
     348    uint blockCursorAdjustment : 1;
    346349    QSizeF pageSize;
    347350    QString title;
  • trunk/src/gui/text/qtextdocumentfragment.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4444#include "qtextcursor_p.h"
    4545#include "qtextlist.h"
    46 #include "private/qunicodetables_p.h"
    4746
    4847#include <qdebug.h>
  • trunk/src/gui/text/qtextdocumentfragment.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qtextdocumentfragment_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qtextdocumentlayout.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    8080// ################ should probably add frameFormatChange notification!
    8181
    82 struct QLayoutStruct;
     82struct QTextLayoutStruct;
    8383
    8484class QTextFrameData : public QTextFrameLayoutData
     
    110110    QFixed maximumWidth;
    111111
    112     QLayoutStruct *currentLayoutStruct;
     112    QTextLayoutStruct *currentLayoutStruct;
    113113
    114114    bool sizeDirty;
     
    124124}
    125125
    126 struct QLayoutStruct {
    127     QLayoutStruct() : maximumWidth(QFIXED_MAX), fullLayout(false)
     126struct QTextLayoutStruct {
     127    QTextLayoutStruct() : maximumWidth(QFIXED_MAX), fullLayout(false)
    128128    {}
    129129    QTextFrame *frame;
     
    328328/*
    329329
    330 Optimisation strategies:
     330Optimization strategies:
    331331
    332332HTML layout:
     
    478478    HitPoint hitTest(QTextBlock bl, const QFixedPoint &point, int *position, QTextLayout **l, Qt::HitTestAccuracy accuracy) const;
    479479
    480     QLayoutStruct layoutCell(QTextTable *t, const QTextTableCell &cell, QFixed width,
    481                             int layoutFrom, int layoutTo, QTextTableData *tableData, QFixed absoluteTableY,
    482                             bool withPageBreaks);
     480    QTextLayoutStruct layoutCell(QTextTable *t, const QTextTableCell &cell, QFixed width,
     481                                 int layoutFrom, int layoutTo, QTextTableData *tableData, QFixed absoluteTableY,
     482                                 bool withPageBreaks);
    483483    void setCellPosition(QTextTable *t, const QTextTableCell &cell, const QPointF &pos);
    484484    QRectF layoutTable(QTextTable *t, int layoutFrom, int layoutTo, QFixed parentY);
     
    491491
    492492    void layoutBlock(const QTextBlock &bl, int blockPosition, const QTextBlockFormat &blockFormat,
    493                      QLayoutStruct *layoutStruct, int layoutFrom, int layoutTo, const QTextBlockFormat *previousBlockFormat);
    494     void layoutFlow(QTextFrame::Iterator it, QLayoutStruct *layoutStruct, int layoutFrom, int layoutTo, QFixed width = 0);
    495     void pageBreakInsideTable(QTextTable *table, QLayoutStruct *layoutStruct);
    496 
    497 
    498     void floatMargins(const QFixed &y, const QLayoutStruct *layoutStruct, QFixed *left, QFixed *right) const;
    499     QFixed findY(QFixed yFrom, const QLayoutStruct *layoutStruct, QFixed requiredWidth) const;
     493                     QTextLayoutStruct *layoutStruct, int layoutFrom, int layoutTo, const QTextBlockFormat *previousBlockFormat);
     494    void layoutFlow(QTextFrame::Iterator it, QTextLayoutStruct *layoutStruct, int layoutFrom, int layoutTo, QFixed width = 0);
     495    void pageBreakInsideTable(QTextTable *table, QTextLayoutStruct *layoutStruct);
     496
     497
     498    void floatMargins(const QFixed &y, const QTextLayoutStruct *layoutStruct, QFixed *left, QFixed *right) const;
     499    QFixed findY(QFixed yFrom, const QTextLayoutStruct *layoutStruct, QFixed requiredWidth) const;
    500500
    501501    QVector<QCheckPoint> checkPoints;
     
    13701370    Q_ASSERT(firstLine.isValid());
    13711371    QPointF pos = (offset + layout->position()).toPoint();
    1372     Qt::LayoutDirection dir = docPrivate->defaultTextOption.textDirection();
    1373     if (blockFormat.hasProperty(QTextFormat::LayoutDirection))
    1374         dir = blockFormat.layoutDirection();
     1372    Qt::LayoutDirection dir = bl.textDirection();
    13751373    {
    13761374        QRectF textRect = firstLine.naturalTextRect();
     
    14881486}
    14891487
    1490 QLayoutStruct QTextDocumentLayoutPrivate::layoutCell(QTextTable *t, const QTextTableCell &cell, QFixed width,
    1491                                                     int layoutFrom, int layoutTo, QTextTableData *td,
    1492                                                     QFixed absoluteTableY, bool withPageBreaks)
     1488QTextLayoutStruct QTextDocumentLayoutPrivate::layoutCell(QTextTable *t, const QTextTableCell &cell, QFixed width,
     1489                                                        int layoutFrom, int layoutTo, QTextTableData *td,
     1490                                                        QFixed absoluteTableY, bool withPageBreaks)
    14931491{
    14941492    LDEBUG << "layoutCell";
    1495     QLayoutStruct layoutStruct;
     1493    QTextLayoutStruct layoutStruct;
    14961494    layoutStruct.frame = t;
    14971495    layoutStruct.minimumWidth = 0;
     
    16421640            // maximum width. otherwise the maxwidth calculation sometimes
    16431641            // returns wrong values
    1644             QLayoutStruct layoutStruct = layoutCell(table, cell, QFIXED_MAX, layoutFrom,
    1645                                                     layoutTo, td, absoluteTableY,
    1646                                                     /*withPageBreaks =*/false);
     1642            QTextLayoutStruct layoutStruct = layoutCell(table, cell, QFIXED_MAX, layoutFrom,
     1643                                                        layoutTo, td, absoluteTableY,
     1644                                                        /*withPageBreaks =*/false);
    16471645
    16481646            // distribute the minimum width over all columns the cell spans
     
    18691867
    18701868            const QFixed width = td->cellWidth(c, cspan) - widthPadding;
    1871             QLayoutStruct layoutStruct = layoutCell(table, cell, width,
    1872                                                     layoutFrom, layoutTo,
    1873                                                     td, absoluteTableY,
    1874                                                     /*withPageBreaks =*/true);
     1869            QTextLayoutStruct layoutStruct = layoutCell(table, cell, width,
     1870                                                       layoutFrom, layoutTo,
     1871                                                       td, absoluteTableY,
     1872                                                       /*withPageBreaks =*/true);
    18751873
    18761874            const QFixed height = layoutStruct.y + bottomPadding + topPadding;
     
    19771975    Q_ASSERT(pd && pd->currentLayoutStruct);
    19781976
    1979     QLayoutStruct *layoutStruct = pd->currentLayoutStruct;
     1977    QTextLayoutStruct *layoutStruct = pd->currentLayoutStruct;
    19801978
    19811979    if (!pd->floats.contains(frame))
     
    21172115    fd->contentsWidth = newContentsWidth;
    21182116
    2119     QLayoutStruct layoutStruct;
     2117    QTextLayoutStruct layoutStruct;
    21202118    layoutStruct.frame = f;
    21212119    layoutStruct.x_left = fd->leftMargin + fd->border + fd->padding;
     
    21802178}
    21812179
    2182 void QTextDocumentLayoutPrivate::layoutFlow(QTextFrame::Iterator it, QLayoutStruct *layoutStruct,
     2180void QTextDocumentLayoutPrivate::layoutFlow(QTextFrame::Iterator it, QTextLayoutStruct *layoutStruct,
    21832181                                            int layoutFrom, int layoutTo, QFixed width)
    21842182{
     
    25102508
    25112509void QTextDocumentLayoutPrivate::layoutBlock(const QTextBlock &bl, int blockPosition, const QTextBlockFormat &blockFormat,
    2512                                              QLayoutStruct *layoutStruct, int layoutFrom, int layoutTo, const QTextBlockFormat *previousBlockFormat)
     2510                                             QTextLayoutStruct *layoutStruct, int layoutFrom, int layoutTo, const QTextBlockFormat *previousBlockFormat)
    25132511{
    25142512    Q_Q(QTextDocumentLayout);
     
    25312529    //QTextFrameData *fd = data(layoutStruct->frame);
    25322530
    2533     Qt::LayoutDirection dir = docPrivate->defaultTextOption.textDirection();
    2534     if (blockFormat.hasProperty(QTextFormat::LayoutDirection))
    2535         dir = blockFormat.layoutDirection();
     2531    Qt::LayoutDirection dir = bl.textDirection();
    25362532
    25372533    QFixed extraMargin;
     
    27192715}
    27202716
    2721 void QTextDocumentLayoutPrivate::floatMargins(const QFixed &y, const QLayoutStruct *layoutStruct,
     2717void QTextDocumentLayoutPrivate::floatMargins(const QFixed &y, const QTextLayoutStruct *layoutStruct,
    27222718                                              QFixed *left, QFixed *right) const
    27232719{
     
    27412737}
    27422738
    2743 QFixed QTextDocumentLayoutPrivate::findY(QFixed yFrom, const QLayoutStruct *layoutStruct, QFixed requiredWidth) const
     2739QFixed QTextDocumentLayoutPrivate::findY(QFixed yFrom, const QTextLayoutStruct *layoutStruct, QFixed requiredWidth) const
    27442740{
    27452741    QFixed right, left;
  • trunk/src/gui/text/qtextdocumentlayout_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qtextdocumentwriter.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qtextdocumentwriter.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qtextengine.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    886886    QFixed wordSpacing = font.d->wordSpacing;
    887887
    888     if (letterSpacingIsAbsolute)
     888    if (letterSpacingIsAbsolute && letterSpacing.value())
    889889        letterSpacing *= font.d->dpi / qt_defaultDpiY();
    890890
     
    895895                    glyphs.advances_x[i-1] += letterSpacing;
    896896                else {
    897                     const QFixed advance = glyphs.advances_x[i-1];
    898                     glyphs.advances_x[i-1] += (letterSpacing - 100) * advance / 100;
     897                    QFixed &advance = glyphs.advances_x[i-1];
     898                    advance += (letterSpacing - 100) * advance / 100;
    899899                }
    900900            }
     
    903903            glyphs.advances_x[si.num_glyphs-1] += letterSpacing;
    904904        else {
    905             const QFixed advance = glyphs.advances_x[si.num_glyphs-1];
    906             glyphs.advances_x[si.num_glyphs-1] += (letterSpacing - 100) * advance / 100;
     905            QFixed &advance = glyphs.advances_x[si.num_glyphs-1];
     906            advance += (letterSpacing - 100) * advance / 100;
    907907        }
    908908    }
     
    922922    for (int i = 0; i < si.num_glyphs; ++i)
    923923        si.width += glyphs.advances_x[i];
     924}
     925
     926static inline bool hasCaseChange(const QScriptItem &si)
     927{
     928    return si.analysis.flags == QScriptAnalysis::SmallCaps ||
     929           si.analysis.flags == QScriptAnalysis::Uppercase ||
     930           si.analysis.flags == QScriptAnalysis::Lowercase;
    924931}
    925932
     
    10511058        flags |= DesignMetrics;
    10521059
    1053     attributes(); // pre-initialize char attributes
     1060    // pre-initialize char attributes
     1061    if (! attributes())
     1062        return;
    10541063
    10551064    const int len = length(item);
     
    10571066    const QChar *str = layoutData->string.unicode() + si.position;
    10581067    ushort upperCased[256];
    1059     if (si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase
    1060             || si.analysis.flags == QScriptAnalysis::Lowercase) {
     1068    if (hasCaseChange(si)) {
    10611069        ushort *uc = upperCased;
    10621070        if (len > 256)
     
    10721080
    10731081    while (true) {
    1074         ensureSpace(num_glyphs);
     1082        if (! ensureSpace(num_glyphs)) {
     1083            // If str is converted to uppercase/lowercase form with a new buffer,
     1084            // we need to delete that buffer before return for error
     1085            const ushort *uc = reinterpret_cast<const ushort *>(str);
     1086            if (hasCaseChange(si) && uc != upperCased)
     1087                delete [] uc;
     1088            return;
     1089        }
    10751090        num_glyphs = layoutData->glyphLayout.numGlyphs - layoutData->used;
    10761091
     
    10931108
    10941109    const ushort *uc = reinterpret_cast<const ushort *>(str);
    1095     if ((si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase
    1096          || si.analysis.flags == QScriptAnalysis::Lowercase)
    1097         && uc != upperCased)
     1110    if (hasCaseChange(si) && uc != upperCased)
    10981111        delete [] uc;
    10991112}
     
    11251138
    11261139    HB_ShaperItem entire_shaper_item;
    1127     entire_shaper_item.kerning_applied = false;
     1140    qMemSet(&entire_shaper_item, 0, sizeof(entire_shaper_item));
    11281141    entire_shaper_item.string = reinterpret_cast<const HB_UChar16 *>(layoutData->string.constData());
    11291142    entire_shaper_item.stringLength = layoutData->string.length();
     
    11321145    entire_shaper_item.item.length = length(item);
    11331146    entire_shaper_item.item.bidiLevel = si.analysis.bidiLevel;
    1134     entire_shaper_item.glyphIndicesPresent = false;
    11351147
    11361148    HB_UChar16 upperCased[256]; // XXX what about making this 4096, so we don't have to extend it ever.
    1137     if (si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase
    1138             || si.analysis.flags == QScriptAnalysis::Lowercase) {
     1149    if (hasCaseChange(si)) {
    11391150        HB_UChar16 *uc = upperCased;
    11401151        if (entire_shaper_item.item.length > 256)
     
    11581169
    11591170    entire_shaper_item.num_glyphs = qMax(layoutData->glyphLayout.numGlyphs - layoutData->used, int(entire_shaper_item.item.length));
    1160     ensureSpace(entire_shaper_item.num_glyphs);
     1171    if (! ensureSpace(entire_shaper_item.num_glyphs)) {
     1172        if (hasCaseChange(si))
     1173            delete [] const_cast<HB_UChar16 *>(entire_shaper_item.string);
     1174        return;
     1175    }
    11611176    QGlyphLayout initialGlyphs = availableGlyphs(&si).mid(0, entire_shaper_item.num_glyphs);
    11621177
    11631178    if (!stringToGlyphs(&entire_shaper_item, &initialGlyphs, font)) {
    1164         ensureSpace(entire_shaper_item.num_glyphs);
     1179        if (! ensureSpace(entire_shaper_item.num_glyphs)) {
     1180            if (hasCaseChange(si))
     1181                delete [] const_cast<HB_UChar16 *>(entire_shaper_item.string);
     1182            return;
     1183        }
    11651184        initialGlyphs = availableGlyphs(&si).mid(0, entire_shaper_item.num_glyphs);
    11661185
    11671186        if (!stringToGlyphs(&entire_shaper_item, &initialGlyphs, font)) {
    11681187            // ############ if this happens there's a bug in the fontengine
    1169             if ((si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase
    1170                     || si.analysis.flags == QScriptAnalysis::Lowercase) && entire_shaper_item.string != upperCased)
     1188            if (hasCaseChange(si) && entire_shaper_item.string != upperCased)
    11711189                delete [] const_cast<HB_UChar16 *>(entire_shaper_item.string);
    11721190            return;
     
    12331251
    12341252        do {
    1235             ensureSpace(glyph_pos + shaper_item.num_glyphs + remaining_glyphs);
     1253            if (! ensureSpace(glyph_pos + shaper_item.num_glyphs + remaining_glyphs)) {
     1254                if (hasCaseChange(si))
     1255                    delete [] const_cast<HB_UChar16 *>(entire_shaper_item.string);
     1256                return;
     1257            }
    12361258
    12371259            const QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos);
     
    12731295    layoutData->used += si.num_glyphs;
    12741296
    1275     if ((si.analysis.flags == QScriptAnalysis::SmallCaps || si.analysis.flags == QScriptAnalysis::Uppercase)
    1276         && entire_shaper_item.string != upperCased)
     1297    if (hasCaseChange(si) && entire_shaper_item.string != upperCased)
    12771298        delete [] const_cast<HB_UChar16 *>(entire_shaper_item.string);
    12781299}
     
    13001321
    13011322QTextEngine::QTextEngine(const QString &str, const QFont &f)
    1302     : fnt(f)
     1323    : text(str),
     1324      fnt(f)
    13031325{
    13041326    init(this);
    1305     text = str;
    13061327}
    13071328
     
    13191340
    13201341    itemize();
    1321     ensureSpace(layoutData->string.length());
     1342    if (! ensureSpace(layoutData->string.length()))
     1343        return NULL;
    13221344
    13231345    QVarLengthArray<HB_ScriptItem> hbScriptItems(layoutData->items.size());
     
    14061428    bool ignore = ignoreBidi;
    14071429#endif
    1408     if (!ignore && option.textDirection() == Qt::LeftToRight) {
     1430
     1431    bool rtl = isRightToLeft();
     1432
     1433    if (!ignore && !rtl) {
    14091434        ignore = true;
    14101435        const QChar *start = layoutData->string.unicode();
     
    14221447    QScriptAnalysis *analysis = scriptAnalysis.data();
    14231448
    1424     QBidiControl control(option.textDirection() == Qt::RightToLeft);
     1449    QBidiControl control(rtl);
    14251450
    14261451    if (ignore) {
     
    15171542}
    15181543
     1544bool QTextEngine::isRightToLeft() const
     1545{
     1546    switch (option.textDirection()) {
     1547    case Qt::LeftToRight:
     1548        return false;
     1549    case Qt::RightToLeft:
     1550        return true;
     1551    default:
     1552        break;
     1553    }
     1554    // this places the cursor in the right position depending on the keyboard layout
     1555    if (layoutData->string.isEmpty())
     1556        return QApplication::keyboardInputDirection() == Qt::RightToLeft;
     1557    return layoutData->string.isRightToLeft();
     1558}
     1559
     1560
    15191561int QTextEngine::findItem(int strPos) const
    15201562{
    15211563    itemize();
    1522 
    1523     // ##### use binary search
    1524     int item;
    1525     for (item = layoutData->items.size()-1; item > 0; --item) {
    1526         if (layoutData->items[item].position <= strPos)
    1527             break;
    1528     }
    1529     return item;
     1564    int left = 0;
     1565    int right = layoutData->items.size()-1;
     1566    while(left <= right) {
     1567        int middle = ((right-left)/2)+left;
     1568        if (strPos > layoutData->items[middle].position)
     1569            left = middle+1;
     1570        else if(strPos < layoutData->items[middle].position)
     1571            right = middle-1;
     1572        else {
     1573            return middle;
     1574        }
     1575    }
     1576    return right;
    15301577}
    15311578
     
    16001647    for (int i = 0; i < layoutData->items.size(); i++) {
    16011648        const QScriptItem *si = layoutData->items.constData() + i;
    1602         QFontEngine *fe = fontEngine(*si);
    16031649
    16041650        int pos = si->position;
     
    16301676                    charFrom++;
    16311677            if (charFrom < ilen) {
     1678                QFontEngine *fe = fontEngine(*si);
    16321679                glyphStart = logClusters[charFrom];
    16331680                int charEnd = from + len - 1 - pos;
     
    16481695                }
    16491696            }
    1650 
    1651             glyph_t glyph = glyphs.glyphs[logClusters[ilen - 1]];
    1652             glyph_metrics_t gi = fe->boundingBox(glyph);
    1653             if (gi.isValid())
    1654                 gm.width -= qRound(gi.xoff - gi.x - gi.width);
    16551697        }
    16561698    }
     
    18381880            return; // no justification at end of paragraph
    18391881        if (end && layoutData->items[findItem(end-1)].analysis.flags == QScriptAnalysis::LineOrParagraphSeparator)
    1840             return; // no justification at the end of an explicitely separated line
     1882            return; // no justification at the end of an explicitly separated line
    18411883    }
    18421884
     
    18461888    // don't include trailing white spaces when doing justification
    18471889    int line_length = line.length;
    1848     const HB_CharAttributes *a = attributes()+line.from;
     1890    const HB_CharAttributes *a = attributes();
     1891    if (! a)
     1892        return;
     1893    a += line.from;
    18491894    while (line_length && a[line_length-1].whiteSpace)
    18501895        --line_length;
     
    19051950//                     qDebug("kashida position at %d in word", kashida_pos);
    19061951                    set(&justificationPoints[nPoints], kashida_type, g.mid(kashida_pos), fontEngine(si));
    1907                     minKashida = qMin(minKashida, justificationPoints[nPoints].kashidaWidth);
    1908                     maxJustify = qMax(maxJustify, justificationPoints[nPoints].type);
    1909                     ++nPoints;
     1952                    if (justificationPoints[nPoints].kashidaWidth > 0) {
     1953                        minKashida = qMin(minKashida, justificationPoints[nPoints].kashidaWidth);
     1954                        maxJustify = qMax(maxJustify, justificationPoints[nPoints].type);
     1955                        ++nPoints;
     1956                    }
    19101957                }
    19111958                kashida_pos = -1;
     
    19311978        if (kashida_pos >= 0) {
    19321979            set(&justificationPoints[nPoints], kashida_type, g.mid(kashida_pos), fontEngine(si));
    1933             minKashida = qMin(minKashida, justificationPoints[nPoints].kashidaWidth);
    1934             maxJustify = qMax(maxJustify, justificationPoints[nPoints].type);
    1935             ++nPoints;
     1980            if (justificationPoints[nPoints].kashidaWidth > 0) {
     1981                minKashida = qMin(minKashida, justificationPoints[nPoints].kashidaWidth);
     1982                maxJustify = qMax(maxJustify, justificationPoints[nPoints].type);
     1983                ++nPoints;
     1984            }
    19361985        }
    19371986    }
     
    20272076    used = 0;
    20282077    hasBidi = false;
    2029     inLayout = false;
     2078    layoutState = LayoutEmpty;
    20302079    haveCharAttributes = false;
    20312080    logClustersPtr = 0;
     
    20612110    used = 0;
    20622111    hasBidi = false;
    2063     inLayout = false;
     2112    layoutState = LayoutEmpty;
    20642113    haveCharAttributes = false;
    20652114}
     
    20722121}
    20732122
    2074 void QTextEngine::LayoutData::reallocate(int totalGlyphs)
     2123bool QTextEngine::LayoutData::reallocate(int totalGlyphs)
    20752124{
    20762125    Q_ASSERT(totalGlyphs >= glyphLayout.numGlyphs);
    20772126    if (memory_on_stack && available_glyphs >= totalGlyphs) {
    20782127        glyphLayout.grow(glyphLayout.data(), totalGlyphs);
    2079         return;
     2128        return true;
    20802129    }
    20812130
     
    20852134
    20862135    int newAllocated = space_charAttributes + space_glyphs + space_logClusters;
    2087     Q_ASSERT(newAllocated >= allocated);
     2136    // These values can be negative if the length of string/glyphs causes overflow,
     2137    // we can't layout such a long string all at once, so return false here to
     2138    // indicate there is a failure
     2139    if (space_charAttributes < 0 || space_logClusters < 0 || space_glyphs < 0 || newAllocated < allocated) {
     2140        layoutState = LayoutFailed;
     2141        return false;
     2142    }
     2143
    20882144    void **newMem = memory;
    20892145    newMem = (void **)::realloc(memory_on_stack ? 0 : memory, newAllocated*sizeof(void *));
    2090     Q_CHECK_PTR(newMem);
    2091     if (memory_on_stack && newMem)
     2146    if (!newMem) {
     2147        layoutState = LayoutFailed;
     2148        return false;
     2149    }
     2150    if (memory_on_stack)
    20922151        memcpy(newMem, memory, allocated*sizeof(void *));
    20932152    memory = newMem;
     
    21062165
    21072166    allocated = newAllocated;
     2167    return true;
    21082168}
    21092169
     
    21372197        layoutData->used = 0;
    21382198        layoutData->hasBidi = false;
    2139         layoutData->inLayout = false;
     2199        layoutData->layoutState = LayoutEmpty;
    21402200        layoutData->haveCharAttributes = false;
    21412201    }
     
    22082268    case '?':
    22092269    case '!':
     2270    case '@':
     2271    case '#':
     2272    case '$':
    22102273    case ':':
    22112274    case ';':
     
    22282291    case '\'':
    22292292    case '"':
     2293    case '`':
    22302294    case '~':
    22312295    case '|':
     
    22962360
    22972361            HB_CharAttributes *attributes = const_cast<HB_CharAttributes *>(this->attributes());
     2362            if (!attributes)
     2363                return QString();
     2364
    22982365            unsigned short *logClusters = this->logClusters(&si);
    22992366            QGlyphLayout glyphs = shapedGlyphs(&si);
     
    23672434
    23682435    const HB_CharAttributes *attributes = this->attributes();
     2436    if (!attributes)
     2437        return QString();
    23692438
    23702439    if (mode == Qt::ElideRight) {
     
    24532522
    24542523    int itemToSplit = 0;
    2455     while (itemToSplit < layoutData->items.size() && layoutData->items[itemToSplit].position <= strPos)
     2524    while (itemToSplit < layoutData->items.size() && layoutData->items.at(itemToSplit).position <= strPos)
    24562525        itemToSplit++;
    24572526    itemToSplit--;
    2458     if (layoutData->items[itemToSplit].position == strPos) {
     2527    if (layoutData->items.at(itemToSplit).position == strPos) {
    24592528        // already a split at the requested position
    24602529        return;
    24612530    }
    2462     splitItem(itemToSplit, strPos - layoutData->items[itemToSplit].position);
     2531    splitItem(itemToSplit, strPos - layoutData->items.at(itemToSplit).position);
    24632532}
    24642533
     
    24682537        return;
    24692538
    2470     layoutData->items.insert(item + 1, QScriptItem(layoutData->items[item]));
     2539    layoutData->items.insert(item + 1, layoutData->items[item]);
    24712540    QScriptItem &oldItem = layoutData->items[item];
    24722541    QScriptItem &newItem = layoutData->items[item+1];
     
    25132582    QList<QTextOption::Tab> tabArray = option.tabs();
    25142583    if (!tabArray.isEmpty()) {
    2515         if (option.textDirection() == Qt::RightToLeft) { // rebase the tabArray positions.
     2584        if (isRightToLeft()) { // rebase the tabArray positions.
    25162585            QList<QTextOption::Tab> newTabs;
    25172586            QList<QTextOption::Tab>::Iterator iter = tabArray.begin();
     
    26112680
    26122681QStackTextEngine::QStackTextEngine(const QString &string, const QFont &f)
    2613     : _layoutData(string, _memory, MemSize)
    2614 {
    2615     fnt = f;
    2616     text = string;
     2682    : QTextEngine(string, f),
     2683      _layoutData(string, _memory, MemSize)
     2684{
    26172685    stackEngine = true;
    26182686    layoutData = &_layoutData;
     
    26512719}
    26522720
     2721QTextItemInt::QTextItemInt(const QGlyphLayout &g, QFont *font, const QChar *chars_, int numChars, QFontEngine *fe)
     2722    : flags(0), justified(false), underlineStyle(QTextCharFormat::NoUnderline),
     2723      num_chars(numChars), chars(chars_), logClusters(0), f(font),  glyphs(g), fontEngine(fe)
     2724{
     2725}
     2726
    26532727QTextItemInt QTextItemInt::midItem(QFontEngine *fontEngine, int firstGlyphIndex, int numGlyphs) const
    26542728{
  • trunk/src/gui/text/qtextengine_mac.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qtextengine_p.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    312312    {}
    313313    QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFormat &format = QTextCharFormat());
     314    QTextItemInt(const QGlyphLayout &g, QFont *font, const QChar *chars, int numChars, QFontEngine *fe);
    314315
    315316    /// copy the structure items, adjusting the glyphs arrays to the right subarrays.
     
    390391    uint hasTrailingSpaces : 1;
    391392    uint leadingIncluded : 1;
    392     QFixed height() const { return ascent + descent + 1
     393    QFixed height() const { return (ascent + descent).ceil() + 1
    393394                            + (leadingIncluded?  qMax(QFixed(),leading) : QFixed()); }
    394395    QFixed base() const { return ascent
     
    416417class Q_GUI_EXPORT QTextEngine {
    417418public:
     419    enum LayoutState {
     420        LayoutEmpty,
     421        InLayout,
     422        LayoutFailed,
     423    };
    418424    struct LayoutData {
    419425        LayoutData(const QString &str, void **stack_memory, int mem_size);
     
    428434        mutable int used;
    429435        uint hasBidi : 1;
    430         uint inLayout : 1;
     436        uint layoutState : 2;
    431437        uint memory_on_stack : 1;
    432438        bool haveCharAttributes;
    433439        QString string;
    434         void reallocate(int totalGlyphs);
     440        bool reallocate(int totalGlyphs);
    435441    };
    436442
     
    458464    void itemize() const;
    459465
     466    bool isRightToLeft() const;
    460467    static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder);
    461468
     
    519526    }
    520527
    521     inline void ensureSpace(int nGlyphs) const {
     528    inline bool ensureSpace(int nGlyphs) const {
    522529        if (layoutData->glyphLayout.numGlyphs - layoutData->used < nGlyphs)
    523             layoutData->reallocate((((layoutData->used + nGlyphs)*3/2 + 15) >> 4) << 4);
     530            return layoutData->reallocate((((layoutData->used + nGlyphs)*3/2 + 15) >> 4) << 4);
     531        return true;
    524532    }
    525533
  • trunk/src/gui/text/qtextformat.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    266266};
    267267
    268 // this is only safe if sizeof(int) == sizeof(float)
     268// this is only safe because sizeof(int) == sizeof(float)
    269269static inline uint hash(float d)
    270270{
     271#ifdef Q_CC_GNU
     272    // this is a GCC extension and isn't guaranteed to work in other compilers
     273    // the reinterpret_cast below generates a strict-aliasing warning with GCC
     274    union { float f; uint u; } cvt;
     275    cvt.f = d;
     276    return cvt.u;
     277#else
    271278    return reinterpret_cast<uint&>(d);
     279#endif
    272280}
    273281
     
    901909int QTextFormat::intProperty(int propertyId) const
    902910{
     911    // required, since the default layout direction has to be LayoutDirectionAuto, which is not integer 0
     912    int def = (propertyId == QTextFormat::LayoutDirection) ? int(Qt::LayoutDirectionAuto) : 0;
     913
    903914    if (!d)
    904         return 0;
     915        return def;
    905916    const QVariant prop = d->property(propertyId);
    906917    if (prop.userType() != QVariant::Int)
    907         return 0;
     918        return def;
    908919    return prop.toInt();
    909920}
  • trunk/src/gui/text/qtextformat.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qtextformat_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qtexthtmlparser.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    5454#include "qtextcursor.h"
    5555#include "qfont_p.h"
    56 #include "private/qunicodetables_p.h"
    5756#include "private/qfunctions_p.h"
    5857
  • trunk/src/gui/text/qtexthtmlparser_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qtextimagehandler.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qtextimagehandler_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qtextlayout.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    7070        || (eng->option.flags() & QTextOption::IncludeTrailingSpaces)
    7171        || !(eng->option.alignment() & Qt::AlignRight)
    72         || (eng->option.textDirection() != Qt::RightToLeft))
     72        || !eng->isRightToLeft())
    7373        return QFixed();
    7474
    7575    int pos = line.length;
    7676    const HB_CharAttributes *attributes = eng->attributes();
     77    if (!attributes)
     78        return QFixed();
    7779    while (pos > 0 && attributes[line.from + pos - 1].whiteSpace)
    7880        --pos;
     
    8789    if (!line.justified && line.width != QFIXED_MAX) {
    8890        int align = eng->option.alignment();
    89         if (align & Qt::AlignJustify && eng->option.textDirection() == Qt::RightToLeft)
     91        if (align & Qt::AlignJustify && eng->isRightToLeft())
    9092            align = Qt::AlignRight;
    9193        if (align & Qt::AlignRight)
     
    283285    \reentrant
    284286
    285     \brief The QTextLayout class is used to lay out and paint a single
    286     paragraph of text.
     287    \brief The QTextLayout class is used to lay out and render text.
    287288
    288289    \ingroup richtext-processing
    289290
    290     It offers most features expected from a modern text layout
     291    It offers many features expected from a modern text layout
    291292    engine, including Unicode compliant rendering, line breaking and
    292293    handling of cursor positioning. It can also produce and render
     
    298299    probably won't need to use it directly.
    299300
    300     QTextLayout can currently deal with plain text and rich text
    301     paragraphs that are part of a QTextDocument.
    302 
    303     QTextLayout can be used to create a sequence of QTextLine's with
    304     given widths and can position them independently on the screen.
    305     Once the layout is done, these lines can be drawn on a paint
    306     device.
    307 
    308     Here's some pseudo code that presents the layout phase:
     301    QTextLayout can be used with both plain and rich text.
     302
     303    QTextLayout can be used to create a sequence of QTextLine
     304    instances with given widths and can position them independently
     305    on the screen. Once the layout is done, these lines can be drawn
     306    on a paint device.
     307
     308    The text to be laid out can be provided in the constructor or set with
     309    setText().
     310
     311    The layout can be seen as a sequence of QTextLine objects; use createLine()
     312    to create a QTextLine instance, and lineAt() or lineForTextPosition() to retrieve
     313    created lines.
     314
     315    Here is a code snippet that demonstrates the layout phase:
    309316    \snippet doc/src/snippets/code/src_gui_text_qtextlayout.cpp 0
    310317
    311     The text can be drawn by calling the layout's draw() function:
     318    The text can then be rendered by calling the layout's draw() function:
    312319    \snippet doc/src/snippets/code/src_gui_text_qtextlayout.cpp 1
    313320
    314     The text layout's text is set in the constructor or with
    315     setText(). The layout can be seen as a sequence of QTextLine
    316     objects; use lineAt() or lineForTextPosition() to get a QTextLine,
    317     createLine() to create one. For a given position in the text you
    318     can find a valid cursor position with isValidCursorPosition(),
    319     nextCursorPosition(), and previousCursorPosition(). The layout
    320     itself can be positioned with setPosition(); it has a
    321     boundingRect(), and a minimumWidth() and a maximumWidth(). A text
    322     layout can be drawn on a painter device using draw().
     321    For a given position in the text you can find a valid cursor position with
     322    isValidCursorPosition(), nextCursorPosition(), and previousCursorPosition().
     323
     324    The QTextLayout itself can be positioned with setPosition(); it has a
     325    boundingRect(), and a minimumWidth() and a maximumWidth().
     326
     327    \sa QStaticText
    323328
    324329*/
     
    599604{
    600605#ifndef QT_NO_DEBUG
    601     if (d->layoutData && d->layoutData->inLayout) {
     606    if (d->layoutData && d->layoutData->layoutState == QTextEngine::InLayout) {
    602607        qWarning("QTextLayout::beginLayout: Called while already doing layout");
    603608        return;
     
    607612    d->clearLineData();
    608613    d->itemize();
    609     d->layoutData->inLayout = true;
     614    d->layoutData->layoutState = QTextEngine::InLayout;
    610615}
    611616
     
    616621{
    617622#ifndef QT_NO_DEBUG
    618     if (!d->layoutData || !d->layoutData->inLayout) {
     623    if (!d->layoutData || d->layoutData->layoutState == QTextEngine::LayoutEmpty) {
    619624        qWarning("QTextLayout::endLayout: Called without beginLayout()");
    620625        return;
     
    625630        QTextLine(l-1, d).setNumColumns(INT_MAX);
    626631    }
    627     d->layoutData->inLayout = false;
     632    d->layoutData->layoutState = QTextEngine::LayoutEmpty;
    628633    if (!d->cacheGlyphs)
    629634        d->freeMemory();
     
    755760{
    756761#ifndef QT_NO_DEBUG
    757     if (!d->layoutData || !d->layoutData->inLayout) {
     762    if (!d->layoutData || d->layoutData->layoutState == QTextEngine::LayoutEmpty) {
    758763        qWarning("QTextLayout::createLine: Called without layouting");
    759764        return QTextLine();
    760765    }
    761766#endif
     767    if (d->layoutData->layoutState == QTextEngine::LayoutFailed)
     768        return QTextLine();
     769
    762770    int l = d->lines.size();
    763771    if (l && d->lines.at(l-1).length < 0) {
     
    859867        xmin = qMin(xmin, si.x);
    860868        ymin = qMin(ymin, si.y);
    861         xmax = qMax(xmax, si.x+qMax(si.width, si.textWidth));
     869        QFixed lineWidth = si.width < QFIXED_MAX ? qMax(si.width, si.textWidth) : si.textWidth;
     870        xmax = qMax(xmax, si.x+lineWidth);
    862871        // ### shouldn't the ascent be used in ymin???
    863872        ymax = qMax(ymax, si.y+si.height());
     
    12091218        bool hasText = (selection.format.foreground().style() != Qt::NoBrush);
    12101219        bool hasBackground= (selection.format.background().style() != Qt::NoBrush);
    1211        
     1220
    12121221        if (hasBackground) {
    12131222            selection.format.setProperty(ObjectSelectionBrush, selection.format.property(QTextFormat::BackgroundBrush));
     
    13371346    QFixed base = sl.base();
    13381347    QFixed descent = sl.descent;
    1339     bool rightToLeft = (d->option.textDirection() == Qt::RightToLeft);
     1348    bool rightToLeft = d->isRightToLeft();
    13401349    if (itm >= 0) {
    13411350        const QScriptItem &si = d->layoutData->items.at(itm);
     
    15711580}
    15721581
     1582/*! \since 4.7
     1583  Returns the horizontal advance of the text. The advance of the text
     1584  is the distance from its position to the next position at which
     1585  text would naturally be drawn.
     1586
     1587  By adding the advance to the position of the text line and using this
     1588  as the position of a second text line, you will be able to position
     1589  the two lines side-by-side without gaps in-between.
     1590*/
     1591qreal QTextLine::horizontalAdvance() const
     1592{
     1593    return eng->lines[i].textAdvance.toReal();
     1594}
     1595
    15731596/*!
    15741597    Lays out the line with the given \a width. The line is filled from
     
    15931616        && line.textWidth <= line.width
    15941617        && line.from + line.length == eng->layoutData->string.length())
    1595         // no need to do anything if the line is already layouted and the last one. This optimisation helps
     1618        // no need to do anything if the line is already layouted and the last one. This optimization helps
    15961619        // when using things in a single line layout.
    15971620        return;
     
    16471670        LineBreakHelper()
    16481671            : glyphCount(0), maxGlyphs(0), currentPosition(0), fontEngine(0), logClusters(0),
    1649               manualWrap(false)
     1672              manualWrap(false), whiteSpaceOrObject(true)
    16501673        {
    16511674        }
     
    16701693
    16711694        bool manualWrap;
     1695        bool whiteSpaceOrObject;
    16721696
    16731697        bool checkFullOtherwiseExtend(QScriptLine &line);
     
    16791703
    16801704        inline glyph_t currentGlyph() const
     1705        {           
     1706            Q_ASSERT(currentPosition > 0);
     1707            Q_ASSERT(logClusters[currentPosition - 1] < glyphs.numGlyphs);
     1708
     1709            return glyphs.glyphs[logClusters[currentPosition - 1]];
     1710        }
     1711
     1712        inline void adjustRightBearing(glyph_t glyph)
    16811713        {
    1682             Q_ASSERT(currentPosition > 0);
    1683             return glyphs.glyphs[logClusters[currentPosition - 1]];
     1714            qreal rb;
     1715            fontEngine->getGlyphBearings(glyph, 0, &rb);
     1716            rightBearing = qMin(QFixed(), QFixed::fromReal(rb));
    16841717        }
    16851718
     
    16881721            if (currentPosition <= 0)
    16891722                return;
    1690 
    1691             qreal rb;
    1692             fontEngine->getGlyphBearings(currentGlyph(), 0, &rb);
    1693             rightBearing = qMin(QFixed(), QFixed::fromReal(rb));
     1723            adjustRightBearing(currentGlyph());
    16941724        }
    16951725
     
    17021732
    17031733inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line)
    1704 {       
     1734{
    17051735    LB_DEBUG("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal());
    17061736
     
    17681798    lbh.manualWrap = (wrapMode == QTextOption::ManualWrap || wrapMode == QTextOption::NoWrap);
    17691799
    1770     // #### binary search!
    17711800    int item = -1;
    1772     int newItem;
    1773     for (newItem = eng->layoutData->items.size()-1; newItem > 0; --newItem) {
    1774         if (eng->layoutData->items[newItem].position <= line.from)
     1801    int newItem = -1;
     1802    int left = 0;
     1803    int right = eng->layoutData->items.size()-1;
     1804    while(left <= right) {
     1805        int middle = ((right-left)/2)+left;
     1806        if (line.from > eng->layoutData->items[middle].position)
     1807            left = middle+1;
     1808        else if(line.from < eng->layoutData->items[middle].position)
     1809            right = middle-1;
     1810        else {
     1811            newItem = middle;
    17751812            break;
    1776     }
     1813        }
     1814    }
     1815    if (newItem == -1)
     1816        newItem = right;
    17771817
    17781818    LB_DEBUG("from: %d: item=%d, total %d, width available %f", line.from, newItem, eng->layoutData->items.size(), line.width.toReal());
     
    17811821
    17821822    const HB_CharAttributes *attributes = eng->attributes();
     1823    if (!attributes)
     1824        return;
    17831825    lbh.currentPosition = line.from;
    17841826    int end = 0;
     
    17941836                eng->shape(item);
    17951837                attributes = eng->attributes();
     1838                if (!attributes)
     1839                    return;
    17961840                lbh.logClusters = eng->layoutData->logClustersPtr;
    17971841            }
     
    18151859
    18161860        if (current.analysis.flags == QScriptAnalysis::Tab && (alignment & (Qt::AlignLeft | Qt::AlignRight | Qt::AlignCenter | Qt::AlignJustify))) {
     1861            lbh.whiteSpaceOrObject = true;
    18171862            if (lbh.checkFullOtherwiseExtend(line))
    18181863                goto found;
     
    18311876                goto found;
    18321877        } else if (current.analysis.flags == QScriptAnalysis::LineOrParagraphSeparator) {
     1878            lbh.whiteSpaceOrObject = true;
    18331879            // if the line consists only of the line separator make sure
    18341880            // we have a sane height
     
    18441890            goto found;
    18451891        } else if (current.analysis.flags == QScriptAnalysis::Object) {
     1892            lbh.whiteSpaceOrObject = true;
    18461893            lbh.tmpData.length++;
    18471894
     
    18571904                goto found;
    18581905        } else if (attributes[lbh.currentPosition].whiteSpace) {
     1906            lbh.whiteSpaceOrObject = true;
    18591907            while (lbh.currentPosition < end && attributes[lbh.currentPosition].whiteSpace)
    18601908                addNextCluster(lbh.currentPosition, end, lbh.spaceData, lbh.glyphCount,
     
    18661914            }
    18671915        } else {
     1916            lbh.whiteSpaceOrObject = false;
    18681917            bool sb_or_ws = false;
     1918            glyph_t previousGlyph = 0;
     1919            if (lbh.currentPosition > 0 && lbh.logClusters[lbh.currentPosition - 1] <lbh.glyphs.numGlyphs)
     1920                previousGlyph = lbh.currentGlyph(); // needed to calculate right bearing later
    18691921            do {
    18701922                addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount,
     
    19101962            // expand the text beyond the edge.
    19111963            if (sb_or_ws|breakany) {
    1912                 if (lbh.calculateNewWidth(line) + lbh.minimumRightBearing > line.width)
     1964                QFixed rightBearing = lbh.rightBearing; // store previous right bearing
     1965#if !defined(Q_WS_MAC)
     1966                if (lbh.calculateNewWidth(line) - lbh.minimumRightBearing > line.width)
     1967#endif
    19131968                    lbh.adjustRightBearing();
    19141969                if (lbh.checkFullOtherwiseExtend(line)) {
     1970                    // we are too wide, fix right bearing
     1971                    if (rightBearing <= 0)
     1972                        lbh.rightBearing = rightBearing; // take from cache
     1973                    else if (previousGlyph > 0)
     1974                        lbh.adjustRightBearing(previousGlyph);
    19151975                    if (!breakany) {
    19161976                        line.textWidth += lbh.softHyphenWidth;
     
    19261986    LB_DEBUG("reached end of line");
    19271987    lbh.checkFullOtherwiseExtend(line);
    1928 found:       
    1929     if (lbh.rightBearing > 0) // If right bearing has not yet been adjusted
     1988found:
     1989    if (lbh.rightBearing > 0 && !lbh.whiteSpaceOrObject) // If right bearing has not yet been adjusted
    19301990        lbh.adjustRightBearing();
    19311991    line.textAdvance = line.textWidth;
  • trunk/src/gui/text/qtextlayout.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    203203
    204204    qreal naturalTextWidth() const;
     205    qreal horizontalAdvance() const;
    205206    QRectF naturalTextRect() const;
    206207
  • trunk/src/gui/text/qtextlist.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    236236                                // c[i] == 4|5|9|40|50|90|400|500|900
    237237                                if ((i-2) % 4) {
    238                                     // c[i] == 4|9|40|90|400|900 => with substraction (IV, IX, XL, XC, ...)
     238                                    // c[i] == 4|9|40|90|400|900 => with subtraction (IV, IX, XL, XC, ...)
    239239                                    numDigits = 2;
    240240                                }
     
    263263            Q_ASSERT(false);
    264264    }
    265     if (blockFormat.layoutDirection() == Qt::RightToLeft)
     265    if (blockIt.textDirection() == Qt::RightToLeft)
    266266        return result.prepend(QLatin1Char('.'));
    267267    return result + QLatin1Char('.');
  • trunk/src/gui/text/qtextlist.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qtextobject.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    617617/*!
    618618    Returns an iterator pointing to the first document element inside the frame.
     619    Please see the document \l{STL-style-Iterators} for more information.
    619620
    620621    \sa end()
     
    629630
    630631/*!
    631     Returns an iterator pointing to the last document element inside the frame.
    632 
     632    Returns an iterator pointing to the position past the last document element inside the frame.
     633    Please see the document \l{STL-Style Iterators} for more information.   
    633634    \sa begin()
    634635*/
     
    11411142
    11421143/*!
     1144  \since 4.7
     1145
     1146  Returns the resolved text direction.
     1147
     1148  If the block has no explicit direction set, it will resolve the
     1149  direction from the blocks content. Returns either Qt::LeftToRight
     1150  or Qt::RightToLeft.
     1151
     1152  \sa QTextFormat::layoutDirection(), QString::isRightToLeft(), Qt::LayoutDirection
     1153*/
     1154Qt::LayoutDirection QTextBlock::textDirection() const
     1155{
     1156    Qt::LayoutDirection dir = blockFormat().layoutDirection();
     1157    if (dir != Qt::LayoutDirectionAuto)
     1158        return dir;
     1159
     1160    dir = p->defaultTextOption.textDirection();
     1161    if (dir != Qt::LayoutDirectionAuto)
     1162        return dir;
     1163
     1164    const QString buffer = p->buffer();
     1165
     1166    const int pos = position();
     1167    QTextDocumentPrivate::FragmentIterator it = p->find(pos);
     1168    QTextDocumentPrivate::FragmentIterator end = p->find(pos + length() - 1); // -1 to omit the block separator char
     1169    for (; it != end; ++it) {
     1170        const QTextFragmentData * const frag = it.value();
     1171        const QChar *p = buffer.constData() + frag->stringPosition;
     1172        const QChar * const end = p + frag->size_array[0];
     1173        while (p < end) {
     1174            switch(QChar::direction(p->unicode()))
     1175            {
     1176            case QChar::DirL:
     1177                return Qt::LeftToRight;
     1178            case QChar::DirR:
     1179            case QChar::DirAL:
     1180                return Qt::RightToLeft;
     1181            default:
     1182                break;
     1183            }
     1184            ++p;
     1185        }
     1186    }
     1187    return Qt::LeftToRight;
     1188}
     1189
     1190/*!
    11431191    Returns the block's contents as plain text.
    11441192
     
    14411489QTextBlock QTextBlock::next() const
    14421490{
    1443     if (!p)
     1491    if (!isValid())
    14441492        return QTextBlock();
    14451493
     
    14571505QTextBlock QTextBlock::previous() const
    14581506{
    1459     if (!p)
     1507    if (!isValid())
    14601508        return QTextBlock();
    14611509
  • trunk/src/gui/text/qtextobject.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    221221    QTextCharFormat charFormat() const;
    222222    int charFormatIndex() const;
     223
     224    Qt::LayoutDirection textDirection() const;
    223225
    224226    QString text() const;
  • trunk/src/gui/text/qtextobject_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qtextodfwriter.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    494494    if (format.hasProperty(QTextFormat::TabPositions)) {
    495495        QList<QTextOption::Tab> tabs = format.tabPositions();
    496         writer.writeStartElement(styleNS, QString::fromLatin1("style-tab-stops"));
     496        writer.writeStartElement(styleNS, QString::fromLatin1("tab-stops"));
    497497        QList<QTextOption::Tab>::Iterator iterator = tabs.begin();
    498498        while(iterator != tabs.end()) {
    499             writer.writeEmptyElement(styleNS, QString::fromLatin1("style-tab-stop"));
     499            writer.writeEmptyElement(styleNS, QString::fromLatin1("tab-stop"));
    500500            writer.writeAttribute(styleNS, QString::fromLatin1("position"), pixelToPoint(iterator->position) );
    501501            QString type;
     
    512512        }
    513513
    514         writer.writeEndElement(); // style-tab-stops
     514        writer.writeEndElement(); // tab-stops
    515515    }
    516516
     
    699699            writer.writeAttribute(foNS, QString::fromLatin1("padding-top"), pixelToPoint(padding));
    700700        if (format.bottomPadding() > 0)
    701             writer.writeAttribute(foNS, QString::fromLatin1("padding-top"), pixelToPoint(format.bottomPadding()));
     701            writer.writeAttribute(foNS, QString::fromLatin1("padding-bottom"), pixelToPoint(format.bottomPadding()));
    702702        if (format.leftPadding() > 0)
    703             writer.writeAttribute(foNS, QString::fromLatin1("padding-top"), pixelToPoint(format.leftPadding()));
     703            writer.writeAttribute(foNS, QString::fromLatin1("padding-left"), pixelToPoint(format.leftPadding()));
    704704        if (format.rightPadding() > 0)
    705             writer.writeAttribute(foNS, QString::fromLatin1("padding-top"), pixelToPoint(format.rightPadding()));
     705            writer.writeAttribute(foNS, QString::fromLatin1("padding-right"), pixelToPoint(format.rightPadding()));
    706706    }
    707707
  • trunk/src/gui/text/qtextodfwriter_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qtextoption.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    6666      d(0)
    6767{
    68     direction = QApplication::layoutDirection();
     68    direction = Qt::LayoutDirectionAuto;
    6969}
    7070
     
    146146    \sa tabArray(), setTabStop(), setTabs()
    147147*/
    148 void QTextOption::setTabArray(QList<qreal> tabStops)
     148void QTextOption::setTabArray(QList<qreal> tabStops) // Qt5: const ref
    149149{
    150150    if (!d)
     
    166166    \sa tabStops()
    167167*/
    168 void QTextOption::setTabs(QList<QTextOption::Tab> tabStops)
     168void QTextOption::setTabs(QList<QTextOption::Tab> tabStops) // Qt5: const ref
    169169{
    170170    if (!d)
     
    392392
    393393/*!
     394    \fn Tab::Tab(qreal pos, TabType tabType, QChar delim = QChar())
     395   
     396    Creates a tab with the given position, tab type, and delimiter
     397    (\a pos, \a tabType, \a delim).
     398
     399    \note \a delim is only used when \a tabType is DelimiterTab.
     400
     401    \since 4.7
     402*/
     403
     404/*!
    394405    \fn bool Tab::operator==(const Tab &other) const
    395406
  • trunk/src/gui/text/qtextoption.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    6969    struct Q_GUI_EXPORT Tab {
    7070        inline Tab() : position(80), type(QTextOption::LeftTab) { }
     71        inline Tab(qreal pos, TabType tabType, QChar delim = QChar())
     72            : position(pos), type(tabType), delimiter(delim) {}
    7173
    7274        inline bool operator==(const Tab &other) const {
     
    135137    uint wordWrap : 4;
    136138    uint design : 1;
    137     uint direction : 1;
    138     uint unused : 19;
     139    uint direction : 2;
     140    uint unused : 18;
    139141    uint f;
    140142    qreal tab;
  • trunk/src/gui/text/qtexttable.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    755755    p->beginEditBlock();
    756756
     757    QList<int> extendedSpans;
    757758    for (int i = 0; i < d->nRows; ++i) {
    758759        int cell;
     
    761762        else
    762763            cell = d->grid[i*d->nCols + pos];
    763         QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell);
    764         QTextCharFormat fmt = c->charFormat(it->format);
    765764        if (pos > 0 && pos < d->nCols && cell == d->grid[i*d->nCols + pos - 1]) {
    766765            // cell spans the insertion place, extend it
    767             fmt.setTableCellColumnSpan(fmt.tableCellColumnSpan() + num);
    768             p->setCharFormat(it.position(), 1, fmt);
     766            if (!extendedSpans.contains(cell)) {
     767                QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell);
     768                QTextCharFormat fmt = c->charFormat(it->format);
     769                fmt.setTableCellColumnSpan(fmt.tableCellColumnSpan() + num);
     770                p->setCharFormat(it.position(), 1, fmt);
     771                d->dirty = true;
     772                extendedSpans << cell;
     773            }
    769774        } else {
     775            /* If the next cell is spanned from the row above, we need to find the right position
     776            to insert to */
     777            if (i > 0 && pos < d->nCols && cell == d->grid[(i-1) * d->nCols + pos]) {
     778                int gridIndex = i*d->nCols + pos;
     779                const int gridEnd = d->nRows * d->nCols - 1;
     780                while (gridIndex < gridEnd && cell == d->grid[gridIndex]) {
     781                    ++gridIndex;
     782                }
     783                if (gridIndex == gridEnd)
     784                    cell = d->fragment_end;
     785                else
     786                    cell = d->grid[gridIndex];
     787            }
     788            QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell);
     789            QTextCharFormat fmt = c->charFormat(it->format);
    770790            fmt.setTableCellRowSpan(1);
    771791            fmt.setTableCellColumnSpan(1);
     
    916936        for (int c = pos; c < pos + num; ++c) {
    917937            int cell = d->grid[r*d->nCols + c];
    918             if (touchedCells.contains(cell))
    919                 continue;
    920             touchedCells << cell;
    921938            QTextDocumentPrivate::FragmentIterator it(&p->fragmentMap(), cell);
    922939            QTextCharFormat fmt = collection->charFormat(it->format);
    923940            int span = fmt.tableCellColumnSpan();
     941            if (touchedCells.contains(cell) && span <= 1)
     942                continue;
     943            touchedCells << cell;
     944
    924945            if (span > 1) {
    925946                fmt.setTableCellColumnSpan(span - 1);
  • trunk/src/gui/text/qtexttable.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qtexttable_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/gui/text/qzip.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    281281}
    282282
     283static QDateTime readMSDosDate(const uchar *src)
     284{
     285    uint dosDate = readUInt(src);
     286    quint64 uDate;
     287    uDate = (quint64)(dosDate >> 16);
     288    uint tm_mday = (uDate & 0x1f);
     289    uint tm_mon =  ((uDate & 0x1E0) >> 5);
     290    uint tm_year = (((uDate & 0x0FE00) >> 9) + 1980);
     291    uint tm_hour = ((dosDate & 0xF800) >> 11);
     292    uint tm_min =  ((dosDate & 0x7E0) >> 5);
     293    uint tm_sec =  ((dosDate & 0x1f) << 1);
     294
     295    return QDateTime(QDate(tm_year, tm_mon, tm_mday), QTime(tm_hour, tm_min, tm_sec));
     296}
     297
    283298struct LocalFileHeader
    284299{
     
    344359
    345360QZipReader::FileInfo::FileInfo()
    346     : isDir(false), isFile(true), isSymLink(false), crc32(0), size(0)
     361    : isDir(false), isFile(false), isSymLink(false), crc32(0), size(0)
    347362{
    348363}
     
    366381    crc32 = other.crc32;
    367382    size = other.size;
     383    lastModified = other.lastModified;
    368384    return *this;
     385}
     386
     387bool QZipReader::FileInfo::isValid() const
     388{
     389    return isDir || isFile || isSymLink;
    369390}
    370391
     
    404425    fileInfo.crc32 = readUInt(header.h.crc_32);
    405426    fileInfo.size = readUInt(header.h.uncompressed_size);
     427    fileInfo.lastModified = readMSDosDate(header.h.last_mod_file);
    406428}
    407429
     
    751773
    752774/*!
     775    Returns device used for reading zip archive.
     776*/
     777QIODevice* QZipReader::device() const
     778{
     779    return d->device;
     780}
     781
     782/*!
    753783    Returns true if the user can read the file; otherwise returns false.
    754784*/
     
    796826/*!
    797827    Returns a FileInfo of an entry in the zipfile.
    798     The \a index is the index into the directoy listing of the zipfile.
     828    The \a index is the index into the directory listing of the zipfile.
     829    Returns an invalid FileInfo if \a index is out of boundaries.
    799830
    800831    \sa fileInfoList()
     
    804835    d->scanFiles();
    805836    QZipReader::FileInfo fi;
    806     d->fillFileInfo(index, fi);
     837    if (index >= 0 && index < d->fileHeaders.count())
     838        d->fillFileInfo(index, fi);
    807839    return fi;
    808840}
     
    10231055
    10241056/*!
     1057    Returns device used for writing zip archive.
     1058*/
     1059QIODevice* QZipWriter::device() const
     1060{
     1061    return d->device;
     1062}
     1063
     1064/*!
    10251065    Returns true if the user can write to the archive; otherwise returns false.
    10261066*/
  • trunk/src/gui/text/qzipreader_p.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    5656//
    5757
     58#include <QtCore/qdatetime.h>
    5859#include <QtCore/qfile.h>
    5960#include <QtCore/qstring.h>
     
    6364class QZipReaderPrivate;
    6465
    65 class Q_AUTOTEST_EXPORT QZipReader
     66class Q_GUI_EXPORT QZipReader
    6667{
    6768public:
     
    7172    ~QZipReader();
    7273
     74    QIODevice* device() const;
     75
    7376    bool isReadable() const;
    7477    bool exists() const;
    7578
    76     struct Q_AUTOTEST_EXPORT FileInfo
     79    struct Q_GUI_EXPORT FileInfo
    7780    {
    7881        FileInfo();
     
    8083        ~FileInfo();
    8184        FileInfo &operator=(const FileInfo &other);
     85        bool isValid() const;
    8286        QString filePath;
    8387        uint isDir : 1;
     
    8791        uint crc32;
    8892        qint64 size;
     93        QDateTime lastModified;
    8994        void *d;
    9095    };
  • trunk/src/gui/text/qzipwriter_p.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    7070    ~QZipWriter();
    7171
     72    QIODevice* device() const;
     73
    7274    bool isWritable() const;
    7375    bool exists() const;
  • trunk/src/gui/text/text.pri

    r569 r846  
    3838        text/qzipreader_p.h \
    3939        text/qzipwriter_p.h \
    40         text/qtextodfwriter_p.h
     40        text/qtextodfwriter_p.h \
     41        text/qstatictext_p.h \
     42        text/qstatictext.h
    4143
    4244SOURCES += \
     
    6769        text/qcssparser.cpp \
    6870        text/qzip.cpp \
    69         text/qtextodfwriter.cpp
     71        text/qtextodfwriter.cpp \
     72        text/qstatictext.cpp
    7073
    7174win32 {
     
    146149        ../3rdparty/freetype/src/base/ftmm.c \
    147150        ../3rdparty/freetype/src/base/fttype1.c \
    148           ../3rdparty/freetype/src/base/ftbitmap.c\
     151        ../3rdparty/freetype/src/base/ftsynth.c \
     152        ../3rdparty/freetype/src/base/ftbitmap.c \
    149153        ../3rdparty/freetype/src/bdf/bdf.c \
    150154        ../3rdparty/freetype/src/cache/ftcache.c \
     
    211215    include($$QT_SOURCE_TREE/config.tests/unix/freetype/freetype.pri)
    212216    LIBS_PRIVATE += -lfreetype
    213 } else {
    214     DEFINES *= QT_NO_FREETYPE
    215217}
    216218
Note: See TracChangeset for help on using the changeset viewer.