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:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • 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
Note: See TracChangeset for help on using the changeset viewer.